diff --git a/prefabs/enemies/boss/boss.tscn b/prefabs/enemies/boss/boss.tscn new file mode 100644 index 0000000..49f18b6 --- /dev/null +++ b/prefabs/enemies/boss/boss.tscn @@ -0,0 +1,29 @@ +[gd_scene load_steps=5 format=3 uid="uid://cpi5lgdlnvhlg"] + +[ext_resource type="Script" path="res://scripts/enemies/Boss.cs" id="1_jbh6o"] +[ext_resource type="SpriteFrames" uid="uid://dmjrl5432nw0h" path="res://sprites/enemies/boss/boss.tres" id="1_ktxai"] + +[sub_resource type="CircleShape2D" id="CircleShape2D_ed3jd"] +radius = 20.0 + +[sub_resource type="CircleShape2D" id="CircleShape2D_5aovn"] +radius = 14.0 + +[node name="boss" type="CharacterBody2D"] +script = ExtResource("1_jbh6o") + +[node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="."] +sprite_frames = ExtResource("1_ktxai") + +[node name="Sprite2D" type="Sprite2D" parent="AnimatedSprite2D"] + +[node name="Area2D" type="Area2D" parent="."] + +[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D"] +shape = SubResource("CircleShape2D_ed3jd") + +[node name="CollisionShape2D" type="CollisionShape2D" parent="."] +position = Vector2(0, -2) +shape = SubResource("CircleShape2D_5aovn") + +[connection signal="body_entered" from="Area2D" to="." method="_OnAttack"] diff --git a/prefabs/enemies/boss/claw.tscn b/prefabs/enemies/boss/claw.tscn new file mode 100644 index 0000000..2068990 --- /dev/null +++ b/prefabs/enemies/boss/claw.tscn @@ -0,0 +1,31 @@ +[gd_scene load_steps=5 format=3 uid="uid://bihh0dp1vbqfu"] + +[ext_resource type="Script" path="res://scripts/enemies/Claw.cs" id="1_gwnpn"] +[ext_resource type="SpriteFrames" uid="uid://cv5pr1b527h20" path="res://sprites/enemies/boss/clow.tres" id="1_wyb73"] + +[sub_resource type="CircleShape2D" id="CircleShape2D_v67co"] +radius = 14.0 + +[sub_resource type="CircleShape2D" id="CircleShape2D_smr3g"] +radius = 20.0 + +[node name="claw" type="CharacterBody2D"] +script = ExtResource("1_gwnpn") + +[node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="."] +sprite_frames = ExtResource("1_wyb73") + +[node name="Sprite2D" type="Sprite2D" parent="AnimatedSprite2D"] + +[node name="CollisionShape2D" type="CollisionShape2D" parent="."] +position = Vector2(-2, 0) +shape = SubResource("CircleShape2D_v67co") + +[node name="Area2D" type="Area2D" parent="."] + +[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D"] +position = Vector2(-2, 0) +shape = SubResource("CircleShape2D_smr3g") + +[connection signal="body_entered" from="Area2D" to="." method="_OnEntered"] +[connection signal="body_exited" from="Area2D" to="." method="_OnExited"] diff --git a/scripts/Constants.cs b/scripts/Constants.cs index 088df03..89c287e 100644 --- a/scripts/Constants.cs +++ b/scripts/Constants.cs @@ -12,4 +12,6 @@ public static class Constants public const float MaxFlashlightEnergy = 100; public const float FlashlightEnergyPerCharge = 40; public const float FlashlightDischargeModifier = 10; + + public const float BossInjureTimeout = 0.5f; } diff --git a/scripts/enemies/Boss.cs b/scripts/enemies/Boss.cs new file mode 100644 index 0000000..6067bb3 --- /dev/null +++ b/scripts/enemies/Boss.cs @@ -0,0 +1,68 @@ +using Godot; +using System; + +public partial class Boss : CharacterBody2D +{ + [Signal] + public delegate void KilledEventHandler(); + + [Export] public int MaxHp = 6; + + public enum State + { + Default, + Injured + } + + private AnimatedSprite2D _sprite; + private State _state = State.Default; + private int _currentHp; + private float _injureTimeout = Constants.BossInjureTimeout; + // Called when the node enters the scene tree for the first time. + public override void _Ready() + { + _sprite = (AnimatedSprite2D)FindChild("AnimatedSprite2D"); + _currentHp = MaxHp; + } + + // Called every frame. 'delta' is the elapsed time since the previous frame. + public override void _Process(double delta) + { + } + + public override void _PhysicsProcess(double delta) + { + _injureTimeout -= (float)delta; + switch (_state) + { + case State.Default: + _sprite.Play("default"); + break; + case State.Injured: + _sprite.Play("injured"); + if (_injureTimeout < 0) + { + _state = State.Default; + } + break; + } + if (_currentHp <= 0) + { + EmitSignal(SignalName.Killed); + } + } + + + private void _OnAttack(Node2D body) + { + if (body is LivingArmor armor) + { + _currentHp -= 1; + _state = State.Injured; + _injureTimeout = Constants.BossInjureTimeout; + armor.Kill(this); + if (_currentHp <= 0) + GD.Print($"{this.Name} was killed."); + } + } +} diff --git a/scripts/enemies/Claw.cs b/scripts/enemies/Claw.cs new file mode 100644 index 0000000..80f5972 --- /dev/null +++ b/scripts/enemies/Claw.cs @@ -0,0 +1,81 @@ +using Godot; +using System; + +public partial class Claw : CharacterBody2D +{ + [Export] public float MovingSpeed = 32f; + public enum State + { + Moving, + Prepare, + Attack + } + + private State _state = State.Moving; + private float _stateTimeout = 0; + private bool _isPlayerNearBy = false; + private AnimatedSprite2D _sprite; + + // Called when the node enters the scene tree for the first time. + public override void _Ready() + { + _sprite = (AnimatedSprite2D)FindChild("AnimatedSprite2D"); + } + + // Called every frame. 'delta' is the elapsed time since the previous frame. + public override void _Process(double delta) + { + } + + public override void _PhysicsProcess(double delta) + { + _stateTimeout -= (float)delta; + switch (_state) + { + case State.Moving: + var direction = (Player.Instance.Position - Position).Normalized(); + Velocity = direction * MovingSpeed; + _sprite.FlipH = Velocity.X < 0.001f; + _sprite.Play("default"); + MoveAndSlide(); + break; + case State.Prepare: + _sprite.Play("prepare"); + if (_stateTimeout < 0) + { + _state = State.Attack; + _stateTimeout = 0.25f; + } + break; + case State.Attack: + _sprite.Play("attack"); + if (_stateTimeout < 0) + { + _state = State.Moving; + if (_isPlayerNearBy) + Player.Instance.Kill(this); + } + break; + } + } + + + private void _OnEntered(Node2D body) + { + if (body is Player) + { + _state = State.Prepare; + _isPlayerNearBy = true; + _stateTimeout = 0.5f; + } + } + + + private void _OnExited(Node2D body) + { + _isPlayerNearBy = false; + } + + +} + diff --git a/scripts/enemies/LivingArmor.cs b/scripts/enemies/LivingArmor.cs index b6977d2..0f43f3d 100644 --- a/scripts/enemies/LivingArmor.cs +++ b/scripts/enemies/LivingArmor.cs @@ -161,10 +161,14 @@ public partial class LivingArmor : CharacterBody2D foreach (var body in _bodiesInSight) { var distance = (body.Position - Position).Length(); - GD.Print($"{body.Name}"); switch (body) { + case Boss boss: + _target = boss; + break; case Wretched wretched: + if (_target is Boss) + continue; if (targetDistance < 0 || targetDistance > distance) { targetDistance = distance; @@ -172,12 +176,8 @@ public partial class LivingArmor : CharacterBody2D } break; case Player player: - - if (_target is Wretched) - { + if (_target is Wretched or Boss) continue; - } - _target = player; break; } @@ -227,16 +227,16 @@ public partial class LivingArmor : CharacterBody2D private void _OnBodyEntered(Node2D body) { - if (body is not Wretched and not Player) + if (body is not Wretched and not Player and not Boss) return; - + GD.Print($"{body.Name} Entered"); _bodiesInSight.Add(body); } private void _OnBodyExited(Node2D body) { - if (body is not Wretched and not Player) + if (body is not Wretched and not Player and not Boss) return; if (body == _target) { diff --git a/sprites/enemies/boss/boss.png b/sprites/enemies/boss/boss.png new file mode 100644 index 0000000..40ae263 Binary files /dev/null and b/sprites/enemies/boss/boss.png differ diff --git a/sprites/enemies/boss/boss.png.import b/sprites/enemies/boss/boss.png.import new file mode 100644 index 0000000..ee72935 --- /dev/null +++ b/sprites/enemies/boss/boss.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bnm5j2hre4rek" +path="res://.godot/imported/boss.png-5670e652cef28f46b18e47f5bde75d03.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://sprites/enemies/boss/boss.png" +dest_files=["res://.godot/imported/boss.png-5670e652cef28f46b18e47f5bde75d03.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/enemies/boss/boss.tres b/sprites/enemies/boss/boss.tres new file mode 100644 index 0000000..551cdbb --- /dev/null +++ b/sprites/enemies/boss/boss.tres @@ -0,0 +1,30 @@ +[gd_resource type="SpriteFrames" load_steps=4 format=3 uid="uid://dmjrl5432nw0h"] + +[ext_resource type="Texture2D" uid="uid://bnm5j2hre4rek" path="res://sprites/enemies/boss/boss.png" id="1_x8bho"] + +[sub_resource type="AtlasTexture" id="AtlasTexture_611s7"] +atlas = ExtResource("1_x8bho") +region = Rect2(0, 0, 32, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_ilows"] +atlas = ExtResource("1_x8bho") +region = Rect2(32, 0, 32, 32) + +[resource] +animations = [{ +"frames": [{ +"duration": 1.0, +"texture": SubResource("AtlasTexture_611s7") +}], +"loop": true, +"name": &"default", +"speed": 5.0 +}, { +"frames": [{ +"duration": 1.0, +"texture": SubResource("AtlasTexture_ilows") +}], +"loop": true, +"name": &"injured", +"speed": 5.0 +}] diff --git a/sprites/enemies/boss/claw.png b/sprites/enemies/boss/claw.png new file mode 100644 index 0000000..0228dde Binary files /dev/null and b/sprites/enemies/boss/claw.png differ diff --git a/sprites/enemies/boss/claw.png.import b/sprites/enemies/boss/claw.png.import new file mode 100644 index 0000000..5ceb2e6 --- /dev/null +++ b/sprites/enemies/boss/claw.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ddic3cif33i1d" +path="res://.godot/imported/claw.png-ba410f614702a9844b8399581c498cc2.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://sprites/enemies/boss/claw.png" +dest_files=["res://.godot/imported/claw.png-ba410f614702a9844b8399581c498cc2.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/enemies/boss/clow.tres b/sprites/enemies/boss/clow.tres new file mode 100644 index 0000000..8db3bd8 --- /dev/null +++ b/sprites/enemies/boss/clow.tres @@ -0,0 +1,42 @@ +[gd_resource type="SpriteFrames" load_steps=5 format=3 uid="uid://cv5pr1b527h20"] + +[ext_resource type="Texture2D" uid="uid://ddic3cif33i1d" path="res://sprites/enemies/boss/claw.png" id="1_svj1b"] + +[sub_resource type="AtlasTexture" id="AtlasTexture_ellfe"] +atlas = ExtResource("1_svj1b") +region = Rect2(64, 0, 32, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_joy44"] +atlas = ExtResource("1_svj1b") +region = Rect2(0, 0, 32, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_vbtsi"] +atlas = ExtResource("1_svj1b") +region = Rect2(32, 0, 32, 32) + +[resource] +animations = [{ +"frames": [{ +"duration": 1.0, +"texture": SubResource("AtlasTexture_ellfe") +}], +"loop": true, +"name": &"attack", +"speed": 5.0 +}, { +"frames": [{ +"duration": 1.0, +"texture": SubResource("AtlasTexture_joy44") +}], +"loop": true, +"name": &"default", +"speed": 5.0 +}, { +"frames": [{ +"duration": 1.0, +"texture": SubResource("AtlasTexture_vbtsi") +}], +"loop": true, +"name": &"prepare", +"speed": 5.0 +}]