Hi all,

I am new to Godot and game development more generally, though I have some background in statistical coding. I am attempting to create a game where resources will spawn in within a map, and a player will go around and collect them. I have a tilemaplayer with collisions set up with my player so that he can't run through walls, and I am not trying to instantiate the resource into a scene at a random location without overlapping the player or any walls.

I found some questions that suggested using an Area2D and checking has_overlapping_bodies() or areas, others that suggest using PhysicsShapQueryParameters2D, and more but haven't been able to get one to work.

Some background on the current organization of the game:
I have the Main scene, with a UserInterface that extends control and contains the main gameplay area in its own scene surrounded by HBoxContainers on each side. playarea is the main gameplay scene residing within UserInterface that is a center container, followed by a SubviewportContainer, SubViewport, and the Map TileMapLayer (which currently also houses the player scene in these early stages of building).

In the image below, you can see that the food item is spawning over the top of a wall that has a collision set up. The food collider is on layer 3, player on 2, tilemap on 1. Food masks 1 and 2, Player 1 and 3, and tilemap 2 and 3 so that shouldn't be the issue.

The GDscript on the SubViewport is below:

extends SubViewport

var FoodScene : PackedScene = preload("res://food.tscn")
var _food_collision : CollisionShape2D
var _food : Node
@onready var map : Node = $Map 

func _ready() -> void:
	ev.spawn_food.connect(_on_spawn_food)


func _on_spawn_food() -> void:
	var _food : Node = FoodScene.instantiate()
	map.add_child(_food)
	_food_collision = _food.get_child(0)
	var _food_val : int = 1
	_food.position = Vector2(500,500)
	print(_food.has_overlapping_bodies(),"bodies?")
	print(_food.has_overlapping_areas(),"areas?")
	_food.body_entered.connect(_on_food_body_entered.bind(_food_val,_food))
	

func _on_food_body_entered(body : Node, _food_val : int, _food : Node) -> void :
	if body.name == "Player":
		gv.food_resource += _food_val
		ev.food_updated.emit() 
		ev.food_consumed.emit()
		map.remove_child.call_deferred(_food)
		
		
func _physics_process(delta: float) -> void:
	if _food:
		print(_food.has_overlapping_bodies(),"bodies?")
		print(_food.has_overlapping_areas(),"areas?")

Here is the playarea scene to show you how things are setup:

I tried testing has_overlapping in both _physics_process and outside it, but they all return false. Is this because the position is being hardcoded rather than using move and slide or something? Eventually, once I have this working, I will want to be using a blank Area2D to run the check before actually spawning any food.

  • xyz replied to this.
    • Best Answerset by brmdvste

    brmdvste Collisions are tested once per frame. Try waiting for at least one physics tick between adding the area node to the scene and querying its overlap

    # add to scene here
    await get_tree().physics_frame
    # query overlap here
    • Best Answerset by brmdvste

    brmdvste Collisions are tested once per frame. Try waiting for at least one physics tick between adding the area node to the scene and querying its overlap

    # add to scene here
    await get_tree().physics_frame
    # query overlap here

      xyz
      Thank you, I think this will work for me in the main spawn function. Do you know why my code would fail while running in the _physics_process? I thought I would be getting around exactly the issue you describe by running there, but it was repeatedly printing a false result each frame.

      • xyz replied to this.

        brmdvste It doesn't matter where it runs. Collisions will be tested by the engine only after all of your script code for the current frame has been executed. So if you add something to the scene tree this frame, you cannot know if it collided or not until the next frame. There are ways to test immediately using PhysicsDirectSpaceState2D, but it's a little bit more involved as you need to construct a query via PhysicsShapeQueryParameters2D object where you "manually" supply a collision shape and its transform along other collision parameters.