Instantiate a scene that is properly snapped to floor

Godot Version

v4.2.stable.mono.official [46dc27791]

Question

Hi all,

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.

1 Like

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.

1 Like

I will try both of these approaches, thank you!

Is there any concern for performance when using a raycast every half second of game time or so?

Oh folks, does it make sense to just visit the scene of this enemy, view it from the front, and raise it 1 unit?

Is this what folks usually do?

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.)

1 Like

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.

Not to draw this out, but one last thing: Is there no way to change the pivot point on a 3D node? Seems the only way is to re-parent: Change Anchor Point of 3D Object - #5 by thatblockypenguin

I could also just do as you said @neozuki and offset the mesh and collision.

Okay, my problem should be solved here. Thank you!

1 Like