mirror of
https://gitlab.com/MaddoScientisto/cirnogodot.git
synced 2026-06-01 08:55:35 +00:00
Add FSM components for player and enemy state management, including initialization and module resolution
This commit is contained in:
parent
18683c0680
commit
b6cc5a00e8
57 changed files with 526 additions and 506 deletions
0
.github/copilot-instructions.md
vendored
0
.github/copilot-instructions.md
vendored
|
|
@ -1,4 +1,4 @@
|
||||||
[gd_scene load_steps=11 format=3 uid="uid://chpxebhg36bcb"]
|
[gd_scene format=3 uid="uid://chpxebhg36bcb"]
|
||||||
|
|
||||||
[ext_resource type="PackedScene" uid="uid://bv7tjma3g7nkf" path="res://Scenes/Actors/3D/game_controller.tscn" id="1_d6hgs"]
|
[ext_resource type="PackedScene" uid="uid://bv7tjma3g7nkf" path="res://Scenes/Actors/3D/game_controller.tscn" id="1_d6hgs"]
|
||||||
[ext_resource type="Resource" uid="uid://bxju78og0t8ca" path="res://Resources/Maps/3D/IsoMapTest3.tres" id="2_l3eiy"]
|
[ext_resource type="Resource" uid="uid://bxju78og0t8ca" path="res://Resources/Maps/3D/IsoMapTest3.tres" id="2_l3eiy"]
|
||||||
|
|
@ -16,28 +16,28 @@ reflected_light_source = 1
|
||||||
|
|
||||||
[sub_resource type="CameraAttributesPractical" id="CameraAttributesPractical_w45nv"]
|
[sub_resource type="CameraAttributesPractical" id="CameraAttributesPractical_w45nv"]
|
||||||
|
|
||||||
[node name="Factory3" type="Node3D"]
|
[node name="Factory3" type="Node3D" unique_id=1937514110]
|
||||||
|
|
||||||
[node name="GameController" parent="." node_paths=PackedStringArray("_cameraTarget") instance=ExtResource("1_d6hgs")]
|
[node name="GameController" parent="." unique_id=1180859733 node_paths=PackedStringArray("_cameraTarget") instance=ExtResource("1_d6hgs")]
|
||||||
_cameraTarget = NodePath("../CameraTarget")
|
_cameraTarget = NodePath("../CameraTarget")
|
||||||
MapResource = ExtResource("2_l3eiy")
|
MapResource = ExtResource("2_l3eiy")
|
||||||
SpawnMarkers = Dictionary[int, NodePath]({
|
SpawnMarkers = Dictionary[int, NodePath]({
|
||||||
0: NodePath("../StartPosition")
|
0: NodePath("../StartPosition")
|
||||||
})
|
})
|
||||||
|
|
||||||
[node name="DirectionalLight3D_Original" type="DirectionalLight3D" parent="."]
|
[node name="DirectionalLight3D_Original" type="DirectionalLight3D" parent="." unique_id=1574778523]
|
||||||
transform = Transform3D(0.442606, -0.744379, 0.5, 0.287606, 0.645974, 0.707107, -0.849343, -0.169167, 0.5, 28.5973, 5.82742, 17.535)
|
transform = Transform3D(0.442606, -0.744379, 0.5, 0.287606, 0.645974, 0.707107, -0.849343, -0.169167, 0.5, 28.5973, 5.82742, 17.535)
|
||||||
visible = false
|
visible = false
|
||||||
light_energy = 1.375
|
light_energy = 1.375
|
||||||
light_bake_mode = 1
|
light_bake_mode = 1
|
||||||
shadow_enabled = true
|
shadow_enabled = true
|
||||||
|
|
||||||
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
|
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="." unique_id=2188957]
|
||||||
transform = Transform3D(0.401703, -0.767225, 0.5, 0.322119, 0.629476, 0.707107, -0.857248, -0.122987, 0.5, 28.5973, 5.82742, 17.535)
|
transform = Transform3D(0.401703, -0.767225, 0.5, 0.322119, 0.629476, 0.707107, -0.857248, -0.122987, 0.5, 28.5973, 5.82742, 17.535)
|
||||||
light_energy = 1.375
|
light_energy = 1.375
|
||||||
light_bake_mode = 1
|
light_bake_mode = 1
|
||||||
|
|
||||||
[node name="DirectionalLight3D2" type="DirectionalLight3D" parent="."]
|
[node name="DirectionalLight3D2" type="DirectionalLight3D" parent="." unique_id=28867131]
|
||||||
transform = Transform3D(0.0306036, -0.825802, -0.56313, -0.675985, -0.43211, 0.596931, -0.73628, 0.362399, -0.571454, 27.8154, 5.82742, 13.9456)
|
transform = Transform3D(0.0306036, -0.825802, -0.56313, -0.675985, -0.43211, 0.596931, -0.73628, 0.362399, -0.571454, 27.8154, 5.82742, 13.9456)
|
||||||
light_energy = 0.932
|
light_energy = 0.932
|
||||||
light_bake_mode = 1
|
light_bake_mode = 1
|
||||||
|
|
@ -45,15 +45,15 @@ shadow_enabled = true
|
||||||
shadow_blur = 0.51
|
shadow_blur = 0.51
|
||||||
sky_mode = 1
|
sky_mode = 1
|
||||||
|
|
||||||
[node name="StartPosition" type="Marker3D" parent="."]
|
[node name="StartPosition" type="Marker3D" parent="." unique_id=840698087]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -8.524396, 1.4927001, 1.6348801)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -8.524396, 1.4927001, 1.6348801)
|
||||||
script = ExtResource("8_jaqd3")
|
script = ExtResource("8_jaqd3")
|
||||||
|
|
||||||
[node name="CameraTarget" type="Marker3D" parent="."]
|
[node name="CameraTarget" type="Marker3D" parent="." unique_id=1770556508]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -7.0461216, 2.33215, 2.5474238)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -7.0461216, 2.33215, 2.5474238)
|
||||||
script = ExtResource("9_py8ao")
|
script = ExtResource("9_py8ao")
|
||||||
|
|
||||||
[node name="Camera3D" type="Camera3D" parent="."]
|
[node name="Camera3D" type="Camera3D" parent="." unique_id=1465586253]
|
||||||
physics_interpolation_mode = 1
|
physics_interpolation_mode = 1
|
||||||
transform = Transform3D(0.7071068, -0.49999997, 0.50000006, 0, 0.7071069, 0.70710677, -0.7071068, -0.49999997, 0.50000006, -3.7983856, 7.935, 5.0604153)
|
transform = Transform3D(0.7071068, -0.49999997, 0.50000006, 0, 0.7071069, 0.70710677, -0.7071068, -0.49999997, 0.50000006, -3.7983856, 7.935, 5.0604153)
|
||||||
projection = 1
|
projection = 1
|
||||||
|
|
@ -63,12 +63,12 @@ MaxAimOffsetDistance = 16.0
|
||||||
CameraOffset = Vector3(8, 8, 8)
|
CameraOffset = Vector3(8, 8, 8)
|
||||||
TargetPath = NodePath("../CameraTarget")
|
TargetPath = NodePath("../CameraTarget")
|
||||||
|
|
||||||
[node name="TestLevel3" parent="." instance=ExtResource("11_l3eiy")]
|
[node name="TestLevel3" parent="." unique_id=615675558 instance=ExtResource("11_l3eiy")]
|
||||||
|
|
||||||
[node name="AudioStreamPlayer2D" parent="." instance=ExtResource("12_44k7r")]
|
[node name="AudioStreamPlayer2D" parent="." unique_id=254428228 instance=ExtResource("12_44k7r")]
|
||||||
autoplay = true
|
autoplay = true
|
||||||
MusicData = ExtResource("13_isg5t")
|
MusicData = ExtResource("13_isg5t")
|
||||||
|
|
||||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
|
[node name="WorldEnvironment" type="WorldEnvironment" parent="." unique_id=1912346680]
|
||||||
environment = SubResource("Environment_d6hgs")
|
environment = SubResource("Environment_d6hgs")
|
||||||
camera_attributes = SubResource("CameraAttributesPractical_w45nv")
|
camera_attributes = SubResource("CameraAttributesPractical_w45nv")
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
[gd_scene load_steps=38 format=3 uid="uid://bh3vxmqflijgj"]
|
[gd_scene format=3 uid="uid://bh3vxmqflijgj"]
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://dwregubt4iila" path="res://Scripts/Components/FSM/Enemy/3D/EnemyProxy3D.cs" id="1_a3crc"]
|
[ext_resource type="Script" uid="uid://dwregubt4iila" path="res://Scripts/Components/FSM/Enemy/3D/EnemyProxy3D.cs" id="1_a3crc"]
|
||||||
[ext_resource type="Resource" uid="uid://ccym6mcq4fbul" path="res://Resources/Enemies/Fairy_Guard_3D.tres" id="2_jgarc"]
|
[ext_resource type="Resource" uid="uid://ccym6mcq4fbul" path="res://Resources/Enemies/Fairy_Guard_3D.tres" id="2_jgarc"]
|
||||||
[ext_resource type="Script" uid="uid://c651imhj6rjsh" path="res://Scripts/Components/FSM/Enemy/3D/EnemyStateMachine3D.cs" id="2_xne4s"]
|
[ext_resource type="Script" uid="uid://c651imhj6rjsh" path="res://Scripts/Components/FSM/Enemy/3D/EnemyStateMachine3D.cs" id="2_xne4s"]
|
||||||
[ext_resource type="Script" uid="uid://cy34e3htvbvnl" path="res://Scripts/Components/FSM/Enemy/3D/Init.cs" id="4_jgarc"]
|
[ext_resource type="Script" uid="uid://dkmwqvhenu1xq" path="res://Scripts/Components/FSM/Enemy/3D/InitState.cs" id="4_2ut2v"]
|
||||||
[ext_resource type="Script" uid="uid://jpdgfn701crh" path="res://Scripts/Components/FSM/Enemy/3D/Idle.cs" id="5_rg1hb"]
|
[ext_resource type="Script" uid="uid://jpdgfn701crh" path="res://Scripts/Components/FSM/Enemy/3D/Idle.cs" id="5_rg1hb"]
|
||||||
[ext_resource type="Script" uid="uid://dvtdw2hcp4rm2" path="res://Scripts/Components/FSM/Enemy/3D/Alert.cs" id="6_jgarc"]
|
[ext_resource type="Script" uid="uid://dvtdw2hcp4rm2" path="res://Scripts/Components/FSM/Enemy/3D/Alert.cs" id="6_jgarc"]
|
||||||
[ext_resource type="Script" uid="uid://crahxykgis2bp" path="res://Scripts/Components/FSM/Enemy/3D/Shooting.cs" id="7_rg1hb"]
|
[ext_resource type="Script" uid="uid://crahxykgis2bp" path="res://Scripts/Components/FSM/Enemy/3D/Shooting.cs" id="7_rg1hb"]
|
||||||
|
|
@ -88,36 +88,30 @@ animations = [{
|
||||||
"speed": 5.0
|
"speed": 5.0
|
||||||
}]
|
}]
|
||||||
|
|
||||||
[node name="Enemy" type="CharacterBody3D" node_paths=PackedStringArray("EnemyFSM")]
|
[node name="Enemy" type="CharacterBody3D" unique_id=1428692983 node_paths=PackedStringArray("EnemyFSM")]
|
||||||
collision_layer = 64
|
collision_layer = 64
|
||||||
collision_mask = 1553
|
collision_mask = 1553
|
||||||
script = ExtResource("1_a3crc")
|
script = ExtResource("1_a3crc")
|
||||||
EnemyFSM = NodePath("StateMachine")
|
EnemyFSM = NodePath("StateMachine")
|
||||||
EnemyResource = ExtResource("2_jgarc")
|
EnemyResource = ExtResource("2_jgarc")
|
||||||
|
|
||||||
[node name="CollisionShape2D" type="CollisionShape3D" parent="."]
|
[node name="CollisionShape2D" type="CollisionShape3D" parent="." unique_id=397512658]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.047, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.047, 0)
|
||||||
shape = SubResource("CapsuleShape3D_jgarc")
|
shape = SubResource("CapsuleShape3D_jgarc")
|
||||||
|
|
||||||
[node name="StateMachine" type="Node" parent="."]
|
[node name="StateMachine" type="Node" parent="." unique_id=146081447]
|
||||||
script = ExtResource("2_xne4s")
|
script = ExtResource("2_xne4s")
|
||||||
|
|
||||||
[node name="Init" type="Node" parent="StateMachine" node_paths=PackedStringArray("Storage", "DetectionProvider", "HealthProvider", "_moduleNodes")]
|
[node name="Init" type="Node" parent="StateMachine" unique_id=321304267 node_paths=PackedStringArray("_moduleNodes")]
|
||||||
script = ExtResource("4_jgarc")
|
script = ExtResource("4_2ut2v")
|
||||||
Storage = NodePath("../../Storage")
|
|
||||||
DetectionProvider = NodePath("../../PlayerDetectionProvider")
|
|
||||||
HealthProvider = NodePath("../../DamageReceiver/HealthProvider")
|
|
||||||
_moduleNodes = [NodePath("../../AnimationModule")]
|
_moduleNodes = [NodePath("../../AnimationModule")]
|
||||||
|
|
||||||
[node name="Idle" type="Node" parent="StateMachine" node_paths=PackedStringArray("Storage", "PlayerDetection", "GravityProvider", "_moduleNodes")]
|
[node name="Idle" type="Node" parent="StateMachine" unique_id=1798192567 node_paths=PackedStringArray("_moduleNodes")]
|
||||||
script = ExtResource("5_rg1hb")
|
script = ExtResource("5_rg1hb")
|
||||||
Storage = NodePath("../../Storage")
|
|
||||||
PlayerDetection = NodePath("../../PlayerDetectionProvider")
|
|
||||||
GravityProvider = NodePath("../../GravityProvider")
|
|
||||||
DebugEnabled = true
|
DebugEnabled = true
|
||||||
_moduleNodes = [NodePath("../../DamageModule"), NodePath("../../AnimationModule"), NodePath("../../SoundModule")]
|
_moduleNodes = [NodePath("../../DamageModule"), NodePath("../../AnimationModule"), NodePath("../../SoundModule")]
|
||||||
|
|
||||||
[node name="Alert" type="Node" parent="StateMachine" node_paths=PackedStringArray("Storage", "PlayerDetection", "NavigationModule", "GravityProvider", "_moduleNodes")]
|
[node name="Alert" type="Node" parent="StateMachine" unique_id=2023331935 node_paths=PackedStringArray("Storage", "PlayerDetection", "NavigationModule", "GravityProvider", "_moduleNodes")]
|
||||||
script = ExtResource("6_jgarc")
|
script = ExtResource("6_jgarc")
|
||||||
Storage = NodePath("../../Storage")
|
Storage = NodePath("../../Storage")
|
||||||
PlayerDetection = NodePath("../../PlayerDetectionProvider")
|
PlayerDetection = NodePath("../../PlayerDetectionProvider")
|
||||||
|
|
@ -126,32 +120,28 @@ GravityProvider = NodePath("../../GravityProvider")
|
||||||
DebugEnabled = true
|
DebugEnabled = true
|
||||||
_moduleNodes = [NodePath("../../DamageModule"), NodePath("../../AnimationModule"), NodePath("../../SoundModule")]
|
_moduleNodes = [NodePath("../../DamageModule"), NodePath("../../AnimationModule"), NodePath("../../SoundModule")]
|
||||||
|
|
||||||
[node name="Shooting" type="Node" parent="StateMachine" node_paths=PackedStringArray("Storage", "PlayerDetection", "EquippedWeapon", "NavigationModule", "GravityProvider", "_moduleNodes")]
|
[node name="Shooting" type="Node" parent="StateMachine" unique_id=767265433 node_paths=PackedStringArray("EquippedWeapon", "_moduleNodes")]
|
||||||
script = ExtResource("7_rg1hb")
|
script = ExtResource("7_rg1hb")
|
||||||
Storage = NodePath("../../Storage")
|
|
||||||
PlayerDetection = NodePath("../../PlayerDetectionProvider")
|
|
||||||
EquippedWeapon = NodePath("../../Weapon")
|
EquippedWeapon = NodePath("../../Weapon")
|
||||||
NavigationModule = NodePath("../../NavigationProvider")
|
|
||||||
GravityProvider = NodePath("../../GravityProvider")
|
|
||||||
_moduleNodes = [NodePath("../../DamageModule"), NodePath("../../AnimationModule"), NodePath("../../SoundModule")]
|
_moduleNodes = [NodePath("../../DamageModule"), NodePath("../../AnimationModule"), NodePath("../../SoundModule")]
|
||||||
|
|
||||||
[node name="Dead" type="Node" parent="StateMachine" node_paths=PackedStringArray("Storage", "_moduleNodes")]
|
[node name="Dead" type="Node" parent="StateMachine" unique_id=1312501461 node_paths=PackedStringArray("Storage", "_moduleNodes")]
|
||||||
script = ExtResource("8_5j04l")
|
script = ExtResource("8_5j04l")
|
||||||
Storage = NodePath("../../Storage")
|
Storage = NodePath("../../Storage")
|
||||||
_moduleNodes = [NodePath("../../LootModule")]
|
_moduleNodes = [NodePath("../../LootModule")]
|
||||||
|
|
||||||
[node name="Controlled" type="Node" parent="StateMachine" node_paths=PackedStringArray("Storage", "_moduleNodes")]
|
[node name="Controlled" type="Node" parent="StateMachine" unique_id=481921517 node_paths=PackedStringArray("Storage", "_moduleNodes")]
|
||||||
script = ExtResource("9_dm2sd")
|
script = ExtResource("9_dm2sd")
|
||||||
Storage = NodePath("../../Storage")
|
Storage = NodePath("../../Storage")
|
||||||
_moduleNodes = [NodePath("../../DamageModule")]
|
_moduleNodes = [NodePath("../../DamageModule")]
|
||||||
|
|
||||||
[node name="AnimationModule" type="Node" parent="." node_paths=PackedStringArray("AnimationProvider", "Storage", "HealthProvider")]
|
[node name="AnimationModule" type="Node" parent="." unique_id=920204467 node_paths=PackedStringArray("AnimationProvider", "Storage", "HealthProvider")]
|
||||||
script = ExtResource("10_d6h7c")
|
script = ExtResource("10_d6h7c")
|
||||||
AnimationProvider = NodePath("../AnimationProvider")
|
AnimationProvider = NodePath("../AnimationProvider")
|
||||||
Storage = NodePath("../Storage")
|
Storage = NodePath("../Storage")
|
||||||
HealthProvider = NodePath("../DamageReceiver/HealthProvider")
|
HealthProvider = NodePath("../DamageReceiver/HealthProvider")
|
||||||
|
|
||||||
[node name="AnimationProvider" type="Node3D" parent="." node_paths=PackedStringArray("AnimatedSprite")]
|
[node name="AnimationProvider" type="Node3D" parent="." unique_id=2053395074 node_paths=PackedStringArray("AnimatedSprite")]
|
||||||
script = ExtResource("10_5gcuf")
|
script = ExtResource("10_5gcuf")
|
||||||
AnimatedSprite = NodePath("../AnimatedSprite3D")
|
AnimatedSprite = NodePath("../AnimatedSprite3D")
|
||||||
WalkRightAnimationName = &"right"
|
WalkRightAnimationName = &"right"
|
||||||
|
|
@ -160,7 +150,7 @@ WalkDownAnimationName = &"down"
|
||||||
WalkUpAnimationName = &"up"
|
WalkUpAnimationName = &"up"
|
||||||
BlinkMaterial = ExtResource("10_05pdu")
|
BlinkMaterial = ExtResource("10_05pdu")
|
||||||
|
|
||||||
[node name="AnimatedSprite3D" type="AnimatedSprite3D" parent="."]
|
[node name="AnimatedSprite3D" type="AnimatedSprite3D" parent="." unique_id=1186020475]
|
||||||
transform = Transform3D(0.707107, -0.5, 0.5, 0, 0.707107, 0.707107, -0.707107, -0.5, 0.5, 0, 0, 0)
|
transform = Transform3D(0.707107, -0.5, 0.5, 0, 0.707107, 0.707107, -0.707107, -0.5, 0.5, 0, 0, 0)
|
||||||
material_override = SubResource("ShaderMaterial_d6h7c")
|
material_override = SubResource("ShaderMaterial_d6h7c")
|
||||||
pixel_size = 0.05
|
pixel_size = 0.05
|
||||||
|
|
@ -172,38 +162,38 @@ frame = 2
|
||||||
frame_progress = 0.92087
|
frame_progress = 0.92087
|
||||||
script = ExtResource("11_jgarc")
|
script = ExtResource("11_jgarc")
|
||||||
|
|
||||||
[node name="Storage" type="Node" parent="." node_paths=PackedStringArray("Root")]
|
[node name="Storage" type="Node" parent="." unique_id=8651828 node_paths=PackedStringArray("Root")]
|
||||||
script = ExtResource("11_xne4s")
|
script = ExtResource("11_xne4s")
|
||||||
Root = NodePath("..")
|
Root = NodePath("..")
|
||||||
|
|
||||||
[node name="PlayerDetectionProvider" type="Area3D" parent="."]
|
[node name="PlayerDetectionProvider" type="Area3D" parent="." unique_id=77201234]
|
||||||
collision_layer = 0
|
collision_layer = 0
|
||||||
collision_mask = 2
|
collision_mask = 2
|
||||||
script = ExtResource("13_rg1hb")
|
script = ExtResource("13_rg1hb")
|
||||||
ObstaclesCollisionMask = 17
|
ObstaclesCollisionMask = 17
|
||||||
|
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="PlayerDetectionProvider"]
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="PlayerDetectionProvider" unique_id=1149305496]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.557434, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.557434, 0)
|
||||||
shape = SubResource("CylinderShape3D_5j04l")
|
shape = SubResource("CylinderShape3D_5j04l")
|
||||||
|
|
||||||
[node name="NavigationProvider" type="Node" parent="." node_paths=PackedStringArray("NavigationAgent", "StorageModule")]
|
[node name="NavigationProvider" type="Node" parent="." unique_id=1851675964 node_paths=PackedStringArray("NavigationAgent", "StorageModule")]
|
||||||
script = ExtResource("14_dm2sd")
|
script = ExtResource("14_dm2sd")
|
||||||
NavigationAgent = NodePath("../NavigationAgent3D")
|
NavigationAgent = NodePath("../NavigationAgent3D")
|
||||||
StorageModule = NodePath("../Storage")
|
StorageModule = NodePath("../Storage")
|
||||||
|
|
||||||
[node name="NavigationAgent3D" type="NavigationAgent3D" parent="."]
|
[node name="NavigationAgent3D" type="NavigationAgent3D" parent="." unique_id=1202654381]
|
||||||
path_postprocessing = 1
|
path_postprocessing = 1
|
||||||
debug_enabled = true
|
debug_enabled = true
|
||||||
|
|
||||||
[node name="Weapon" parent="." instance=ExtResource("15_27vgy")]
|
[node name="Weapon" parent="." unique_id=771249458 instance=ExtResource("15_27vgy")]
|
||||||
|
|
||||||
[node name="DamageModule" type="Node" parent="." node_paths=PackedStringArray("DamageReceiver", "StorageModule", "AnimationProvider")]
|
[node name="DamageModule" type="Node" parent="." unique_id=430721165 node_paths=PackedStringArray("DamageReceiver", "StorageModule", "AnimationProvider")]
|
||||||
script = ExtResource("16_27vgy")
|
script = ExtResource("16_27vgy")
|
||||||
DamageReceiver = NodePath("../DamageReceiver")
|
DamageReceiver = NodePath("../DamageReceiver")
|
||||||
StorageModule = NodePath("../Storage")
|
StorageModule = NodePath("../Storage")
|
||||||
AnimationProvider = NodePath("../AnimationProvider")
|
AnimationProvider = NodePath("../AnimationProvider")
|
||||||
|
|
||||||
[node name="DamageReceiver" type="Area3D" parent="." node_paths=PackedStringArray("HealthProvider")]
|
[node name="DamageReceiver" type="Area3D" parent="." unique_id=1792872756 node_paths=PackedStringArray("HealthProvider")]
|
||||||
collision_layer = 64
|
collision_layer = 64
|
||||||
collision_mask = 8
|
collision_mask = 8
|
||||||
script = ExtResource("17_tabhk")
|
script = ExtResource("17_tabhk")
|
||||||
|
|
@ -211,20 +201,20 @@ HealthProvider = NodePath("HealthProvider")
|
||||||
BulletGroup = 2
|
BulletGroup = 2
|
||||||
DeleteParentOnDeath = false
|
DeleteParentOnDeath = false
|
||||||
|
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="DamageReceiver"]
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="DamageReceiver" unique_id=1457345703]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.00463867, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.00463867, 0)
|
||||||
shape = SubResource("CylinderShape3D_uv2lf")
|
shape = SubResource("CylinderShape3D_uv2lf")
|
||||||
|
|
||||||
[node name="HealthProvider" type="Node" parent="DamageReceiver"]
|
[node name="HealthProvider" type="Node" parent="DamageReceiver" unique_id=610376220]
|
||||||
script = ExtResource("18_4fnoq")
|
script = ExtResource("18_4fnoq")
|
||||||
ResourceName = "Health"
|
ResourceName = "Health"
|
||||||
|
|
||||||
[node name="GravityProvider" type="Node" parent="."]
|
[node name="GravityProvider" type="Node" parent="." unique_id=2086594224]
|
||||||
script = ExtResource("25_qg061")
|
script = ExtResource("25_qg061")
|
||||||
Gravity = -20.0
|
Gravity = -20.0
|
||||||
MaxFallSpeed = 50.0
|
MaxFallSpeed = 50.0
|
||||||
|
|
||||||
[node name="SoundModule" type="Node" parent="." node_paths=PackedStringArray("DamageReceiver", "StorageModule", "HitPlayer", "DeathPlayer", "AlertPlayer")]
|
[node name="SoundModule" type="Node" parent="." unique_id=540759764 node_paths=PackedStringArray("DamageReceiver", "StorageModule", "HitPlayer", "DeathPlayer", "AlertPlayer")]
|
||||||
script = ExtResource("26_ojvcb")
|
script = ExtResource("26_ojvcb")
|
||||||
DamageReceiver = NodePath("../DamageReceiver")
|
DamageReceiver = NodePath("../DamageReceiver")
|
||||||
StorageModule = NodePath("../Storage")
|
StorageModule = NodePath("../Storage")
|
||||||
|
|
@ -232,19 +222,19 @@ HitPlayer = NodePath("HitPlayer")
|
||||||
DeathPlayer = NodePath("DeathPlayer")
|
DeathPlayer = NodePath("DeathPlayer")
|
||||||
AlertPlayer = NodePath("AlertPlayer")
|
AlertPlayer = NodePath("AlertPlayer")
|
||||||
|
|
||||||
[node name="HitPlayer" type="AudioStreamPlayer3D" parent="SoundModule"]
|
[node name="HitPlayer" type="AudioStreamPlayer3D" parent="SoundModule" unique_id=1334761769]
|
||||||
unit_size = 30.0
|
unit_size = 30.0
|
||||||
bus = &"Effects"
|
bus = &"Effects"
|
||||||
|
|
||||||
[node name="AlertPlayer" type="AudioStreamPlayer3D" parent="SoundModule"]
|
[node name="AlertPlayer" type="AudioStreamPlayer3D" parent="SoundModule" unique_id=1111891836]
|
||||||
unit_size = 30.0
|
unit_size = 30.0
|
||||||
bus = &"Effects"
|
bus = &"Effects"
|
||||||
|
|
||||||
[node name="DeathPlayer" type="AudioStreamPlayer3D" parent="SoundModule"]
|
[node name="DeathPlayer" type="AudioStreamPlayer3D" parent="SoundModule" unique_id=1385917323]
|
||||||
unit_size = 30.0
|
unit_size = 30.0
|
||||||
bus = &"Effects"
|
bus = &"Effects"
|
||||||
|
|
||||||
[node name="Hitbox" type="AnimatedSprite3D" parent="."]
|
[node name="Hitbox" type="AnimatedSprite3D" parent="." unique_id=123796697]
|
||||||
transform = Transform3D(0.707107, -0.5, 0.5, 0, 0.707107, 0.707107, -0.707107, -0.5, 0.5, 0, 0, 0)
|
transform = Transform3D(0.707107, -0.5, 0.5, 0, 0.707107, 0.707107, -0.707107, -0.5, 0.5, 0, 0, 0)
|
||||||
material_overlay = SubResource("StandardMaterial3D_2ut2v")
|
material_overlay = SubResource("StandardMaterial3D_2ut2v")
|
||||||
ignore_occlusion_culling = true
|
ignore_occlusion_culling = true
|
||||||
|
|
@ -254,11 +244,11 @@ texture_filter = 0
|
||||||
render_priority = -1
|
render_priority = -1
|
||||||
sprite_frames = SubResource("SpriteFrames_t121s")
|
sprite_frames = SubResource("SpriteFrames_t121s")
|
||||||
|
|
||||||
[node name="LootModule" type="Node" parent="." node_paths=PackedStringArray("StorageModule")]
|
[node name="LootModule" type="Node" parent="." unique_id=729648693 node_paths=PackedStringArray("StorageModule")]
|
||||||
script = ExtResource("28_2ut2v")
|
script = ExtResource("28_2ut2v")
|
||||||
StorageModule = NodePath("../Storage")
|
StorageModule = NodePath("../Storage")
|
||||||
|
|
||||||
[node name="Shadow2" type="Decal" parent="."]
|
[node name="Shadow2" type="Decal" parent="." unique_id=2007780472]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.13562012, -0.118652344, 0.13336182)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.13562012, -0.118652344, 0.13336182)
|
||||||
size = Vector3(0.5, 0.7373047, 0.5)
|
size = Vector3(0.5, 0.7373047, 0.5)
|
||||||
texture_albedo = ExtResource("28_t121s")
|
texture_albedo = ExtResource("28_t121s")
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Cirno.Scripts.Components.FSM;
|
||||||
using Cirno.Scripts.Components.FSM._3DPlayer;
|
using Cirno.Scripts.Components.FSM._3DPlayer;
|
||||||
using Godot;
|
using Godot;
|
||||||
using Godot.Collections;
|
using Godot.Collections;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Cirno.Scripts.Components.FSM;
|
||||||
using Godot;
|
using Godot;
|
||||||
using GTweens.Builders;
|
using GTweens.Builders;
|
||||||
using GTweens.Easings;
|
using GTweens.Easings;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using Cirno.Scripts;
|
using Cirno.Scripts;
|
||||||
using Cirno.Scripts.Components.Actors;
|
using Cirno.Scripts.Components.Actors;
|
||||||
|
using Cirno.Scripts.Components.FSM;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
public partial class EnemyPossessionMovement : ActorFreeMovement
|
public partial class EnemyPossessionMovement : ActorFreeMovement
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
using System.Threading.Tasks;
|
using Cirno.Scripts.Components.Actors;
|
||||||
using Cirno.Scripts.Components.Actors;
|
|
||||||
using Cirno.Scripts.Components.Actors._3D;
|
using Cirno.Scripts.Components.Actors._3D;
|
||||||
using Cirno.Scripts.Utils;
|
using Cirno.Scripts.Utils;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
@ -14,39 +13,34 @@ public partial class Active : BaseState<PlayerState, CharacterBody3D>
|
||||||
[Export] private InputProvider _inputProvider;
|
[Export] private InputProvider _inputProvider;
|
||||||
[Export] public PlayerAnimationProvider3D AnimationProvider { get; private set; }
|
[Export] public PlayerAnimationProvider3D AnimationProvider { get; private set; }
|
||||||
|
|
||||||
[Export] public IsoPlayerStorageModule Storage { get; private set; }
|
private IsoPlayerStorageModule Storage { get; set; }
|
||||||
|
|
||||||
[Export] public PlayerDamageReceiver3D DamageReceiver { get; private set; }
|
[Export] public PlayerDamageReceiver3D DamageReceiver { get; private set; }
|
||||||
|
|
||||||
//[Export] public PlayerHitboxSpriteProvider3D HitboxSpriteProvider { get; private set; }
|
|
||||||
|
|
||||||
public override void Init(IStateMachine<PlayerState, CharacterBody3D> machine)
|
public override void Init(IStateMachine<PlayerState, CharacterBody3D> machine)
|
||||||
{
|
{
|
||||||
base.Init(machine);
|
base.Init(machine);
|
||||||
|
|
||||||
//_hud = Hud.Instance;
|
if (machine is IsoPlayerStateMachine sm)
|
||||||
|
Storage = sm.Storage;
|
||||||
|
|
||||||
DamageReceiver.Death += () => { ChangeState(PlayerState.Dead); };
|
DamageReceiver.Death += () => { ChangeState(PlayerState.Dead); };
|
||||||
|
|
||||||
DamageReceiver.HealthDecreased += (value, newValue, maxValue) =>
|
DamageReceiver.HealthDecreased += (_, _, _) =>
|
||||||
{
|
{
|
||||||
AnimationProvider.Blink();
|
AnimationProvider.Blink();
|
||||||
};
|
};
|
||||||
|
|
||||||
DamageReceiver.ShieldDecreased += (value, newValue, maxValue) =>
|
DamageReceiver.ShieldDecreased += (_, _, _) =>
|
||||||
{
|
{
|
||||||
AnimationProvider.PlayShieldAnimation();
|
AnimationProvider.PlayShieldAnimation();
|
||||||
|
};
|
||||||
};
|
|
||||||
|
|
||||||
DamageReceiver.Init(StateMachine);
|
DamageReceiver.Init(StateMachine);
|
||||||
|
|
||||||
DamageReceiver.RefillHealth();
|
DamageReceiver.RefillHealth();
|
||||||
DamageReceiver.RefillShield();
|
DamageReceiver.RefillShield();
|
||||||
|
|
||||||
//_activationProvider.Init(MainObject);
|
|
||||||
|
|
||||||
//_weaponProvider.Init(MainObject);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void EnterState()
|
public override void EnterState()
|
||||||
|
|
@ -78,19 +72,10 @@ public partial class Active : BaseState<PlayerState, CharacterBody3D>
|
||||||
DamageReceiver.Enabled = false;
|
DamageReceiver.Enabled = false;
|
||||||
|
|
||||||
_canOpenInventory = true;
|
_canOpenInventory = true;
|
||||||
// _activationProvider.Enabled = false;
|
// _activation_provider.Enabled = false;
|
||||||
// _interactionController.Enabled = false;
|
// _interactionController.Enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PhysicsProcessState(double delta)
|
|
||||||
{
|
|
||||||
// Reset at start of frame
|
|
||||||
//MainObject.Velocity = Vector2.Zero;
|
|
||||||
|
|
||||||
// Process modules
|
|
||||||
base.PhysicsProcessState(delta);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ProcessState(double delta)
|
public override void ProcessState(double delta)
|
||||||
{
|
{
|
||||||
base.ProcessState(delta);
|
base.ProcessState(delta);
|
||||||
|
|
@ -102,14 +87,13 @@ public partial class Active : BaseState<PlayerState, CharacterBody3D>
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool _canOpenInventory = true;
|
private bool _canOpenInventory = true;
|
||||||
private double _inventoryCooldown = 0;
|
private double _inventoryCooldown;
|
||||||
|
|
||||||
private void HandleInputHotkeys(double delta)
|
private void HandleInputHotkeys(double delta)
|
||||||
{
|
{
|
||||||
if (_canOpenInventory && _inputProvider.GetInventoryJustPressed())
|
if (_canOpenInventory && _inputProvider.GetInventoryJustPressed())
|
||||||
{
|
{
|
||||||
_canOpenInventory = false;
|
_canOpenInventory = false;
|
||||||
|
|
||||||
GameStateManager.SetState(GameState.Inventory);
|
GameStateManager.SetState(GameState.Inventory);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -127,7 +111,6 @@ public partial class Active : BaseState<PlayerState, CharacterBody3D>
|
||||||
if (_inputProvider.GetPauseJustPressed())
|
if (_inputProvider.GetPauseJustPressed())
|
||||||
{
|
{
|
||||||
GameStateManager.Instance.Pause();
|
GameStateManager.Instance.Pause();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
using Cirno.Scripts.Components.Actors._3D;
|
using Cirno.Scripts.Components.Actors._3D;
|
||||||
using Cirno.Scripts.Components.FSM.Player;
|
|
||||||
using Cirno.Scripts.Utils;
|
using Cirno.Scripts.Utils;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
|
|
@ -11,11 +10,13 @@ public partial class Cutscene : BaseState<PlayerState, CharacterBody3D>
|
||||||
|
|
||||||
[Export] public PlayerAnimationProvider3D AnimationProvider { get; set; }
|
[Export] public PlayerAnimationProvider3D AnimationProvider { get; set; }
|
||||||
|
|
||||||
[Export] public IsoPlayerStorageModule PlayerStorage { get; private set; }
|
private IsoPlayerStorageModule PlayerStorage { get; set; }
|
||||||
|
|
||||||
public override void Init(IStateMachine<PlayerState, CharacterBody3D> machine)
|
public override void Init(IStateMachine<PlayerState, CharacterBody3D> machine)
|
||||||
{
|
{
|
||||||
base.Init(machine);
|
base.Init(machine);
|
||||||
|
if (machine is IsoPlayerStateMachine sm)
|
||||||
|
PlayerStorage = sm.Storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void EnterState()
|
public override void EnterState()
|
||||||
|
|
@ -40,15 +41,4 @@ public partial class Cutscene : BaseState<PlayerState, CharacterBody3D>
|
||||||
AnimationProvider.SetAnimation(MainObject.Velocity.ToVector2());
|
AnimationProvider.SetAnimation(MainObject.Velocity.ToVector2());
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PhysicsProcessState(double delta)
|
|
||||||
{
|
|
||||||
// Reset at start of frame
|
|
||||||
//MainObject.Velocity = Vector2.Zero;
|
|
||||||
|
|
||||||
// Process modules
|
|
||||||
base.PhysicsProcessState(delta);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -9,18 +9,33 @@ public partial class Dead : BaseState<PlayerState, CharacterBody3D>
|
||||||
{
|
{
|
||||||
public override PlayerState StateId => PlayerState.Dead;
|
public override PlayerState StateId => PlayerState.Dead;
|
||||||
|
|
||||||
[Export]
|
|
||||||
private ActorResourceProvider _motivationProvider;
|
private ActorResourceProvider _motivationProvider;
|
||||||
[Export]
|
|
||||||
private InputProvider _inputProvider;
|
private InputProvider _inputProvider;
|
||||||
|
|
||||||
[Export]
|
|
||||||
private ActorResourceProvider _healthProvider;
|
private ActorResourceProvider _healthProvider;
|
||||||
|
|
||||||
[Export]
|
|
||||||
private PlayerAnimationProvider3D _animationProvider;
|
private PlayerAnimationProvider3D _animationProvider;
|
||||||
|
|
||||||
private bool _isGameOver = false;
|
private bool _isGameOver;
|
||||||
|
|
||||||
|
public override void Init(IStateMachine<PlayerState, CharacterBody3D> machine)
|
||||||
|
{
|
||||||
|
base.Init(machine);
|
||||||
|
// try to obtain common providers via modules/storage
|
||||||
|
if (machine is IsoPlayerStateMachine sm)
|
||||||
|
{
|
||||||
|
var storage = sm.Storage;
|
||||||
|
// store references if present on storage
|
||||||
|
_motivationProvider = storage.Root.GetNodeOrNull<ActorResourceProvider>("MotivationProvider");
|
||||||
|
_healthProvider = storage.Root.GetNodeOrNull<ActorResourceProvider>("HealthProvider");
|
||||||
|
}
|
||||||
|
// fallback to searching on the actor
|
||||||
|
_motivationProvider ??= StateMachine.GetModule<ActorResourceProvider>();
|
||||||
|
_healthProvider ??= StateMachine.GetModule<ActorResourceProvider>();
|
||||||
|
|
||||||
|
_animationProvider ??= StateMachine.GetModule<PlayerAnimationProvider3D>();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public override void EnterState()
|
public override void EnterState()
|
||||||
{
|
{
|
||||||
|
|
@ -50,10 +65,6 @@ public partial class Dead : BaseState<PlayerState, CharacterBody3D>
|
||||||
Hud.Instance.HideTerminated();
|
Hud.Instance.HideTerminated();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PhysicsProcessState(double delta)
|
|
||||||
{
|
|
||||||
base.PhysicsProcessState(delta);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ProcessState(double delta)
|
public override void ProcessState(double delta)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,14 @@ public partial class Drowning : BaseState<PlayerState, CharacterBody3D>
|
||||||
{
|
{
|
||||||
public override PlayerState StateId => PlayerState.Drowning;
|
public override PlayerState StateId => PlayerState.Drowning;
|
||||||
|
|
||||||
[Export]
|
|
||||||
private PlayerAnimationProvider3D _animationProvider;
|
private PlayerAnimationProvider3D _animationProvider;
|
||||||
|
|
||||||
|
public override void Init(IStateMachine<PlayerState, CharacterBody3D> machine)
|
||||||
|
{
|
||||||
|
base.Init(machine);
|
||||||
|
_animationProvider ??= StateMachine.GetModule<PlayerAnimationProvider3D>();
|
||||||
|
}
|
||||||
|
|
||||||
public override void EnterState()
|
public override void EnterState()
|
||||||
{
|
{
|
||||||
_animationProvider.PlayDrowningAnimation();
|
_animationProvider.PlayDrowningAnimation();
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
using System.Threading.Tasks;
|
using Godot;
|
||||||
using Godot;
|
|
||||||
|
|
||||||
namespace Cirno.Scripts.Components.FSM._3DPlayer;
|
namespace Cirno.Scripts.Components.FSM._3DPlayer;
|
||||||
|
|
||||||
|
|
@ -9,9 +8,9 @@ public partial class Init : BaseState<PlayerState, CharacterBody3D>
|
||||||
|
|
||||||
public override void EnterState()
|
public override void EnterState()
|
||||||
{
|
{
|
||||||
// _storageModule.FacingDirection = ((PlayerStateMachine)StateMachine).StartingDirection;
|
// Use Godot timer instead of Task.Delay to stay on main thread
|
||||||
// _animationProvider.PlayUnteleportAnimation();
|
var timer = GetTree().CreateTimer(0.5f);
|
||||||
_ = AutoSwitchToStart();
|
timer.Timeout += () => StateMachine.SetState(PlayerState.Active);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ExitState()
|
public override void ExitState()
|
||||||
|
|
@ -28,10 +27,4 @@ public partial class Init : BaseState<PlayerState, CharacterBody3D>
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task AutoSwitchToStart()
|
|
||||||
{
|
|
||||||
await Task.Delay(500);
|
|
||||||
StateMachine.SetState(PlayerState.Active);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -8,7 +8,7 @@ namespace Cirno.Scripts.Components.FSM._3DPlayer;
|
||||||
|
|
||||||
public partial class IsoMovementModule : ModuleBase<PlayerState, CharacterBody3D>
|
public partial class IsoMovementModule : ModuleBase<PlayerState, CharacterBody3D>
|
||||||
{
|
{
|
||||||
[Export] public IsoPlayerStorageModule PlayerStorage { get; private set; }
|
private IsoPlayerStorageModule PlayerStorage { get; set; }
|
||||||
[Export] private InputProvider _inputProvider;
|
[Export] private InputProvider _inputProvider;
|
||||||
|
|
||||||
[Export] public PlayerHitboxSpriteProvider3D HitboxSpriteProvider { get; private set; }
|
[Export] public PlayerHitboxSpriteProvider3D HitboxSpriteProvider { get; private set; }
|
||||||
|
|
@ -29,9 +29,6 @@ public partial class IsoMovementModule : ModuleBase<PlayerState, CharacterBody3D
|
||||||
|
|
||||||
public int MovementSpeed => _isStrafing ? StrafeSpeed : Speed;
|
public int MovementSpeed => _isStrafing ? StrafeSpeed : Speed;
|
||||||
|
|
||||||
private IStateMachine<PlayerState, CharacterBody3D> _stateMachine;
|
|
||||||
private CharacterBody3D MainObject => _stateMachine.MainObject;
|
|
||||||
|
|
||||||
public override void EnterState(PlayerState state)
|
public override void EnterState(PlayerState state)
|
||||||
{
|
{
|
||||||
_accelerationPerSecond = Speed / Acceleration;
|
_accelerationPerSecond = Speed / Acceleration;
|
||||||
|
|
@ -44,7 +41,8 @@ public partial class IsoMovementModule : ModuleBase<PlayerState, CharacterBody3D
|
||||||
|
|
||||||
public override void Init(IStateMachine<PlayerState, CharacterBody3D> machine)
|
public override void Init(IStateMachine<PlayerState, CharacterBody3D> machine)
|
||||||
{
|
{
|
||||||
_stateMachine = machine;
|
base.Init(machine);
|
||||||
|
PlayerStorage ??= StateMachine.GetModule<IsoPlayerStorageModule>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Process(double delta)
|
public override void Process(double delta)
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
using Cirno.Scripts.Components.Actors;
|
using Cirno.Scripts.Components.Actors;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
using Cirno.Scripts.Resources.Loot;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Cirno.Scripts.Components.FSM._3DPlayer;
|
namespace Cirno.Scripts.Components.FSM._3DPlayer;
|
||||||
|
|
||||||
public partial class IsoPlayerStorageModule : Node
|
public partial class IsoPlayerStorageModule : Node, IFSMStorage, IActorStorage
|
||||||
{
|
{
|
||||||
[Export] public IsoPlayerFSMProxy Root { get; private set; }
|
[Export] public IsoPlayerFSMProxy Root { get; private set; }
|
||||||
|
|
||||||
|
|
@ -14,4 +16,7 @@ public partial class IsoPlayerStorageModule : Node
|
||||||
public Vector2 FacingDirection { get; set; } = Vector2.Down;
|
public Vector2 FacingDirection { get; set; } = Vector2.Down;
|
||||||
public Vector2 AimingDirection { get; set; } = Vector2.Down;
|
public Vector2 AimingDirection { get; set; } = Vector2.Down;
|
||||||
public Vector2 MovementDirection { get; set; } = Vector2.Zero;
|
public Vector2 MovementDirection { get; set; } = Vector2.Zero;
|
||||||
|
|
||||||
|
// Implement LootDrops for IFSMStorage (players may not drop loot but expose empty list)
|
||||||
|
public IEnumerable<LootDrop> LootDrops => new LootDrop[0];
|
||||||
}
|
}
|
||||||
|
|
@ -4,9 +4,6 @@ namespace Cirno.Scripts.Components.FSM._3DPlayer;
|
||||||
|
|
||||||
public partial class PlayerAcidDeathModule : ModuleBase<PlayerState, CharacterBody3D>
|
public partial class PlayerAcidDeathModule : ModuleBase<PlayerState, CharacterBody3D>
|
||||||
{
|
{
|
||||||
private IStateMachine<PlayerState, CharacterBody3D> _stateMachine;
|
|
||||||
private CharacterBody3D MainObject => _stateMachine.MainObject;
|
|
||||||
|
|
||||||
private bool _enabled = false;
|
private bool _enabled = false;
|
||||||
|
|
||||||
public override void EnterState(PlayerState state)
|
public override void EnterState(PlayerState state)
|
||||||
|
|
@ -21,7 +18,7 @@ public partial class PlayerAcidDeathModule : ModuleBase<PlayerState, CharacterBo
|
||||||
|
|
||||||
public override void Init(IStateMachine<PlayerState, CharacterBody3D> machine)
|
public override void Init(IStateMachine<PlayerState, CharacterBody3D> machine)
|
||||||
{
|
{
|
||||||
_stateMachine = machine;
|
base.Init(machine);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Process(double delta)
|
public override void Process(double delta)
|
||||||
|
|
@ -38,6 +35,6 @@ public partial class PlayerAcidDeathModule : ModuleBase<PlayerState, CharacterBo
|
||||||
{
|
{
|
||||||
if (!_enabled) return;
|
if (!_enabled) return;
|
||||||
GD.Print("Oh no acid");
|
GD.Print("Oh no acid");
|
||||||
_stateMachine.SetState(PlayerState.Dead);
|
StateMachine.SetState(PlayerState.Dead);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
13
Scripts/Components/FSM/3DPlayer/PlayerState.cs
Normal file
13
Scripts/Components/FSM/3DPlayer/PlayerState.cs
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
namespace Cirno.Scripts.Components.FSM;
|
||||||
|
|
||||||
|
public enum PlayerState
|
||||||
|
{
|
||||||
|
Init,
|
||||||
|
Active,
|
||||||
|
Cutscene,
|
||||||
|
Teleporting,
|
||||||
|
UnTeleporting,
|
||||||
|
Controlling,
|
||||||
|
Dead,
|
||||||
|
Drowning,
|
||||||
|
}
|
||||||
1
Scripts/Components/FSM/3DPlayer/PlayerState.cs.uid
Normal file
1
Scripts/Components/FSM/3DPlayer/PlayerState.cs.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://7thusbxv3r2n
|
||||||
|
|
@ -8,10 +8,7 @@ public partial class PlayerWeaponModule3D : ModuleBase<PlayerState, CharacterBod
|
||||||
[Export] public PlayerWeaponProvider3D WeaponProvider { get; private set; }
|
[Export] public PlayerWeaponProvider3D WeaponProvider { get; private set; }
|
||||||
|
|
||||||
[Export] public InputProvider InputProvider { get; private set; }
|
[Export] public InputProvider InputProvider { get; private set; }
|
||||||
[Export] public IsoPlayerStorageModule Storage { get; private set; }
|
private IsoPlayerStorageModule Storage { get; set; }
|
||||||
|
|
||||||
private IStateMachine<PlayerState, CharacterBody3D> _stateMachine;
|
|
||||||
private CharacterBody3D MainObject => _stateMachine.MainObject;
|
|
||||||
|
|
||||||
public override void EnterState(PlayerState state)
|
public override void EnterState(PlayerState state)
|
||||||
{
|
{
|
||||||
|
|
@ -25,8 +22,8 @@ public partial class PlayerWeaponModule3D : ModuleBase<PlayerState, CharacterBod
|
||||||
|
|
||||||
public override void Init(IStateMachine<PlayerState, CharacterBody3D> machine)
|
public override void Init(IStateMachine<PlayerState, CharacterBody3D> machine)
|
||||||
{
|
{
|
||||||
_stateMachine = machine;
|
base.Init(machine);
|
||||||
|
Storage ??= StateMachine.GetModule<IsoPlayerStorageModule>();
|
||||||
WeaponProvider.Init(MainObject);
|
WeaponProvider.Init(MainObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,4 @@
|
||||||
using Cirno.Scripts.Components.Actors._3D;
|
using Cirno.Scripts.Components.Actors._3D;
|
||||||
using Cirno.Scripts.Components.FSM.Player;
|
|
||||||
using Cirno.Scripts.Utils;
|
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
namespace Cirno.Scripts.Components.FSM._3DPlayer;
|
namespace Cirno.Scripts.Components.FSM._3DPlayer;
|
||||||
|
|
@ -9,38 +7,24 @@ public partial class Teleporting : BaseState<PlayerState, CharacterBody3D>
|
||||||
{
|
{
|
||||||
public override PlayerState StateId => PlayerState.Teleporting;
|
public override PlayerState StateId => PlayerState.Teleporting;
|
||||||
|
|
||||||
[Export] public PlayerAnimationProvider3D AnimationProvider { get; set; }
|
private PlayerAnimationProvider3D AnimationProvider { get; set; }
|
||||||
|
|
||||||
public override void Init(IStateMachine<PlayerState, CharacterBody3D> machine)
|
public override void Init(IStateMachine<PlayerState, CharacterBody3D> machine)
|
||||||
{
|
{
|
||||||
base.Init(machine);
|
base.Init(machine);
|
||||||
|
AnimationProvider ??= StateMachine.GetModule<PlayerAnimationProvider3D>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void EnterState()
|
public override void EnterState()
|
||||||
{
|
{
|
||||||
base.EnterState();
|
base.EnterState();
|
||||||
AnimationProvider.PlayTeleportAnimation();
|
AnimationProvider?.PlayTeleportAnimation();
|
||||||
MainObject.Velocity = Vector3.Zero;
|
MainObject.Velocity = Vector3.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ExitState()
|
|
||||||
{
|
|
||||||
base.ExitState();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ProcessState(double delta)
|
public override void ProcessState(double delta)
|
||||||
{
|
{
|
||||||
base.ProcessState(delta);
|
base.ProcessState(delta);
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void PhysicsProcessState(double delta)
|
|
||||||
{
|
|
||||||
// Process modules
|
|
||||||
base.PhysicsProcessState(delta);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,4 @@
|
||||||
using Cirno.Scripts.Components.Actors._3D;
|
using Cirno.Scripts.Components.Actors._3D;
|
||||||
using Cirno.Scripts.Components.FSM.Player;
|
|
||||||
using Cirno.Scripts.Utils;
|
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
namespace Cirno.Scripts.Components.FSM._3DPlayer;
|
namespace Cirno.Scripts.Components.FSM._3DPlayer;
|
||||||
|
|
@ -9,37 +7,17 @@ public partial class UnTeleporting : BaseState<PlayerState, CharacterBody3D>
|
||||||
{
|
{
|
||||||
public override PlayerState StateId => PlayerState.UnTeleporting;
|
public override PlayerState StateId => PlayerState.UnTeleporting;
|
||||||
|
|
||||||
[Export] public PlayerAnimationProvider3D AnimationProvider { get; set; }
|
private PlayerAnimationProvider3D AnimationProvider { get; set; }
|
||||||
|
|
||||||
public override void Init(IStateMachine<PlayerState, CharacterBody3D> machine)
|
public override void Init(IStateMachine<PlayerState, CharacterBody3D> machine)
|
||||||
{
|
{
|
||||||
base.Init(machine);
|
base.Init(machine);
|
||||||
|
AnimationProvider ??= StateMachine.GetModule<PlayerAnimationProvider3D>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void EnterState()
|
public override void EnterState()
|
||||||
{
|
{
|
||||||
base.EnterState();
|
base.EnterState();
|
||||||
AnimationProvider.PlayUnteleportAnimation();
|
AnimationProvider?.PlayUnteleportAnimation();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ExitState()
|
|
||||||
{
|
|
||||||
base.ExitState();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ProcessState(double delta)
|
|
||||||
{
|
|
||||||
base.ProcessState(delta);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void PhysicsProcessState(double delta)
|
|
||||||
{
|
|
||||||
// Process modules
|
|
||||||
base.PhysicsProcessState(delta);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -7,15 +7,23 @@ public partial class Idle : EnemyStateBase3D
|
||||||
{
|
{
|
||||||
public override EnemyState StateId => EnemyState.Idle;
|
public override EnemyState StateId => EnemyState.Idle;
|
||||||
|
|
||||||
[Export] public EnemyStorage3D Storage { get; private set; }
|
private EnemyStorage3D Storage { get; set; }
|
||||||
[Export] public PlayerDetection3D PlayerDetection { get; private set; }
|
private PlayerDetection3D PlayerDetection { get; set; }
|
||||||
|
|
||||||
[Export] public GravityProvider GravityProvider { get; private set; }
|
private GravityProvider GravityProvider { get; set; }
|
||||||
|
|
||||||
[Export] public bool DebugEnabled { get; set; } = false;
|
[Export] public bool DebugEnabled { get; set; } = false;
|
||||||
|
|
||||||
private bool _isPlayerInRange = false;
|
private bool _isPlayerInRange = false;
|
||||||
|
|
||||||
|
public override void Init(IStateMachine<EnemyState, CharacterBody3D> machine)
|
||||||
|
{
|
||||||
|
base.Init(machine);
|
||||||
|
Storage ??= StateMachine.GetModule<EnemyStorage3D>();
|
||||||
|
PlayerDetection ??= StateMachine.GetModule<PlayerDetection3D>();
|
||||||
|
GravityProvider ??= StateMachine.GetModule<GravityProvider>();
|
||||||
|
}
|
||||||
|
|
||||||
public override void EnterState()
|
public override void EnterState()
|
||||||
{
|
{
|
||||||
base.EnterState();
|
base.EnterState();
|
||||||
|
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
using Cirno.Scripts.Components.Actors;
|
|
||||||
using Cirno.Scripts.Enums;
|
|
||||||
using Godot;
|
|
||||||
|
|
||||||
namespace Cirno.Scripts.Components.FSM.Enemy._3D;
|
|
||||||
|
|
||||||
public partial class Init : EnemyStateBase3D
|
|
||||||
{
|
|
||||||
public override EnemyState StateId => EnemyState.Init;
|
|
||||||
[Export] public EnemyStorage3D Storage {get; private set;}
|
|
||||||
|
|
||||||
[Export] public PlayerDetection3D DetectionProvider { get; private set; }
|
|
||||||
|
|
||||||
[Export] public ActorResourceProvider HealthProvider { get; private set; }
|
|
||||||
|
|
||||||
public override void EnterState()
|
|
||||||
{
|
|
||||||
//DamageReceiver.HealthProvider.MaxResource = StorageModule.Root.EnemyResource.MaxHealth;
|
|
||||||
DetectionProvider.Initialize(MainObject);
|
|
||||||
Storage.AiState = Storage.Root.StartingAiState;
|
|
||||||
|
|
||||||
Storage.HomePosition = MainObject.GlobalPosition;
|
|
||||||
// TODO: Hide wings
|
|
||||||
// TODO: Hide aiming reticule
|
|
||||||
|
|
||||||
HealthProvider.MaxResource = Storage.Root.EnemyResource.MaxHealth;
|
|
||||||
|
|
||||||
HealthProvider.FillResource();
|
|
||||||
|
|
||||||
StateMachine.SetState(EnemyState.Idle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
uid://cy34e3htvbvnl
|
|
||||||
72
Scripts/Components/FSM/Enemy/3D/InitState.cs
Normal file
72
Scripts/Components/FSM/Enemy/3D/InitState.cs
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
using Cirno.Scripts.Components.Actors;
|
||||||
|
using Cirno.Scripts.Enums;
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace Cirno.Scripts.Components.FSM.Enemy._3D;
|
||||||
|
|
||||||
|
public partial class InitState : EnemyStateBase3D
|
||||||
|
{
|
||||||
|
public override EnemyState StateId => EnemyState.Init;
|
||||||
|
private EnemyStorage3D Storage { get; set; }
|
||||||
|
private PlayerDetection3D DetectionProvider { get; set; }
|
||||||
|
private ActorResourceProvider HealthProvider { get; set; }
|
||||||
|
|
||||||
|
private int _initRetryCount = 0;
|
||||||
|
private const int MaxInitRetries = 20;
|
||||||
|
private const float InitRetryDelaySeconds = 0.05f;
|
||||||
|
|
||||||
|
public override void Init(IStateMachine<EnemyState, CharacterBody3D> machine)
|
||||||
|
{
|
||||||
|
base.Init(machine);
|
||||||
|
// Try an initial resolve; EnterState will retry if necessary
|
||||||
|
Storage ??= StateMachine.GetModule<EnemyStorage3D>();
|
||||||
|
DetectionProvider ??= StateMachine.GetModule<PlayerDetection3D>();
|
||||||
|
HealthProvider ??= StateMachine.GetModule<ActorResourceProvider>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override void EnterState()
|
||||||
|
{
|
||||||
|
// Attempt to complete initialization; if modules are missing, retry with a timer
|
||||||
|
TryCompleteInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TryCompleteInit()
|
||||||
|
{
|
||||||
|
// Attempt to resolve modules again in case they were attached after Init
|
||||||
|
Storage ??= StateMachine.GetModule<EnemyStorage3D>();
|
||||||
|
DetectionProvider ??= StateMachine.GetModule<PlayerDetection3D>();
|
||||||
|
HealthProvider ??= StateMachine.GetModule<ActorResourceProvider>();
|
||||||
|
|
||||||
|
if (Storage is null || DetectionProvider is null || HealthProvider is null)
|
||||||
|
{
|
||||||
|
_initRetryCount++;
|
||||||
|
if (_initRetryCount <= MaxInitRetries)
|
||||||
|
{
|
||||||
|
// Schedule a retry shortly to wait for other nodes to finish _Ready
|
||||||
|
var timer = GetTree().CreateTimer(InitRetryDelaySeconds);
|
||||||
|
timer.Timeout += TryCompleteInit;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final failure: log detailed error and bail out to avoid throws
|
||||||
|
var actorName = MainObject?.Name ?? "<unknown>";
|
||||||
|
GD.PrintErr($"[InitState] Failed to resolve required modules on actor '{actorName}' after {_initRetryCount} attempts.\n" +
|
||||||
|
$" Storage: {(Storage is null ? "MISSING" : "OK")},\n" +
|
||||||
|
$" DetectionProvider: {(DetectionProvider is null ? "MISSING" : "OK")},\n" +
|
||||||
|
$" HealthProvider: {(HealthProvider is null ? "MISSING" : "OK")}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// All modules present, proceed with initialization
|
||||||
|
DetectionProvider.Initialize(MainObject);
|
||||||
|
Storage.AiState = Storage.Root.StartingAiState;
|
||||||
|
Storage.HomePosition = MainObject.GlobalPosition;
|
||||||
|
|
||||||
|
HealthProvider.MaxResource = Storage.Root.EnemyResource.MaxHealth;
|
||||||
|
HealthProvider.FillResource();
|
||||||
|
|
||||||
|
// Transition to the Idle state now that initialization is complete
|
||||||
|
StateMachine.SetState(EnemyState.Idle);
|
||||||
|
}
|
||||||
|
}
|
||||||
1
Scripts/Components/FSM/Enemy/3D/InitState.cs.uid
Normal file
1
Scripts/Components/FSM/Enemy/3D/InitState.cs.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://dkmwqvhenu1xq
|
||||||
|
|
@ -9,20 +9,30 @@ public partial class Shooting : EnemyStateBase3D
|
||||||
{
|
{
|
||||||
public override EnemyState StateId => EnemyState.Shooting;
|
public override EnemyState StateId => EnemyState.Shooting;
|
||||||
|
|
||||||
[Export] public EnemyStorage3D Storage { get; private set; }
|
private EnemyStorage3D Storage { get; set; }
|
||||||
|
|
||||||
[Export] public PlayerDetection3D PlayerDetection { get; private set; }
|
private PlayerDetection3D PlayerDetection { get; set; }
|
||||||
|
|
||||||
[Export] public Weapon3D EquippedWeapon;
|
[Export] public Weapon3D EquippedWeapon;
|
||||||
[Export] public NavigationProvider3D NavigationModule { get; private set; }
|
private NavigationProvider3D NavigationModule { get; set; }
|
||||||
|
|
||||||
[Export] public GravityProvider GravityProvider { get; private set; }
|
private GravityProvider GravityProvider { get; set; }
|
||||||
|
|
||||||
private bool _isPlayerInRange = false;
|
private bool _isPlayerInRange;
|
||||||
private Vector3? _currentStrafeTarget = null;
|
private Vector3? _currentStrafeTarget;
|
||||||
private float _strafeSpeed => Storage.EnemyData.StrafeSpeed;
|
private float StrafeSpeed => Storage.EnemyData.StrafeSpeed;
|
||||||
|
|
||||||
|
private double _responseTimer;
|
||||||
|
|
||||||
|
public override void Init(IStateMachine<EnemyState, CharacterBody3D> machine)
|
||||||
|
{
|
||||||
|
base.Init(machine);
|
||||||
|
Storage ??= StateMachine.GetModule<EnemyStorage3D>();
|
||||||
|
PlayerDetection ??= StateMachine.GetModule<PlayerDetection3D>();
|
||||||
|
NavigationModule ??= StateMachine.GetModule<NavigationProvider3D>();
|
||||||
|
GravityProvider ??= StateMachine.GetModule<GravityProvider>();
|
||||||
|
}
|
||||||
|
|
||||||
private double _responseTimer = 0;
|
|
||||||
public override void EnterState()
|
public override void EnterState()
|
||||||
{
|
{
|
||||||
base.EnterState();
|
base.EnterState();
|
||||||
|
|
@ -31,12 +41,13 @@ public partial class Shooting : EnemyStateBase3D
|
||||||
|
|
||||||
PlayerDetection.PlayerOutOfRange += PlayerDetectionOnPlayerOutOfRange;
|
PlayerDetection.PlayerOutOfRange += PlayerDetectionOnPlayerOutOfRange;
|
||||||
|
|
||||||
//DamageReceiver.ChangeState(true);
|
if (Storage is null || PlayerDetection is null) return;
|
||||||
|
|
||||||
//DamageReceiver.HealthProvider.ResourceDepleted += HealthProviderOnResourceDepleted;
|
if (EquippedWeapon != null)
|
||||||
|
{
|
||||||
EquippedWeapon.WeaponData = Storage.Root.EnemyResource.Weapon;
|
EquippedWeapon.WeaponData = Storage.Root.EnemyResource.Weapon;
|
||||||
EquippedWeapon.Init();
|
EquippedWeapon.Init();
|
||||||
|
}
|
||||||
|
|
||||||
_currentStrafeTarget = null;
|
_currentStrafeTarget = null;
|
||||||
|
|
||||||
|
|
@ -56,24 +67,22 @@ public partial class Shooting : EnemyStateBase3D
|
||||||
|
|
||||||
PlayerDetection.PlayerOutOfRange -= PlayerDetectionOnPlayerOutOfRange;
|
PlayerDetection.PlayerOutOfRange -= PlayerDetectionOnPlayerOutOfRange;
|
||||||
|
|
||||||
//DamageReceiver.HealthProvider.ResourceDepleted -= HealthProviderOnResourceDepleted;
|
|
||||||
|
|
||||||
_currentStrafeTarget = null;
|
_currentStrafeTarget = null;
|
||||||
|
|
||||||
//DamageReceiver.ChangeState(false);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PhysicsProcessState(double delta)
|
public override void PhysicsProcessState(double delta)
|
||||||
{
|
{
|
||||||
base.PhysicsProcessState(delta);
|
base.PhysicsProcessState(delta);
|
||||||
|
|
||||||
|
if (Storage is null || PlayerDetection is null || NavigationModule is null || GravityProvider is null)
|
||||||
|
return;
|
||||||
|
|
||||||
if (PlayerDetection.IsPlayerInRange(Storage.Root.EnemyResource.ViewRange) && PlayerDetection.IsPlayerInSight())
|
if (PlayerDetection.IsPlayerInRange(Storage.Root.EnemyResource.ViewRange) && PlayerDetection.IsPlayerInSight())
|
||||||
{
|
{
|
||||||
// SHOOT
|
// SHOOT
|
||||||
Shoot();
|
Shoot();
|
||||||
|
|
||||||
if (_strafeSpeed > 0)
|
if (StrafeSpeed > 0)
|
||||||
{
|
{
|
||||||
// Check if a strafe position is needed
|
// Check if a strafe position is needed
|
||||||
if (!_currentStrafeTarget.HasValue || NavigationModule.IsNavigationFinished())
|
if (!_currentStrafeTarget.HasValue || NavigationModule.IsNavigationFinished())
|
||||||
|
|
@ -100,7 +109,7 @@ public partial class Shooting : EnemyStateBase3D
|
||||||
if (_currentStrafeTarget.HasValue)
|
if (_currentStrafeTarget.HasValue)
|
||||||
{
|
{
|
||||||
NavigationModule.SetTarget(_currentStrafeTarget.Value);
|
NavigationModule.SetTarget(_currentStrafeTarget.Value);
|
||||||
NavigationModule.Move(_strafeSpeed);
|
NavigationModule.Move(StrafeSpeed);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate gravity
|
// Calculate gravity
|
||||||
|
|
@ -111,6 +120,8 @@ public partial class Shooting : EnemyStateBase3D
|
||||||
|
|
||||||
private Vector3? CalculateStrafePosition()
|
private Vector3? CalculateStrafePosition()
|
||||||
{
|
{
|
||||||
|
if (!PlayerDetection.LastKnownPlayerPosition.HasValue) return null;
|
||||||
|
|
||||||
var playerPos = PlayerDetection.LastKnownPlayerPosition.Value;
|
var playerPos = PlayerDetection.LastKnownPlayerPosition.Value;
|
||||||
var enemyPos = MainObject.GlobalPosition;
|
var enemyPos = MainObject.GlobalPosition;
|
||||||
|
|
||||||
|
|
@ -149,16 +160,10 @@ public partial class Shooting : EnemyStateBase3D
|
||||||
|
|
||||||
private Vector2 GetShootDirection()
|
private Vector2 GetShootDirection()
|
||||||
{
|
{
|
||||||
// if (Storage.EnemyData.PredictPlayer && PlayerDetection.LastKnowPlayerVelocity.HasValue)
|
if (!PlayerDetection.LastKnownPlayerPosition.HasValue)
|
||||||
// {
|
return Vector2.Zero;
|
||||||
// var predictedDirection = MathFunctions.PredictInterceptPosition(MainObject.GlobalPosition,
|
|
||||||
// PlayerDetection.LastKnownPlayerPosition.Value, PlayerDetection.LastKnowPlayerVelocity.Value,
|
|
||||||
// EquippedWeapon.WeaponData.BulletData.BulletSpeed);
|
|
||||||
// if (predictedDirection.HasValue) return (predictedDirection.Value - MainObject.GlobalPosition).Normalized();
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
|
|
||||||
return ( PlayerDetection.LastKnownPlayerPosition.Value - MainObject.GlobalPosition).ToVector2().Normalized();
|
return (PlayerDetection.LastKnownPlayerPosition.Value - MainObject.GlobalPosition).ToVector2().Normalized();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Shoot()
|
private void Shoot()
|
||||||
|
|
|
||||||
|
|
@ -8,16 +8,26 @@ public partial class Alert : EnemyStateBase
|
||||||
{
|
{
|
||||||
public override EnemyState StateId => EnemyState.Alert;
|
public override EnemyState StateId => EnemyState.Alert;
|
||||||
|
|
||||||
[Export] public EnemyStorageModule StorageModule { get; private set; }
|
private EnemyStorageModule StorageModule { get; set; }
|
||||||
|
|
||||||
[Export] public PlayerDetectionModule PlayerDetection { get; private set; }
|
private PlayerDetectionModule PlayerDetection { get; set; }
|
||||||
|
|
||||||
[Export] public GenericDamageReceiver DamageReceiver { get; private set; }
|
private GenericDamageReceiver DamageReceiver { get; set; }
|
||||||
|
|
||||||
[Export] public NavigationMovementModule NavigationModule { get; private set; }
|
private NavigationMovementModule NavigationModule { get; set; }
|
||||||
|
|
||||||
private bool _isPlayerInRange = false;
|
private bool _isPlayerInRange = false;
|
||||||
|
|
||||||
|
public override void Init(IStateMachine<EnemyState, CharacterBody2D> machine)
|
||||||
|
{
|
||||||
|
base.Init(machine);
|
||||||
|
// Try to resolve modules via the state machine so the same modules can be reused without per-state exports
|
||||||
|
StorageModule ??= StateMachine.GetModule<EnemyStorageModule>();
|
||||||
|
PlayerDetection ??= StateMachine.GetModule<PlayerDetectionModule>();
|
||||||
|
DamageReceiver ??= StateMachine.GetModule<GenericDamageReceiver>();
|
||||||
|
NavigationModule ??= StateMachine.GetModule<NavigationMovementModule>();
|
||||||
|
}
|
||||||
|
|
||||||
public override void EnterState()
|
public override void EnterState()
|
||||||
{
|
{
|
||||||
base.EnterState();
|
base.EnterState();
|
||||||
|
|
@ -25,8 +35,6 @@ public partial class Alert : EnemyStateBase
|
||||||
|
|
||||||
PlayerDetection.SetRange(StorageModule.Root.EnemyResource.PlayerDetectionRange);
|
PlayerDetection.SetRange(StorageModule.Root.EnemyResource.PlayerDetectionRange);
|
||||||
|
|
||||||
//_isPlayerInRange = PlayerDetection.IsPlayerInRange(StorageModule.Root.EnemyResource.ViewRange);
|
|
||||||
//GD.Print($"Player In Range: {_isPlayerInRange}");
|
|
||||||
|
|
||||||
PlayerDetection.PlayerInRange += PlayerDetectionOnPlayerInRange;
|
PlayerDetection.PlayerInRange += PlayerDetectionOnPlayerInRange;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,17 +8,14 @@ public partial class Controlled : EnemyStateBase
|
||||||
{
|
{
|
||||||
public override EnemyState StateId => EnemyState.Controlled;
|
public override EnemyState StateId => EnemyState.Controlled;
|
||||||
|
|
||||||
[Export]
|
private EnemyStorageModule StorageModule { get; set; }
|
||||||
public EnemyStorageModule StorageModule { get; private set; }
|
|
||||||
|
|
||||||
[Export]
|
private GenericDamageReceiver DamageReceiver { get; set; }
|
||||||
public GenericDamageReceiver DamageReceiver { get; private set; }
|
|
||||||
|
|
||||||
[Export]
|
[Export]
|
||||||
private InputProvider _inputProvider;
|
private InputProvider _inputProvider;
|
||||||
|
|
||||||
[Export]
|
private PlayerCrosshairProvider CrosshairProvider { get; set; }
|
||||||
public PlayerCrosshairProvider CrosshairProvider { get; private set; }
|
|
||||||
|
|
||||||
[Export] public Weapon EquippedWeapon { get; private set; }
|
[Export] public Weapon EquippedWeapon { get; private set; }
|
||||||
|
|
||||||
|
|
@ -28,6 +25,14 @@ public partial class Controlled : EnemyStateBase
|
||||||
|
|
||||||
private bool _isStrafing = false;
|
private bool _isStrafing = false;
|
||||||
|
|
||||||
|
public override void Init(IStateMachine<EnemyState, CharacterBody2D> machine)
|
||||||
|
{
|
||||||
|
base.Init(machine);
|
||||||
|
StorageModule ??= StateMachine.GetModule<EnemyStorageModule>();
|
||||||
|
DamageReceiver ??= StateMachine.GetModule<GenericDamageReceiver>();
|
||||||
|
CrosshairProvider ??= StateMachine.GetModule<PlayerCrosshairProvider>();
|
||||||
|
}
|
||||||
|
|
||||||
public override void EnterState()
|
public override void EnterState()
|
||||||
{
|
{
|
||||||
base.EnterState();
|
base.EnterState();
|
||||||
|
|
@ -80,10 +85,6 @@ public partial class Controlled : EnemyStateBase
|
||||||
|
|
||||||
if (Input.IsActionJustPressed(ControlEndAction))
|
if (Input.IsActionJustPressed(ControlEndAction))
|
||||||
{
|
{
|
||||||
// if (GameManager.Instance.ToggleControlMode() is GameState.Playing)
|
|
||||||
// {
|
|
||||||
// ResumeControl();
|
|
||||||
// }
|
|
||||||
StateMachine.SetState(EnemyState.Idle);
|
StateMachine.SetState(EnemyState.Idle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -126,7 +127,6 @@ public partial class Controlled : EnemyStateBase
|
||||||
|
|
||||||
// Shoot at the player's last known position
|
// Shoot at the player's last known position
|
||||||
EquippedWeapon.ShootDirection = direction;
|
EquippedWeapon.ShootDirection = direction;
|
||||||
//StorageModule.FacingDirection = direction;
|
|
||||||
//StorageModule.FacingDirection = direction.SnapToCardinal().Normalized();
|
//StorageModule.FacingDirection = direction.SnapToCardinal().Normalized();
|
||||||
|
|
||||||
EquippedWeapon.Shoot(BulletOwner.Player);
|
EquippedWeapon.Shoot(BulletOwner.Player);
|
||||||
|
|
|
||||||
|
|
@ -7,18 +7,16 @@ public partial class Dead : EnemyStateBase
|
||||||
{
|
{
|
||||||
public override EnemyState StateId => EnemyState.Dead;
|
public override EnemyState StateId => EnemyState.Dead;
|
||||||
|
|
||||||
[Export]
|
private EnemyStorageModule StorageModule { get; set; }
|
||||||
public EnemyStorageModule StorageModule { get; private set; }
|
|
||||||
|
|
||||||
[Export]
|
private EnemyDropsProvider DropsProvider { get; set; }
|
||||||
public EnemyDropsProvider DropsProvider { get; private set; }
|
|
||||||
|
|
||||||
// public override void Init(IStateMachine<EnemyState, CharacterBody2D> machine)
|
public override void Init(IStateMachine<EnemyState, CharacterBody2D> machine)
|
||||||
// {
|
{
|
||||||
// base.Init(machine);
|
base.Init(machine);
|
||||||
//
|
StorageModule ??= StateMachine.GetModule<EnemyStorageModule>();
|
||||||
//
|
DropsProvider ??= StateMachine.GetModule<EnemyDropsProvider>();
|
||||||
// }
|
}
|
||||||
|
|
||||||
public override void EnterState()
|
public override void EnterState()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,15 @@ using System.Linq;
|
||||||
using Cirno.Scripts.Resources;
|
using Cirno.Scripts.Resources;
|
||||||
using Cirno.Scripts.Resources.Loot;
|
using Cirno.Scripts.Resources.Loot;
|
||||||
using Godot;
|
using Godot;
|
||||||
using Godot.Collections;
|
|
||||||
|
|
||||||
namespace Cirno.Scripts.Components.FSM.Enemy;
|
namespace Cirno.Scripts.Components.FSM.Enemy;
|
||||||
|
|
||||||
public partial class EnemyStorageModule : Node2D, IFSMStorage
|
public partial class EnemyStorageModule : Node2D, IFSMStorage, IActorStorage
|
||||||
{
|
{
|
||||||
[Export]
|
[Export]
|
||||||
public EnemyFSMProxy Root { get; private set; }
|
public EnemyFSMProxy Root { get; private set; }
|
||||||
|
|
||||||
public Node2D RootAsNode => Root;
|
public Node RootAsNode => Root;
|
||||||
|
|
||||||
public EnemyResource EnemyData => Root.EnemyResource;
|
public EnemyResource EnemyData => Root.EnemyResource;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,21 +11,22 @@ public partial class Idle : EnemyStateBase
|
||||||
// Scan for player, move to alert if found
|
// Scan for player, move to alert if found
|
||||||
// Receive damage, move to alert if received
|
// Receive damage, move to alert if received
|
||||||
|
|
||||||
[Export]
|
private EnemyStorageModule StorageModule { get; set; }
|
||||||
public EnemyStorageModule StorageModule { get; private set; }
|
|
||||||
|
|
||||||
[Export]
|
private PlayerDetectionModule PlayerDetection { get; set; }
|
||||||
public PlayerDetectionModule PlayerDetection { get; private set; }
|
|
||||||
|
|
||||||
[Export]
|
private GenericDamageReceiver DamageReceiver { get; set; }
|
||||||
public GenericDamageReceiver DamageReceiver { get; private set; }
|
|
||||||
|
|
||||||
// public override void Init(IStateMachine<EnemyState, CharacterBody2D> machine)
|
|
||||||
// {
|
|
||||||
// base.Init(machine);
|
|
||||||
// }
|
|
||||||
private bool _isPlayerInRange = false;
|
private bool _isPlayerInRange = false;
|
||||||
|
|
||||||
|
public override void Init(IStateMachine<EnemyState, CharacterBody2D> machine)
|
||||||
|
{
|
||||||
|
base.Init(machine);
|
||||||
|
StorageModule ??= StateMachine.GetModule<EnemyStorageModule>();
|
||||||
|
PlayerDetection ??= StateMachine.GetModule<PlayerDetectionModule>();
|
||||||
|
DamageReceiver ??= StateMachine.GetModule<GenericDamageReceiver>();
|
||||||
|
}
|
||||||
|
|
||||||
public override void EnterState()
|
public override void EnterState()
|
||||||
{
|
{
|
||||||
base.EnterState();
|
base.EnterState();
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
uid://rrelumir3g6n
|
|
||||||
|
|
@ -4,15 +4,20 @@ using Godot;
|
||||||
|
|
||||||
namespace Cirno.Scripts.Components.FSM.Enemy;
|
namespace Cirno.Scripts.Components.FSM.Enemy;
|
||||||
|
|
||||||
public partial class Init : EnemyStateBase
|
public partial class InitState : EnemyStateBase
|
||||||
{
|
{
|
||||||
public override EnemyState StateId => EnemyState.Init;
|
public override EnemyState StateId => EnemyState.Init;
|
||||||
|
|
||||||
[Export]
|
private GenericDamageReceiver DamageReceiver { get; set; }
|
||||||
public GenericDamageReceiver DamageReceiver { get; private set; }
|
|
||||||
|
|
||||||
[Export]
|
private EnemyStorageModule StorageModule { get; set; }
|
||||||
public EnemyStorageModule StorageModule { get; private set; }
|
|
||||||
|
public override void Init(IStateMachine<EnemyState, CharacterBody2D> machine)
|
||||||
|
{
|
||||||
|
base.Init(machine);
|
||||||
|
DamageReceiver ??= StateMachine.GetModule<GenericDamageReceiver>();
|
||||||
|
StorageModule ??= StateMachine.GetModule<EnemyStorageModule>();
|
||||||
|
}
|
||||||
|
|
||||||
public override void EnterState()
|
public override void EnterState()
|
||||||
{
|
{
|
||||||
1
Scripts/Components/FSM/Enemy/InitState.cs.uid
Normal file
1
Scripts/Components/FSM/Enemy/InitState.cs.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://geli5yyi4m8d
|
||||||
|
|
@ -9,17 +9,13 @@ public partial class Shooting : EnemyStateBase
|
||||||
{
|
{
|
||||||
public override EnemyState StateId => EnemyState.Shooting;
|
public override EnemyState StateId => EnemyState.Shooting;
|
||||||
|
|
||||||
[Export]
|
private EnemyStorageModule StorageModule { get; set; }
|
||||||
public EnemyStorageModule StorageModule { get; private set; }
|
|
||||||
|
|
||||||
[Export]
|
private PlayerDetectionModule PlayerDetection { get; set; }
|
||||||
public PlayerDetectionModule PlayerDetection { get; private set; }
|
|
||||||
|
|
||||||
[Export]
|
private GenericDamageReceiver DamageReceiver { get; set; }
|
||||||
public GenericDamageReceiver DamageReceiver { get; private set; }
|
|
||||||
|
|
||||||
[Export]
|
private NavigationMovementModule NavigationModule { get; set; }
|
||||||
public NavigationMovementModule NavigationModule { get; private set; }
|
|
||||||
|
|
||||||
// [Export] public float MaxStrafeDistance { get; private set; } = 64f;
|
// [Export] public float MaxStrafeDistance { get; private set; } = 64f;
|
||||||
// [Export] public float MinStrafeDistance { get; private set; } = 16f;
|
// [Export] public float MinStrafeDistance { get; private set; } = 16f;
|
||||||
|
|
@ -34,6 +30,15 @@ public partial class Shooting : EnemyStateBase
|
||||||
|
|
||||||
private double _responseTimer = 0;
|
private double _responseTimer = 0;
|
||||||
|
|
||||||
|
public override void Init(IStateMachine<EnemyState, CharacterBody2D> machine)
|
||||||
|
{
|
||||||
|
base.Init(machine);
|
||||||
|
StorageModule ??= StateMachine.GetModule<EnemyStorageModule>();
|
||||||
|
PlayerDetection ??= StateMachine.GetModule<PlayerDetectionModule>();
|
||||||
|
DamageReceiver ??= StateMachine.GetModule<GenericDamageReceiver>();
|
||||||
|
NavigationModule ??= StateMachine.GetModule<NavigationMovementModule>();
|
||||||
|
}
|
||||||
|
|
||||||
public override void EnterState()
|
public override void EnterState()
|
||||||
{
|
{
|
||||||
base.EnterState();
|
base.EnterState();
|
||||||
|
|
|
||||||
11
Scripts/Components/FSM/IActorStorage.cs
Normal file
11
Scripts/Components/FSM/IActorStorage.cs
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace Cirno.Scripts.Components.FSM;
|
||||||
|
|
||||||
|
public interface IActorStorage
|
||||||
|
{
|
||||||
|
public Vector2 FacingDirection { get; set; }
|
||||||
|
public Vector2 AimingDirection { get; set; }
|
||||||
|
public Vector2 MovementDirection { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
1
Scripts/Components/FSM/IActorStorage.cs.uid
Normal file
1
Scripts/Components/FSM/IActorStorage.cs.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://rrdnrqkw8pna
|
||||||
|
|
@ -7,5 +7,5 @@ namespace Cirno.Scripts.Components.FSM;
|
||||||
public interface IFSMStorage
|
public interface IFSMStorage
|
||||||
{
|
{
|
||||||
public IEnumerable<LootDrop> LootDrops { get; }
|
public IEnumerable<LootDrop> LootDrops { get; }
|
||||||
public Node2D RootAsNode { get; }
|
public Node RootAsNode { get; }
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Collections.Generic;
|
#nullable enable
|
||||||
|
using System.Collections.Generic;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
namespace Cirno.Scripts.Components.FSM;
|
namespace Cirno.Scripts.Components.FSM;
|
||||||
|
|
@ -15,4 +16,7 @@ public interface IStateMachine<TKey, [MustBeVariant] TType>
|
||||||
public TKey GetState();
|
public TKey GetState();
|
||||||
|
|
||||||
public TType MainObject { get; }
|
public TType MainObject { get; }
|
||||||
|
|
||||||
|
// Allow states to query modules by type from the owning actor
|
||||||
|
public T? GetModule<T>() where T : Node;
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Collections.Generic;
|
#nullable enable
|
||||||
|
using System.Collections.Generic;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
namespace Cirno.Scripts.Components.FSM;
|
namespace Cirno.Scripts.Components.FSM;
|
||||||
|
|
@ -8,13 +9,15 @@ public abstract partial class IsoStateMachineBase<TKey, TType> : Node, IStateMac
|
||||||
where TType : Node
|
where TType : Node
|
||||||
{
|
{
|
||||||
public Dictionary<TKey, IState<TKey, TType>> States { get; set; } = new();
|
public Dictionary<TKey, IState<TKey, TType>> States { get; set; } = new();
|
||||||
public TKey CurrentStateIndex { get; set; }
|
public TKey CurrentStateIndex { get; set; } = default!;
|
||||||
public IState<TKey, TType> CurrentState => States[CurrentStateIndex];
|
public IState<TKey, TType> CurrentState => States[CurrentStateIndex];
|
||||||
public abstract TKey InitialState { get; protected set; }
|
public abstract TKey InitialState { get; protected set; }
|
||||||
|
|
||||||
private TType _mainObject;
|
private TType _mainObject = default!;
|
||||||
public TType MainObject => _mainObject;
|
public TType MainObject => _mainObject;
|
||||||
|
|
||||||
|
private bool _hasState;
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
_mainObject = this.GetParent<TType>();
|
_mainObject = this.GetParent<TType>();
|
||||||
|
|
@ -38,23 +41,38 @@ public abstract partial class IsoStateMachineBase<TKey, TType> : Node, IStateMac
|
||||||
|
|
||||||
public void SetState(TKey stateId)
|
public void SetState(TKey stateId)
|
||||||
{
|
{
|
||||||
if (CurrentStateIndex is not null)
|
if (_hasState)
|
||||||
{
|
{
|
||||||
|
// Keep track of previous state and exit it
|
||||||
|
// PreviousStateIndex is not part of this base; derived classes may add it if needed
|
||||||
CurrentState.ExitState();
|
CurrentState.ExitState();
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrentStateIndex = stateId;
|
CurrentStateIndex = stateId;
|
||||||
CurrentState.EnterState();
|
CurrentState.EnterState();
|
||||||
|
_hasState = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implement the GetModule<T>() helper so this base class satisfies the IStateMachine interface
|
||||||
|
public T? GetModule<T>() where T : Node
|
||||||
|
{
|
||||||
|
if (MainObject is null) return default;
|
||||||
|
foreach (var child in MainObject.GetChildren())
|
||||||
|
{
|
||||||
|
if (child is T t) return t;
|
||||||
|
}
|
||||||
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _Process(double delta)
|
public override void _Process(double delta)
|
||||||
{
|
{
|
||||||
if (CurrentStateIndex is null) return;
|
if (!_hasState) return;
|
||||||
CurrentState.ProcessState(delta);
|
CurrentState.ProcessState(delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _PhysicsProcess(double delta)
|
public override void _PhysicsProcess(double delta)
|
||||||
{
|
{
|
||||||
if (CurrentStateIndex is null) return;
|
if (!_hasState) return;
|
||||||
CurrentState.PhysicsProcessState(delta);
|
CurrentState.PhysicsProcessState(delta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -6,9 +6,18 @@ public abstract partial class ModuleBase<TKey, TType> : Node, IModule<TKey, TTyp
|
||||||
where TKey : notnull
|
where TKey : notnull
|
||||||
where TType : Node
|
where TType : Node
|
||||||
{
|
{
|
||||||
|
// Provide the state machine reference for derived modules to use without repeating boilerplate
|
||||||
|
protected IStateMachine<TKey, TType> StateMachine { get; private set; }
|
||||||
|
protected TType MainObject => StateMachine.MainObject;
|
||||||
|
|
||||||
|
// Default Init behaviour sets the state machine reference. Derived classes can still override
|
||||||
|
public virtual void Init(IStateMachine<TKey, TType> machine)
|
||||||
|
{
|
||||||
|
StateMachine = machine;
|
||||||
|
}
|
||||||
|
|
||||||
public abstract void EnterState(TKey state);
|
public abstract void EnterState(TKey state);
|
||||||
public abstract void ExitState(TKey state);
|
public abstract void ExitState(TKey state);
|
||||||
public abstract void Init(IStateMachine<TKey, TType> machine);
|
|
||||||
public abstract void Process(double delta);
|
public abstract void Process(double delta);
|
||||||
public abstract void PhysicsProcess(double delta);
|
public abstract void PhysicsProcess(double delta);
|
||||||
}
|
}
|
||||||
|
|
@ -21,19 +21,20 @@ public partial class Active : PlayerStateBase
|
||||||
[Export] public float Acceleration = 8f;
|
[Export] public float Acceleration = 8f;
|
||||||
[Export] public float Deceleration = 8f;
|
[Export] public float Deceleration = 8f;
|
||||||
|
|
||||||
[ExportCategory("Providers")] [Export] private PlayerWeaponProvider _weaponProvider;
|
// Providers previously exported on the state — resolve them from the actor via the state machine
|
||||||
[Export] private PlayerAnimationProvider _animationProvider;
|
private PlayerWeaponProvider _weaponProvider;
|
||||||
[Export] private PlayerCrosshairProvider _crosshairProvider;
|
private PlayerAnimationProvider _animationProvider;
|
||||||
[Export] private PlayerHitboxSpriteProvider _hitboxSpriteProvider;
|
private PlayerCrosshairProvider _crosshairProvider;
|
||||||
|
private PlayerHitboxSpriteProvider _hitboxSprite_provider;
|
||||||
|
|
||||||
[Export] private InputProvider _inputProvider;
|
private InputProvider _inputProvider;
|
||||||
|
|
||||||
[Export] private PlayerDamageReceiver _damageReceiver;
|
private PlayerDamageReceiver _damageReceiver;
|
||||||
[Export] private ActivationProvider _activationProvider;
|
private ActivationProvider _activationProvider;
|
||||||
|
|
||||||
[Export] private InteractionController _interactionController;
|
private InteractionController _interaction_controller;
|
||||||
|
|
||||||
[Export] private PlayerStorageModule _storageModule;
|
private PlayerStorageModule _storageModule;
|
||||||
|
|
||||||
private bool _isStrafing;
|
private bool _isStrafing;
|
||||||
|
|
||||||
|
|
@ -49,31 +50,46 @@ public partial class Active : PlayerStateBase
|
||||||
|
|
||||||
_hud = Hud.Instance;
|
_hud = Hud.Instance;
|
||||||
|
|
||||||
_damageReceiver.Death += () => { ChangeState(PlayerState.Dead); };
|
// Resolve modules from the actor attached to this state machine
|
||||||
|
_weaponProvider ??= StateMachine.GetModule<PlayerWeaponProvider>();
|
||||||
|
_animationProvider ??= StateMachine.GetModule<PlayerAnimationProvider>();
|
||||||
|
_crosshairProvider ??= StateMachine.GetModule<PlayerCrosshairProvider>();
|
||||||
|
_hitboxSprite_provider ??= StateMachine.GetModule<PlayerHitboxSpriteProvider>();
|
||||||
|
|
||||||
_damageReceiver.HealthDecreased += (value, newValue, maxValue) =>
|
_inputProvider ??= StateMachine.GetModule<InputProvider>();
|
||||||
|
|
||||||
|
_damageReceiver ??= StateMachine.GetModule<PlayerDamageReceiver>();
|
||||||
|
_activationProvider ??= StateMachine.GetModule<ActivationProvider>();
|
||||||
|
|
||||||
|
_interaction_controller ??= StateMachine.GetModule<InteractionController>();
|
||||||
|
|
||||||
|
_storageModule ??= StateMachine.GetModule<PlayerStorageModule>();
|
||||||
|
|
||||||
|
if (_damageReceiver != null)
|
||||||
{
|
{
|
||||||
_animationProvider.Blink();
|
_damageReceiver.Death += () => { ChangeState(PlayerState.Dead); };
|
||||||
//_hud.UpdateHealth(value, maxValue);
|
|
||||||
};
|
|
||||||
|
|
||||||
_damageReceiver.ShieldDecreased += (value, newValue, maxValue) =>
|
_damageReceiver.HealthDecreased += (_, _, _) =>
|
||||||
{
|
{
|
||||||
_animationProvider.PlayShieldAnimation();
|
_animationProvider?.Blink();
|
||||||
//_hud.UpdateShield(value, maxValue);
|
//_hud.UpdateHealth(value, maxValue);
|
||||||
};
|
};
|
||||||
|
|
||||||
_damageReceiver.Init(StateMachine);
|
_damageReceiver.ShieldDecreased += (_, _, _) =>
|
||||||
|
{
|
||||||
|
_animationProvider?.PlayShieldAnimation();
|
||||||
|
//_hud.UpdateShield(value, maxValue);
|
||||||
|
};
|
||||||
|
|
||||||
_damageReceiver.RefillHealth();
|
_damageReceiver.Init(StateMachine);
|
||||||
_damageReceiver.RefillShield();
|
|
||||||
|
|
||||||
_activationProvider.Init(MainObject);
|
_damageReceiver.RefillHealth();
|
||||||
|
_damageReceiver.RefillShield();
|
||||||
|
}
|
||||||
|
|
||||||
//_weaponProvider = stateMachine.GetNode<PlayerWeaponProvider>("WeaponProvider");
|
_activationProvider?.Init(MainObject);
|
||||||
//_animationProvider = stateMachine.GetNode<PlayerAnimationProvider>("AnimationProvider");
|
|
||||||
|
|
||||||
_weaponProvider.Init(MainObject);
|
_weaponProvider?.Init(MainObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void EnterState()
|
public override void EnterState()
|
||||||
|
|
@ -81,11 +97,11 @@ public partial class Active : PlayerStateBase
|
||||||
base.EnterState();
|
base.EnterState();
|
||||||
// enable sprite
|
// enable sprite
|
||||||
// enable crosshair
|
// enable crosshair
|
||||||
_crosshairProvider.Show();
|
_crosshairProvider?.Show();
|
||||||
_animationProvider.ShowSprite();
|
_animationProvider?.ShowSprite();
|
||||||
_damageReceiver.Enabled = true;
|
if (_damageReceiver != null) _damageReceiver.Enabled = true;
|
||||||
_activationProvider.Enabled = true;
|
if (_activationProvider != null) _activationProvider.Enabled = true;
|
||||||
_interactionController.Enabled = true;
|
if (_interaction_controller != null) _interaction_controller.Enabled = true;
|
||||||
|
|
||||||
_accelerationPerSecond = Speed / Acceleration;
|
_accelerationPerSecond = Speed / Acceleration;
|
||||||
_decelerationPerSecond = Speed / Deceleration;
|
_decelerationPerSecond = Speed / Deceleration;
|
||||||
|
|
@ -94,14 +110,14 @@ public partial class Active : PlayerStateBase
|
||||||
public override void ExitState()
|
public override void ExitState()
|
||||||
{
|
{
|
||||||
base.ExitState();
|
base.ExitState();
|
||||||
_animationProvider.SetAnimationSpeed(Vector2.Zero);
|
_animationProvider?.SetAnimationSpeed(Vector2.Zero);
|
||||||
//_animationProvider.SetAnimation(Vector2.Zero);
|
//_animation_provider.SetAnimation(Vector2.Zero);
|
||||||
_crosshairProvider.Hide();
|
_crosshairProvider?.Hide();
|
||||||
_hitboxSpriteProvider.Hide();
|
_hitboxSprite_provider?.Hide();
|
||||||
|
|
||||||
_damageReceiver.Enabled = false;
|
if (_damageReceiver != null) _damageReceiver.Enabled = false;
|
||||||
_activationProvider.Enabled = false;
|
if (_activationProvider != null) _activationProvider.Enabled = false;
|
||||||
_interactionController.Enabled = false;
|
if (_interaction_controller != null) _interaction_controller.Enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private float _accelerationPerSecond;
|
private float _accelerationPerSecond;
|
||||||
|
|
@ -147,7 +163,7 @@ public partial class Active : PlayerStateBase
|
||||||
_isStrafing = _inputProvider.GetStrafePressed();
|
_isStrafing = _inputProvider.GetStrafePressed();
|
||||||
|
|
||||||
// Toggle visibility of the hitbox sprite based on strafing
|
// Toggle visibility of the hitbox sprite based on strafing
|
||||||
_hitboxSpriteProvider.SetVisibility(_isStrafing);
|
_hitboxSprite_provider?.SetVisibility(_isStrafing);
|
||||||
|
|
||||||
var rightStickInput = _inputProvider.GetAimInput().Normalized();
|
var rightStickInput = _inputProvider.GetAimInput().Normalized();
|
||||||
|
|
||||||
|
|
@ -164,13 +180,13 @@ public partial class Active : PlayerStateBase
|
||||||
}
|
}
|
||||||
// }
|
// }
|
||||||
|
|
||||||
_animationProvider.SetAnimationSpeed(MainObject.Velocity);
|
_animationProvider?.SetAnimationSpeed(MainObject.Velocity);
|
||||||
_animationProvider.SetAnimation(FacingDirection);
|
_animationProvider?.SetAnimation(FacingDirection);
|
||||||
|
|
||||||
HandleWeaponSwitch();
|
HandleWeaponSwitch();
|
||||||
_weaponProvider.Update(delta);
|
_weaponProvider?.Update(delta);
|
||||||
|
|
||||||
//_crosshairProvider.UpdatePosition(FacingDirection);
|
//_crosshair_provider.UpdatePosition(FacingDirection);
|
||||||
|
|
||||||
HandleShoot();
|
HandleShoot();
|
||||||
|
|
||||||
|
|
@ -200,28 +216,28 @@ public partial class Active : PlayerStateBase
|
||||||
{
|
{
|
||||||
if (_inputProvider.GetReloadJustPressed())
|
if (_inputProvider.GetReloadJustPressed())
|
||||||
{
|
{
|
||||||
_weaponProvider.Reload();
|
_weaponProvider?.Reload();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_inputProvider.GetShootPressed()) return;
|
if (!_inputProvider.GetShootPressed()) return;
|
||||||
_weaponProvider.Shoot(this.FacingDirection);
|
_weaponProvider?.Shoot(this.FacingDirection);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleInteraction()
|
private void HandleInteraction()
|
||||||
{
|
{
|
||||||
_activationProvider.HandleInteraction();
|
_activationProvider?.HandleInteraction();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleWeaponSwitch()
|
private void HandleWeaponSwitch()
|
||||||
{
|
{
|
||||||
if (_inputProvider.GetWeaponNextJustPressed())
|
if (_inputProvider.GetWeaponNextJustPressed())
|
||||||
{
|
{
|
||||||
_weaponProvider.NextWeapon();
|
_weaponProvider?.NextWeapon();
|
||||||
}
|
}
|
||||||
else if (_inputProvider.GetWeaponPreviousJustPressed())
|
else if (_inputProvider.GetWeaponPreviousJustPressed())
|
||||||
{
|
{
|
||||||
_weaponProvider.PreviousWeapon();
|
_weaponProvider?.PreviousWeapon();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -6,11 +6,13 @@ public partial class Drowning : PlayerStateBase
|
||||||
{
|
{
|
||||||
public override PlayerState StateId => PlayerState.Drowning;
|
public override PlayerState StateId => PlayerState.Drowning;
|
||||||
|
|
||||||
[Export]
|
|
||||||
private PlayerAnimationProvider _animationProvider;
|
private PlayerAnimationProvider _animationProvider;
|
||||||
|
|
||||||
public override void EnterState()
|
public override void EnterState()
|
||||||
{
|
{
|
||||||
|
_animationProvider ??= StateMachine.GetModule<PlayerAnimationProvider>();
|
||||||
|
if (_animationProvider is null) return;
|
||||||
|
|
||||||
_animationProvider.PlayDrowningAnimation();
|
_animationProvider.PlayDrowningAnimation();
|
||||||
|
|
||||||
// Wait for animation to be over and switch to death
|
// Wait for animation to be over and switch to death
|
||||||
|
|
@ -19,6 +21,7 @@ public partial class Drowning : PlayerStateBase
|
||||||
|
|
||||||
private void AnimationProviderOnOnAnimationEnded(StringName animationName)
|
private void AnimationProviderOnOnAnimationEnded(StringName animationName)
|
||||||
{
|
{
|
||||||
|
if (_animationProvider is null) return;
|
||||||
if (animationName != _animationProvider.DrowningAnimationName) return;
|
if (animationName != _animationProvider.DrowningAnimationName) return;
|
||||||
|
|
||||||
_animationProvider.OnAnimationEnded -= AnimationProviderOnOnAnimationEnded;
|
_animationProvider.OnAnimationEnded -= AnimationProviderOnOnAnimationEnded;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
namespace Cirno.Scripts.Components.FSM.Player;
|
namespace Cirno.Scripts.Components.FSM.Player;
|
||||||
|
|
@ -8,16 +6,27 @@ public partial class Init : PlayerStateBase
|
||||||
{
|
{
|
||||||
public override PlayerState StateId => PlayerState.Init;
|
public override PlayerState StateId => PlayerState.Init;
|
||||||
|
|
||||||
[Export]
|
|
||||||
private PlayerAnimationProvider _animationProvider;
|
private PlayerAnimationProvider _animationProvider;
|
||||||
|
|
||||||
[Export] private PlayerStorageModule _storageModule;
|
private PlayerStorageModule _storageModule;
|
||||||
|
|
||||||
public override void EnterState()
|
public override void EnterState()
|
||||||
{
|
{
|
||||||
_storageModule.FacingDirection = ((PlayerStateMachine)StateMachine).StartingDirection;
|
// Resolve modules lazily to avoid method/class name conflicts with Init
|
||||||
_animationProvider.PlayUnteleportAnimation();
|
_animationProvider ??= StateMachine.GetModule<PlayerAnimationProvider>();
|
||||||
_ = AutoSwitchToStart();
|
_storageModule ??= StateMachine.GetModule<PlayerStorageModule>();
|
||||||
|
|
||||||
|
if (_storageModule != null)
|
||||||
|
_storageModule.FacingDirection = ((PlayerStateMachine)StateMachine).StartingDirection;
|
||||||
|
|
||||||
|
if (_animationProvider != null)
|
||||||
|
{
|
||||||
|
_animationProvider.PlayUnteleportAnimation();
|
||||||
|
// If you need to wait for animation end, subscribe here
|
||||||
|
}
|
||||||
|
|
||||||
|
var timer = GetTree().CreateTimer(0.5f);
|
||||||
|
timer.Timeout += () => StateMachine.SetState(PlayerState.Active);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ExitState()
|
public override void ExitState()
|
||||||
|
|
@ -34,10 +43,4 @@ public partial class Init : PlayerStateBase
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task AutoSwitchToStart()
|
|
||||||
{
|
|
||||||
await Task.Delay(500);
|
|
||||||
StateMachine.SetState(PlayerState.Active);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
using System;
|
using Cirno.Scripts.Components.Actors;
|
||||||
using Cirno.Scripts.Components.Actors;
|
|
||||||
using Cirno.Scripts.Resources;
|
using Cirno.Scripts.Resources;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
|
|
@ -13,7 +12,7 @@ public partial class PlayerFSMItemUseModule : ModuleBase<PlayerState, CharacterB
|
||||||
[Export]
|
[Export]
|
||||||
public ActorResourceProvider Shield { get; set; }
|
public ActorResourceProvider Shield { get; set; }
|
||||||
|
|
||||||
[Export] private PlayerStorageModule _storageModule;
|
private PlayerStorageModule _storageModule;
|
||||||
|
|
||||||
public Vector2 FacingDirection
|
public Vector2 FacingDirection
|
||||||
{
|
{
|
||||||
|
|
@ -21,7 +20,7 @@ public partial class PlayerFSMItemUseModule : ModuleBase<PlayerState, CharacterB
|
||||||
private set => _storageModule.FacingDirection = value;
|
private set => _storageModule.FacingDirection = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Enabled { get; set; } = false;
|
public bool Enabled { get; set; }
|
||||||
|
|
||||||
public override void EnterState(PlayerState state)
|
public override void EnterState(PlayerState state)
|
||||||
{
|
{
|
||||||
|
|
@ -40,6 +39,7 @@ public partial class PlayerFSMItemUseModule : ModuleBase<PlayerState, CharacterB
|
||||||
{
|
{
|
||||||
InventoryManager.Instance.ItemUsed += this.UseItem;
|
InventoryManager.Instance.ItemUsed += this.UseItem;
|
||||||
_machine = machine;
|
_machine = machine;
|
||||||
|
_storageModule ??= StateMachine.GetModule<PlayerStorageModule>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UseItem(LootItem item, int totalcount)
|
private void UseItem(LootItem item, int totalcount)
|
||||||
|
|
@ -48,94 +48,8 @@ public partial class PlayerFSMItemUseModule : ModuleBase<PlayerState, CharacterB
|
||||||
GD.Print($"Used {item.ItemName} in player");
|
GD.Print($"Used {item.ItemName} in player");
|
||||||
|
|
||||||
item.ItemEffect?.Execute(this, item);
|
item.ItemEffect?.Execute(this, item);
|
||||||
|
|
||||||
return;
|
|
||||||
|
|
||||||
// switch (item.Item)
|
|
||||||
// {
|
|
||||||
// case ItemTypes.KeycardRed:
|
|
||||||
// break;
|
|
||||||
// case ItemTypes.KeycardBlue:
|
|
||||||
// break;
|
|
||||||
// case ItemTypes.KeycardGreen:
|
|
||||||
// break;
|
|
||||||
// case ItemTypes.Ammo:
|
|
||||||
// break;
|
|
||||||
// case ItemTypes.Medkit:
|
|
||||||
// Heal(item);
|
|
||||||
// break;
|
|
||||||
// case ItemTypes.FrogBomb:
|
|
||||||
// SpawnSpiderBomb(item);
|
|
||||||
// break;
|
|
||||||
// case ItemTypes.Bomb:
|
|
||||||
// SpawnBomb(item);
|
|
||||||
// break;
|
|
||||||
// case ItemTypes.Mine:
|
|
||||||
// break;
|
|
||||||
// case ItemTypes.Battery:
|
|
||||||
// RechargeShield(item);
|
|
||||||
// break;
|
|
||||||
// case ItemTypes.Weapon:
|
|
||||||
// break;
|
|
||||||
// case ItemTypes.Power:
|
|
||||||
// break;
|
|
||||||
// case ItemTypes.Points:
|
|
||||||
// break;
|
|
||||||
// case ItemTypes.Credits:
|
|
||||||
// break;
|
|
||||||
// case ItemTypes.KeyItem:
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// private void SpawnBomb(LootItem item)
|
|
||||||
// {
|
|
||||||
// GD.Print("Spawned bomb");
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private void Heal(LootItem item)
|
|
||||||
// {
|
|
||||||
// Health.CurrentResource += Mathf.CeilToInt(Health.MaxResource * 25 / 100);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private void RechargeShield(LootItem item)
|
|
||||||
// {
|
|
||||||
// Shield.CurrentResource += Mathf.CeilToInt(Health.MaxResource * 25 / 100);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private void SpawnSpiderBomb(LootItem item)
|
|
||||||
// {
|
|
||||||
// //var bullet = item.WeaponData.BulletData.BulletScene.Instantiate<Bullet>();
|
|
||||||
// //bullet.Initialize(item.WeaponData.BulletData.MakeBullet(this.GlobalPosition, 1,0, 0), GameManager.Instance);
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// //InventoryManager.Instance.RemoveItem(item.ItemKey, 1);
|
|
||||||
// // emit projectile
|
|
||||||
// var bullet = this.CreateChildOf<Bullet>(GameManager.Instance.BulletsContainer, item.WeaponData.BulletData.BulletScene, this.GlobalPosition);
|
|
||||||
//
|
|
||||||
// var bulletData = item.WeaponData.MakeBullet(this.GlobalPosition);
|
|
||||||
//
|
|
||||||
// bullet.Initialize(bulletData, GameManager.Instance);
|
|
||||||
// bullet.SetDirection(FacingDirection);
|
|
||||||
// bullet.RotateSpriteDegrees(-90);
|
|
||||||
// //bullet.SetDirection(_facingDirection);
|
|
||||||
// bullet.Speed = item.WeaponData.BulletData.BulletSpeed;
|
|
||||||
//
|
|
||||||
// _machine.SetState(PlayerState.Controlling);
|
|
||||||
//
|
|
||||||
// //RequestMovementDisable(true);
|
|
||||||
// // set camera
|
|
||||||
// GameManager.Instance.CameraTargetObject(bullet);
|
|
||||||
// // set event destroy
|
|
||||||
// bullet.OnDestroy += () =>
|
|
||||||
// {
|
|
||||||
// GameManager.Instance.CameraTargetPlayer();
|
|
||||||
// _machine.SetState(PlayerState.Active);
|
|
||||||
// //RequestMovementDisable(false);
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
|
|
||||||
public override void Process(double delta)
|
public override void Process(double delta)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,12 @@ public partial class Teleporting : PlayerStateBase
|
||||||
{
|
{
|
||||||
public override PlayerState StateId => PlayerState.Teleporting;
|
public override PlayerState StateId => PlayerState.Teleporting;
|
||||||
|
|
||||||
[Export]
|
|
||||||
private PlayerAnimationProvider _animationProvider;
|
private PlayerAnimationProvider _animationProvider;
|
||||||
|
|
||||||
public override void EnterState()
|
public override void EnterState()
|
||||||
{
|
{
|
||||||
_animationProvider.PlayTeleportAnimation();
|
_animationProvider ??= StateMachine.GetModule<PlayerAnimationProvider>();
|
||||||
|
_animationProvider?.PlayTeleportAnimation();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ExitState()
|
public override void ExitState()
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,13 @@ namespace Cirno.Scripts.Components.FSM.Player;
|
||||||
|
|
||||||
public partial class UnTeleporting : PlayerStateBase
|
public partial class UnTeleporting : PlayerStateBase
|
||||||
{
|
{
|
||||||
public override PlayerState StateId => PlayerState.UnTeleporting
|
public override PlayerState StateId => PlayerState.UnTeleporting;
|
||||||
;
|
|
||||||
[Export]
|
|
||||||
private PlayerAnimationProvider _animationProvider;
|
private PlayerAnimationProvider _animationProvider;
|
||||||
|
|
||||||
public override void EnterState()
|
public override void EnterState()
|
||||||
{
|
{
|
||||||
_animationProvider.PlayUnteleportAnimation();
|
_animationProvider ??= StateMachine.GetModule<PlayerAnimationProvider>();
|
||||||
|
_animationProvider?.PlayUnteleportAnimation();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ExitState()
|
public override void ExitState()
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Collections.Generic;
|
#nullable enable
|
||||||
|
using System.Collections.Generic;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
namespace Cirno.Scripts.Components.FSM;
|
namespace Cirno.Scripts.Components.FSM;
|
||||||
|
|
@ -7,14 +8,21 @@ public abstract partial class StateMachineBase<TKey, TType> : Node, IStateMachin
|
||||||
where TKey : notnull
|
where TKey : notnull
|
||||||
where TType : Node
|
where TType : Node
|
||||||
{
|
{
|
||||||
|
[Signal]
|
||||||
|
public delegate void StateChangedEventHandler(Variant from, Variant to);
|
||||||
|
|
||||||
public Dictionary<TKey, IState<TKey, TType>> States { get; set; } = new();
|
public Dictionary<TKey, IState<TKey, TType>> States { get; set; } = new();
|
||||||
public TKey CurrentStateIndex { get; set; }
|
public TKey CurrentStateIndex { get; set; }
|
||||||
|
public TKey PreviousStateIndex { get; private set; }
|
||||||
public IState<TKey, TType> CurrentState => States[CurrentStateIndex];
|
public IState<TKey, TType> CurrentState => States[CurrentStateIndex];
|
||||||
public abstract TKey InitialState { get; protected set; }
|
public abstract TKey InitialState { get; protected set; }
|
||||||
|
|
||||||
private TType _mainObject;
|
private TType _mainObject = default!;
|
||||||
public TType MainObject => _mainObject;
|
public TType MainObject => _mainObject;
|
||||||
|
|
||||||
|
// Internal flag to indicate if a state has been set previously
|
||||||
|
private bool _hasState;
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
_mainObject = this.GetParent<TType>();
|
_mainObject = this.GetParent<TType>();
|
||||||
|
|
@ -38,23 +46,54 @@ public abstract partial class StateMachineBase<TKey, TType> : Node, IStateMachin
|
||||||
|
|
||||||
public void SetState(TKey stateId)
|
public void SetState(TKey stateId)
|
||||||
{
|
{
|
||||||
if (CurrentStateIndex is not null)
|
if (_hasState)
|
||||||
{
|
{
|
||||||
|
PreviousStateIndex = CurrentStateIndex;
|
||||||
CurrentState.ExitState();
|
CurrentState.ExitState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var from = _hasState ? CurrentStateIndex.ToString() : string.Empty;
|
||||||
CurrentStateIndex = stateId;
|
CurrentStateIndex = stateId;
|
||||||
|
var to = CurrentStateIndex.ToString();
|
||||||
CurrentState.EnterState();
|
CurrentState.EnterState();
|
||||||
|
_hasState = true;
|
||||||
|
EmitSignal(nameof(StateChanged), from, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the first descendant under the main object (root node that owns this state machine)
|
||||||
|
/// that matches the requested type T, or null if none found. This lets states fetch
|
||||||
|
/// modules attached to the actor without per-state editor wiring.
|
||||||
|
/// </summary>
|
||||||
|
public T? GetModule<T>() where T : Node
|
||||||
|
{
|
||||||
|
if (MainObject is null) return default;
|
||||||
|
return FindInChildren<T>(MainObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static T? FindInChildren<T>(Node parent) where T : Node
|
||||||
|
{
|
||||||
|
foreach (var obj in parent.GetChildren())
|
||||||
|
{
|
||||||
|
if (obj is T t) return t;
|
||||||
|
if (obj is Node node)
|
||||||
|
{
|
||||||
|
var found = FindInChildren<T>(node);
|
||||||
|
if (found is not null) return found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _Process(double delta)
|
public override void _Process(double delta)
|
||||||
{
|
{
|
||||||
if (CurrentStateIndex is null) return;
|
if (!_hasState) return;
|
||||||
CurrentState.ProcessState(delta);
|
CurrentState.ProcessState(delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _PhysicsProcess(double delta)
|
public override void _PhysicsProcess(double delta)
|
||||||
{
|
{
|
||||||
if (CurrentStateIndex is null) return;
|
if (!_hasState) return;
|
||||||
CurrentState.PhysicsProcessState(delta);
|
CurrentState.PhysicsProcessState(delta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8,6 +8,8 @@ using Cirno.Scripts.Components.Actors;
|
||||||
using Cirno.Scripts.Resources;
|
using Cirno.Scripts.Resources;
|
||||||
using Godot.Collections;
|
using Godot.Collections;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Cirno.Scripts.Components.FSM;
|
||||||
|
using Cirno.Scripts.Components.FSM._3DPlayer;
|
||||||
using Cirno.Scripts.Controllers;
|
using Cirno.Scripts.Controllers;
|
||||||
using Cirno.Scripts.Utils;
|
using Cirno.Scripts.Utils;
|
||||||
|
|
||||||
|
|
@ -586,14 +588,4 @@ public partial class PlayerMovement : CharacterBody2D, IDestructible
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum PlayerState
|
|
||||||
{
|
|
||||||
Init,
|
|
||||||
Active,
|
|
||||||
Cutscene,
|
|
||||||
Teleporting,
|
|
||||||
UnTeleporting,
|
|
||||||
Controlling,
|
|
||||||
Dead,
|
|
||||||
Drowning,
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using Godot;
|
using Cirno.Scripts.Components.FSM;
|
||||||
|
using Godot;
|
||||||
|
|
||||||
namespace Cirno.Scripts.Resources.Events;
|
namespace Cirno.Scripts.Resources.Events;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Cirno.Scripts.Components.FSM;
|
||||||
using Godot;
|
using Godot;
|
||||||
using GTweens.Builders;
|
using GTweens.Builders;
|
||||||
using GTweens.Easings;
|
using GTweens.Easings;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using Cirno.Scripts.Components.FSM.Player;
|
using Cirno.Scripts.Components.FSM;
|
||||||
|
using Cirno.Scripts.Components.FSM.Player;
|
||||||
using Cirno.Scripts.Controllers;
|
using Cirno.Scripts.Controllers;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
@tool
|
@tool
|
||||||
class_name BaseViewer
|
class_name BaseViewer
|
||||||
extends PanelContainer
|
extends PanelContainer
|
||||||
|
|
||||||
|
|
@ -173,4 +173,3 @@ func _should_show_3d() -> bool:
|
||||||
func _log_to_dock(message: String, color: Color = Color.WHITE) -> void:
|
func _log_to_dock(message: String, color: Color = Color.WHITE) -> void:
|
||||||
if _dock and _dock.has_method("add_log"):
|
if _dock and _dock.has_method("add_log"):
|
||||||
_dock.call("add_log", message, color)
|
_dock.call("add_log", message, color)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
@tool
|
@tool
|
||||||
extends BaseCreatorDialog
|
extends BaseCreatorDialog
|
||||||
|
|
||||||
# Popup window for configuring bullet parameters before creation
|
# Popup window for configuring bullet parameters before creation
|
||||||
|
|
@ -371,4 +371,3 @@ func _show_error(message: String) -> void:
|
||||||
dialog.title = "Error"
|
dialog.title = "Error"
|
||||||
add_child(dialog)
|
add_child(dialog)
|
||||||
dialog.popup_centered()
|
dialog.popup_centered()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
@tool
|
@tool
|
||||||
extends BaseViewer
|
extends BaseViewer
|
||||||
|
|
||||||
# Displays all bullets from the Resources/Bullets folders in a grid format
|
# Displays all bullets from the Resources/Bullets folders in a grid format
|
||||||
|
|
@ -330,4 +330,3 @@ func _open_bullet_dialog(is_3d: bool, prefill_data: Dictionary = {}) -> void:
|
||||||
dialog.call_deferred("setup_bullet", _editor_interface, is_3d, prefill_data)
|
dialog.call_deferred("setup_bullet", _editor_interface, is_3d, prefill_data)
|
||||||
dialog.call_deferred("connect", "bullet_data_confirmed", _on_duplicate_bullet_confirmed)
|
dialog.call_deferred("connect", "bullet_data_confirmed", _on_duplicate_bullet_confirmed)
|
||||||
dialog.call_deferred("popup_centered")
|
dialog.call_deferred("popup_centered")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
@tool
|
@tool
|
||||||
extends BaseCreatorDialog
|
extends BaseCreatorDialog
|
||||||
|
|
||||||
signal enemy_data_confirmed(enemy_data: Dictionary)
|
signal enemy_data_confirmed(enemy_data: Dictionary)
|
||||||
|
|
@ -303,6 +303,3 @@ func _on_create_pressed() -> void:
|
||||||
_save_dialog_size_and_position()
|
_save_dialog_size_and_position()
|
||||||
enemy_data_confirmed.emit(enemy_data)
|
enemy_data_confirmed.emit(enemy_data)
|
||||||
queue_free()
|
queue_free()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
@tool
|
@tool
|
||||||
extends BaseViewer
|
extends BaseViewer
|
||||||
|
|
||||||
# Displays all enemies from directory structure or database
|
# Displays all enemies from directory structure or database
|
||||||
|
|
@ -224,5 +224,3 @@ func _on_create_enemy_pressed() -> void:
|
||||||
dialog.enemy_data_confirmed.connect(func(enemy_data):
|
dialog.enemy_data_confirmed.connect(func(enemy_data):
|
||||||
duplicate_enemy_requested.emit(enemy_data)
|
duplicate_enemy_requested.emit(enemy_data)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -511,4 +511,3 @@ func _create_enemy_resource(path: String, enemy_data: Dictionary) -> bool:
|
||||||
return false
|
return false
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue