3D enemy stop doing anything the second I jump.

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Bri1216

Hi, I’ve been working on a FPS game and the enemy Ai stop working the second I’m in a different height or get too close. Here’s the code. I should add that the problem only occur with a long range enemy, melee enemies are unaffected. My guess is it has to do with sight angle and los.

 extends Character
onready var character_mover = $CharacterMover
onready var anim_player = $Graphics/AnimationPlayer
onready var health_mananger = $HealthManager
onready var aimer = $AimAtObject
var start_pos : Vector3
var start_facing_dir : Vector3
var nav 

enum STATES {IDLE, CHASE, ATTACK, DEAD}
var cur_state = STATES.IDLE

var player = null
var cur_target : Character
var path = []

export var sight_angle = 45.0
export var turn_speed = 360.0
#export var jump_timer = 2.0
export var attack_angle = 5.0
export var attack_range = 2.0
export var attack_rate = 0.5
export var attack_anim_speed_mod = 0.5
var attack_timer : Timer
var can_attack = true

signal attack
signal chase
signal death
var alive = true

func _ready():
	var navigation = get_tree().get_nodes_in_group("Navigation")[0]
	player = get_tree().get_nodes_in_group("player")[0]
	nav = navigation
	attack_timer = Timer.new()
	attack_timer.wait_time = attack_rate
	attack_timer.connect("timeout", self, "finish_attack")
	attack_timer.one_shot = true
	add_child(attack_timer)
	start_pos = global_transform.origin
	start_facing_dir = -global_transform.basis.z
	var bone_attachments = $Graphics/Armature/Skeleton.get_children()
	for bone_attachment in bone_attachments:
		for child in bone_attachment.get_children():
			if child is HitBox:
				child.connect("hurt", self, "hurt")
	
	health_mananger.connect("dead", self, "set_state_dead")
	health_mananger.connect("gibbed", $Graphics, "hide")
	character_mover.init(self)
	set_state_idle()

func _process(delta):
	match cur_state:
		STATES.IDLE:
			process_state_idle(delta)
		STATES.CHASE:
			process_state_chase(delta)
		STATES.ATTACK:
			process_state_attack(delta)
		STATES.DEAD:
			process_state_dead(delta)
	

func set_state_idle():
	cur_state = STATES.IDLE
	anim_player.play("idle_loop")

func set_state_chase():
	cur_state = STATES.CHASE
	anim_player.play("walk_loop", 0.2)
	emit_signal("chase")

func set_state_attack():
	cur_state = STATES.ATTACK

func set_state_dead():
	cur_state = STATES.DEAD
	anim_player.play("death")
	

func process_state_idle(delta):
	if can_see_player():
		set_state_chase()
		
func process_state_chase(delta):
	if within_dis_of_player(attack_range) or has_los_player():
		set_state_attack()
	var player_pos = player.global_transform.origin
	var our_pos = global_transform.origin
	path = nav.get_simple_path(our_pos, player_pos)
	var goal_pos = player_pos
	if path.size() > 1:
		goal_pos = path[1]

	var dir = goal_pos - our_pos
	dir.y = 0
	character_mover.set_move_vec(dir)
	face_dir(dir, delta)

func process_state_attack(delta):
	character_mover.set_move_vec(Vector3.ZERO)
	if can_attack:
		if !within_dis_of_player(attack_range) or !can_see_player():
			set_state_chase()
		elif !player_within_angle(attack_angle):
				face_dir(global_transform.origin.direction_to(player.global_transform.origin), delta)
				
		else:
			start_attack(delta)
			
		

func process_state_dead(delta):
	if character_mover.body_to_move.is_on_floor():
		$CollisionShape.disabled = true
		alive = false
		emit_death_signal()
		character_mover.freeze()

func hurt(damage: int, dir: Vector3):
	if cur_state == STATES.IDLE:
		set_state_chase()
	health_mananger.hurt(damage, dir)
	
func start_attack(delta):
	can_attack = false
	anim_player.play("attack", -1, attack_anim_speed_mod)
	attack_timer.start()
	aimer.face_point(player.global_transform.origin + Vector3.UP, delta)
	

func emit_attack_signal():
	emit_signal("attack")
	
func emit_death_signal():
	return true

func finish_attack():
	can_attack = true
	
func can_see_player():
	return player_within_angle(sight_angle) and has_los_player()
	
	
func player_within_angle(angle: float):
	var dir_to_player = global_transform.origin.direction_to(player.global_transform.origin)
	var forwards = global_transform.basis.z
	return rad2deg(forwards.angle_to(dir_to_player)) <= angle

func has_los_player():
	var our_pos = global_transform.origin + Vector3.UP
	var player_pos = player.global_transform.origin + Vector3.UP
	
	var space_state = get_world().get_direct_space_state()
	
	var result = space_state.intersect_ray(our_pos, player_pos, [], 1)
	if result:
		return false
	return true

func face_dir(dir: Vector3, delta):
	var angle_diff = global_transform.basis.z.angle_to(dir)
	var turn_right = sign(global_transform.basis.x.dot(dir))
	if abs(angle_diff) < deg2rad(turn_speed) * delta:
		rotation.y = atan2(dir.x, dir.z)
	else:
		rotation.y += deg2rad(turn_speed) * delta * turn_right
		

func alert(check_los=true):
	if cur_state != STATES.IDLE:
		return
	if check_los and !has_los_player():
		return
	set_state_chase()

func within_dis_of_player(dis: float):
	return global_transform.origin.distance_to(player.global_transform.origin) < attack_range
:bust_in_silhouette: Reply From: Bri1216

Someone on reddit helped me figured it out. I had to make a vision manager with a Vector math based functions. Also had to change how the state attack process work to not use a else statement. Probably gonna need to fine tune it some more but at least it can keep up with the player.