#has_overlapping_bodies() not giving the right output when it should

1 messages · Page 1 of 1 (latest)

vital elk
#

Some context:
So I'm trying to make a building system equivalent to the one in stardew valley and I'm having a issue with a bug

How i do it:

to find where I'm placing something I use a marker2d with a texture and a area2d with a collision
the code to positioning the marker2d and its children:

func _physics_process(delta):

  mouse_pos = get_global_mouse_position()
  grid_pos = tilemap.local_to_map(mouse_pos)
  snapped_pos = tilemap.map_to_local(grid_pos)

  object_placer.global_position = snapped_pos
  object_placer_texture.global_position = snapped_pos

after this i run some code that creates a object on the snapped_pos and that code starts like this:

  var itemid = Global.current_held_item #is a int
  var object = load_item_data(itemid,"object") #is a bool false = item, true = object

  if Input.is_action_just_pressed("ui_interact"):
    if object == true:
      if marker_area.has_overlapping_bodies() == false:  #this is where the problem is
        #after this is the code that loads and instantiate the scene to make a object

The problem: (attached video should show it)
the problem is that if I move my mouse on top of a existing body (that's what the marker_area checking for) and click interact fast enough it still places a object even though there's a overlapping body but for some reason it doesn't detect it so if you do a frame perfect (I find it quite easy to be honest) button press i can place a object on top of a existing object

what I've tried to fix it:

  • I've tried using _process() instead of _physics_process()
  • I've tried making a bool variable for whether or not its inside a object and then making that variable update every frame, physics frame, on "func _input(Input):" and on "func _on_area_2d_body_entered()" (and exited)

if anyone know why doesn't detect that its on top of a different body immediately or even better know how to fix it would appreciate the help

vital elk
#

so after searching a litle (by a litle i mean ive in total spent ~8 hours on this bug) i found this in the docs

● bool has_overlapping_bodies() const

Returns true if intersecting any PhysicsBody2Ds or TileMaps, otherwise returns false. The overlapping body's CollisionObject2D.collision_layer must be part of this area's CollisionObject2D.collision_mask in order to be detected.

For performance reasons (collisions are all processed at the same time) the list of overlapping bodies is modified once during the physics step, not immediately after objects are moved. Consider using signals instead.

its the bottom paragraph
but when i use signals like this:

var marker_cell_already_occupied


func _on_area_2d_body_entered(body: Node2D) -> void:
    marker_cell_already_occupied = true

func _on_area_2d_body_exited(body: Node2D) -> void:
    marker_cell_already_occupied = false

and then changing the if statement "marker_area.has_overlapping_bodies()" with "marker_cell_already_occupied" it still doesnt work and then i get the bug where when moving fast between neighboring physic bodys sometimes it ends up as false when it should be true

loud bloom
#

Just to be on the safe side, is your tilemap is at (0, 0)?

vital elk
#

yes and has tiles that is 64x64

#

and the positions are in the midle

#

also a little more context ive tryed with a print(snapped_pos) and then a print(marker2d.globalpos) they match up and have been moved inside the tile it just hasnt updated it yet when i press the button

loud bloom
#

If your buildings and tiles are always grid aligned, you can check if tiles are occupied instead of using collisions altogether

vital elk
#

wdym if the tiles are occupied?

#

please elaborate

loud bloom
#

let's say you want to place a structure and the game determines it tries to place at cell (0, 3). So you check what is at cell (0,3) and if you find that it is empty, you allow to place the structure. If you find grass for example, you can still allow to place it but if you find a part of a different structure, you can forbid placing the new structure

vital elk
#

where does it store that bool? inside the tilemap or?

loud bloom
#

you can get which tile/cell is at the grid position and based on what tile it is you can do the check

#

iirc you maybe can add a property directly into tileset instead of having a function but im not fully sure

vital elk
#

yeah ive already got the grid_pos

#

wich is the tile cell coordiante like (0,3)

#

so what you mean is that i can somehow tell the tilemap "hey ive got coordinate is there something here" and it will reply either "yes sorry" or "no" after wich it places and i now make it say "yes sorry" for that cell?

loud bloom
#

so i've remember the part of storing custom data in tilemap

vital elk
#

ok that sounds like exactly what im looking for

loud bloom
#

and if you have 2x2 or 4x4 structure, you just check a larger area

vital elk
#

how about a 3x3?

#

i dont think ill go above 3x3 but ill def use 3x3 or 2x3 or some non rectangulare shapes

loud bloom
#

let's say you want to place 2x3 structure which top-left corner is at (0,3), so you would need to check (0,3), (1,3), (0, 4), (1, 4), (0, 5), (1, 5).

vital elk
#

yeah ok

#

a little different note here:

#

is it possiable to make some sort of template node

#

like i would make a node called object_root and whenever i make a new object i use it as well a root but then have it be uniqe for all objects, sort off

#

like i want to just be able to copy paste the code that is shared by almost all objects without having to copy paste it into every single objects script

#

so like having a node that is inside all objects that handles it or smth

#

im aware it was a bad explanation

loud bloom
#

It might work but I think that it can be done better if common script is a child instead of being a parent

vital elk
#

so a sibling to all the objects nodes?

#

like this?

vital elk
loud bloom
loud bloom
vital elk
loud bloom
vital elk
#

ok so i can just make some code saying the tiles that the players cornors covers arent buildable got it

#
#

shows exactly how to use custom build data and happens to do it almost with the sme purpose

#

could i make a script that on _ready() makes all tiles tiles with collision on top of it (im gonna use layers and masks for this ofc) be set to not buildable

#

im thinking this cus then when i make save files or change any preset objects in the game they are automaticly set

loud bloom
vital elk
#

yeah i mean kinda like what i had before but having it set the tile's data only on ready

vital elk
#

you caused me about 5 headaches but saved me from at least 20 tysm

#

it almost works as i want i just need to add some finishing touches

vital elk
#

so now i got it working (again tysm)
now i got the problem with the fact i want to be able to pick up objects and well idk how to detect if there is a object/what object there is

loud bloom
vital elk
#

i managed it by using a dictionary with the coords as a key and the objects id as the value so ive got a plant with that

#

also i manged to make a scene called object manager that makes all pre-existing objects tiles be set to the correct thing and add their id and coords to the dict