1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
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_material: StandardMaterial3D
@onready var red_material = preload("res://models/red_material.tres")
var mesh_ready = false
func _ready() -> void:
if gravity_enabled:
motion_mode = MotionMode.MOTION_MODE_GROUNDED
NavigationServer3D.connect("map_changed", map_changed)
original_material = $MeshInstance3D.get_active_material(0)
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():
$MeshInstance3D.set_surface_override_material(0, red_material)
$HitTimer.start()
func _on_level_generator_astar_created(in_astar: AStar3D) -> void:
astar = in_astar
has_astar = true
func _on_hit_timer_timeout() -> void:
$MeshInstance3D.set_surface_override_material(0, original_material)
$HitTimer.stop()
get_parent().remove_child(self)
queue_free()
|