simple change of condition logic made a bit more challenging it for player
func _physics_process(delta: float) -> void:
if not is_on_floor():
velocity.y -= gravity * delta
if player_is_visible():
navigation_agent_3d.target_position = player.global_position
var next_position = navigation_agent_3d.get_next_path_position()
var direction = global_position.direction_to(next_position)
look_at_target(direction)
velocity.x = direction.x * SPEED
velocity.z = direction.z * SPEED
else:
var next_position = navigation_agent_3d.get_next_path_position()
var direction = global_position.direction_to(next_position)
look_at_target(direction)
velocity.x = direction.x * SPEED
velocity.z = direction.z * SPEED
move_and_slide()
ok this could be further improved as I figure out the physic frame on first frame haven’t collided with wall
extends CharacterBody3D
@onready var navigation_agent_3d: NavigationAgent3D = $NavigationAgent3D
var gravity: float = 9.8
const SPEED = 5.0
var player
var game_ready = false
func _ready() -> void:
player = get_tree().get_first_node_in_group("Player")
await get_tree().physics_frame
await get_tree().physics_frame
game_ready = true
func _physics_process(delta: float) -> void:
if game_ready == true:
if not is_on_floor():
velocity.y -= gravity * delta
if player_is_visible():
navigation_agent_3d.target_position = player.global_position
var next_position = navigation_agent_3d.get_next_path_position()
var direction = global_position.direction_to(next_position)
look_at_target(direction)
velocity.x = direction.x * SPEED
velocity.z = direction.z * SPEED
else:
var next_position = navigation_agent_3d.get_next_path_position()
var direction = global_position.direction_to(next_position)
look_at_target(direction)
velocity.x = direction.x * SPEED
velocity.z = direction.z * SPEED
move_and_slide()
else:
pass
# Main Logic with raycast from NPC to Player (no offsets for now)
func player_is_visible() -> bool:
if player == null:
return false
var space_state = get_world_3d().direct_space_state
var from = global_position
var to = player.global_position
var query = PhysicsRayQueryParameters3D.create(from, to)
query.exclude = [self]
var result = space_state.intersect_ray(query)
if result.is_empty():
return true
else:
return result.collider == player
func look_at_target(direction: Vector3) -> void:
var adjusted_direction = direction
adjusted_direction.y = 0
if adjusted_direction.length_squared() < 0.0001:
return
look_at(global_position + adjusted_direction, Vector3.UP, true)