Look_at not following vector in y axis (when jumping)

Godot Version

4.6.1

Question

I'm trying to code an enemy to do certain actions when they're looking at the player. I'm making a vision script for the enemy by making a collision cone to detect when the player is in front of them, and then do a raycast to look at the player. It's mostly working, with one problem - it doesn't follow the player up and down, i.e. when the player jumps. Here is the code:



func sight() -> void:
	var overlaps = $visioncone.get_overlapping_bodies()
	player_present = false
	if overlaps.size() > 0:
		for overlap in overlaps:
			if overlap.name == "Player":
				playerposition = overlap.global_position
				print(playerposition)
				player_present = true
		if player_present:
			$visionraycast.look_at(playerposition)
			$visionraycast.force_raycast_update()
			if $visionraycast.is_colliding():
				var collider = $visionraycast.get_collider()
				print(collider.name)


A couple of weird things are happening. First, when I print the playerposition, it is returning an accurate 3D vector (including a changing y value when I jump). Also, when I view the raycast in the debug options, it does follow the players feet in 3D (i.e. it looks down when the player is closer to the enemy and at a more horizontal angle when further away). However, when I jump, the raycast remains planted in the floor below the player. Even weirder, when I jump, the collider.name returns the wall behind the player rather than the floor! I think the problem is with look_at, and I have tried inserting the Vector3.UP as an argument and it doesn't change any behaviour. Any help appreciated, thank you!

look_at() aims the negative z axis. Ray in the raycast node points down the negative y axis by default.

Hm OK, so is there a way I can make it unconstrained in Y so it can also look up slightly as well as down?

If you want look_at() to aim your raycast properly, its ray direction should be -z instead of default -y.

Added to what was already explained, a common mistake is related to axis. When you want to look up or down, you rotate through X.

I see, thank you. I already have the raycast target position as 0, 0, -100 in the inspector, and I have tried passing $visionraycast.look_at(playerposition,Vector3.FORWARD) and $visionraycast.look_at(playerposition,Vector3.RIGHT) and still getting the same results. Then I tried $visionraycast.rotate_x(PI) before calling look_at and still got the same result, so I’m not entirely sure how to achieve what you’re describing. Sorry if I‘m being stupid, I’m quite new to this.

Enable debug-display of collision shapes to see where your raycast is aiming at runtime.

Aren’t you able to rotate first around UP and then around RIGHT?

I’ve had the debug display on the whole time and it’s behaviour has been consistent throughout - it looks at the player but seems unable to look above y=0 (relative to the raycast position).
And $visionraycast.rotate(Vector3.UP,PI) followed by $visionraycast.rotate(Vector3.RIGHT,PI) doesn’t change anything, either…

Also, you should break the loop when player is found. If something else is in the cone and it gets iterated over after the player, its position will override the player position previously stored in playerposition

If something else is in the cone and it gets iterated over after the player, its position will override the player position previously stored in playerposition

I might be missing something, but due to the “if” statement, that would only happen if the other object is named “Player”, wouldn’t it? I have tested this by running behind obstacles etc. and that part of the code seems fine, the raycast continuously tracks the player and returns the accurate playerposition, even with several other objects in the cone.

Can you post a video showing the ray at runtime.

Post the player scene structure.