Grid level logic and real-time-physic?

Started by
8 comments, last by Angelic Ice 6 years, 9 months ago

Hello everyone!

In my last thread, I was all about serialising a grid-map and its running animation-processes. Now, the thread made think:

Is the grid-format really the right way to go?

The overall game is based on clicking-on-grids (every grid-slot contains a field, e.g. stone-field, to walk on etc.). Clicking a grid-slot may alter neighbours of the grid, too. That is why I decided to have an list/vector/.. to represent my grid. The issue is, that characters continuously move on the grid. If one clicks on a grid with a character on it, the interaction will be different. Additionally, if a character starts to move from grid 1 to 2, the consequences shall only apply once the character is actually in near of cause (stepping on a nail on grid 2).

What consequences? Imagine, the character starts walking, as every grid is larger than the character, it will take a while until the character crosses the border to grid 2. Multiple cases can occur:

The earth-field in grid-slot 2 might fall down into the void. The consequence would be: The character falls down once they cross the border to grid-slot 2. Another consequence could be an obstacle that hurts the character upon collision. It would look weird, if the obstacle is very small and the character gets damaged just after crossing the border. E.g. a nail. The damage to the character should be applied, once the character actually steps on it. Nonetheless, every obstacle might disappear just a few centimetres before colliding. Vanished fields might reappear, nails dis/appear.

Now, what options do I have? I would like to be able to build the level in a grid-logic. Selecting a field-type (e.g. stone) and inserting them into a grid-slot, then placing an object (character, enemy, ...) onto them.

At the moment I handle this by having a z-axis, representing the height, e.g. ground being 1, things on a grid being 2.

Simply: I want to keep the grid-feeling (especially for editing/creating levels in a grid), but interactions (collision etc.) shall be bound to hit-boxes, to provide a kind of real-time-feeling. I saw grid-games, that simply decide the logic/consequences just before transitioning to the next grid-slot, but that is too early for my needs. Doing a full 3d world feels overkill, as the presented logic is still provided in grids.

Hopefully my explanation of my issue was understandable enough, I'm not really sure myself, haha. Anyway, thanks for your time : )

 

Advertisement

There's no reason why you couldn't have both. If you have your grid of stuff, then assuming all of your entities (like nails) are placed in the centre of each tile, you can easily calculate the actual coordinates of the entity: If your nail is on tile (m, n), then its coordinates are x = tile_width * m + tile_width / 2, y = tile_height * n + tile_height / 2 – this is the centre of the nail's bounding rectangle.

Now if you also have the coordinates of the player, you can easily do your collision checking. In fact, your player can only be on at most two tiles at once (when it's at the border between two tiles), which simplifies your collision checking significantly – you only check for collisions on the tiles the player is overlapping with.

Since you want to be able to move your player in a continuous manner, you'll probably want to represent its location either directly in coordinates (and then calculating the tile it's on from those coordinates), or as the tile + offset within the tile. This of course applies to anything else that's allowed to move continuously in your world.

In other words, have a grid representation that you'll use for interacting with the world with each tile having a list of entities that are located on it (so that you can do something to those entities when you click the tile or when the tile falls into the void or whatever), and also have continuous Euclidean coordinates for collisions and rendering things on screen.

With this approach, you'll have to do some thinking about entities that can stand inbetween tiles – i.e. chiefly the player. Concretely, you'll need to consider the question of which tile the entity is on – is it on the original tile until it moves completely onto the other one? Does it switch exactly halfway through? Is it on both tiles at the same time for a brief period of time? This depends on the results you want to achieve – if the player is halfway between tiles and one of the tiles dispappears, does the player die? It also affects how you process things – if let's say you drop a bomb on a tile that damages all entities within a 5-tile radius, you want to process each entity only once – if an entity is simultaneously registered on two tiles, you'll have to set some flag to make sure you don't process it twice. If it can only ever be registered on one tile, then you don't have to worry.

It sounds to me as though the grid is really only used to place tiles and discretize player movement. Other than that, everything else can be done in continuous 2D coordinates. In other words, the grid is used as a constraint, but not necessarily as an actual model.

For instance, when the player clicks on position (x,y), you determine that location to be inside tile (m,n), and translate the action to "move to the center of (m,n)". When you create the level and say that a grass tile exists at tile (a,b), that can be translated to position (z,w) based on the size of tiles. However the grid in these cases is really only used as a tool to guide level creation and constrain movement. The rest of your logic doesn't have to know this grid exists at all, and can just operate in traditional 2D space.

If you really want to define key bits of game behaviour in the continuous domain, such as using hit-boxes for collisions, then I think Zipster's approach of "continuous, but quantized" is the way to go. You need functions to be able to convert from continuous space to the middle/edges of a tile, and vice versa, and then you can use whatever logic makes sense in each case.

But, previous caveats in other threads about the 'true' game state apply. If your game requires that the characters start and finish on grid boundaries then you don't want to be serialising the continuous in-between states unless you are absolutely 100% totally sure that you have a robust mechanism for ensuring that they will reach the destination grid boundary after you reload.

Thanks a lot for the delighting input!

One important operations with the grid-system would be clicking on one grid-slot and being able to find neighbours in a reliable and quick manner of course. That means, every grid-field, as a grass-tile or stone one, is capable of knowing their neighbours.

I think, in a real 2d-field, I would have to keep grid-coordinates as well and then simply convert them to possible grid-neighbour-tiles?

Edit: Forgot to add, that one grid should be able to identify currently "attached" objects, as in, what object stands on me? But I think that is easy to add anyway.

 

 

1 hour ago, Angelic Ice said:

Thanks a lot for the delighting input!

One important operations with the grid-system would be clicking on one grid-slot and being able to find neighbours in a reliable and quick manner of course. That means, every grid-field, as a grass-tile or stone one, is capable of knowing their neighbours.

I think, in a real 2d-field, I would have to keep grid-coordinates as well and then simply convert them to possible grid-neighbour-tiles?

Edit: Forgot to add, that one grid should be able to identify currently "attached" objects, as in, what object stands on me? But I think that is easy to add anyway.

It's entirely acceptable (and virtually necessary) to maintain multiple models and representations of your game world for different gameplay or engine components that need to see and interact with the world in different ways. For instance, a list of tiles works well for field placement (stone, grass, etc.) and general pathfinding, while continuous 2D coordinates work best for collision, rendering, physics, etc. As long they're kept in sync, or the data you need can be easily derived, everything is happy.

Instead of trying to bend your logic to work around the limitations of any particular view, you simply have multiple views that you keep in sync. It moves the burden from your game code to your "sync" code, which is another problem that has to be solved, but typically this code can be written in an abstract, non-game-specific manner that makes it highly reusable.

Take a graphics library as an example. It doesn't know anything about your "game", it only sees the world as a hierarchical scene comprised of nodes, meshes, lights, etc. It's the job of your game engine to build this scene based on the specifics of your game and keep it updated as the game world changes (update transforms, visibility, etc.). This is some extra work, however the process of converting "game objects" to "graphics objects" can usually be abstracted and generalized to a point where you can reuse the process for any number of games, truly limiting the amount of rework you have to do per-game to actual, game-specific logic.

Thanks : ) I decided to go with a complete 2d-physics-system with a "grid-interface" to access grid-slots.

Thanks a lot! I decided to go with a real 2d game-field and leverage a grid-interface to guarantee accessing and placing the right grid-slots.

There is only one question, I thought about assigning every moving (and static) entity's bounding box to all grid-slots on which they stand in order to simplify collision detection. I'm running a quad-tree for my GUI, not sure if that is a suitable solution for a grid-imitating field though, as I do not seek to have a maximum bucket capacity - one grid is one quad with no further quads.

My grid-slots are isometric, if that matters. Are there already know data structures to handle such?

I mean if there is no other solution, I would just implement my own isometric quad-tree that does not add further quad-trees : )

 

 

Seems odd to use a quad-tree when you already have a grid right there, ready to be used. Both are essentially spatial partitioning structures, after all.

True, I should probably just check upon every pixel-motion, on which grids the current entity is and then check against others that are currently on that grid, too. Thanks a lot!

 

This topic is closed to new replies.

Advertisement