From fdec052c16ed7abd07cd27e0de497794371b2e1d Mon Sep 17 00:00:00 2001 From: Marco Date: Wed, 5 Feb 2025 19:41:49 +0100 Subject: [PATCH] Danmaku system --- Cirno.sln.DotSettings.user | 2 + Resources/BossPhases/TestBoss1.tres | 43 +++++++++ Resources/Patterns/rumia_ns_1.tres | 21 +++++ Resources/Patterns/rumia_ns_2.tres | 47 ++++++++++ Scenes/Actors/Rumia.tscn | 85 ++++++++++++++++++ Scenes/Maps/BossTestArena.tscn | 15 +++- Scenes/Weapons/Bullets/enemyBullet_green.tscn | 30 +++++++ Scenes/Weapons/Bullets/enemyBullet_mid.tscn | 30 +++++++ .../Weapons/Bullets/enemyBullet_yellow.tscn | 27 ++++++ Scripts/Actors/Boss.cs | 54 +++++++++++ Scripts/AttackPatterns/MovementPattern.cs | 54 +++++++++++ Scripts/AttackPatterns/PatternTest.cs | 45 ++++++++++ Scripts/AttackPatterns/SpiralPattern.cs | 47 ++++++++++ Scripts/AttackPatterns/TargetedPattern.cs | 54 +++++++++++ Scripts/Bullet.cs | 1 - Scripts/Components/BulletSpawner.cs | 53 +++++++++++ Scripts/Enemy.cs | 17 +++- Scripts/GameManager.cs | 4 + Scripts/Resources/AttackPattern.cs | 13 +++ Scripts/Resources/BossPhase.cs | 35 ++++++++ Scripts/Resources/DecreasingSpeedModifier.cs | 14 +++ Scripts/Resources/IBulletModifier.cs | 6 ++ Scripts/Resources/PatternGroup.cs | 42 +++++++++ Scripts/Resources/SimpleMovementPattern.cs | 37 ++++++++ Scripts/Weapon.cs | 1 - Sprites/Actors/Rumia.aseprite | 3 + Sprites/Actors/Rumia.png | 3 + Sprites/Actors/Rumia.png.import | 34 +++++++ Sprites/Bullets/mid_bullet.aseprite | 3 + Sprites/Bullets/mid_bullet.png | 3 + Sprites/Bullets/mid_bullet.png.import | 34 +++++++ Sprites/Bullets/small_bullet_green.ase | Bin 0 -> 624 bytes Sprites/Bullets/small_bullet_green.png | 3 + Sprites/Bullets/small_bullet_green.png.import | 34 +++++++ Sprites/Bullets/small_bullet_yellow.ase | Bin 0 -> 627 bytes Sprites/Bullets/small_bullet_yellow.png | 3 + .../Bullets/small_bullet_yellow.png.import | 34 +++++++ project.godot | 2 +- 38 files changed, 924 insertions(+), 9 deletions(-) create mode 100644 Resources/BossPhases/TestBoss1.tres create mode 100644 Resources/Patterns/rumia_ns_1.tres create mode 100644 Resources/Patterns/rumia_ns_2.tres create mode 100644 Scenes/Actors/Rumia.tscn create mode 100644 Scenes/Weapons/Bullets/enemyBullet_green.tscn create mode 100644 Scenes/Weapons/Bullets/enemyBullet_mid.tscn create mode 100644 Scenes/Weapons/Bullets/enemyBullet_yellow.tscn create mode 100644 Scripts/Actors/Boss.cs create mode 100644 Scripts/AttackPatterns/MovementPattern.cs create mode 100644 Scripts/AttackPatterns/PatternTest.cs create mode 100644 Scripts/AttackPatterns/SpiralPattern.cs create mode 100644 Scripts/AttackPatterns/TargetedPattern.cs create mode 100644 Scripts/Components/BulletSpawner.cs create mode 100644 Scripts/Resources/AttackPattern.cs create mode 100644 Scripts/Resources/BossPhase.cs create mode 100644 Scripts/Resources/DecreasingSpeedModifier.cs create mode 100644 Scripts/Resources/IBulletModifier.cs create mode 100644 Scripts/Resources/PatternGroup.cs create mode 100644 Scripts/Resources/SimpleMovementPattern.cs create mode 100644 Sprites/Actors/Rumia.aseprite create mode 100644 Sprites/Actors/Rumia.png create mode 100644 Sprites/Actors/Rumia.png.import create mode 100644 Sprites/Bullets/mid_bullet.aseprite create mode 100644 Sprites/Bullets/mid_bullet.png create mode 100644 Sprites/Bullets/mid_bullet.png.import create mode 100644 Sprites/Bullets/small_bullet_green.ase create mode 100644 Sprites/Bullets/small_bullet_green.png create mode 100644 Sprites/Bullets/small_bullet_green.png.import create mode 100644 Sprites/Bullets/small_bullet_yellow.ase create mode 100644 Sprites/Bullets/small_bullet_yellow.png create mode 100644 Sprites/Bullets/small_bullet_yellow.png.import diff --git a/Cirno.sln.DotSettings.user b/Cirno.sln.DotSettings.user index 30725965..d534dd91 100644 --- a/Cirno.sln.DotSettings.user +++ b/Cirno.sln.DotSettings.user @@ -1,5 +1,7 @@  + ForceIncluded ForceIncluded ForceIncluded ForceIncluded + ForceIncluded ForceIncluded \ No newline at end of file diff --git a/Resources/BossPhases/TestBoss1.tres b/Resources/BossPhases/TestBoss1.tres new file mode 100644 index 00000000..df11424d --- /dev/null +++ b/Resources/BossPhases/TestBoss1.tres @@ -0,0 +1,43 @@ +[gd_resource type="Resource" script_class="BossPhase" load_steps=9 format=3 uid="uid://ks6fypeil6gk"] + +[ext_resource type="Script" path="res://Scripts/Resources/BossPhase.cs" id="1_0cgch"] +[ext_resource type="Script" path="res://Scripts/Resources/SimpleMovementPattern.cs" id="1_xksf5"] +[ext_resource type="Resource" uid="uid://csudslb5tliw4" path="res://Resources/Patterns/rumia_ns_1.tres" id="2_3486e"] +[ext_resource type="Resource" uid="uid://du2kuv125vbrx" path="res://Resources/Patterns/rumia_ns_2.tres" id="3_mwcf3"] + +[sub_resource type="Resource" id="Resource_acaax"] +script = ExtResource("1_xksf5") +relativeTargetPosition = Vector2(-100, 20) +moveDuration = 4.0 +transitionType = 1 +easeType = 2 +WaitForCompletion = false + +[sub_resource type="Resource" id="Resource_o8win"] +script = ExtResource("1_xksf5") +relativeTargetPosition = Vector2(0, 0) +moveDuration = 4.0 +transitionType = 1 +easeType = 2 +WaitForCompletion = false + +[sub_resource type="Resource" id="Resource_k77ig"] +script = ExtResource("1_xksf5") +relativeTargetPosition = Vector2(-100, 20) +moveDuration = 4.0 +transitionType = 1 +easeType = 2 +WaitForCompletion = false + +[sub_resource type="Resource" id="Resource_5ocg5"] +script = ExtResource("1_xksf5") +relativeTargetPosition = Vector2(0, 0) +moveDuration = 4.0 +transitionType = 1 +easeType = 2 +WaitForCompletion = false + +[resource] +script = ExtResource("1_0cgch") +Threshold = 20 +Patterns = Array[Resource]([SubResource("Resource_acaax"), ExtResource("2_3486e"), ExtResource("3_mwcf3"), SubResource("Resource_o8win"), ExtResource("2_3486e"), ExtResource("3_mwcf3"), SubResource("Resource_k77ig"), ExtResource("2_3486e"), ExtResource("3_mwcf3"), SubResource("Resource_5ocg5"), ExtResource("2_3486e"), ExtResource("3_mwcf3")]) diff --git a/Resources/Patterns/rumia_ns_1.tres b/Resources/Patterns/rumia_ns_1.tres new file mode 100644 index 00000000..8ec43e54 --- /dev/null +++ b/Resources/Patterns/rumia_ns_1.tres @@ -0,0 +1,21 @@ +[gd_resource type="Resource" script_class="TargetedPattern" load_steps=5 format=3 uid="uid://csudslb5tliw4"] + +[ext_resource type="PackedScene" uid="uid://by2rk6gx67f7e" path="res://Scenes/Weapons/Bullets/enemyBullet_yellow.tscn" id="1_pocps"] +[ext_resource type="Script" path="res://Scripts/Resources/DecreasingSpeedModifier.cs" id="2_wxqq0"] +[ext_resource type="Script" path="res://Scripts/AttackPatterns/TargetedPattern.cs" id="3_ht3k1"] + +[sub_resource type="Resource" id="Resource_jeq72"] +script = ExtResource("2_wxqq0") +decreaseRate = 4.0 + +[resource] +script = ExtResource("3_ht3k1") +BulletScene = ExtResource("1_pocps") +bulletSpeed = 50.0 +duration = 4.0 +burstInterval = 0.4 +bulletsPerShot = 10 +spread = 0.0 +owner = 2 +modifier = SubResource("Resource_jeq72") +WaitForCompletion = true diff --git a/Resources/Patterns/rumia_ns_2.tres b/Resources/Patterns/rumia_ns_2.tres new file mode 100644 index 00000000..4367a6fb --- /dev/null +++ b/Resources/Patterns/rumia_ns_2.tres @@ -0,0 +1,47 @@ +[gd_resource type="Resource" script_class="PatternGroup" load_steps=8 format=3 uid="uid://du2kuv125vbrx"] + +[ext_resource type="PackedScene" uid="uid://b0clsnefjsohc" path="res://Scenes/Weapons/Bullets/enemyBullet_mid.tscn" id="1_tt36x"] +[ext_resource type="Script" path="res://Scripts/AttackPatterns/SpiralPattern.cs" id="2_ee42k"] +[ext_resource type="PackedScene" uid="uid://dohakkayqj4w2" path="res://Scenes/Weapons/Bullets/enemyBullet_green.tscn" id="3_gr7a3"] +[ext_resource type="Script" path="res://Scripts/Resources/PatternGroup.cs" id="3_jvysx"] + +[sub_resource type="Resource" id="Resource_ne4q3"] +script = ExtResource("2_ee42k") +BulletScene = ExtResource("1_tt36x") +bulletSpeed = 20.0 +bulletCount = 10 +rotationSpeed = 120.0 +duration = 4.0 +burstInterval = 2.0 +spread = 360.0 +owner = 2 +WaitForCompletion = true + +[sub_resource type="Resource" id="Resource_kohuh"] +script = ExtResource("2_ee42k") +BulletScene = ExtResource("3_gr7a3") +bulletSpeed = 20.0 +bulletCount = 16 +rotationSpeed = 120.0 +duration = 4.0 +burstInterval = 2.0 +spread = 360.0 +owner = 2 +WaitForCompletion = true + +[sub_resource type="Resource" id="Resource_depjj"] +script = ExtResource("2_ee42k") +BulletScene = ExtResource("1_tt36x") +bulletSpeed = 30.0 +bulletCount = 10 +rotationSpeed = 120.0 +duration = 4.0 +burstInterval = 2.0 +spread = 360.0 +owner = 2 +WaitForCompletion = true + +[resource] +script = ExtResource("3_jvysx") +patterns = Array[Resource]([SubResource("Resource_ne4q3"), SubResource("Resource_kohuh"), SubResource("Resource_depjj")]) +WaitForCompletion = true diff --git a/Scenes/Actors/Rumia.tscn b/Scenes/Actors/Rumia.tscn new file mode 100644 index 00000000..7663992d --- /dev/null +++ b/Scenes/Actors/Rumia.tscn @@ -0,0 +1,85 @@ +[gd_scene load_steps=12 format=3 uid="uid://d1rlw6ddpmrn8"] + +[ext_resource type="Script" path="res://Scripts/Actors/Boss.cs" id="1_na4uq"] +[ext_resource type="Resource" uid="uid://ks6fypeil6gk" path="res://Resources/BossPhases/TestBoss1.tres" id="2_1rhf6"] +[ext_resource type="Texture2D" uid="uid://bcqgke6dthlrj" path="res://Sprites/Actors/Rumia.png" id="2_7k5gp"] +[ext_resource type="Script" path="res://Scripts/Components/ProximityPlayerDetection.cs" id="3_gka5j"] +[ext_resource type="PackedScene" uid="uid://crry0rgk7a8sm" path="res://Scenes/Weapons/BaseWeapon.tscn" id="4_xc6nm"] +[ext_resource type="PackedScene" uid="uid://cuixq5ex0j40h" path="res://Scenes/enemyBullet.tscn" id="5_g1p0m"] +[ext_resource type="Script" path="res://Scripts/Components/BulletSpawner.cs" id="7_2obh7"] + +[sub_resource type="CircleShape2D" id="CircleShape2D_8gtts"] +radius = 7.0 + +[sub_resource type="CircleShape2D" id="CircleShape2D_cacb5"] +radius = 4.0 + +[sub_resource type="CircleShape2D" id="CircleShape2D_v711r"] +radius = 85.0529 + +[sub_resource type="RectangleShape2D" id="RectangleShape2D_m1rsg"] +size = Vector2(8, 12) + +[node name="Rumia" type="CharacterBody2D" groups=["Destroyable"]] +collision_layer = 16 +collision_mask = 9 +script = ExtResource("1_na4uq") +Phases = Array[Resource]([ExtResource("2_1rhf6")]) +metadata/_edit_group_ = true + +[node name="Sprite2D" type="Sprite2D" parent="."] +texture = ExtResource("2_7k5gp") + +[node name="Damage_HitBox" type="CollisionShape2D" parent="."] +visible = false +shape = SubResource("CircleShape2D_8gtts") + +[node name="RigidBody2D" type="RigidBody2D" parent="."] +collision_layer = 16 + +[node name="CollisionShape2D" type="CollisionShape2D" parent="RigidBody2D"] +visible = false +position = Vector2(0, 5) +shape = SubResource("CircleShape2D_cacb5") + +[node name="PlayerDetection" type="Area2D" parent="."] +visible = false +collision_layer = 16 +collision_mask = 2 +script = ExtResource("3_gka5j") + +[node name="PlayerDetectionArea" type="CollisionShape2D" parent="PlayerDetection"] +shape = SubResource("CircleShape2D_v711r") + +[node name="ShootTimer" type="Timer" parent="."] +wait_time = 0.4 +one_shot = true + +[node name="Weapon" parent="." instance=ExtResource("4_xc6nm")] +BulletScene = ExtResource("5_g1p0m") +BulletCapacity = 4 +BulletSpeed = 50.0 + +[node name="NavigationAgent2D" type="NavigationAgent2D" parent="."] +target_desired_distance = 64.0 +path_max_distance = 800.0 +path_postprocessing = 1 +avoidance_enabled = true +debug_enabled = true +debug_path_custom_color = Color(1, 0, 0, 1) + +[node name="DamageHitbox" type="Area2D" parent="."] +collision_layer = 16 +collision_mask = 9 + +[node name="CollisionShape2D" type="CollisionShape2D" parent="DamageHitbox"] +shape = SubResource("RectangleShape2D_m1rsg") + +[node name="BulletSpawner" type="Node2D" parent="."] +script = ExtResource("7_2obh7") +BulletScene = ExtResource("5_g1p0m") + +[connection signal="area_entered" from="PlayerDetection" to="PlayerDetection" method="_on_area_entered"] +[connection signal="area_exited" from="PlayerDetection" to="." method="_on_area_exited"] +[connection signal="velocity_computed" from="NavigationAgent2D" to="." method="_on_navigation_agent_2d_velocity_computed"] +[connection signal="area_entered" from="DamageHitbox" to="." method="_on_damage_hitbox_area_entered"] diff --git a/Scenes/Maps/BossTestArena.tscn b/Scenes/Maps/BossTestArena.tscn index 746b37af..794ada79 100644 --- a/Scenes/Maps/BossTestArena.tscn +++ b/Scenes/Maps/BossTestArena.tscn @@ -1,6 +1,17 @@ -[gd_scene load_steps=2 format=3 uid="uid://bu5fvatj2j08j"] +[gd_scene load_steps=4 format=3 uid="uid://bu5fvatj2j08j"] [ext_resource type="Script" path="res://Scripts/GameManager.cs" id="1_paetl"] +[ext_resource type="PackedScene" uid="uid://d1rlw6ddpmrn8" path="res://Scenes/Actors/Rumia.tscn" id="2_47q21"] +[ext_resource type="PackedScene" uid="uid://bghghp5ep4w2j" path="res://Scenes/player.tscn" id="2_f17ts"] -[node name="BossTestArena" type="Node2D"] +[node name="GameScene" type="Node2D" node_paths=PackedStringArray("PlayerSpawnMarker")] script = ExtResource("1_paetl") +PlayerTemplate = ExtResource("2_f17ts") +PlayerSpawnMarker = NodePath("PlayerStartPosition") + +[node name="Rumia" parent="." instance=ExtResource("2_47q21")] +position = Vector2(163, 37) +Health = 40.0 + +[node name="PlayerStartPosition" type="Marker2D" parent="."] +position = Vector2(178, 115) diff --git a/Scenes/Weapons/Bullets/enemyBullet_green.tscn b/Scenes/Weapons/Bullets/enemyBullet_green.tscn new file mode 100644 index 00000000..05641c8c --- /dev/null +++ b/Scenes/Weapons/Bullets/enemyBullet_green.tscn @@ -0,0 +1,30 @@ +[gd_scene load_steps=4 format=3 uid="uid://dohakkayqj4w2"] + +[ext_resource type="Script" path="res://Scripts/Bullet.cs" id="1_vg1kg"] +[ext_resource type="Texture2D" uid="uid://dmwi86k7hr8sl" path="res://Sprites/Bullets/small_bullet_green.png" id="2_divgu"] + +[sub_resource type="CircleShape2D" id="CircleShape2D_jxptd"] +radius = 2.23607 + +[node name="Bullet" type="Area2D" groups=["bullets"]] +collision_layer = 128 +collision_mask = 71 +script = ExtResource("1_vg1kg") +Speed = 200.0 +Owner = 2 +metadata/_edit_group_ = true + +[node name="Sprite2D" type="Sprite2D" parent="."] +texture = ExtResource("2_divgu") + +[node name="CollisionShape2D" type="CollisionShape2D" parent="."] +shape = SubResource("CircleShape2D_jxptd") + +[node name="Node2D" type="Node2D" parent="."] +editor_description = "Player Bullet" + +[node name="VisibleOnScreenNotifier2D" type="VisibleOnScreenNotifier2D" parent="."] + +[connection signal="area_entered" from="." to="." method="_on_area_entered"] +[connection signal="body_entered" from="." to="." method="_on_body_entered"] +[connection signal="screen_exited" from="VisibleOnScreenNotifier2D" to="." method="_on_visible_on_screen_notifier_2d_screen_exited"] diff --git a/Scenes/Weapons/Bullets/enemyBullet_mid.tscn b/Scenes/Weapons/Bullets/enemyBullet_mid.tscn new file mode 100644 index 00000000..949e888a --- /dev/null +++ b/Scenes/Weapons/Bullets/enemyBullet_mid.tscn @@ -0,0 +1,30 @@ +[gd_scene load_steps=4 format=3 uid="uid://b0clsnefjsohc"] + +[ext_resource type="Script" path="res://Scripts/Bullet.cs" id="1_w5w28"] +[ext_resource type="Texture2D" uid="uid://c4ijhpgbwmbr8" path="res://Sprites/Bullets/mid_bullet.png" id="2_5gscp"] + +[sub_resource type="CircleShape2D" id="CircleShape2D_jxptd"] +radius = 4.0 + +[node name="Bullet" type="Area2D" groups=["bullets"]] +collision_layer = 128 +collision_mask = 71 +script = ExtResource("1_w5w28") +Speed = 200.0 +Owner = 2 +metadata/_edit_group_ = true + +[node name="Sprite2D" type="Sprite2D" parent="."] +texture = ExtResource("2_5gscp") + +[node name="CollisionShape2D" type="CollisionShape2D" parent="."] +shape = SubResource("CircleShape2D_jxptd") + +[node name="Node2D" type="Node2D" parent="."] +editor_description = "Player Bullet" + +[node name="VisibleOnScreenNotifier2D" type="VisibleOnScreenNotifier2D" parent="."] + +[connection signal="area_entered" from="." to="." method="_on_area_entered"] +[connection signal="body_entered" from="." to="." method="_on_body_entered"] +[connection signal="screen_exited" from="VisibleOnScreenNotifier2D" to="." method="_on_visible_on_screen_notifier_2d_screen_exited"] diff --git a/Scenes/Weapons/Bullets/enemyBullet_yellow.tscn b/Scenes/Weapons/Bullets/enemyBullet_yellow.tscn new file mode 100644 index 00000000..25347832 --- /dev/null +++ b/Scenes/Weapons/Bullets/enemyBullet_yellow.tscn @@ -0,0 +1,27 @@ +[gd_scene load_steps=4 format=3 uid="uid://by2rk6gx67f7e"] + +[ext_resource type="Script" path="res://Scripts/Bullet.cs" id="1_hd5v3"] +[ext_resource type="Texture2D" uid="uid://s5argltaljmq" path="res://Sprites/Bullets/small_bullet_yellow.png" id="2_c3vqu"] + +[sub_resource type="CircleShape2D" id="CircleShape2D_jxptd"] +radius = 2.23607 + +[node name="Bullet" type="Area2D" groups=["bullets"]] +collision_layer = 128 +collision_mask = 71 +script = ExtResource("1_hd5v3") +Speed = 200.0 +Owner = 2 +metadata/_edit_group_ = true + +[node name="Sprite2D" type="Sprite2D" parent="."] +texture = ExtResource("2_c3vqu") + +[node name="CollisionShape2D" type="CollisionShape2D" parent="."] +shape = SubResource("CircleShape2D_jxptd") + +[node name="VisibleOnScreenNotifier2D" type="VisibleOnScreenNotifier2D" parent="."] + +[connection signal="area_entered" from="." to="." method="_on_area_entered"] +[connection signal="body_entered" from="." to="." method="_on_body_entered"] +[connection signal="screen_exited" from="VisibleOnScreenNotifier2D" to="." method="_on_visible_on_screen_notifier_2d_screen_exited"] diff --git a/Scripts/Actors/Boss.cs b/Scripts/Actors/Boss.cs new file mode 100644 index 00000000..f0f31d71 --- /dev/null +++ b/Scripts/Actors/Boss.cs @@ -0,0 +1,54 @@ +using Cirno.Scripts.Resources; +using Godot; +using Godot.Collections; + +namespace Cirno.Scripts.Actors; + +public partial class Boss : Enemy +{ + [Export] private Array Phases; + private int currentPhaseIndex = 0; + + private GameManager _gameManager; + + private Vector2 _homePosition; + public Vector2 HomePosition => _homePosition; + + public GameManager GameManager => _gameManager; + + private BossPhase CurrentPhase => Phases[currentPhaseIndex]; + + public override void _Ready() + { + base._Ready(); + _gameManager = GetNode("/root/GameScene"); + + _homePosition = this.GlobalPosition; + + StartPhase(CurrentPhase); + } + + public override void _Process(double delta) + { + base._Process(delta); + + CurrentPhase.UpdatePhase(delta); + if (_currentHealth <= CurrentPhase.Threshold && currentPhaseIndex + 1 < Phases.Count) + { + currentPhaseIndex++; + StartPhase(CurrentPhase); + } + + } + + private void StartPhase(BossPhase phase) + { + phase.Start(this); + } + + public void TakeDamage(int amount) + { + _currentHealth -= amount; + } + +} \ No newline at end of file diff --git a/Scripts/AttackPatterns/MovementPattern.cs b/Scripts/AttackPatterns/MovementPattern.cs new file mode 100644 index 00000000..9f75f601 --- /dev/null +++ b/Scripts/AttackPatterns/MovementPattern.cs @@ -0,0 +1,54 @@ +using Cirno.Scripts.Actors; +using Cirno.Scripts.Resources; +using Godot; + +namespace Cirno.Scripts.AttackPatterns; + +[GlobalClass] +public partial class MovementPattern : AttackPattern +{ + [Export] private Vector2 relativeTargetPosition; + [Export] private float moveDuration = 2f; + [Export] private Tween.TransitionType transitionType = Tween.TransitionType.Linear; + [Export] private Tween.EaseType easeType = Tween.EaseType.InOut; + [Export] private AttackPattern shootingPattern; + + + private Tween tween; + private bool isComplete = false; + + public override void Start(Boss boss) + { + Boss = boss; + tween = boss.CreateTween(); + isComplete = false; + + Vector2 targetPosition = (Boss?.HomePosition ?? boss.GlobalPosition) + this.relativeTargetPosition; + + + tween.TweenProperty(Boss, "position", targetPosition, moveDuration) + .SetTrans(transitionType) + .SetEase(easeType) + .Finished += () => isComplete = true; + + if (shootingPattern != null && !WaitForCompletion) + { + shootingPattern.Start(boss); + } + } + + public override void UpdatePattern(double delta) + { + if (shootingPattern != null && !WaitForCompletion) + { + shootingPattern.UpdatePattern(delta); + } + } + + public override bool IsComplete() + { + if (WaitForCompletion && shootingPattern != null) + return isComplete && shootingPattern.IsComplete(); + return isComplete; + } +} \ No newline at end of file diff --git a/Scripts/AttackPatterns/PatternTest.cs b/Scripts/AttackPatterns/PatternTest.cs new file mode 100644 index 00000000..ba5295a9 --- /dev/null +++ b/Scripts/AttackPatterns/PatternTest.cs @@ -0,0 +1,45 @@ +using Cirno.Scripts.Actors; +using Cirno.Scripts.Components; +using Cirno.Scripts.Resources; +using Godot; + +namespace Cirno.Scripts.AttackPatterns; + +[GlobalClass] +public partial class PatternTest : AttackPattern +{ + [Export] public PackedScene BulletScene; + [Export] private float bulletSpeed = 5f; + [Export] private int bulletCount = 12; + [Export] private float duration = 3f; + [Export] private float burstInterval = 0.5f; + [Export] private BulletOwner owner = BulletOwner.Enemy; + + private double timer; + private double burstTimer; + private BulletSpawner spawner; + + public override void Start(Boss boss) + { + Boss = boss; + timer = 0; + burstTimer = 0; + spawner = boss.GetNode("BulletSpawner"); + } + + public override void UpdatePattern(double delta) + { + timer += delta; + burstTimer += delta; + if (timer < duration && burstTimer >= burstInterval) + { + spawner.SpawnBullet(Boss.GlobalPosition, Vector2.Right, bulletSpeed, owner, bulletCount, bulletScene: BulletScene); + burstTimer = 0; + } + } + + public override bool IsComplete() + { + return timer >= duration; + } +} \ No newline at end of file diff --git a/Scripts/AttackPatterns/SpiralPattern.cs b/Scripts/AttackPatterns/SpiralPattern.cs new file mode 100644 index 00000000..0cc4bf71 --- /dev/null +++ b/Scripts/AttackPatterns/SpiralPattern.cs @@ -0,0 +1,47 @@ +using Cirno.Scripts.Actors; +using Cirno.Scripts.Components; +using Cirno.Scripts.Resources; +using Godot; + +namespace Cirno.Scripts.AttackPatterns; + +[GlobalClass] +public partial class SpiralPattern : AttackPattern +{ + [Export] public PackedScene BulletScene; + [Export] private float bulletSpeed = 5f; + [Export] private int bulletCount = 16; + [Export] private float rotationSpeed = 90f; + [Export] private float duration = 5f; + [Export] private float burstInterval = 0.5f; + [Export] private float spread = 360f; + [Export] private BulletOwner owner = BulletOwner.Enemy; + + private double timer; + private double burstTimer; + private BulletSpawner spawner; + + public override void Start(Boss boss) + { + Boss = boss; + timer = 0; + burstTimer = burstInterval; // start immediately + spawner = boss.GetNode("BulletSpawner"); + } + + public override void UpdatePattern(double delta) + { + timer += delta; + burstTimer += delta; + if (timer < duration && burstTimer >= burstInterval) + { + spawner.SpawnSpiralPattern(Boss.GlobalPosition, bulletSpeed, owner, bulletCount, rotationSpeed, timer, spread, BulletScene); + burstTimer = 0; + } + } + + public override bool IsComplete() + { + return timer >= duration; + } +} diff --git a/Scripts/AttackPatterns/TargetedPattern.cs b/Scripts/AttackPatterns/TargetedPattern.cs new file mode 100644 index 00000000..195a1b4a --- /dev/null +++ b/Scripts/AttackPatterns/TargetedPattern.cs @@ -0,0 +1,54 @@ +using Cirno.Scripts.Actors; +using Cirno.Scripts.Components; +using Cirno.Scripts.Resources; + +namespace Cirno.Scripts.AttackPatterns; + +using Godot; + +[GlobalClass] +public partial class TargetedPattern : AttackPattern +{ + [Export] public PackedScene BulletScene; + + [Export] private float bulletSpeed = 5f; + [Export] private float duration = 3f; + [Export] private float burstInterval = 0.5f; + [Export] private int bulletsPerShot = 1; + [Export] private float spread = 0f; + [Export] private BulletOwner owner = BulletOwner.Enemy; + [Export] private Resource modifier; + + private double timer; + private double burstTimer; + private BulletSpawner spawner; + //private Node2D player; + private GameManager _gameManager; + + public override void Start(Boss boss) + { + _gameManager = boss.GetNode("/root/GameScene"); + + Boss = boss; + timer = 0; + burstTimer = 0; + spawner = boss.GetNode("BulletSpawner"); + + } + + public override void UpdatePattern(double delta) + { + timer += delta; + burstTimer += delta; + if (timer < duration && burstTimer >= burstInterval && _gameManager.PlayerPosition.HasValue) + { + spawner.SpawnTargetedBullet(Boss.GlobalPosition, _gameManager.PlayerPosition.Value, bulletSpeed, owner, BulletScene, bulletsPerShot, spread, modifier as IBulletModifier); + burstTimer = 0; + } + } + + public override bool IsComplete() + { + return timer >= duration; + } +} \ No newline at end of file diff --git a/Scripts/Bullet.cs b/Scripts/Bullet.cs index bcae18ea..7345eb82 100644 --- a/Scripts/Bullet.cs +++ b/Scripts/Bullet.cs @@ -42,7 +42,6 @@ public partial class Bullet : Area2D //Debug.WriteLine($"Bullet Shot at direction {direction.X} {direction.Y}"); } - // Called every frame. 'delta' is the elapsed time since the previous frame. public override void _Process(double delta) { diff --git a/Scripts/Components/BulletSpawner.cs b/Scripts/Components/BulletSpawner.cs new file mode 100644 index 00000000..9dc11827 --- /dev/null +++ b/Scripts/Components/BulletSpawner.cs @@ -0,0 +1,53 @@ +using Cirno.Scripts.Resources; +using Godot; + +namespace Cirno.Scripts.Components; + +public partial class BulletSpawner : Node2D +{ + [Export] public PackedScene BulletScene; + private GameManager _gameManager; + + public override void _Ready() + { + _gameManager = GetNode("/root/GameScene"); + } + + public void SpawnBullet(Vector2 position, Vector2 direction, float speed, BulletOwner owner, int count = 1, float angleOffset = 0, float spread = 0, PackedScene bulletScene = null, IBulletModifier modifier = null) + { + for (int i = 0; i < count; i++) + { + var bullet = this.CreateChildOf(_gameManager.BulletsContainer, bulletScene ?? BulletScene, position); + + //var bullet = BulletScene.Instantiate(); + bullet.Position = position; + bullet.Owner = owner; + //bullet.Speed = speed; + + float modifiedSpeed = modifier?.ModifySpeed(speed, i) ?? speed; + bullet.Speed = modifiedSpeed; + + Vector2 baseDirection = direction == Vector2.Zero ? Vector2.Right : direction.Normalized(); + float baseAngle = Mathf.Atan2(baseDirection.Y, baseDirection.X); + //float angle = angleOffset + (360 / count) * i; + float angle = baseAngle + Mathf.DegToRad(angleOffset + (spread / count) * i); + Vector2 bulletDirection = new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)); + //Vector2 bulletDirection = new Vector2(Mathf.Cos(Mathf.DegToRad(angle)), Mathf.Sin(Mathf.DegToRad(angle))); + + bullet.SetDirection(bulletDirection); + //GetParent().AddChild(bullet); + } + } + + public void SpawnTargetedBullet(Vector2 position, Vector2 target, float speed, BulletOwner owner, PackedScene bulletScene = null, int burstCount = 1, float spread = 0, IBulletModifier modifier = null) + { + Vector2 direction = (target - position).Normalized(); + SpawnBullet(position, direction, speed, owner, burstCount, spread: spread, bulletScene: bulletScene, modifier: modifier); + } + + public void SpawnSpiralPattern(Vector2 position, float speed, BulletOwner owner, int bulletCount, float rotationSpeed, double time, float spread, PackedScene bulletScene = null) + { + float angleOffset = (float)(rotationSpeed * time); + SpawnBullet(position, Vector2.Right, speed, owner, bulletCount, angleOffset, spread, bulletScene: bulletScene); + } +} \ No newline at end of file diff --git a/Scripts/Enemy.cs b/Scripts/Enemy.cs index 67ea24e7..f7d0ae8b 100644 --- a/Scripts/Enemy.cs +++ b/Scripts/Enemy.cs @@ -8,6 +8,12 @@ using Godot.Collections; public partial class Enemy : CharacterBody2D { private InteractionController _cachedPlayer; + public InteractionController CachedPlayer + { + get => _cachedPlayer; + protected set => _cachedPlayer = value; + } + private EnemyState _currentState = EnemyState.Idle; [Export] public float Health = 4f; @@ -20,7 +26,7 @@ public partial class Enemy : CharacterBody2D [Export] public Weapon EquippedWeapon; - private float _currentHealth = 0f; + protected float _currentHealth = 0f; private bool _isDestroyed = false; @@ -52,9 +58,12 @@ public partial class Enemy : CharacterBody2D _navigationAgent = GetNodeOrNull("NavigationAgent2D"); - _alarmManager = GetNode("/root/GameScene/AlarmManager"); - - _alarmManager.AlarmEnabled += AlarmManagerOnAlarmEnabled; + _alarmManager = GetNodeOrNull("/root/GameScene/AlarmManager"); + + if (_alarmManager != null) + { + _alarmManager.AlarmEnabled += AlarmManagerOnAlarmEnabled; + } } private void AlarmManagerOnAlarmEnabled(Vector2 location) diff --git a/Scripts/GameManager.cs b/Scripts/GameManager.cs index fde89439..24b66717 100644 --- a/Scripts/GameManager.cs +++ b/Scripts/GameManager.cs @@ -7,9 +7,13 @@ public partial class GameManager : Node2D private Hud _hud; private PlayerMovement _player; + + public PlayerMovement Player => _player; private Node2D _cameraTarget; + public Vector2? PlayerPosition => _player?.GlobalPosition ?? null; + [Export] public PackedScene PlayerTemplate { get; set; } diff --git a/Scripts/Resources/AttackPattern.cs b/Scripts/Resources/AttackPattern.cs new file mode 100644 index 00000000..ad81916d --- /dev/null +++ b/Scripts/Resources/AttackPattern.cs @@ -0,0 +1,13 @@ +using Cirno.Scripts.Actors; +using Godot; + +namespace Cirno.Scripts.Resources; + +public abstract partial class AttackPattern : Resource +{ + public Boss Boss; + [Export] public bool WaitForCompletion = true; + public abstract void Start(Boss boss); + public abstract void UpdatePattern(double delta); + public abstract bool IsComplete(); +} \ No newline at end of file diff --git a/Scripts/Resources/BossPhase.cs b/Scripts/Resources/BossPhase.cs new file mode 100644 index 00000000..aca76e01 --- /dev/null +++ b/Scripts/Resources/BossPhase.cs @@ -0,0 +1,35 @@ +using Cirno.Scripts.Actors; +using Godot; +using Godot.Collections; + +namespace Cirno.Scripts.Resources; + +[GlobalClass] +public partial class BossPhase : Resource +{ + [Export] public int Threshold; + [Export] public Array Patterns; + + private int currentPatternIndex = 0; + private double patternTimer; + + public void Start(Boss boss) + { + currentPatternIndex = 0; + Patterns[currentPatternIndex].Start(boss); + } + + public void UpdatePhase(double delta) + { + patternTimer += delta; + var currentPattern = Patterns[currentPatternIndex]; + + currentPattern.UpdatePattern(delta); + + if (!currentPattern.WaitForCompletion || currentPattern.IsComplete()) + { + currentPatternIndex = (currentPatternIndex + 1) % Patterns.Count; + Patterns[currentPatternIndex].Start(currentPattern.Boss); + } + } +} \ No newline at end of file diff --git a/Scripts/Resources/DecreasingSpeedModifier.cs b/Scripts/Resources/DecreasingSpeedModifier.cs new file mode 100644 index 00000000..545e53ce --- /dev/null +++ b/Scripts/Resources/DecreasingSpeedModifier.cs @@ -0,0 +1,14 @@ +using Godot; + +namespace Cirno.Scripts.Resources; + +[GlobalClass] +public partial class DecreasingSpeedModifier : Resource, IBulletModifier +{ + [Export] private float decreaseRate = 0.1f; + + public float ModifySpeed(float baseSpeed, int bulletIndex) + { + return Mathf.Max(0, baseSpeed - (decreaseRate * bulletIndex)); + } +} \ No newline at end of file diff --git a/Scripts/Resources/IBulletModifier.cs b/Scripts/Resources/IBulletModifier.cs new file mode 100644 index 00000000..114e7c84 --- /dev/null +++ b/Scripts/Resources/IBulletModifier.cs @@ -0,0 +1,6 @@ +namespace Cirno.Scripts.Resources; + +public interface IBulletModifier +{ + float ModifySpeed(float baseSpeed, int bulletIndex); +} \ No newline at end of file diff --git a/Scripts/Resources/PatternGroup.cs b/Scripts/Resources/PatternGroup.cs new file mode 100644 index 00000000..077ec874 --- /dev/null +++ b/Scripts/Resources/PatternGroup.cs @@ -0,0 +1,42 @@ +using Godot; +using System.Collections.Generic; +using Cirno.Scripts.Actors; +using Godot.Collections; + +namespace Cirno.Scripts.Resources; + +[GlobalClass] +public partial class PatternGroup : AttackPattern +{ + [Export] private Array patterns; + private int currentPatternIndex = 0; + + public override void Start(Boss boss) + { + Boss = boss; + currentPatternIndex = 0; + patterns[currentPatternIndex].Start(boss); + } + + public override void UpdatePattern(double delta) + { + if (currentPatternIndex < patterns.Count) + { + patterns[currentPatternIndex].UpdatePattern(delta); + + if (!patterns[currentPatternIndex].WaitForCompletion || patterns[currentPatternIndex].IsComplete()) + { + currentPatternIndex++; + if (currentPatternIndex < patterns.Count) + { + patterns[currentPatternIndex].Start(Boss); + } + } + } + } + + public override bool IsComplete() + { + return currentPatternIndex >= patterns.Count; + } +} diff --git a/Scripts/Resources/SimpleMovementPattern.cs b/Scripts/Resources/SimpleMovementPattern.cs new file mode 100644 index 00000000..5179a6ca --- /dev/null +++ b/Scripts/Resources/SimpleMovementPattern.cs @@ -0,0 +1,37 @@ +using Cirno.Scripts.Actors; +using Godot; + +namespace Cirno.Scripts.Resources; + +[GlobalClass] +public partial class SimpleMovementPattern : AttackPattern +{ + [Export] private Vector2 relativeTargetPosition; + [Export] private float moveDuration = 2f; + [Export] private Tween.TransitionType transitionType = Tween.TransitionType.Linear; + [Export] private Tween.EaseType easeType = Tween.EaseType.InOut; + + private Tween tween; + private bool isComplete = false; + + public override void Start(Boss boss) + { + Boss = boss; + tween = boss.CreateTween(); + isComplete = false; + + Vector2 targetPosition = (Boss?.HomePosition ?? boss.GlobalPosition) + relativeTargetPosition; + + tween.TweenProperty(Boss, "position", targetPosition, moveDuration) + .SetTrans(transitionType) + .SetEase(easeType) + .Finished += () => isComplete = true; + } + + public override void UpdatePattern(double delta) { } + + public override bool IsComplete() + { + return isComplete; + } +} diff --git a/Scripts/Weapon.cs b/Scripts/Weapon.cs index f8b3479d..6e78f0af 100644 --- a/Scripts/Weapon.cs +++ b/Scripts/Weapon.cs @@ -97,7 +97,6 @@ public partial class Weapon : Node2D // Rotate the ShootDirection by the spread angle Vector2 spreadDirection = ShootDirection.Rotated(Mathf.DegToRad(spreadOffset)); - var bullet = this.CreateChildOf(_gameManager.BulletsContainer, BulletScene, _muzzle.GlobalPosition); diff --git a/Sprites/Actors/Rumia.aseprite b/Sprites/Actors/Rumia.aseprite new file mode 100644 index 00000000..d12d4724 --- /dev/null +++ b/Sprites/Actors/Rumia.aseprite @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e4b18da862b2c05c3f301384228fa9a26910d78c2aa7d2d27b4bf080048203ac +size 747 diff --git a/Sprites/Actors/Rumia.png b/Sprites/Actors/Rumia.png new file mode 100644 index 00000000..30388367 --- /dev/null +++ b/Sprites/Actors/Rumia.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d56a902fe7d5dac26a5fd07fa7b457346dca049ee695f61cce40aa72643fe374 +size 302 diff --git a/Sprites/Actors/Rumia.png.import b/Sprites/Actors/Rumia.png.import new file mode 100644 index 00000000..c7aee731 --- /dev/null +++ b/Sprites/Actors/Rumia.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bcqgke6dthlrj" +path="res://.godot/imported/Rumia.png-17dc64f86b8ab2ed278a5be8a865a79b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Sprites/Actors/Rumia.png" +dest_files=["res://.godot/imported/Rumia.png-17dc64f86b8ab2ed278a5be8a865a79b.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/Sprites/Bullets/mid_bullet.aseprite b/Sprites/Bullets/mid_bullet.aseprite new file mode 100644 index 00000000..5d03ef2a --- /dev/null +++ b/Sprites/Bullets/mid_bullet.aseprite @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:64927260c2b071963e7d1c78d9f562d4a0eeeb14995cd22b102cc10d9f93acf9 +size 596 diff --git a/Sprites/Bullets/mid_bullet.png b/Sprites/Bullets/mid_bullet.png new file mode 100644 index 00000000..421e814d --- /dev/null +++ b/Sprites/Bullets/mid_bullet.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6a22fcb0add8362552e80cdc0e9ac8e5fd9fc5bb60988f66c8c7414ccb416aeb +size 164 diff --git a/Sprites/Bullets/mid_bullet.png.import b/Sprites/Bullets/mid_bullet.png.import new file mode 100644 index 00000000..ccbbd377 --- /dev/null +++ b/Sprites/Bullets/mid_bullet.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c4ijhpgbwmbr8" +path="res://.godot/imported/mid_bullet.png-1ac58965f8b5ef0dd6b167a05ec5fb5b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Sprites/Bullets/mid_bullet.png" +dest_files=["res://.godot/imported/mid_bullet.png-1ac58965f8b5ef0dd6b167a05ec5fb5b.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/Sprites/Bullets/small_bullet_green.ase b/Sprites/Bullets/small_bullet_green.ase new file mode 100644 index 0000000000000000000000000000000000000000..ebf9152a469141aefcd4af5ea598e65b761a6bb9 GIT binary patch literal 624 zcmcJNF;Bu^5QeV^(ZRvV!~{(jiEa|Nj%+3@){zARbzw118g-GDMG^SKZllW$b#lw4$RO}4L2lh4$gw;2FS60S zMVhiTB8mo2&-qmH4|G27!@1{!^S-ZI&xpLFo-A^F@kFG;^H+KCY$!{d|ELeP|Gej% zY7T)Fo(11Y&d81ESN;5CvN3bxTAflK%Jj{GK&3>!9#eR(J5ZW7uioETFC(a}7$!jg zUwP#-?7@Dw1>@Q_EEP&HtrcJ;wVl_U0XzyjHcxGT7=|!O5;$_aN!)(5TODhu?I#Jm z*mqiLy1`Zk9=cmC+T1HYL5bT?2civLvi93dz5r5ML{-9(j96r{K&_Z4mSfl>0rv5Z zaa>~=znH}-Ht}c%%^fsT=12p)n31AcF#Un7nYKR%r)Ac1a&UZBJ=wF?7s+sxKhn6e em_6;5qbT~;^{dNUuiy6C`qr4={gmbU=JPM*`>{s= literal 0 HcmV?d00001 diff --git a/Sprites/Bullets/small_bullet_yellow.png b/Sprites/Bullets/small_bullet_yellow.png new file mode 100644 index 00000000..0868634f --- /dev/null +++ b/Sprites/Bullets/small_bullet_yellow.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:200e2933ad737c8ba640f9ad03cd82070531073dea8821ed618b064a8e0c0154 +size 110 diff --git a/Sprites/Bullets/small_bullet_yellow.png.import b/Sprites/Bullets/small_bullet_yellow.png.import new file mode 100644 index 00000000..3a90d65d --- /dev/null +++ b/Sprites/Bullets/small_bullet_yellow.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://s5argltaljmq" +path="res://.godot/imported/small_bullet_yellow.png-41c6526899201bd1a4e75ddd93c0f76e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Sprites/Bullets/small_bullet_yellow.png" +dest_files=["res://.godot/imported/small_bullet_yellow.png-41c6526899201bd1a4e75ddd93c0f76e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/project.godot b/project.godot index f09111a0..8a599ab4 100644 --- a/project.godot +++ b/project.godot @@ -21,7 +21,7 @@ Settings/temporaryLogLifetime=5.0 [application] config/name="Cirno" -run/main_scene="res://Scenes/test.tscn" +run/main_scene="res://Scenes/Maps/BossTestArena.tscn" config/features=PackedStringArray("4.3", "C#", "GL Compatibility") config/icon="res://icon.svg"