extends CharacterBody3D ## Speed of enemy @export var speed: float = 2.0 ## Target for enemy to follow @export var target: Node3D ## Whether to use gravity on enemy @export var gravity_enabled: bool = true ## Use nav mesh or dumb path finding @export var use_nav_mesh: bool = true @onready var nav_agent: NavigationAgent3D = $NavigationAgent3D var has_astar: bool = false var astar: AStar3D var tar_vec: Vector3 var gravity : float = ProjectSettings.get_setting("physics/3d/default_gravity") var original_color: Color var mesh_ready = false func _ready() -> void: if gravity_enabled: motion_mode = MotionMode.MOTION_MODE_GROUNDED NavigationServer3D.connect("map_changed", map_changed) func map_changed(_rid): print("Map changed") mesh_ready = true func chase_target(delta: float) -> void: var target_pos = target.position var direction = (target_pos - position).normalized() if direction: velocity.x = direction.x * speed velocity.z = direction.z * speed else: velocity.x = move_toward(velocity.x, 0, speed) velocity.z = move_toward(velocity.z, 0, speed) if not is_on_floor() and gravity_enabled: velocity.y -= gravity * delta move_and_slide() func update_target_location(target_location: Vector3): nav_agent.target_position = target_location func chase_nav_mesh(delta: float): if not mesh_ready: return if target != null: update_target_location(target.global_position) var current_location = global_transform.origin var next_location = nav_agent.get_next_path_position() var new_velocity = (next_location - current_location).normalized() * speed #print("Target is ", next_location) # We only want to navigate on XZ plane new_velocity.y = 0 velocity = velocity.move_toward(new_velocity, .25) if not is_on_floor() and gravity_enabled: velocity.y -= gravity * delta else: velocity.y = 0 move_and_slide() func _physics_process(delta: float) -> void: if target == null: return if Input.is_action_pressed("ui_right"): return if use_nav_mesh: chase_nav_mesh(delta) return if not has_astar: # Just try to chase player directly chase_target(delta) return var target_pos = target.position var closest_me = astar.get_closest_point(position) var closest_target = astar.get_closest_point(target_pos) var direction: Vector3 if closest_me == closest_target: direction = (target_pos - position).normalized() else: var target_path = astar.get_point_path(closest_me, closest_target) if len(target_path) >= 2: direction = (target_path[1] - position).normalized() if direction: #velocity.x = move_toward(velocity.x, direction.x * speed, 10.0 * delta) #velocity.z = move_toward(velocity.z, direction.z * speed, 10.0 * delta) velocity.x = direction.x * speed velocity.z = direction.z * speed else: velocity.x = move_toward(velocity.x, 0, speed) velocity.z = move_toward(velocity.z, 0, speed) move_and_slide() func on_hit(_hit_position: Vector3) -> void: if $HitTimer.is_stopped(): var material: StandardMaterial3D = $MeshInstance3D.get_active_material(0) original_color = material.albedo_color material.albedo_color = Color(1.0, 0.0, 0.0, 1.0) $HitTimer.start() func _on_level_generator_astar_created(in_astar: AStar3D) -> void: astar = in_astar has_astar = true func _on_hit_timer_timeout() -> void: var material: StandardMaterial3D = $MeshInstance3D.get_active_material(0) material.albedo_color = original_color $HitTimer.stop()