pretty happy with basic AI behavior

This commit is contained in:
derek
2025-04-29 11:02:12 -05:00
parent ccb4781460
commit a287710a7b
10 changed files with 86 additions and 75 deletions

View File

@@ -1,4 +1,4 @@
[gd_scene load_steps=12 format=3 uid="uid://cfaydhd6u5bmb"]
[gd_scene load_steps=15 format=3 uid="uid://cfaydhd6u5bmb"]
[ext_resource type="Script" uid="uid://bkii8jwf0k7tq" path="res://scripts/LevelManager.gd" id="1_wa46b"]
[ext_resource type="PackedScene" uid="uid://24slv0pyxcd5" path="res://assets/level_bounds.tscn" id="2_a2a5u"]
@@ -9,13 +9,23 @@
[ext_resource type="PackedScene" uid="uid://c7dhavrt11u55" path="res://enemy_spawner.tscn" id="6_5u3xe"]
[ext_resource type="PackedScene" uid="uid://drwae3loscbw7" path="res://assets/player.tscn" id="7_540vx"]
[ext_resource type="PackedScene" uid="uid://dvmqvjrnt4sgh" path="res://respawn_enemies_button.tscn" id="7_i7wgr"]
[ext_resource type="Material" uid="uid://bb0beroi2p3gd" path="res://assets/materials/FrostedGlass.tres" id="7_t6ubg"]
[sub_resource type="BoxShape3D" id="BoxShape3D_t6ubg"]
size = Vector3(92.25, 82.386, 76.6396)
[sub_resource type="NavigationMesh" id="NavigationMesh_wa46b"]
vertices = PackedVector3Array(-19.5, 1, 0, -5, 1, 0, -4.75, 1, -1.5, -2.75, 1, -19.5, -19.5, 1, -19.5, -2.75, 1, -1.5, 2.75, 1, -1.5, 3, 1, -19.5, 5.75, 1, -1.25, 19.5, 1, -1.5, 19.5, 1, -19.5, 6.25, 1, 11.25, 4.5, 1, 11.5, 4.5, 1, 19.5, 19.5, 1, 19.5, 6.25, 1, -1, -4, 4.5, -0.5, -4, 4.5, 0.5, 3, 4.5, 0.5, 3, 4.5, -0.5, -3.75, 1, -0.25, -3.75, 1, 0.25, 3, 1, 0.25, 3, 1, -0.25, 4, 5, -0.25, 4, 5, 10.5, 5.25, 5, 10.5, 5.25, 5, -0.25, 3, 1, 11.25, 3, 1, 1.5, -4.75, 1, 1.5, -19.5, 1, 19.5, 4.25, 1, 1.5, 4.25, 1, 10.25, 5, 1, 10.25, 5, 1, 1.25)
polygons = [PackedInt32Array(1, 0, 2), PackedInt32Array(2, 0, 4), PackedInt32Array(2, 4, 3), PackedInt32Array(3, 5, 2), PackedInt32Array(5, 3, 6), PackedInt32Array(6, 3, 7), PackedInt32Array(8, 6, 9), PackedInt32Array(9, 6, 7), PackedInt32Array(9, 7, 10), PackedInt32Array(12, 11, 13), PackedInt32Array(13, 11, 14), PackedInt32Array(15, 8, 9), PackedInt32Array(15, 9, 11), PackedInt32Array(11, 9, 14), PackedInt32Array(19, 18, 16), PackedInt32Array(16, 18, 17), PackedInt32Array(23, 22, 20), PackedInt32Array(20, 22, 21), PackedInt32Array(27, 26, 24), PackedInt32Array(24, 26, 25), PackedInt32Array(28, 12, 13), PackedInt32Array(30, 29, 28), PackedInt32Array(0, 1, 30), PackedInt32Array(28, 13, 30), PackedInt32Array(30, 13, 0), PackedInt32Array(0, 13, 31), PackedInt32Array(33, 32, 34), PackedInt32Array(34, 32, 35)]
vertices = PackedVector3Array(-19.5, 1, 0, -5, 1, 0, -4.75, 1, -1.5, -2.75, 1, -19.5, -19.5, 1, -19.5, -2.75, 1, -1.5, 2.75, 1, -1.5, 3, 1, -19.5, 5.75, 1, -1.25, 19.5, 1, -1.5, 19.5, 1, -19.5, 6.25, 1, 11.25, 4.75, 1, 11.5, 4.75, 1, 19.5, 19.5, 1, 19.5, 6.25, 1, -1, -4, 4.5, -0.5, -4, 4.5, 0.5, 3, 4.5, 0.5, 3, 4.5, -0.5, -3.75, 1, -0.25, -3.75, 1, 0.25, 3, 1, 0.25, 3, 1, -0.25, 4, 5, -0.25, 4, 5, 10.5, 5.25, 5, 10.5, 5.25, 5, -0.25, -19.5, 1, 12, -8.75, 1, 12, -8.5, 1, 11.25, -5, 1, 1, -6, 1, 10.75, -4.5, 1, 1.5, 4.25, 1, 1.5, 4.25, 1, 10.25, 5, 1, 10.25, 5, 1, 1.25, 3, 1, 10.75, 3, 1, 1.5, -8.25, 1, 12.25, -8.5, 1, 18.25, -9.5, 1, 18.5, -9.5, 1, 19.5, 3.25, 1, 11.5, -10, 4, 13.25, -9.75, 4, 17.5, -9.25, 4, 13.5, -9.25, 4, 13, -19.5, 4, 13, -10.75, 1, 18.25, -19.5, 1, 19.5, -10.75, 1, 14.25, -19.5, 1, 14.25)
polygons = [PackedInt32Array(1, 0, 2), PackedInt32Array(2, 0, 4), PackedInt32Array(2, 4, 3), PackedInt32Array(3, 5, 2), PackedInt32Array(5, 3, 6), PackedInt32Array(6, 3, 7), PackedInt32Array(8, 6, 9), PackedInt32Array(9, 6, 7), PackedInt32Array(9, 7, 10), PackedInt32Array(12, 11, 13), PackedInt32Array(13, 11, 14), PackedInt32Array(15, 8, 9), PackedInt32Array(15, 9, 11), PackedInt32Array(11, 9, 14), PackedInt32Array(19, 18, 16), PackedInt32Array(16, 18, 17), PackedInt32Array(23, 22, 20), PackedInt32Array(20, 22, 21), PackedInt32Array(27, 26, 24), PackedInt32Array(24, 26, 25), PackedInt32Array(30, 29, 28), PackedInt32Array(31, 30, 1), PackedInt32Array(1, 30, 28), PackedInt32Array(1, 28, 0), PackedInt32Array(33, 32, 31), PackedInt32Array(31, 32, 30), PackedInt32Array(35, 34, 36), PackedInt32Array(36, 34, 37), PackedInt32Array(39, 38, 33), PackedInt32Array(33, 38, 32), PackedInt32Array(29, 30, 40), PackedInt32Array(40, 30, 32), PackedInt32Array(42, 41, 43), PackedInt32Array(43, 41, 13), PackedInt32Array(44, 12, 13), PackedInt32Array(40, 32, 41), PackedInt32Array(41, 32, 38), PackedInt32Array(41, 38, 44), PackedInt32Array(41, 44, 13), PackedInt32Array(48, 47, 45), PackedInt32Array(45, 47, 46), PackedInt32Array(48, 45, 49), PackedInt32Array(42, 43, 50), PackedInt32Array(50, 43, 51), PackedInt32Array(52, 50, 53), PackedInt32Array(53, 50, 51)]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_t6ubg"]
transparency = 1
albedo_color = Color(1, 1, 1, 0.14902)
roughness = 0.1
refraction_enabled = true
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_sdike"]
albedo_color = Color(1, 1, 1, 0.211765)
[node name="AI Test Scene" type="Node3D"]
script = ExtResource("1_wa46b")
@@ -56,6 +66,19 @@ use_collision = true
size = Vector3(2.18811, 5.13403, 11.5242)
material = ExtResource("4_t6ubg")
[node name="CSGBox3D4" type="CSGBox3D" parent="NavigationRegion3D"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -14.3731, 1.5141, 13.0335)
use_collision = true
size = Vector3(11.0513, 4.0282, 1)
material = SubResource("StandardMaterial3D_t6ubg")
[node name="CSGBox3D5" type="CSGBox3D" parent="NavigationRegion3D"]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -9.57032, 1.56372, 15.2494)
material_override = ExtResource("7_t6ubg")
use_collision = true
size = Vector3(5.10229, 4.0282, 1)
material = SubResource("StandardMaterial3D_sdike")
[node name="Level" type="Node3D" parent="."]
script = ExtResource("5_sdike")
start_enemies = 1

View File

@@ -871,7 +871,6 @@ initial_state = NodePath("Idle")
[node name="Idle" type="Node" parent="StateMachine" node_paths=PackedStringArray("enemy")]
script = ExtResource("7_cwyr0")
enemy = NodePath("../..")
can_see = true
[node name="Stunned" type="Node" parent="StateMachine" node_paths=PackedStringArray("stunned_stars", "enemy")]
script = ExtResource("8_wpql0")
@@ -887,7 +886,6 @@ metadata/_custom_type_script = "uid://dhxolagi0b5s1"
script = ExtResource("10_gicen")
alarm_sound = NodePath("../../AUIDO/Alarm")
enemy = NodePath("../..")
can_see = true
[node name="Reload" type="Node" parent="StateMachine" node_paths=PackedStringArray("reload_sound", "enemy")]
script = ExtResource("11_ekglj")
@@ -983,11 +981,6 @@ top_level = true
target_position = Vector3(0, 0, -50)
collision_mask = 5
[node name="SpiderLookNext" type="RayCast3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.00161432, 1.62046, 0.00134204)
target_position = Vector3(0, 0, -50)
collision_mask = 5
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
root_node = NodePath("../Icosphere_002")
libraries = {

View File

@@ -15,6 +15,7 @@ var visibility_timer
func Enter():
super()
enemy.cache_player_pos()
visibility_timer = time_before_losing_visual
update_waypoint()
enemy.turret_material.emission_enabled = true
@@ -31,6 +32,8 @@ func current_target():
return enemy.point_of_interest
func Update(delta):
enemy.cache_player_pos()
if !enemy.is_player_visible():
if visibility_timer > 0:
visibility_timer -= delta
@@ -73,9 +76,7 @@ func Physics_Update(delta):
var direction = local_destination.normalized()
if enemy.global_position.distance_to(local_destination) > 1:
enemy.velocity = direction * move_speed
enemy.spider_look_next.look_at(destination)
var look_target = enemy.spider_look_next.global_rotation.y
enemy.global_rotation.y = lerp(enemy.global_rotation.y,look_target,delta * 3)
enemy.global_rotation.y = rotate_to_face2D(enemy,move_target(),delta,turret_speed)
func attack():
fire(enemy.barrel_1)

View File

@@ -55,10 +55,4 @@ func Physics_Update(delta : float):
var direction = local_destination.normalized()
if enemy.global_position.distance_to(local_destination) > 1:
enemy.velocity = direction * idle_speed
enemy.spider_look_next.look_at(destination)
var look_target = enemy.spider_look_next.global_rotation.y
enemy.global_rotation.y = lerp(enemy.global_rotation.y,look_target,delta * 3)
if enemy.turret_look.is_colliding() and enemy.turret_look.get_collider() is Player:
Transitioned.emit(self,"attack")
enemy.global_rotation.y = rotate_to_face2D(enemy,destination,delta,turret_speed)

View File

@@ -21,8 +21,8 @@ func Exit():
enemy.servo_single.play()
func update_waypoint():
var direction = (player.global_position - enemy.global_position).normalized()
enemy.nav_agent.set_target_position(direction * run_distance)
#var direction = (player.global_position - enemy.global_position).normalized()
enemy.nav_agent.set_target_position(move_target())
func Update(delta):
if heartbeat > 0:
@@ -39,7 +39,7 @@ func Update(delta):
func Physics_Update(delta):
enemy.turret_look_next.look_at(player.global_position)
enemy.turret_look_next.look_at(move_target())
enemy.turret_look.rotation = lerp(enemy.turret_look.rotation,Vector3(deg_to_rad(90),0,0),delta * enemy.turret_look_speed)
var destination = enemy.nav_agent.get_next_path_position()
@@ -47,15 +47,13 @@ func Physics_Update(delta):
var direction = local_destination.normalized()
if enemy.global_position.distance_to(local_destination) > 1:
enemy.velocity = direction * move_speed
enemy.spider_look_next.look_at(player.global_position)
var look_target = enemy.spider_look_next.global_rotation.y
enemy.global_rotation.y = lerp(enemy.global_rotation.y,look_target,delta * body_turn_speed)
enemy.global_rotation.y = rotate_to_face2D(enemy,move_target(),delta,turret_speed)
func finished_reload():
if enemy.turret_look_next.is_colliding():
if enemy.turret_look_next.get_collider() is Player:
Transitioned.emit(self,"attack")
else:
Transitioned.emit(self,"idle")
Transitioned.emit(self,"search")
else:
Transitioned.emit(self,"idle")
Transitioned.emit(self,"search")

View File

@@ -1,61 +1,41 @@
extends EnemyState
class_name EnemySearch
@export var idle_speed : float = 1.5
var search_timer
var move_direction : Vector3
var scan_direction : float
var search_time : float
var scan_time : float
const WANDER_AMT = 50
const TURRET_TURN_AMT : float = 90.0
const TURRET_SCAN_SPEED : float = .5
const SEARCH_TIME_MAX : float = 10.0
func Enter():
super()
search_point()
scan_direction = deg_to_rad(TURRET_TURN_AMT)
search_timer = SEARCH_TIME_MAX
func Update(delta: float):
super(delta)
attack_on_sight()
if search_time > 0:
search_time -= delta
if search_timer > 0:
search_timer -= delta
else:
Transitioned.emit(self,"idle")
if scan_time > 0:
scan_time -= delta
else:
randomize_turret_scan()
attack_on_sight()
search_point()
if enemy.global_position.distance_to(move_target_adj()) < 1:
Transitioned.emit(self,"idle")
func Physics_Update(delta : float):
if enemy:
#turret transform
enemy.turret_look.rotation = lerp(enemy.turret_look.rotation,enemy.turret_look_next.rotation,delta * TURRET_SCAN_SPEED)
enemy.turret_look_next.look_at(move_target())
enemy.turret_look.rotation = lerp(enemy.turret_look.rotation,enemy.turret_look_next.rotation,delta * turret_speed)
var destination = enemy.nav_agent.get_next_path_position()
var local_destination = destination - enemy.global_position
var direction = local_destination.normalized()
if enemy.global_position.distance_to(local_destination) > 1:
enemy.velocity = direction * idle_speed
enemy.spider_look_next.look_at(destination)
var look_target = enemy.spider_look_next.global_rotation.y
enemy.global_rotation.y = lerp(enemy.global_rotation.y,look_target,delta * 3)
enemy.velocity = direction * move_speed
enemy.global_rotation.y = rotate_to_face2D(enemy,move_target(),delta,turret_speed)
if enemy.turret_look.is_colliding() and enemy.turret_look.get_collider() is Player:
Transitioned.emit(self,"attack")
func search_point():
enemy.nav_agent.set_target_position(move_target())
search_time = randf_range(3,10)
func randomize_turret_scan():
scan_direction = -scan_direction
enemy.turret_look_next.rotation = Vector3(0,scan_direction,0)
scan_time = randf_range(5,10)

View File

@@ -3,7 +3,8 @@ class_name EnemyState
@export var enemy : CharacterBody3D
@export var move_speed : float = 3
@export var can_see : bool = false # indicates whether the enemy is able to see things in the state
@export var turret_speed : float = 6.0
@export var can_see : bool = true # indicates whether the enemy is able to see things in the state
@export var time_to_lose_target = 1.0
@onready var target_lost_timer = time_to_lose_target
@@ -14,7 +15,7 @@ func Update(delta):
func move_target():
if enemy.player_last_seen != null:
return enemy.player_last_seen
elif enemy.points_of_interest.size() > 0:
elif enemy.points_of_interest != null:
var move_point = {"loudness" : 0.0,"point" : Vector3.ZERO}
for point in enemy.points_of_interest:
if point["loudness"] > move_point["loudness"]:
@@ -27,7 +28,29 @@ func attack_on_sight():
if can_see:
if enemy.is_player_in_area() and enemy.is_player_visible():
Transitioned.emit(self,"attack")
if enemy.turret_look.is_colliding():
if enemy.turret_look.get_collider() is Player:
Transitioned.emit(self,"attack")
func search_on_lost_target(delta):
if !enemy.is_player_visible():
Transitioned.emit(self,"attack")
func move_target_adj():
var position = move_target()
return Vector3(position.x,enemy.global_position.y,position.z)
func rotate_to_face2D(object,target,delta,turn_speed):
#to allow both nodes and positions to be passed to this function, test the target and use Vector3 coords
var target_transformed
if target == null:
target_transformed = object.global_position
elif target is Vector3:
target_transformed = target
elif target is Node3D:
target_transformed = target.global_position
var pos2d = Vector2(object.global_position.x,object.global_position.z)
var target_pos2d = Vector2(target_transformed.x,target_transformed.z)
var direction = (pos2d - target_pos2d)
return lerp_angle(object.rotation.y,atan2(direction.x,direction.y),delta * turn_speed)

View File

@@ -84,7 +84,7 @@ func _process(delta):
cam_target.global_position = lerp(cam_target.global_position,target_pos_adjusted,delta * MOVE_SPEED)
look_ray.global_position = target_pos_adjusted
look_ray.look_at(Vector3(target.global_position), Vector3.UP)
camera.rotation = lerp_angle(camera.rotation,look_ray.rotation,delta * CAMERA_LOOK_SPEED)
camera.rotation = lerp(camera.rotation,look_ray.rotation,delta * CAMERA_LOOK_SPEED)
camera.fov = lerp(camera.fov, 40.0, delta * 5)
1:
#aim at player from enemy

View File

@@ -17,7 +17,8 @@ func _on_body_exited(body: Node3D) -> void:
if level_control.gamemode.die_on_leaving_bounds == true:
get_tree().current_scene.die()
else:
body.global_position = body.last_ground_pos + Vector3(0,10,0)
body.velocity = Vector3.ZERO
body.global_position = body.last_ground_pos + Vector3(0,.1,0)
func toggle_collision(collision_state):
check_collision = collision_state

View File

@@ -39,7 +39,6 @@ var last_enemy : bool = false
@onready var knocked_timer = $Timers/knocked_timer
@onready var stunned_timer = $Timers/stunned_timer
@onready var turret_look_next = $TurretLookNext
@onready var spider_look_next = $SpiderLookNext
@onready var body = $body
@onready var audio_fire = $AUIDO/Fire
@onready var turret = $TurretLook/Turret
@@ -103,7 +102,6 @@ func _process(delta):
line_of_sight.global_position = global_position
move_and_slide()
look_at_player()
cache_player_pos()
if debug_tools:
debug_marker()