update
This commit is contained in:
5
scenes/enemy/boss.gd
Normal file
5
scenes/enemy/boss.gd
Normal file
@@ -0,0 +1,5 @@
|
||||
extends "res://scenes/enemy/enemy.gd"
|
||||
|
||||
func _ready() -> void:
|
||||
super._ready()
|
||||
add_to_group("boss")
|
||||
1
scenes/enemy/boss.gd.uid
Normal file
1
scenes/enemy/boss.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bkehq3dqyp2yd
|
||||
108
scenes/enemy/boss.tscn
Normal file
108
scenes/enemy/boss.tscn
Normal file
@@ -0,0 +1,108 @@
|
||||
[gd_scene load_steps=6 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://scenes/enemy/boss.gd" id="1"]
|
||||
[ext_resource type="Script" path="res://scenes/healthbar.gd" id="4"]
|
||||
[ext_resource type="Script" path="res://scenes/enemy/enemy_movement.gd" id="5"]
|
||||
[ext_resource type="Resource" path="res://scenes/enemy/boss_stats.tres" id="8"]
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_1"]
|
||||
radius = 0.6
|
||||
height = 2.0
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_2"]
|
||||
radius = 0.6
|
||||
height = 2.0
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_health_bg"]
|
||||
bg_color = Color(0.3, 0.1, 0.1, 1)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_health_fill"]
|
||||
bg_color = Color(0.2, 0.8, 0.2, 1)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_shield_bg"]
|
||||
bg_color = Color(0.1, 0.1, 0.3, 1)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_shield_fill"]
|
||||
bg_color = Color(0.2, 0.5, 0.9, 1)
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_1"]
|
||||
albedo_color = Color(0.6, 0.1, 0.6, 1)
|
||||
|
||||
[sub_resource type="SphereMesh" id="SphereMesh_1"]
|
||||
radius = 0.75
|
||||
height = 1.5
|
||||
material = SubResource("StandardMaterial3D_1")
|
||||
|
||||
[sub_resource type="SphereShape3D" id="SphereShape3D_1"]
|
||||
radius = 8.0
|
||||
|
||||
[node name="Boss" type="CharacterBody3D"]
|
||||
script = ExtResource("1")
|
||||
stats = ExtResource("8")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||
shape = SubResource("CapsuleShape3D_1")
|
||||
|
||||
[node name="Mesh" type="MeshInstance3D" parent="."]
|
||||
transform = Transform3D(1.5, 0, 0, 0, 1.5, 0, 0, 0, 1.5, 0, 0, 0)
|
||||
mesh = SubResource("SphereMesh_1")
|
||||
|
||||
[node name="HitArea" type="Area3D" parent="."]
|
||||
collision_layer = 4
|
||||
collision_mask = 0
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="HitArea"]
|
||||
shape = SubResource("CapsuleShape3D_2")
|
||||
|
||||
[node name="NavigationAgent3D" type="NavigationAgent3D" parent="."]
|
||||
|
||||
[node name="EnemyMovement" type="Node" parent="."]
|
||||
script = ExtResource("5")
|
||||
|
||||
[node name="DetectionArea" type="Area3D" parent="."]
|
||||
collision_layer = 0
|
||||
collision_mask = 1
|
||||
monitoring = true
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="DetectionArea"]
|
||||
shape = SubResource("SphereShape3D_1")
|
||||
|
||||
[node name="Healthbar" type="Sprite3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.0, 0)
|
||||
billboard = 1
|
||||
pixel_size = 0.01
|
||||
script = ExtResource("4")
|
||||
|
||||
[node name="SubViewport" type="SubViewport" parent="Healthbar"]
|
||||
transparent_bg = true
|
||||
size = Vector2i(104, 29)
|
||||
|
||||
[node name="Border" type="ColorRect" parent="Healthbar/SubViewport"]
|
||||
offset_right = 104.0
|
||||
offset_bottom = 29.0
|
||||
color = Color(1, 0.9, 0.2, 1)
|
||||
|
||||
[node name="HealthBar" type="ProgressBar" parent="Healthbar/SubViewport"]
|
||||
offset_left = 2.0
|
||||
offset_top = 2.0
|
||||
offset_right = 102.0
|
||||
offset_bottom = 12.0
|
||||
theme_override_styles/background = SubResource("StyleBoxFlat_health_bg")
|
||||
theme_override_styles/fill = SubResource("StyleBoxFlat_health_fill")
|
||||
max_value = 500.0
|
||||
value = 500.0
|
||||
show_percentage = false
|
||||
|
||||
[node name="ShieldBar" type="ProgressBar" parent="Healthbar/SubViewport"]
|
||||
offset_left = 2.0
|
||||
offset_top = 15.0
|
||||
offset_right = 102.0
|
||||
offset_bottom = 27.0
|
||||
theme_override_styles/background = SubResource("StyleBoxFlat_shield_bg")
|
||||
theme_override_styles/fill = SubResource("StyleBoxFlat_shield_fill")
|
||||
max_value = 100.0
|
||||
value = 100.0
|
||||
show_percentage = false
|
||||
|
||||
[connection signal="body_entered" from="DetectionArea" to="." method="_on_detection_area_body_entered"]
|
||||
[connection signal="body_exited" from="DetectionArea" to="." method="_on_detection_area_body_exited"]
|
||||
2
scenes/enemy/boss_stats.gd
Normal file
2
scenes/enemy/boss_stats.gd
Normal file
@@ -0,0 +1,2 @@
|
||||
extends EnemyStats
|
||||
class_name BossStats
|
||||
1
scenes/enemy/boss_stats.gd.uid
Normal file
1
scenes/enemy/boss_stats.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bio01w2gd5e7q
|
||||
20
scenes/enemy/boss_stats.tres
Normal file
20
scenes/enemy/boss_stats.tres
Normal file
@@ -0,0 +1,20 @@
|
||||
[gd_resource type="Resource" script_class="BossStats" load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://scenes/enemy/boss_stats.gd" id="1"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1")
|
||||
max_health = 500.0
|
||||
health_regen = 0.0
|
||||
max_shield = 100.0
|
||||
shield_regen_delay = 5.0
|
||||
shield_regen_time = 8.0
|
||||
speed = 3.0
|
||||
attack_range = 2.0
|
||||
attack_cooldown = 1.5
|
||||
attack_damage = 5.0
|
||||
regen_fast = 0.1
|
||||
regen_slow = 0.01
|
||||
aggro_decay = 1.0
|
||||
portal_radius = 10.0
|
||||
alert_radius = 10.0
|
||||
37
scenes/enemy/enemy.gd
Normal file
37
scenes/enemy/enemy.gd
Normal file
@@ -0,0 +1,37 @@
|
||||
extends CharacterBody3D
|
||||
|
||||
enum State { IDLE, CHASE, ATTACK, RETURN }
|
||||
|
||||
@export var stats: BaseStats
|
||||
|
||||
var state: int = State.IDLE
|
||||
var target: Node3D = null
|
||||
var spawn_position: Vector3
|
||||
var portal: Node3D = null
|
||||
var gravity: float = ProjectSettings.get_setting("physics/3d/default_gravity")
|
||||
|
||||
func _ready() -> void:
|
||||
spawn_position = global_position
|
||||
add_to_group("enemies")
|
||||
Stats.register(self, stats)
|
||||
EventBus.entity_died.connect(_on_entity_died)
|
||||
|
||||
func _exit_tree() -> void:
|
||||
Stats.deregister(self)
|
||||
|
||||
func _on_entity_died(entity: Node) -> void:
|
||||
if entity == self:
|
||||
queue_free()
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
if not is_on_floor():
|
||||
velocity.y -= gravity * delta
|
||||
move_and_slide()
|
||||
|
||||
func _on_detection_area_body_entered(body: Node3D) -> void:
|
||||
if body is CharacterBody3D and body.name == "Player":
|
||||
EventBus.enemy_detected.emit(self, body)
|
||||
|
||||
func _on_detection_area_body_exited(body: Node3D) -> void:
|
||||
if body is CharacterBody3D and body.name == "Player":
|
||||
EventBus.enemy_lost.emit(self, body)
|
||||
1
scenes/enemy/enemy.gd.uid
Normal file
1
scenes/enemy/enemy.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bwi75jx0agktd
|
||||
107
scenes/enemy/enemy.tscn
Normal file
107
scenes/enemy/enemy.tscn
Normal file
@@ -0,0 +1,107 @@
|
||||
[gd_scene load_steps=6 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://scenes/enemy/enemy.gd" id="1"]
|
||||
[ext_resource type="Script" path="res://scenes/healthbar.gd" id="4"]
|
||||
[ext_resource type="Script" path="res://scenes/enemy/enemy_movement.gd" id="5"]
|
||||
[ext_resource type="Resource" path="res://scenes/enemy/enemy_stats.tres" id="8"]
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_1"]
|
||||
radius = 0.4
|
||||
height = 1.5
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_2"]
|
||||
radius = 0.4
|
||||
height = 1.5
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_health_bg"]
|
||||
bg_color = Color(0.3, 0.1, 0.1, 1)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_health_fill"]
|
||||
bg_color = Color(0.2, 0.8, 0.2, 1)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_shield_bg"]
|
||||
bg_color = Color(0.1, 0.1, 0.3, 1)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_shield_fill"]
|
||||
bg_color = Color(0.2, 0.5, 0.9, 1)
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_1"]
|
||||
albedo_color = Color(0.8, 0.1, 0.1, 1)
|
||||
|
||||
[sub_resource type="SphereMesh" id="SphereMesh_1"]
|
||||
radius = 0.5
|
||||
height = 1.0
|
||||
material = SubResource("StandardMaterial3D_1")
|
||||
|
||||
[sub_resource type="SphereShape3D" id="SphereShape3D_1"]
|
||||
radius = 10.0
|
||||
|
||||
[node name="Enemy" type="CharacterBody3D"]
|
||||
script = ExtResource("1")
|
||||
stats = ExtResource("8")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||
shape = SubResource("CapsuleShape3D_1")
|
||||
|
||||
[node name="Mesh" type="MeshInstance3D" parent="."]
|
||||
mesh = SubResource("SphereMesh_1")
|
||||
|
||||
[node name="HitArea" type="Area3D" parent="."]
|
||||
collision_layer = 4
|
||||
collision_mask = 0
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="HitArea"]
|
||||
shape = SubResource("CapsuleShape3D_2")
|
||||
|
||||
[node name="NavigationAgent3D" type="NavigationAgent3D" parent="."]
|
||||
|
||||
[node name="EnemyMovement" type="Node" parent="."]
|
||||
script = ExtResource("5")
|
||||
|
||||
[node name="DetectionArea" type="Area3D" parent="."]
|
||||
collision_layer = 0
|
||||
collision_mask = 1
|
||||
monitoring = true
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="DetectionArea"]
|
||||
shape = SubResource("SphereShape3D_1")
|
||||
|
||||
[node name="Healthbar" type="Sprite3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, 0)
|
||||
billboard = 1
|
||||
pixel_size = 0.01
|
||||
script = ExtResource("4")
|
||||
|
||||
[node name="SubViewport" type="SubViewport" parent="Healthbar"]
|
||||
transparent_bg = true
|
||||
size = Vector2i(104, 29)
|
||||
|
||||
[node name="Border" type="ColorRect" parent="Healthbar/SubViewport"]
|
||||
offset_right = 104.0
|
||||
offset_bottom = 29.0
|
||||
color = Color(1, 0.9, 0.2, 1)
|
||||
|
||||
[node name="HealthBar" type="ProgressBar" parent="Healthbar/SubViewport"]
|
||||
offset_left = 2.0
|
||||
offset_top = 2.0
|
||||
offset_right = 102.0
|
||||
offset_bottom = 12.0
|
||||
theme_override_styles/background = SubResource("StyleBoxFlat_health_bg")
|
||||
theme_override_styles/fill = SubResource("StyleBoxFlat_health_fill")
|
||||
max_value = 100.0
|
||||
value = 100.0
|
||||
show_percentage = false
|
||||
|
||||
[node name="ShieldBar" type="ProgressBar" parent="Healthbar/SubViewport"]
|
||||
offset_left = 2.0
|
||||
offset_top = 15.0
|
||||
offset_right = 102.0
|
||||
offset_bottom = 27.0
|
||||
theme_override_styles/background = SubResource("StyleBoxFlat_shield_bg")
|
||||
theme_override_styles/fill = SubResource("StyleBoxFlat_shield_fill")
|
||||
max_value = 50.0
|
||||
value = 50.0
|
||||
show_percentage = false
|
||||
|
||||
[connection signal="body_entered" from="DetectionArea" to="." method="_on_detection_area_body_entered"]
|
||||
[connection signal="body_exited" from="DetectionArea" to="." method="_on_detection_area_body_exited"]
|
||||
62
scenes/enemy/enemy_movement.gd
Normal file
62
scenes/enemy/enemy_movement.gd
Normal file
@@ -0,0 +1,62 @@
|
||||
extends Node
|
||||
|
||||
const SPEED := 3.0
|
||||
const ATTACK_RANGE := 2.0
|
||||
const REGEN_FAST := 0.10
|
||||
const REGEN_SLOW := 0.01
|
||||
|
||||
@onready var enemy: CharacterBody3D = get_parent()
|
||||
@onready var nav_agent: NavigationAgent3D = get_parent().get_node("NavigationAgent3D")
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
match enemy.state:
|
||||
enemy.State.IDLE:
|
||||
enemy.velocity.x = 0
|
||||
enemy.velocity.z = 0
|
||||
enemy.State.CHASE:
|
||||
_chase()
|
||||
enemy.State.RETURN:
|
||||
_return_to_spawn(delta)
|
||||
|
||||
func _chase() -> void:
|
||||
if not is_instance_valid(enemy.target):
|
||||
enemy.state = enemy.State.RETURN
|
||||
return
|
||||
var dist_to_target := enemy.global_position.distance_to(enemy.target.global_position)
|
||||
if dist_to_target <= ATTACK_RANGE:
|
||||
enemy.state = enemy.State.ATTACK
|
||||
return
|
||||
nav_agent.target_position = enemy.target.global_position
|
||||
var next_pos := nav_agent.get_next_path_position()
|
||||
var direction := (next_pos - enemy.global_position).normalized()
|
||||
direction.y = 0
|
||||
enemy.velocity.x = direction.x * SPEED
|
||||
enemy.velocity.z = direction.z * SPEED
|
||||
|
||||
func _return_to_spawn(delta: float) -> void:
|
||||
var dist := enemy.global_position.distance_to(enemy.spawn_position)
|
||||
if dist < 1.0:
|
||||
enemy.state = enemy.State.IDLE
|
||||
enemy.velocity.x = 0
|
||||
enemy.velocity.z = 0
|
||||
return
|
||||
nav_agent.target_position = enemy.spawn_position
|
||||
var next_pos := nav_agent.get_next_path_position()
|
||||
var direction := (next_pos - enemy.global_position).normalized()
|
||||
direction.y = 0
|
||||
enemy.velocity.x = direction.x * SPEED
|
||||
enemy.velocity.z = direction.z * SPEED
|
||||
_regenerate(delta)
|
||||
|
||||
func _regenerate(delta: float) -> void:
|
||||
var health: float = Stats.get_stat(enemy, "health")
|
||||
var max_health: float = Stats.get_stat(enemy, "max_health")
|
||||
if health == null or max_health == null:
|
||||
return
|
||||
if health < max_health:
|
||||
var rate: float = REGEN_FAST
|
||||
if health >= max_health * 0.99:
|
||||
rate = REGEN_SLOW
|
||||
health = min(health + max_health * rate * delta, max_health)
|
||||
Stats.set_stat(enemy, "health", health)
|
||||
EventBus.health_changed.emit(enemy, health, max_health)
|
||||
1
scenes/enemy/enemy_movement.gd.uid
Normal file
1
scenes/enemy/enemy_movement.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://tnx6rbnnngn
|
||||
12
scenes/enemy/enemy_stats.gd
Normal file
12
scenes/enemy/enemy_stats.gd
Normal file
@@ -0,0 +1,12 @@
|
||||
extends BaseStats
|
||||
class_name EnemyStats
|
||||
|
||||
@export var speed := 3.0
|
||||
@export var attack_range := 2.0
|
||||
@export var attack_cooldown := 1.5
|
||||
@export var attack_damage := 5.0
|
||||
@export var regen_fast := 0.10
|
||||
@export var regen_slow := 0.01
|
||||
@export var aggro_decay := 1.0
|
||||
@export var portal_radius := 10.0
|
||||
@export var alert_radius := 10.0
|
||||
1
scenes/enemy/enemy_stats.gd.uid
Normal file
1
scenes/enemy/enemy_stats.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bh2uuuvl30y0x
|
||||
7
scenes/enemy/enemy_stats.tres
Normal file
7
scenes/enemy/enemy_stats.tres
Normal file
@@ -0,0 +1,7 @@
|
||||
[gd_resource type="Resource" script_class="EnemyStats" format=3 uid="uid://cj1shmjwf0xeo"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://bh2uuuvl30y0x" path="res://scenes/enemy/enemy_stats.gd" id="1"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1")
|
||||
max_shield = 50.0
|
||||
Reference in New Issue
Block a user