This is Matt, the creator of Trainyard. @DMGregory summoned me here! :)
It sounds like you're working through the same issues I had to deal with. It's a tricky problem where there isn't necessarily a perfect solution.
One thing to consider is the constraints of the problem. I was targeting a 50mm wide screen on the early iPhones, and Apple's recommendation ...
I think you can solve the two pain points you indicated with a few heuristics.
One is a little hysteresis: once the player is drawing in a particular row/column, keep their drawing cursor locked in that row/column until their mouse/touch point strays more than ~30% of the way into the next row/column.
That gives more tolerance for error, so the player has ...
One of the creators of HAA* (a generalization of HPA*) wrote a very accessible article explaining how it works on aigamedev.com. Unfortunately that site seems to be dead, but fortunately archive.org has the article archived.
I highly recommend reading it, but to summarize: HPA* breaks the map into chunks. In each chunk, you identify the possible entrances/...
Some ways I've seen this solved:
Treat a collision as a failure state
Zachtronics games like SpaceChem and Opus Magnum commonly go this route. The player is challenged to create a program that does not lead to a conflict or collision, and causing one immediately halts execution. The player can then observe the problem, modify the program/machine to avoid it, ...
This is something that Wave Function Collapse as an algorithm is notoriously bad at doing. Because it's always making local decisions based on immediate neighbours, it's difficult to make any global guarantees.
At the level of individual tile neighbours, the tiles in the middle or at the edge of one giant open area look pretty much the same as the tiles in ...
I think you can solve such a problem by introducing simple priority rules or additional gameplay elements. You may see these as instances of suggestions by DMGregory, so I'm just building up additional ideas on top of his answer.
Collision as a failure, by design
Who goes first? Nobody.
When two robots attempt to move into the same cell, a race condition ...
As long as they don't differ too vastly, the ratio of sizes between the two cell types is largely irrelevant to me. I'd also happily use several rows of transitional tiles if their borders can be procedurally determined. I also have no inherent preference for up-point or side-point hexes...
This paragraph made me think of another, more universal solution: ...
This is useful for example when a large area attack is about to happen so Player would like to minimize damage.
Sounds like you're thinking of giving the player the option to specify formations, so other spacing options (like boids) won't work.
I have two ideas for you.
Manhattan distance from origin
What you have sounds good, but you could also try a less-...
I'll be referring as agent to the opponent controlled by the game. And agent controller to the code that, well, controls the agent.
You can have an abstraction for your agent controller, and still allow continuous movement. To do that, you would have code to translate between those representations.
That is, the agent controller would understand the game in ...
You can create a hexagonal pattern with square tiles by creating each logical tile from 2x2 technical tiles and then arranging them in a staggered pattern like this:
This might, however, require quite a lot of transition tiles. But if your engine allows tiles which are larger than the technical grid size, then you can design tiles like this:
Solved like this:
Vector3 lowerLeftTile = new Vector3(Mathf.Min(startPosition.x, endPosition.x), Mathf.Min(startPosition.y, endPosition.y));
Vector3 upperRightTile = new Vector3(Mathf.Max(startPosition.x, endPosition.x), Mathf.Max(startPosition.y, endPosition.y));
for (float x = lowerLeftTile.x; x <= upperRightTile.x; x++)
The solution was to use "A Fast Voxel Traversal Algorithm for Ray Tracing", as suggested by DMGregor, to trace a ray from/to "world" position instead of a grid cell's coordinate. I implemented the algorithm based on this site: https://www.flipcode.com/archives/Raytracing_Topics_Techniques-Part_4_Spatial_Subdivisions.shtml
Some of the ...
It's common for negative zero to behave in unintuitive ways. Complicating things, I wasn't able to find an official doc detailing what sort of behavior a programmer should expect from Godot regarding negative zero.
So the best suggestion I can offer is to special case -0 to behave as needed:
var tempX = int(round(position....
I manage to set up island indexes by flood filling the nodes, in different manner as i was attempting.
Here is the code for further reference:
private static int clusterIndex = 0;
private static bool[,] visited;
public static void FloodIslands()
int width = WorldGrid.Instance.nodeGrid.GetLength(0);
int height = WorldGrid.Instance.nodeGrid....
I would suggest that if your testers found it difficult to draw track shapes they wanted, this may have to do specifically with your using a 4-connected grid (of a certain coarseness of resolution).
Have you considered:
increasing the resolution of the grid, a finer grid giving the player more control over how the track is drawn, while keeping the tracks ...
Check if the cell in the direction of the largest component (in absolute value) is free.
If so, move there. Done.
Check if the cell in the direction of the smallest component (in absolute value) is free.
If so, check if the diagonal cell that's the sum of the two previous offsets checked is also free.
If so, move there. Done.
If not, move to the tile in ...