diff --git a/Resources/BossPhases/Rumia_Lasers.tres b/Resources/BossPhases/Rumia_Lasers.tres new file mode 100644 index 00000000..f19345fe --- /dev/null +++ b/Resources/BossPhases/Rumia_Lasers.tres @@ -0,0 +1,47 @@ +[gd_resource type="Resource" script_class="BossPhase" load_steps=8 format=3 uid="uid://hy1alw04fbds"] + +[ext_resource type="Script" path="res://Scripts/Resources/BossPhase.cs" id="1_kkx86"] +[ext_resource type="PackedScene" uid="uid://djro6xmsq7kqk" path="res://Scenes/Weapons/Bullets/enemyBullet_mid_blue_laser.tscn" id="1_nfjet"] +[ext_resource type="Script" path="res://Scripts/AttackPatterns/LaserPattern.cs" id="2_tctyt"] +[ext_resource type="Script" path="res://Scripts/Resources/TimeModifier.cs" id="2_v7sed"] + +[sub_resource type="Resource" id="Resource_e62ka"] +script = ExtResource("2_v7sed") +TimeInSeconds = 0.8 +ModifierType = 0 +Value = 0.0 + +[sub_resource type="Resource" id="Resource_vkf1u"] +script = ExtResource("2_v7sed") +TimeInSeconds = 0.9 +ModifierType = 2 +Value = 0.0 + +[sub_resource type="Resource" id="Resource_3idsw"] +script = ExtResource("2_tctyt") +SpawnDelay = 1.0 +PreFireTime = 1.8 +LethalTime = 4.0 +PreFireColor = Color(0, 0, 1, 0.501961) +LethalColor = Color(0, 0, 1, 1) +BulletScene = ExtResource("1_nfjet") +bulletSpeed = 40.0 +bulletCount = 8 +rotationSpeed = 0.0 +_rotationOffset = 0.0 +duration = 4.0 +burstInterval = 6.0 +spread = 360.0 +owner = 2 +_damageType = 0 +_bulletDamage = 1.0 +_timeModifiers = Array[Object]([SubResource("Resource_e62ka"), SubResource("Resource_vkf1u")]) +_targetPlayer = false +WaitForCompletion = true + +[resource] +script = ExtResource("1_kkx86") +PhaseName = "" +Threshold = 0 +PlayAnimation = false +Patterns = Array[Object]([SubResource("Resource_3idsw")]) diff --git a/Scenes/Actors/Rumia.tscn b/Scenes/Actors/Rumia.tscn index 466fadd9..ff6e3eda 100644 --- a/Scenes/Actors/Rumia.tscn +++ b/Scenes/Actors/Rumia.tscn @@ -1,9 +1,10 @@ -[gd_scene load_steps=16 format=3 uid="uid://d1rlw6ddpmrn8"] +[gd_scene load_steps=17 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="Resource" uid="uid://ddb5dqocmk6x7" path="res://Resources/BossPhases/Rumia_NS2.tres" id="2_eyxw4"] +[ext_resource type="Resource" uid="uid://hy1alw04fbds" path="res://Resources/BossPhases/Rumia_Lasers.tres" id="2_p8j4e"] [ext_resource type="Script" path="res://Scripts/Components/ProximityPlayerDetection.cs" id="3_gka5j"] [ext_resource type="Resource" uid="uid://ccj0cqbveey8c" path="res://Resources/BossPhases/Rumia_SP1.tres" id="3_j7lbl"] [ext_resource type="Texture2D" uid="uid://csuprfskdo1qp" path="res://Sprites/Portraits/Rumia.png" id="4_at5iq"] @@ -29,7 +30,7 @@ collision_layer = 16 collision_mask = 9 script = ExtResource("1_na4uq") BossName = "Rumia" -Phases = Array[Resource]([ExtResource("2_1rhf6"), ExtResource("3_j7lbl"), ExtResource("2_eyxw4")]) +Phases = Array[Resource]([ExtResource("2_p8j4e"), ExtResource("2_1rhf6"), ExtResource("3_j7lbl"), ExtResource("2_eyxw4")]) BossHudPrefab = ExtResource("4_ehp8q") _bossPortraitTexture = ExtResource("4_at5iq") Health = 400.0 diff --git a/Scenes/Weapons/Bullets/enemyBullet_mid_blue.tscn b/Scenes/Weapons/Bullets/enemyBullet_mid_blue.tscn index a074061e..79c7c1b7 100644 --- a/Scenes/Weapons/Bullets/enemyBullet_mid_blue.tscn +++ b/Scenes/Weapons/Bullets/enemyBullet_mid_blue.tscn @@ -11,7 +11,6 @@ collision_layer = 128 collision_mask = 71 script = ExtResource("1_p8khg") Speed = 200.0 -Owner = 2 metadata/_edit_group_ = true [node name="Sprite2D" type="Sprite2D" parent="."] diff --git a/Scenes/Weapons/Bullets/enemyBullet_mid_blue_laser.tscn b/Scenes/Weapons/Bullets/enemyBullet_mid_blue_laser.tscn new file mode 100644 index 00000000..b71028c2 --- /dev/null +++ b/Scenes/Weapons/Bullets/enemyBullet_mid_blue_laser.tscn @@ -0,0 +1,25 @@ +[gd_scene load_steps=4 format=3 uid="uid://djro6xmsq7kqk"] + +[ext_resource type="Script" path="res://Scripts/Weapons/LaserBullet.cs" id="1_uu40b"] +[ext_resource type="Texture2D" uid="uid://dooyhu8vt63vm" path="res://Sprites/Bullets/mid_bullet_blue.png" id="2_yy4q5"] + +[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_uu40b") +metadata/_edit_group_ = true + +[node name="Sprite2D" type="Sprite2D" parent="."] +texture = ExtResource("2_yy4q5") + +[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/AttackPatterns/LaserPattern.cs b/Scripts/AttackPatterns/LaserPattern.cs new file mode 100644 index 00000000..79444419 --- /dev/null +++ b/Scripts/AttackPatterns/LaserPattern.cs @@ -0,0 +1,28 @@ +using Cirno.Scripts.Components; +using Godot; + +namespace Cirno.Scripts.AttackPatterns; + +[GlobalClass] +public partial class LaserPattern : SpiralPattern +{ + [ExportGroup("Laser")][Export] public float SpawnDelay { get; set; } = 0.3f; // Delay before beam appears + [ExportGroup("Laser")][Export] public float PreFireTime { get; set; } = 0.5f; // Time before laser becomes lethal + [ExportGroup("Laser")][Export] public float LethalTime { get; set; } = 1.5f; // Time laser remains lethal + [ExportGroup("Laser")][Export] public Color PreFireColor { get; set; } = new Color(1, 0, 0, 0.5f); // Thin red beam + [ExportGroup("Laser")][Export] public Color LethalColor { get; set; } = new Color(1, 0, 0, 1.0f); // Thicker beam + + protected override BulletInfo MakeBullet(Vector2 position, Vector2 direction, float angleOffset) + { + var bf = base.MakeBullet(position, direction, angleOffset); + + bf.IsLaser = true; + bf.PreFireTime = PreFireTime; + bf.LethalTime = LethalTime; + bf.PreFireColor = PreFireColor; + bf.LethalColor = LethalColor; + bf.SpawnDelay = SpawnDelay; + + return bf; + } +} \ No newline at end of file diff --git a/Scripts/AttackPatterns/SpiralPattern.cs b/Scripts/AttackPatterns/SpiralPattern.cs index 07a18505..5031d502 100644 --- a/Scripts/AttackPatterns/SpiralPattern.cs +++ b/Scripts/AttackPatterns/SpiralPattern.cs @@ -23,7 +23,9 @@ public partial class SpiralPattern : AttackPattern [Export] private BulletOwner owner = BulletOwner.Enemy; [Export] private DamageType _damageType = DamageType.Neutral; [Export] private float _bulletDamage = 1f; + [ExportGroup("Modifiers")] [Export] private BulletCreationModifier _modifier; + [ExportGroup("Modifiers")] [Export] private Array _timeModifiers; [Export] private bool _targetPlayer = false; @@ -55,29 +57,54 @@ public partial class SpiralPattern : AttackPattern direction = (Boss.GameManager.PlayerPosition.Value - Boss.GlobalPosition).Normalized(); } - spawner.SpawnBullet(new BulletInfo() - { - Position = Boss.GlobalPosition, - Direction = direction, - Speed = bulletSpeed, - Owner = owner, - DamageType = _damageType, - Damage = _bulletDamage, - BulletCount = bulletCount, - Spread = spread, - BulletScene = BulletScene, - RotationOffset = angleOffset, - Modifier = _modifier, - TimeModifiers = ((_timeModifiers?.Where(mod => mod != null)) ?? Array.Empty()).Select(m => new ModifierWrapper() + spawner.SpawnBullet(MakeBullet(Boss.GlobalPosition, direction, angleOffset)); + + // spawner.SpawnBullet(new BulletInfo() + // { + // Position = Boss.GlobalPosition, + // Direction = direction, + // Speed = bulletSpeed, + // Owner = owner, + // DamageType = _damageType, + // Damage = _bulletDamage, + // BulletCount = bulletCount, + // Spread = spread, + // BulletScene = BulletScene, + // RotationOffset = angleOffset, + // Modifier = _modifier, + // TimeModifiers = ((_timeModifiers?.Where(mod => mod != null)) ?? Array.Empty()).Select(m => new ModifierWrapper() + // { + // TimeModifier = m, + // Applied = false + // }).ToList() + // }); + + burstTimer = 0; + } + } + + protected virtual BulletInfo MakeBullet(Vector2 position, Vector2 direction, float angleOffset) + { + return new BulletInfo() + { + Position = position, + Direction = direction, + Speed = bulletSpeed, + Owner = owner, + DamageType = _damageType, + Damage = _bulletDamage, + BulletCount = bulletCount, + Spread = spread, + BulletScene = BulletScene, + RotationOffset = angleOffset, + Modifier = _modifier, + TimeModifiers = ((_timeModifiers?.Where(mod => mod != null)) ?? Array.Empty()).Select(m => + new ModifierWrapper() { TimeModifier = m, Applied = false }).ToList() - }); - - // spawner.SpawnSpiralPattern(Boss.GlobalPosition, bulletSpeed, owner, bulletCount, rotationSpeed, timer, spread, BulletScene); - burstTimer = 0; - } + }; } public override bool IsComplete() diff --git a/Scripts/Bullet.cs b/Scripts/Bullet.cs index b1b58e5a..e2699c75 100644 --- a/Scripts/Bullet.cs +++ b/Scripts/Bullet.cs @@ -18,7 +18,7 @@ public partial class Bullet : Area2D public DamageType DamageType => _bulletInfo?.DamageType ?? DamageType.Neutral; - private Vector2 _direction = Vector2.Right; + protected Vector2 _direction = Vector2.Right; private double _elapsedTime = 0f; private BulletInfo _bulletInfo; @@ -75,7 +75,7 @@ public partial class Bullet : Area2D } } - private void RotateBullet(float degrees) + protected virtual void RotateBullet(float degrees) { float radians = Mathf.DegToRad(degrees); _direction = _direction.Rotated(radians).Normalized(); // Rotate direction @@ -88,6 +88,7 @@ public partial class Bullet : Area2D if (_gameManager.Player != null) { _direction = (_gameManager.Player.GlobalPosition - this.GlobalPosition).Normalized(); + RotateBullet(0); // quick hack to rotate lasers //LookAt(player.GlobalPosition); } } diff --git a/Scripts/Components/BulletSpawner.cs b/Scripts/Components/BulletSpawner.cs index efa61611..87daff4d 100644 --- a/Scripts/Components/BulletSpawner.cs +++ b/Scripts/Components/BulletSpawner.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Cirno.Scripts.Resources; +using Cirno.Scripts.Weapons; using Godot; using Godot.Collections; @@ -18,9 +19,17 @@ public partial class BulletSpawner : Node2D public void SpawnBullet(BulletInfo bulletInfo) { + var bulletScene = bulletInfo.BulletScene ?? BulletScene; + Bullet bullet; + for (int i = 0; i < bulletInfo.BulletCount; i++) { - var bullet = this.CreateChildOf(_gameManager.BulletsContainer, bulletInfo.BulletScene ?? BulletScene, bulletInfo.Position); + if (bulletInfo.IsLaser) + bullet = this.CreateChildOf(_gameManager.BulletsContainer, bulletScene, bulletInfo.Position); + else + bullet = this.CreateChildOf(_gameManager.BulletsContainer, bulletScene, bulletInfo.Position); + + // var bullet = this.CreateChildOf(_gameManager.BulletsContainer, bulletInfo.BulletScene ?? BulletScene, bulletInfo.Position); bullet.Initialize(bulletInfo, _gameManager); @@ -91,4 +100,13 @@ public class BulletInfo public PackedScene DestructionParticlesScene { get; set; } public IBulletModifier Modifier { get; set; } public List TimeModifiers { get; set; } = new List(); -} \ No newline at end of file + + #region Laser + public bool IsLaser { get; set; } + public float SpawnDelay { get; set; } = 0.3f; // Delay before beam appears + public float PreFireTime { get; set; } = 0.5f; // Time before laser becomes lethal + public float LethalTime { get; set; } = 1.5f; // Time laser remains lethal + public Color PreFireColor { get; set; } = new Color(1, 0, 0, 0.5f); // Thin red beam + public Color LethalColor { get; set; } = new Color(1, 0, 0, 1.0f); // Thicker beam + #endregion +} diff --git a/Scripts/Weapons/LaserBullet.cs b/Scripts/Weapons/LaserBullet.cs new file mode 100644 index 00000000..fad05778 --- /dev/null +++ b/Scripts/Weapons/LaserBullet.cs @@ -0,0 +1,82 @@ +using System.Linq; +using Godot; + +namespace Cirno.Scripts.Weapons; + +public partial class LaserBullet : Bullet +{ + private Line2D _beam; + private Timer _preFireTimer; + private Timer _lethalTimer; + private Timer _spawnDelayTimer; + private bool _isLethal = false; + + public override void _Ready() + { + base._Ready(); + _beam = new Line2D + { + DefaultColor = BulletInfo.PreFireColor, + Width = 1, + Visible = false + }; + AddChild(_beam); + _beam.GlobalPosition = this.GlobalPosition; + + // Delay before the beam appears + _spawnDelayTimer = new Timer { WaitTime = BulletInfo.SpawnDelay, OneShot = true }; + _spawnDelayTimer.Timeout += ShowBeam; + AddChild(_spawnDelayTimer); + _spawnDelayTimer.Start(); + + FireLaser(); + } + + public void FireLaser() + { + Vector2 endPoint = GetLaserEndPoint(GlobalPosition, BulletInfo.Direction); + + _beam.ClearPoints(); + _beam.AddPoint(Vector2.Zero); + _beam.AddPoint(ToLocal(endPoint)); + + _preFireTimer = new Timer { WaitTime = BulletInfo.PreFireTime, OneShot = true }; + _preFireTimer.Timeout += MakeLethal; + AddChild(_preFireTimer); + _preFireTimer.Start(); + } + + private void ShowBeam() + { + _beam.Visible = true; + } + + private void MakeLethal() + { + _isLethal = true; + _beam.DefaultColor = BulletInfo.LethalColor; + _beam.Width = 3; + + _lethalTimer = new Timer { WaitTime = BulletInfo.LethalTime, OneShot = true }; + _lethalTimer.Timeout += QueueFree; // Destroy after lethal phase + AddChild(_lethalTimer); + _lethalTimer.Start(); + } + + protected override void RotateBullet(float degrees) + { + base.RotateBullet(degrees); + + _beam.SetPointPosition(_beam.Points.Length -1, ToLocal(GetLaserEndPoint(GlobalPosition, _direction))); + } + + private Vector2 GetLaserEndPoint(Vector2 start, Vector2 direction) + { + var spaceState = GetWorld2D().DirectSpaceState; + var query = PhysicsRayQueryParameters2D.Create(start, start + direction * 1000); + query.CollisionMask = 1 << 0; // World layer + var result = spaceState.IntersectRay(query); + + return result.Count > 0 ? (Vector2)result["position"] : start + direction * 1000; + } +} \ No newline at end of file