0 votes

My entity node structure is:

enter image description here

My game is 2D, topdown, grid based and my goal is to handle collisions using the ID's of the entity instead of having a ton of area2d's and what not. enter image description here
If the bear and zombie meet on adjacent tiles the attack animation will start.

Godot version godot 3.4.2
in Engine by (26 points)
edited by

2 Answers

+1 vote
  1. You need to have a dictionary of tile position : tile content for every tile.

    var tiledata = {Vector2(0,0) : -1, Vector2(0,1) : empty,............. }

  2. You need to code a method to recognize a tile during interaction
    for example
    targettile = startingtile + movement direction
    or check surrounding tiles within a square.

  3. You need to check the contents of targettile in relation to content of startingtile and design IF statement for corrent interaction, for example :

    if tiledata[startingtile] == 1 and tiledata[targettile] == 2 :
    animation.play()

important thing is to design when grid is supposed to check for interaction. Obviously it cannot happen in process(). There must be a queue, an order to grid events, for example : whenever button is pressed grid checks if there will be an interaction with a wall, and only if there is no wall grid changes, and checks for surrounding tiles for additional interaction, and turn ends.
If You need a method to check tiles around a square range, just search it on this site, I have been answering this question a lot lately

by (7,447 points)

tilemap alone is only good for very stiff movement, like tic tac toe or classic ASCII roguelikes. If You want any visual aesthetics You shouldn't go this way.
You need to combine tilemap functionality with dynamic collisions, and it will not be buggy. Imagine something like this :

On entitity colliding with another entity :
       if checksurroundingtiles() detects empty walkable tiles around :
               change movement direction towards one random detected walkable tile

This way You don't have to rely on physics processing and buggy slide movement, but use singular properties of physics engine to enforce stable moevement rules

What movement behavior do You have in mind ?

Okay, then I will reimplement the collision handling with a kinematic body. The behavior is actually pretty simple if a bear collides with a zombie then start the attack attack animation and have them attack each other until one dies. I don't even need to check for surrounding tiles.

But You may want them to approach each other in a way they stay in their tiles, not overlapping. So You will need check of surrounding tiles to detect future collision and make entity wait or go. You will also need tile detection to predict collision with unwalkable tile, so entity may take a turn before it collides and it won't jitter into a wall

How would I be able to have them stay in their tiles and not overlap? Do you think some sort of line of sight algorithm would be good too?

Whenever your entity starts moving towards a direction, it can update its position in your stabledata for the future tile. So whenever another entity is going to approach a new tile, it will check stabledata if it can move to this position ( is there a wall, or is there another entity just walking into it ). If it detects another entity coming, it can wait in the center of its tile, until another entity reaches the center of its tile, and then both play the animation.

You might have seen something similar in old RTS like warcraft2. When 2 units collide in ugly angle, one of them makes a little stop, another one positions itself in fixed distance. This is also a system of a quare tilemap working with collision physics

+1 vote

Inces awnser is spot on, these are just some tips to go along.

First of all, if you need to hold more info per tile (for example, has zombie and is water) consider having other dictionaries (like a json) or arrays as values like so:

var grid : Dictionary = {
    Vector(0,0) : {
        object : zombie,
        terrain : forest,
        has_trap : true,
        walkable: false
        }
    Vector(1,0) : {
        object : wall,
        terrain : grass,
        has_trap : false,
        walkable : false
        }
    ...
}

One advtange of doing this, is that when you later start to code all the logic, for example, if you can walk in the tile or not, you dont have to check if it has a bear, a shark, a castle, etc.. you just check for example, if grid[Vector(x,y)].walkable.

Aside from that, how to to do the checks, and how to change info is 100% dependant on your game, and up to you. For example if a "fight" has to happen always that 2 units end up one next to the other, I would do this:

first, I would put in the object key, an actuall class or node that represents the entity. The important thing is to be able to check if the object is of type say "unit". You also could have a setter function in the grid var, in order to trigger checks when the grid is changed (you could also do the checks based on player input for example). Then i would do this:

func get_neighbors(tile_pos) -> Array:
    # this returns an array holding the 4 neighbors of the given tile

func has_unit(tile_pos) -> bool:
    # returns true if the object value is of type unit

func should_battle(tile_pos) -> bool:
    for tile in get_neighbors(tile_pos):
        if has_unit(tile):
            # trigger the fight 

In this example you would check for should_battle()after a unit moves, using of course the position the unit moved to.

Last advice, making this types of games involves a lot of logic, so they could be quite daunting. I have great love for them though, so if you too, power on!

by (418 points)

Hey Pomelo! Thank you for sharing your knowledge! Just like with Inces, I forgot to mention that my entities are not bound by player movement instead they just move until they hit a wall and change direction based on it. So in the grid dict above, would I have to loop over all the positions and update their object key? Thank you for the extra push I will power on!

Hey, no prob! No you wouldnt need to loop over the dict to change its values. If you are not familiar with dicts, I would recomend reading the Documentation. In summary you just do grid[Vector2(x,y)].object = zombie if you want a zombie at x, y

Of course if the zombie was at, say i, j, before moving, you would also need to do grid[Vector2(i,j)].object = null. Here is when you need to start making lots of functions like for example func move_entity(start_pos, end_pos) that deals with everything that needs to be dealth with when moving a unit (like setting "walkable" to true or false). Then you also need to make other functions to make the "IA" decide in which direction to move, and until what point, etc...

As I said, its quite a bit haha

Ah I see, I will definitely read up the documentation this weekend. Thanks again!

Hey, reading your comment on inces awnser, I understand you have multiple units moving at the same "time". If thats the case, I would suggest having a tick system (like a global counter that goes up), where esentially everything in the world knows when a tick has passed and then they do something. To avoid having a mess with multiple stuff moving around, I would have them act in "turns" (you would still see everything happening at the same time, but in the logic, two different units wont move and ocupy a same tile). In order to do this, when a tick advances, it triggers a, for example, do_turn() in every unit. you could have the units in an array and do:

func _on_tick_up():
    for unit in units:
        unit.do_turn()

I dont know the details of your game, but if you are dealing with grid movement and interactions, and in the mean time there is no player input, you wouldnt need to be checking stuff every frame, so no real need to use _procces()

Hey pomelo, do you think it would be a better idea to create separate scenes for tiles instead of using the tilemap?

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.