I currently spawn an enemy at a height I determined from dragging its scene into the viewport of the Editor, then using the Snap to Floor shortcut, and inspecting the transform. From there, I just declared a variable to that number.
Is there a function or variable already provided that I could use instead to say “Use the height in which the scene is sitting directly on top of the floor’s collision”?
I am not blocked or anything, it just feels odd to use a magic number like this. And, if I ever changed the size of this enemy scene’s collision, I would have to drag it out and “measure” again.
Thanks! Here is my current implementation:
func spawn_enemy_at_random_index():
var spawn_location: PathFollow3D = $"../SpawnPath/SpawnLocation"
spawn_location.progress_ratio = randf()
var new_instance: PackedScene = enemy_types.get("seeker")
var new_enemy: Seeker = new_instance.instantiate() as Seeker
new_enemy.connect("_on_death_occurred", check_remaining_enemies)
self.add_child(new_enemy)
new_enemy.global_position = Vector3(spawn_location.global_position.x, 1.014, spawn_location.global_position.z)
new_enemy.look_at(GlobalReferences.player_reference.global_position)
Never tried it but CollisionShape2D has a shape property which is Shape2D and that class has a get_rect() method for a representation of the shape’s boundary.
Perform a raycast query from the spawn position to a position below it, and then if you get a non empty result spawn your object at result["position"].
Either make sure the spawn position is above the floor or offset the raycast start position to be offset up a bit.
In my experience raycasts are cheap, I assume they’re much cheaper than the cost of more complex (than a line) shapes updating each tick.
Normally things are positioned at 0,0,0 and if it’s meant to be on the floor you offset the mesh and collision, so that the origin is at the “feet.” Otherwise the origin is the center.
If you have hundreds or thousands of casts to keep these things hovering off the ground and it’s starting to be a problem, you’d just “amortize” the cost by (example) giving NPCs random IDs and staggering costly actions with something like if 0==physics frame modulo npcID: update() (really depends on how you set up staggering.)
So what I have found is if I set the X and Y to the global position on my PathFollow3D node, and the Y to the position on the enemy scene itself, it will take the 1 meter offset into account.
I think for the purposes of my game, this will do. But I will definitely look into Raycasts if I have this problem in the future. I think that is the most straightforward path.