diff --git a/Assets/Sounds/karabast.mp3 b/Assets/Sounds/karabast.mp3 new file mode 100644 index 0000000..0221994 Binary files /dev/null and b/Assets/Sounds/karabast.mp3 differ diff --git a/Assets/Sounds/karabast.mp3.import b/Assets/Sounds/karabast.mp3.import new file mode 100644 index 0000000..eb3d2e1 --- /dev/null +++ b/Assets/Sounds/karabast.mp3.import @@ -0,0 +1,19 @@ +[remap] + +importer="mp3" +type="AudioStreamMP3" +uid="uid://cn2wop7rfxku8" +path="res://.godot/imported/karabast.mp3-5fc63c29a959da213d2ed9b8b4c20280.mp3str" + +[deps] + +source_file="res://Assets/Sounds/karabast.mp3" +dest_files=["res://.godot/imported/karabast.mp3-5fc63c29a959da213d2ed9b8b4c20280.mp3str"] + +[params] + +loop=false +loop_offset=0 +bpm=0 +beat_count=0 +bar_beats=4 diff --git a/Assets/Sprites/Characters/doc.ase b/Assets/Sprites/Characters/doc.ase index 2fd3a93..edb9f18 100644 Binary files a/Assets/Sprites/Characters/doc.ase and b/Assets/Sprites/Characters/doc.ase differ diff --git a/Assets/Sprites/Misc/shungite-spike.ase b/Assets/Sprites/Misc/shungite-spike.ase index 2d02919..25cae18 100644 Binary files a/Assets/Sprites/Misc/shungite-spike.ase and b/Assets/Sprites/Misc/shungite-spike.ase differ diff --git a/Assets/Sprites/Misc/shungite-spike.png b/Assets/Sprites/Misc/shungite-spike.png index 7b0591a..4b01111 100644 Binary files a/Assets/Sprites/Misc/shungite-spike.png and b/Assets/Sprites/Misc/shungite-spike.png differ diff --git a/Assets/Sprites/Misc/torch-lamp.ase b/Assets/Sprites/Misc/torch-lamp.ase new file mode 100644 index 0000000..1b40c79 Binary files /dev/null and b/Assets/Sprites/Misc/torch-lamp.ase differ diff --git a/Assets/Sprites/Misc/torch-lamp.png b/Assets/Sprites/Misc/torch-lamp.png new file mode 100644 index 0000000..4e7ef5b Binary files /dev/null and b/Assets/Sprites/Misc/torch-lamp.png differ diff --git a/Assets/Sprites/Misc/torch-lamp.png.import b/Assets/Sprites/Misc/torch-lamp.png.import new file mode 100644 index 0000000..cb8b59d --- /dev/null +++ b/Assets/Sprites/Misc/torch-lamp.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cyldr0ck3yfrp" +path="res://.godot/imported/torch-lamp.png-9d1bb0925cf254976eada5dcc0694a4f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Sprites/Misc/torch-lamp.png" +dest_files=["res://.godot/imported/torch-lamp.png-9d1bb0925cf254976eada5dcc0694a4f.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/Assets/Sprites/Misc/torch.ase b/Assets/Sprites/Misc/torch.ase new file mode 100644 index 0000000..11ff815 Binary files /dev/null and b/Assets/Sprites/Misc/torch.ase differ diff --git a/Assets/Sprites/Misc/torch.png b/Assets/Sprites/Misc/torch.png new file mode 100644 index 0000000..4cb623f Binary files /dev/null and b/Assets/Sprites/Misc/torch.png differ diff --git a/Assets/Sprites/Misc/torch.png.import b/Assets/Sprites/Misc/torch.png.import new file mode 100644 index 0000000..bc91a48 --- /dev/null +++ b/Assets/Sprites/Misc/torch.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://har1bd5u4dq3" +path="res://.godot/imported/torch.png-a5b622a0de1d4e6244fce3f5c31d2324.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Sprites/Misc/torch.png" +dest_files=["res://.godot/imported/torch.png-a5b622a0de1d4e6244fce3f5c31d2324.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/Assets/Sprites/Particles/light-pixel.ase b/Assets/Sprites/Particles/light-pixel.ase new file mode 100644 index 0000000..5e04a30 Binary files /dev/null and b/Assets/Sprites/Particles/light-pixel.ase differ diff --git a/Assets/Sprites/Particles/light-pixel.png b/Assets/Sprites/Particles/light-pixel.png new file mode 100644 index 0000000..338c893 Binary files /dev/null and b/Assets/Sprites/Particles/light-pixel.png differ diff --git a/Assets/Sprites/Particles/light-pixel.png.import b/Assets/Sprites/Particles/light-pixel.png.import new file mode 100644 index 0000000..396acbf --- /dev/null +++ b/Assets/Sprites/Particles/light-pixel.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b8ann6yb8qox4" +path="res://.godot/imported/light-pixel.png-d30110ea010169a59ef281e39651990b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Sprites/Particles/light-pixel.png" +dest_files=["res://.godot/imported/light-pixel.png-d30110ea010169a59ef281e39651990b.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/Assets/Sprites/arena-tileset.ase b/Assets/Sprites/arena-tileset.ase index 7a34fb5..3fefc84 100644 Binary files a/Assets/Sprites/arena-tileset.ase and b/Assets/Sprites/arena-tileset.ase differ diff --git a/Assets/Sprites/arena-tileset.png b/Assets/Sprites/arena-tileset.png index 37205f5..33bc762 100644 Binary files a/Assets/Sprites/arena-tileset.png and b/Assets/Sprites/arena-tileset.png differ diff --git a/BoundingBoxes/Hitbox.cs b/BoundingBoxes/Hitbox.cs index bbe1365..c0bc820 100644 --- a/BoundingBoxes/Hitbox.cs +++ b/BoundingBoxes/Hitbox.cs @@ -80,7 +80,6 @@ public partial class Hitbox : BoundingBox { if (area is BoundingBox box) { - GD.Print("hit"); // we don't want to hurt teammates if (Faction != box.Faction) { diff --git a/Characters/Doc.tscn b/Characters/Doc.tscn index fef7ca4..5593f81 100644 --- a/Characters/Doc.tscn +++ b/Characters/Doc.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=36 format=3 uid="uid://d2skjvvx6fal0"] +[gd_scene load_steps=38 format=3 uid="uid://d2skjvvx6fal0"] [ext_resource type="Script" path="res://Characters/Doc.cs" id="2_3elet"] [ext_resource type="Shader" path="res://Shaders/Flash.gdshader" id="2_5jxom"] @@ -17,6 +17,8 @@ [ext_resource type="AudioStream" uid="uid://k6kpdj1kv0jg" path="res://Assets/Sounds/splat.ogg" id="9_stm0e"] [ext_resource type="Script" path="res://State/NPC/Doc/DocShungiteSpikeState.cs" id="10_bgs6o"] [ext_resource type="Script" path="res://State/NPC/Doc/DocChooseAttackState.cs" id="12_45x13"] +[ext_resource type="Script" path="res://State/NPC/Doc/DocUnwantedFrequencyState.cs" id="12_d51jv"] +[ext_resource type="PackedScene" uid="uid://1y5r6sklwgrp" path="res://Entities/UnwantedFrequency.tscn" id="13_lpj21"] [sub_resource type="ShaderMaterial" id="ShaderMaterial_7n7iy"] resource_local_to_scene = true @@ -257,10 +259,20 @@ ChooseAttackState = NodePath("../ChooseAttack") Doc = NodePath("../..") NPC = NodePath("../..") -[node name="ChooseAttack" type="Node" parent="BossStateMachine" node_paths=PackedStringArray("DartState", "SpikeState", "ExitState", "NPC")] +[node name="UnwantedFrequency" type="Node" parent="BossStateMachine" node_paths=PackedStringArray("ChooseAttackState", "Doc", "NPC")] +script = ExtResource("12_d51jv") +Duration = 4.0 +AttackDuration = 1.0 +Projectile = ExtResource("13_lpj21") +ChooseAttackState = NodePath("../ChooseAttack") +Doc = NodePath("../..") +NPC = NodePath("../..") + +[node name="ChooseAttack" type="Node" parent="BossStateMachine" node_paths=PackedStringArray("DartState", "SpikeState", "UnwantedFrequencyState", "ExitState", "NPC")] script = ExtResource("12_45x13") DartState = NodePath("../Dart") SpikeState = NodePath("../Spike") +UnwantedFrequencyState = NodePath("../UnwantedFrequency") ExitState = NodePath("../Exit") NPC = NodePath("../..") diff --git a/Characters/Player.cs b/Characters/Player.cs index 1891a2f..04e2171 100644 --- a/Characters/Player.cs +++ b/Characters/Player.cs @@ -84,6 +84,25 @@ public sealed partial class Player : Character // TODO: implement visual effects for stun } + public override void OnReceivedDamage( + float damage, + Character inflictor, + float knockback, + Vector2 knockbackOrigin = default, + Vector2 knockbackVector = default) + { + if (damage >= 10 && IsAlive) + { + Camera.Shake(2, 0.5f); + } + base.OnReceivedDamage( + damage, + inflictor, + knockback, + knockbackOrigin, + knockbackVector); + } + public override void Die() { GD.Print("died"); diff --git a/Entities/Projectile.cs b/Entities/Projectile.cs index 3e1a40c..31718a9 100644 --- a/Entities/Projectile.cs +++ b/Entities/Projectile.cs @@ -8,6 +8,9 @@ public partial class Projectile : RigidBody2D { public Vector2 Velocity => Direction * Speed; + [Export] + public string ProjectileName { get; set; } + [Export] public float Speed { get; set; } @@ -25,6 +28,8 @@ public partial class Projectile : RigidBody2D public Character Character { get; set; } + public bool IsDead { get; set; } + public override void _Ready() { Hitbox.Hit += OnHit; @@ -35,15 +40,26 @@ public partial class Projectile : RigidBody2D if (Delay > 0) { Delay -= delta; + if (Delay <= 0) + { + OnDelayEnd(); + } } if ((Lifetime -= delta) <= 0) { - QueueFree(); + if (!IsDead) + { + Die(); + } } } public override void _PhysicsProcess(double delta) { + if (IsDead) + { + return; + } Vector2 velocity = Delay <= 0 ? Velocity : Vector2.Zero; MoveAndCollide(velocity * (float)delta); } @@ -60,4 +76,14 @@ public partial class Projectile : RigidBody2D ); } } + + public virtual void Die() + { + QueueFree(); + } + + public virtual void OnDelayEnd() + { + + } } diff --git a/Entities/ShungiteDart.tscn b/Entities/ShungiteDart.tscn index 302dd9e..dd74cf4 100644 --- a/Entities/ShungiteDart.tscn +++ b/Entities/ShungiteDart.tscn @@ -277,8 +277,10 @@ _data = { [node name="ShungiteDart" type="RigidBody2D" node_paths=PackedStringArray("Hitbox")] script = ExtResource("1_jbgb8") +ProjectileName = "Shungite Dart" Speed = 256.0 Hitbox = NodePath("Hitbox") +Lifetime = 5.0 Delay = 1.0 [node name="Sprite2D" type="AnimatedSprite2D" parent="."] @@ -290,7 +292,7 @@ speed_scale = 4.0 [node name="Hitbox" parent="." instance=ExtResource("3_gdyk8")] Damage = 25.0 -Knockback = 128.0 +Knockback = 64.0 [node name="CollisionShape2D" parent="Hitbox" index="0"] shape = SubResource("RectangleShape2D_fa7yf") diff --git a/Entities/ShungiteSpike.cs b/Entities/ShungiteSpike.cs index c2d8d90..c88eb64 100644 --- a/Entities/ShungiteSpike.cs +++ b/Entities/ShungiteSpike.cs @@ -9,9 +9,6 @@ public partial class ShungiteSpike : Projectile [Export] public PackedScene Dart { get; set; } - [Export] - public double ExplodeTime { get; set; } = 6; - [Export] public BoundingBoxes.Hurtbox Hurtbox { get; set; } @@ -21,18 +18,44 @@ public partial class ShungiteSpike : Projectile [Export] public AnimationPlayer AnimationPlayer { get; set; } + public Vector2 Target { get; set; } + + public double ExplodeTime { get; set; } = 2; + + public double FreezeTime + { + get => _freezeTime; + set + { + _currentFreezeTime = _freezeTime = value; + } + } + private double _currentExplodeTime; + private double _freezeTime; + private double _currentFreezeTime; + private bool _hasFrozen = false; + private bool _hasExploded = false; private Scenes.Map _map; public override void _Ready() { + _currentFreezeTime = FreezeTime; _currentExplodeTime = ExplodeTime; _map = this.GetAncestor(); Hurtbox.ReceivedDamage += OnReceivedDamage; AnimationPlayer.Play("spin"); + AnimationPlayer.AnimationFinished += (StringName anim) => + { + if (anim == "explode") + { + QueueFree(); + } + }; + base._Ready(); } @@ -43,8 +66,21 @@ public partial class ShungiteSpike : Projectile Vector2 knockbackOrigin = default, Vector2 knockbackVector = default) { + // if we were hit by the player before the spike freezes, + // spawn a dart towards where the player is aiming + if (inflictor is Characters.Player player) + { + var mousePos = GetGlobalMousePosition(); + var dart = CreateDart(GlobalPosition.DirectionTo(mousePos)); + dart.Hitbox.Faction = player.Faction; + Hitbox.IsDisabled = true; + } + HitSound.At(GlobalPosition).PlayOneShot(); - QueueFree(); + _hasExploded = true; + _hasFrozen = true; + AnimationPlayer.Stop(); + AnimationPlayer.Play("explode"); } @@ -60,13 +96,27 @@ public partial class ShungiteSpike : Projectile public override void _Process(double delta) { - if ((_currentExplodeTime -= delta) <= 0) + if ((_currentFreezeTime -= delta) <= 0) { - CreateDart(Vector2.Up); - CreateDart(Vector2.Down); - CreateDart(Vector2.Left); - CreateDart(Vector2.Right); - QueueFree(); + if (!_hasFrozen) + { + Speed = 0; + _hasFrozen = true; + AnimationPlayer.Stop(); + } + + if ((_currentExplodeTime -= delta) <= 0) + { + if (!_hasExploded) + { + CreateDart(Vector2.Up); + CreateDart(Vector2.Down); + CreateDart(Vector2.Left); + CreateDart(Vector2.Right); + AnimationPlayer.Play("explode"); + _hasExploded = true; + } + } } } } diff --git a/Entities/ShungiteSpike.tscn b/Entities/ShungiteSpike.tscn index 9393476..f3dec6c 100644 --- a/Entities/ShungiteSpike.tscn +++ b/Entities/ShungiteSpike.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=12 format=3 uid="uid://1tiswf3gtyvv"] +[gd_scene load_steps=13 format=3 uid="uid://1tiswf3gtyvv"] [ext_resource type="Script" path="res://Entities/ShungiteSpike.cs" id="1_pclpe"] [ext_resource type="PackedScene" uid="uid://djaljmco3xo4g" path="res://Entities/ShungiteDart.tscn" id="2_hinxt"] @@ -7,10 +7,90 @@ [ext_resource type="PackedScene" uid="uid://cjgxyhgcyvsv7" path="res://BoundingBoxes/Hurtbox.tscn" id="4_d8dl4"] [ext_resource type="AudioStream" uid="uid://c4n7ioxpukdwi" path="res://Assets/Sounds/parry.wav" id="6_fepye"] -[sub_resource type="RectangleShape2D" id="RectangleShape2D_konb7"] +[sub_resource type="CircleShape2D" id="CircleShape2D_hrev2"] +radius = 8.0 [sub_resource type="CircleShape2D" id="CircleShape2D_kumrg"] -radius = 20.0 +radius = 12.0 + +[sub_resource type="Animation" id="Animation_0vfvo"] +length = 0.001 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Sprite2D:rotation") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("Sprite2D:frame") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [0] +} +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath("Sprite2D:self_modulate") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Color(1, 1, 1, 1)] +} + +[sub_resource type="Animation" id="Animation_0a85j"] +resource_name = "explode" +length = 0.5 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Sprite2D:frame") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2), +"transitions": PackedFloat32Array(1, 1, 1), +"update": 1, +"values": [0, 2, 4] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("Sprite2D:rotation") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0, 0.4), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [0.0, 6.28319] +} +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath("Sprite2D:self_modulate") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0, 0.5), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Color(1, 1, 1, 1), Color(1, 1, 1, 0)] +} [sub_resource type="Animation" id="Animation_dlpaa"] resource_name = "spin" @@ -29,46 +109,34 @@ tracks/0/keys = { "values": [0.0, 6.28319] } -[sub_resource type="Animation" id="Animation_0vfvo"] -length = 0.001 -tracks/0/type = "value" -tracks/0/imported = false -tracks/0/enabled = true -tracks/0/path = NodePath("Sprite2D:rotation") -tracks/0/interp = 1 -tracks/0/loop_wrap = true -tracks/0/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 0, -"values": [0.0] -} - [sub_resource type="AnimationLibrary" id="AnimationLibrary_jj1qe"] _data = { "RESET": SubResource("Animation_0vfvo"), +"explode": SubResource("Animation_0a85j"), "spin": SubResource("Animation_dlpaa") } -[node name="ShungiteSpike" type="RigidBody2D" node_paths=PackedStringArray("Hurtbox", "HitSound", "Hitbox")] +[node name="ShungiteSpike" type="RigidBody2D" node_paths=PackedStringArray("Hurtbox", "HitSound", "AnimationPlayer", "Hitbox")] script = ExtResource("1_pclpe") Dart = ExtResource("2_hinxt") Hurtbox = NodePath("Hurtbox") HitSound = NodePath("AudioStreamPlayer2D") +AnimationPlayer = NodePath("AnimationPlayer") +ProjectileName = "Shungite Spike" +Speed = 96.0 Hitbox = NodePath("Hitbox") [node name="Sprite2D" type="Sprite2D" parent="."] -modulate = Color(1.4, 0, 1.2, 1) -self_modulate = Color(2, 2, 2, 1) texture_filter = 1 texture = ExtResource("2_klp8v") +hframes = 5 [node name="Hitbox" parent="." instance=ExtResource("3_kojrj")] -Damage = 10.0 -Knockback = 256.0 +Damage = 14.0 +Knockback = 200.0 [node name="CollisionShape2D" parent="Hitbox" index="0"] -shape = SubResource("RectangleShape2D_konb7") +shape = SubResource("CircleShape2D_hrev2") [node name="Hurtbox" parent="." instance=ExtResource("4_d8dl4")] diff --git a/Entities/Torch.tscn b/Entities/Torch.tscn new file mode 100644 index 0000000..3d13af6 --- /dev/null +++ b/Entities/Torch.tscn @@ -0,0 +1,79 @@ +[gd_scene load_steps=11 format=3 uid="uid://c1w7t6irnohfx"] + +[ext_resource type="Texture2D" uid="uid://har1bd5u4dq3" path="res://Assets/Sprites/Misc/torch.png" id="1_14bgb"] +[ext_resource type="Texture2D" uid="uid://b8ann6yb8qox4" path="res://Assets/Sprites/Particles/light-pixel.png" id="2_f0xs8"] + +[sub_resource type="AtlasTexture" id="AtlasTexture_js1l1"] +atlas = ExtResource("1_14bgb") +region = Rect2(0, 0, 8, 12) + +[sub_resource type="AtlasTexture" id="AtlasTexture_gdxtl"] +atlas = ExtResource("1_14bgb") +region = Rect2(8, 0, 8, 12) + +[sub_resource type="AtlasTexture" id="AtlasTexture_da7fw"] +atlas = ExtResource("1_14bgb") +region = Rect2(16, 0, 8, 12) + +[sub_resource type="AtlasTexture" id="AtlasTexture_rpccx"] +atlas = ExtResource("1_14bgb") +region = Rect2(24, 0, 8, 12) + +[sub_resource type="AtlasTexture" id="AtlasTexture_crwu1"] +atlas = ExtResource("1_14bgb") +region = Rect2(32, 0, 8, 12) + +[sub_resource type="AtlasTexture" id="AtlasTexture_r3kxc"] +atlas = ExtResource("1_14bgb") +region = Rect2(40, 0, 8, 12) + +[sub_resource type="AtlasTexture" id="AtlasTexture_225la"] +atlas = ExtResource("1_14bgb") +region = Rect2(48, 0, 8, 12) + +[sub_resource type="SpriteFrames" id="SpriteFrames_gf7ku"] +animations = [{ +"frames": [{ +"duration": 1.0, +"texture": SubResource("AtlasTexture_js1l1") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_gdxtl") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_da7fw") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_rpccx") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_crwu1") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_r3kxc") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_225la") +}], +"loop": true, +"name": &"default", +"speed": 5.0 +}] + +[node name="Torch" type="Node2D"] + +[node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="."] +texture_filter = 1 +position = Vector2(0, -12) +sprite_frames = SubResource("SpriteFrames_gf7ku") +autoplay = "default" +frame = 5 +frame_progress = 0.743234 + +[node name="PointLight2D" type="PointLight2D" parent="."] +color = Color(1, 0.898039, 0.686275, 1) +blend_mode = 2 +shadow_enabled = true +shadow_filter_smooth = 3.0 +texture = ExtResource("2_f0xs8") +offset = Vector2(0, 2) diff --git a/Entities/TorchLamp.tscn b/Entities/TorchLamp.tscn new file mode 100644 index 0000000..ba5c3fa --- /dev/null +++ b/Entities/TorchLamp.tscn @@ -0,0 +1,114 @@ +[gd_scene load_steps=16 format=3 uid="uid://ceadk7pam7vab"] + +[ext_resource type="Texture2D" uid="uid://cyldr0ck3yfrp" path="res://Assets/Sprites/Misc/torch-lamp.png" id="1_dlkl0"] +[ext_resource type="Texture2D" uid="uid://b8ann6yb8qox4" path="res://Assets/Sprites/Particles/light-pixel.png" id="2_yuj6j"] + +[sub_resource type="AtlasTexture" id="AtlasTexture_ikvnd"] +atlas = ExtResource("1_dlkl0") +region = Rect2(0, 0, 12, 24) + +[sub_resource type="AtlasTexture" id="AtlasTexture_b7wal"] +atlas = ExtResource("1_dlkl0") +region = Rect2(12, 0, 12, 24) + +[sub_resource type="AtlasTexture" id="AtlasTexture_68y2k"] +atlas = ExtResource("1_dlkl0") +region = Rect2(24, 0, 12, 24) + +[sub_resource type="AtlasTexture" id="AtlasTexture_eib4d"] +atlas = ExtResource("1_dlkl0") +region = Rect2(36, 0, 12, 24) + +[sub_resource type="AtlasTexture" id="AtlasTexture_7q5cd"] +atlas = ExtResource("1_dlkl0") +region = Rect2(48, 0, 12, 24) + +[sub_resource type="AtlasTexture" id="AtlasTexture_k8jtr"] +atlas = ExtResource("1_dlkl0") +region = Rect2(60, 0, 12, 24) + +[sub_resource type="AtlasTexture" id="AtlasTexture_egan1"] +atlas = ExtResource("1_dlkl0") +region = Rect2(72, 0, 12, 24) + +[sub_resource type="AtlasTexture" id="AtlasTexture_eymjc"] +atlas = ExtResource("1_dlkl0") +region = Rect2(84, 0, 12, 24) + +[sub_resource type="AtlasTexture" id="AtlasTexture_go3ky"] +atlas = ExtResource("1_dlkl0") +region = Rect2(96, 0, 12, 24) + +[sub_resource type="AtlasTexture" id="AtlasTexture_rvq52"] +atlas = ExtResource("1_dlkl0") +region = Rect2(108, 0, 12, 24) + +[sub_resource type="AtlasTexture" id="AtlasTexture_cjdtb"] +atlas = ExtResource("1_dlkl0") +region = Rect2(120, 0, 12, 24) + +[sub_resource type="AtlasTexture" id="AtlasTexture_vi5xh"] +atlas = ExtResource("1_dlkl0") +region = Rect2(132, 0, 12, 24) + +[sub_resource type="SpriteFrames" id="SpriteFrames_gf7ku"] +animations = [{ +"frames": [{ +"duration": 1.0, +"texture": SubResource("AtlasTexture_ikvnd") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_b7wal") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_68y2k") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_eib4d") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_7q5cd") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_k8jtr") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_egan1") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_eymjc") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_go3ky") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_rvq52") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_cjdtb") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_vi5xh") +}], +"loop": true, +"name": &"default", +"speed": 10.0 +}] + +[node name="TorchLamp" type="Node2D"] + +[node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="."] +texture_filter = 1 +position = Vector2(0, -12) +sprite_frames = SubResource("SpriteFrames_gf7ku") +autoplay = "default" +frame = 6 +frame_progress = 0.743234 + +[node name="PointLight2D" type="PointLight2D" parent="."] +color = Color(1, 0.827451, 0.619608, 1) +blend_mode = 2 +shadow_enabled = true +shadow_filter_smooth = 3.0 +texture = ExtResource("2_yuj6j") +offset = Vector2(0, 2) diff --git a/Entities/UnwantedFrequency.cs b/Entities/UnwantedFrequency.cs new file mode 100644 index 0000000..e2c9932 --- /dev/null +++ b/Entities/UnwantedFrequency.cs @@ -0,0 +1,75 @@ +using Godot; +using SupaLidlGame.Extensions; + +namespace SupaLidlGame.Entities; + +public partial class UnwantedFrequency : Projectile +{ + [Export] + public Characters.Character Homing { get; set; } + + [Export] + public float HomingVelocity { get; set; } = 1; + + public Utils.Trail Trail { get; set; } + public Node2D TrailRotation { get; set; } + public Node2D TrailPosition { get; set; } + public GpuParticles2D DeathParticles { get; set; } + public Timer DeferDeathTimer { get; set; } + + private double _currentLifetime = 0; + + public override void _Ready() + { + TrailRotation = GetNode("TrailRotation"); + TrailPosition = TrailRotation.GetNode("TrailPosition"); + Trail = TrailPosition.GetNode("Trail"); + DeferDeathTimer = GetNode("DeferDeath"); + DeathParticles = GetNode("DeathParticles"); + Hitbox.Hit += (BoundingBoxes.BoundingBox box) => + { + if (box is BoundingBoxes.Hurtbox && box.Faction != Hitbox.Faction) + { + Die(); + } + }; + base._Ready(); + } + + public override void _Process(double delta) + { + _currentLifetime += delta; + float radians = (float)_currentLifetime * 24; + TrailRotation.Rotation = Direction.Angle(); + TrailPosition.Position = new Vector2(0, 4 * Mathf.Sin(radians)); + + // home towards player + if (Homing is not null) + { + var desired = GlobalPosition.DirectionTo(Homing.GlobalPosition); + //var steer = (desired - Direction) * HomingVelocity * (float)delta; + //float dTheta = Direction.AngleTo(dirToHoming); + //float dTheta = Mathf.Acos(Direction.Dot(dirToHoming)); + + //float max = (float)(delta * HomingRotationalVelocity); + //float rotVel = Mathf.Clamp(dTheta, -max, max); + + Direction += (desired - Direction) * HomingVelocity * (float)delta; + } + + base._Process(delta); + } + + public override void Die() + { + IsDead = Trail.IsDead = Hitbox.IsDisabled = true; + DeferDeathTimer.Timeout += () => + { + QueueFree(); + }; + DeferDeathTimer.Start(); + DeathParticles.Emitting = true; + GetNode("Sound").Stop(); + GetNode("AnimationPlayer").Play("death"); + } +} diff --git a/Entities/UnwantedFrequency.tscn b/Entities/UnwantedFrequency.tscn new file mode 100644 index 0000000..8087070 --- /dev/null +++ b/Entities/UnwantedFrequency.tscn @@ -0,0 +1,130 @@ +[gd_scene load_steps=14 format=3 uid="uid://1y5r6sklwgrp"] + +[ext_resource type="Script" path="res://Entities/UnwantedFrequency.cs" id="1_6sbe0"] +[ext_resource type="PackedScene" uid="uid://du5vhccg75nrq" path="res://BoundingBoxes/Hitbox.tscn" id="2_gxtvd"] +[ext_resource type="PackedScene" uid="uid://cojxmcin13ihm" path="res://Utils/Trail.tscn" id="3_67uhs"] +[ext_resource type="AudioStream" uid="uid://cn2wop7rfxku8" path="res://Assets/Sounds/karabast.mp3" id="4_pbgsi"] + +[sub_resource type="RectangleShape2D" id="RectangleShape2D_30y8q"] +size = Vector2(8, 8) + +[sub_resource type="Curve" id="Curve_eu273"] +_data = [Vector2(0.0618557, 0), 0.0, 0.0, 0, 0, Vector2(0.489691, 1), 0.0, 0.0, 0, 0] +point_count = 2 + +[sub_resource type="Gradient" id="Gradient_dyqhb"] +offsets = PackedFloat32Array(0.00662252, 0.715232, 1) +colors = PackedColorArray(0.996078, 0, 0.164706, 0, 0.996045, 0, 0.166638, 1, 1, 1, 1, 1) + +[sub_resource type="Gradient" id="Gradient_2q0ut"] +offsets = PackedFloat32Array(0.525926, 0.740741, 1) +colors = PackedColorArray(1, 1, 1, 1, 1, 0.00784314, 0.215686, 0.784314, 1, 0, 0, 0) + +[sub_resource type="GradientTexture1D" id="GradientTexture1D_yfhnr"] +gradient = SubResource("Gradient_2q0ut") + +[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_eh1hw"] +particle_flag_disable_z = true +spread = 180.0 +gravity = Vector3(0, 0, 0) +initial_velocity_max = 100.0 +angular_velocity_min = 45.0 +angular_velocity_max = 90.0 +orbit_velocity_min = 0.0 +orbit_velocity_max = 2.0 +color_ramp = SubResource("GradientTexture1D_yfhnr") + +[sub_resource type="Animation" id="Animation_w1abs"] +length = 0.001 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Sound:volume_db") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [-16.0] +} + +[sub_resource type="Animation" id="Animation_0brc4"] +resource_name = "death" +length = 4.0 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Sound:volume_db") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 4), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [-16.0, -64.0] +} + +[sub_resource type="AnimationLibrary" id="AnimationLibrary_v8fdt"] +_data = { +"RESET": SubResource("Animation_w1abs"), +"death": SubResource("Animation_0brc4") +} + +[node name="UnwantedFrequency" type="RigidBody2D" node_paths=PackedStringArray("Hitbox")] +script = ExtResource("1_6sbe0") +HomingVelocity = 1.4 +ProjectileName = "Unwanted Frequency" +Speed = 140.0 +Direction = Vector2(1, 1) +Hitbox = NodePath("Hitbox") +Lifetime = 8.0 + +[node name="Hitbox" parent="." instance=ExtResource("2_gxtvd")] +collision_layer = 0 +monitorable = false +Damage = 12.0 +Knockback = 324.0 + +[node name="CollisionShape2D" parent="Hitbox" index="0"] +shape = SubResource("RectangleShape2D_30y8q") + +[node name="TrailRotation" type="Node2D" parent="."] + +[node name="TrailPosition" type="Node2D" parent="TrailRotation"] + +[node name="Trail" parent="TrailRotation/TrailPosition" instance=ExtResource("3_67uhs")] +self_modulate = Color(2, 2, 2, 1) +width = 2.0 +width_curve = SubResource("Curve_eu273") +default_color = Color(1, 0.0862745, 0.207843, 1) +gradient = SubResource("Gradient_dyqhb") +joint_mode = 2 +begin_cap_mode = 2 +end_cap_mode = 2 +MaximumPoints = 64 +Frequency = 30 + +[node name="DeferDeath" type="Timer" parent="."] +wait_time = 4.0 + +[node name="Sound" type="AudioStreamPlayer2D" parent="."] +stream = ExtResource("4_pbgsi") +volume_db = -16.0 +autoplay = true +max_distance = 64.0 +attenuation = 8.0 + +[node name="DeathParticles" type="GPUParticles2D" parent="."] +emitting = false +process_material = SubResource("ParticleProcessMaterial_eh1hw") +lifetime = 2.0 +one_shot = true +explosiveness = 0.8 + +[node name="AnimationPlayer" type="AnimationPlayer" parent="."] +libraries = { +"": SubResource("AnimationLibrary_v8fdt") +} + +[editable path="Hitbox"] diff --git a/Items/Weapons/Sword.tscn b/Items/Weapons/Sword.tscn index 69f13b2..0b53cac 100644 --- a/Items/Weapons/Sword.tscn +++ b/Items/Weapons/Sword.tscn @@ -377,12 +377,11 @@ environment = SubResource("Environment_72txp") y_sort_enabled = true rotation = -1.5708 -[node name="Trail" parent="Anchor" node_paths=PackedStringArray("Tracking") instance=ExtResource("4_pt6lq")] +[node name="Trail" parent="Anchor" instance=ExtResource("4_pt6lq")] position = Vector2(2.40734, -0.55655) rotation = 0.945464 width_curve = SubResource("Curve_4cxtp") gradient = SubResource("Gradient_2ablm") -Tracking = NodePath("../Node2D/Sprite2D") [node name="Node2D" type="Node2D" parent="Anchor"] y_sort_enabled = true diff --git a/Scenes/Maps/Arena.tscn b/Scenes/Maps/Arena.tscn index c5db8f1..4cf9b93 100644 --- a/Scenes/Maps/Arena.tscn +++ b/Scenes/Maps/Arena.tscn @@ -2,19 +2,16 @@ [ext_resource type="PackedScene" uid="uid://clwv2owvk6abe" path="res://Scenes/BaseMap.tscn" id="1_ifiic"] [ext_resource type="Texture2D" uid="uid://b0yiy7w8nxmas" path="res://Assets/Sprites/arena-tileset.png" id="2_wnjm0"] -[ext_resource type="Texture2D" uid="uid://5k0o7d7j65a4" path="res://Assets/Sprites/arena-tileset-normal.png" id="3_iitgk"] -[ext_resource type="PackedScene" uid="uid://dsr5kkbthpwpl" path="res://Characters/Doc.tscn" id="4_c0csw"] +[ext_resource type="PackedScene" uid="uid://d2skjvvx6fal0" path="res://Characters/Doc.tscn" id="4_c0csw"] [ext_resource type="Shader" path="res://Shaders/Flash.gdshader" id="5_aevwf"] +[ext_resource type="PackedScene" uid="uid://c1w7t6irnohfx" path="res://Entities/Torch.tscn" id="6_1wwor"] +[ext_resource type="PackedScene" uid="uid://ceadk7pam7vab" path="res://Entities/TorchLamp.tscn" id="6_jy3pc"] [sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_8jil2"] polygon = PackedVector2Array(-8, -4, -6, -5, -6, -18, 6, -18, 6, -5, 8, -4, 8, 4, 4, 8, -4, 8, -8, 3.5) -[sub_resource type="CanvasTexture" id="CanvasTexture_dnsyd"] -diffuse_texture = ExtResource("2_wnjm0") -normal_texture = ExtResource("3_iitgk") - [sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_fcd6d"] -texture = SubResource("CanvasTexture_dnsyd") +texture = ExtResource("2_wnjm0") 0:0/0 = 0 0:0/0/physics_layer_0/linear_velocity = Vector2(0, 0) 0:0/0/physics_layer_0/angular_velocity = 0.0 @@ -252,7 +249,7 @@ physics_layer_0/collision_layer = 1 sources/2 = SubResource("TileSetAtlasSource_5yxvt") sources/0 = SubResource("TileSetAtlasSource_fcd6d") -[sub_resource type="ShaderMaterial" id="ShaderMaterial_4g4ap"] +[sub_resource type="ShaderMaterial" id="ShaderMaterial_im5g2"] resource_local_to_scene = true shader = ExtResource("5_aevwf") shader_parameter/color = Quaternion(1, 1, 1, 1) @@ -265,9 +262,42 @@ layer_3/tile_data = PackedInt32Array(-196612, 65536, 1, -131076, 65536, 1, -6554 layer_4/tile_data = PackedInt32Array(-524296, 327680, 0, -589818, 262144, 0, -589817, 262144, 1, -589819, 327680, 0, -589820, 196608, 1, -589821, 327680, 1, -589822, 131072, 1, -589823, 262144, 1, -589824, 327680, 0, -524289, 131072, 1, -524290, 327680, 0, -524291, 327680, 1, -524292, 327680, 1, -524293, 327680, 0, -524294, 131072, 1, -524295, 262144, 1, -589832, 131072, 2, -589831, 131072, 2, -589830, 131072, 2, -589829, 131072, 2, -589828, 131072, 2, -589827, 131072, 2, -589826, 131072, 2, -589825, 131072, 2, -655360, 131072, 2, -655359, 131072, 2, -655358, 131072, 2, -655357, 131072, 2, -655356, 131072, 2, -655355, 131072, 2, -655354, 131072, 2, -655353, 131072, 2, -655352, 327680, 2, -589833, 262144, 2, -524297, 196608, 3, -458761, 196608, 3, -393225, 196608, 3, -327689, 196608, 3, -262153, 196608, 3, -196617, 196608, 3, -131081, 196608, 3, -65545, 196608, 3, -9, 196608, 3, 65527, 196608, 3, 131063, 196608, 3, 196599, 196608, 3, 262135, 196608, 3, 327671, 196608, 3, 393207, 196608, 3, 458743, 196608, 3, 524279, 196608, 3, 262152, 131072, 3, 327688, 131072, 3, 393224, 131072, 3, 458760, 131072, 3, 196616, 131072, 3, 131080, 131072, 3, 65544, 131072, 3, 8, 131072, 3, -65528, 131072, 3, -131064, 131072, 3, -196600, 131072, 3, -262136, 131072, 3, -589816, 131072, 3, -524280, 131072, 3, -458744, 131072, 3, -393208, 131072, 3, -327672, 131072, 3, 589816, 196608, 2, 589817, 196608, 2, 589818, 196608, 2, 589819, 196608, 2, 589820, 196608, 2, 589821, 196608, 2, 589822, 196608, 2, 589823, 196608, 2, 524288, 196608, 2, 524289, 196608, 2, 524290, 196608, 2, 524291, 196608, 2, 524292, 196608, 2, 524293, 196608, 2, 524294, 196608, 2, 524295, 196608, 2, 524296, 327680, 3, 589815, 262144, 3) [node name="CanvasModulate" parent="." index="0"] -color = Color(0.753984, 0.753984, 0.753984, 1) +color = Color(0.501961, 0.501961, 0.501961, 1) [node name="Doc" parent="Entities" index="0" instance=ExtResource("4_c0csw")] -material = SubResource("ShaderMaterial_4g4ap") +material = SubResource("ShaderMaterial_im5g2") PreferredWeightDistance = 256.0 MaxWeightDistance = 32.0 + +[node name="Torch" parent="Entities" index="1" instance=ExtResource("6_1wwor")] +position = Vector2(-120, -112) + +[node name="Torch2" parent="Entities" index="2" instance=ExtResource("6_1wwor")] +position = Vector2(-72, -112) + +[node name="Torch3" parent="Entities" index="3" instance=ExtResource("6_1wwor")] +position = Vector2(-24, -113) + +[node name="Torch4" parent="Entities" index="4" instance=ExtResource("6_1wwor")] +position = Vector2(24, -112) + +[node name="Torch5" parent="Entities" index="5" instance=ExtResource("6_1wwor")] +position = Vector2(72, -112) + +[node name="Torch6" parent="Entities" index="6" instance=ExtResource("6_1wwor")] +position = Vector2(120, -112) + +[node name="TorchLamp" parent="." index="6" instance=ExtResource("6_jy3pc")] +position = Vector2(-96, -120) + +[node name="TorchLamp2" parent="." index="7" instance=ExtResource("6_jy3pc")] +position = Vector2(-48, -120) + +[node name="TorchLamp3" parent="." index="8" instance=ExtResource("6_jy3pc")] +position = Vector2(0, -120) + +[node name="TorchLamp4" parent="." index="9" instance=ExtResource("6_jy3pc")] +position = Vector2(48, -120) + +[node name="TorchLamp5" parent="." index="10" instance=ExtResource("6_jy3pc")] +position = Vector2(96, -120) diff --git a/State/NPC/Doc/DocChooseAttackState.cs b/State/NPC/Doc/DocChooseAttackState.cs index 6959bd7..0a31395 100644 --- a/State/NPC/Doc/DocChooseAttackState.cs +++ b/State/NPC/Doc/DocChooseAttackState.cs @@ -1,4 +1,5 @@ using Godot; +using System.Linq; using System.Collections.Generic; namespace SupaLidlGame.State.NPC.Doc; @@ -11,22 +12,31 @@ public partial class DocChooseAttackState : NPCState [Export] public DocShungiteSpikeState SpikeState { get; set; } + [Export] + public DocUnwantedFrequencyState UnwantedFrequencyState { get; set; } + [Export] public DocExitState ExitState { get; set; } public Characters.Doc Doc => NPC as Characters.Doc; - private List _states = new List(); + private HashSet _possibleStates = new HashSet(); private int _consecutiveAttacks = 0; public override void _Ready() { - _states.Add(DartState); - _states.Add(SpikeState); + ResetStates(); base._Ready(); } + private void ResetStates() + { + _possibleStates.Add(DartState); + _possibleStates.Add(SpikeState); + _possibleStates.Add(UnwantedFrequencyState); + } + public override NPCState Enter(IState previous) { if (previous is not DocTelegraphState) @@ -44,8 +54,16 @@ public partial class DocChooseAttackState : NPCState return ExitState; } + if (_possibleStates.Count == 0) + { + ResetStates(); + } + // choose random attack var random = new System.Random(); - return _states[random.Next(_states.Count)]; + int index = random.Next(_possibleStates.Count); + var state = _possibleStates.ElementAt(index); + _possibleStates.Remove(state); + return state; } } diff --git a/State/NPC/Doc/DocShungiteDartState.cs b/State/NPC/Doc/DocShungiteDartState.cs index f2b2601..23d90d5 100644 --- a/State/NPC/Doc/DocShungiteDartState.cs +++ b/State/NPC/Doc/DocShungiteDartState.cs @@ -47,8 +47,6 @@ public partial class DocShungiteDartState : DocAttackState { var projectile = _map.SpawnEntity(Projectile); projectile.Hitbox.Faction = NPC.Faction; - // global position is (from npc to player) * 2 = (2 * npc) - player - //projectile.GlobalPosition = 2 * NPC.GlobalPosition - playerPos; projectile.GlobalPosition = position; projectile.Direction = direction; projectile.GlobalRotation = direction.Angle(); @@ -60,6 +58,8 @@ public partial class DocShungiteDartState : DocAttackState { var player = _world.CurrentPlayer; var playerPos = player.GlobalPosition; + // global position is (from npc to player) * 2 = (2 * npc) - player + //projectile.GlobalPosition = 2 * NPC.GlobalPosition - playerPos; Vector2 position1 = 2 * NPC.GlobalPosition - playerPos; Vector2 position2 = 2 * playerPos - NPC.GlobalPosition; Vector2 direction1 = position1.DirectionTo(playerPos); diff --git a/State/NPC/Doc/DocShungiteSpikeState.cs b/State/NPC/Doc/DocShungiteSpikeState.cs index 6f76bcb..aee3b37 100644 --- a/State/NPC/Doc/DocShungiteSpikeState.cs +++ b/State/NPC/Doc/DocShungiteSpikeState.cs @@ -5,12 +5,12 @@ namespace SupaLidlGame.State.NPC.Doc; public partial class DocShungiteSpikeState : DocShungiteDartState { - private float _intensity = 1; + protected int _currentAttacks = 0; public override NPCState Enter(IState previous) { - // subtract from total state time by intensity - Duration = _currentDuration = 9 - 2 * Doc.Intensity; + _currentAttacks = 0; + _currentAttackDuration = 1; return base.Enter(previous); } @@ -22,7 +22,6 @@ public partial class DocShungiteSpikeState : DocShungiteDartState as ShungiteSpike; projectile.GlobalRotation = 0; projectile.Delay = 0; - projectile.ExplodeTime = 6 - 2 * Doc.Intensity; projectile.Hitbox.Faction = projectile.Hurtbox.Faction = Doc.Faction; return projectile; } @@ -31,31 +30,37 @@ public partial class DocShungiteSpikeState : DocShungiteDartState { var player = _world.CurrentPlayer; var playerPos = player.GlobalPosition; - Vector2 left = playerPos + Vector2.Left * 64; - Vector2 right = playerPos + Vector2.Right * 64; - Vector2 up = playerPos + Vector2.Up * 64; - Vector2 down = playerPos + Vector2.Down * 64; - SpawnProjectile(left, Vector2.Zero); - SpawnProjectile(right, Vector2.Zero); - SpawnProjectile(up, Vector2.Zero); - SpawnProjectile(down, Vector2.Zero); + var docPos = NPC.GlobalPosition; + var projectile = SpawnProjectile(docPos, Vector2.Zero) as ShungiteSpike; + var projectileSpeed = projectile.Speed = 96; - // only attack once and stop (but keep in this state for 8 seconds) - _currentAttackDuration += 8; + // predict to player's position + var targetPos = Utils.Physics.PredictNewPosition( + docPos, + projectileSpeed, + playerPos, + player.Velocity, + out float time); + projectile.Direction = projectile.GlobalPosition.DirectionTo(targetPos); + projectile.FreezeTime = time + 0.25; // freeze when it reaches target + GD.Print("projectile velocity: " + projectile.Velocity); + + _currentAttackDuration = 1; + _currentAttacks++; } public override NPCState Process(double delta) { - if ((_currentDuration -= delta) <= 0) - { - return ChooseAttackState; - } - if ((_currentAttackDuration -= delta) <= 0) { Attack(); } + if (_currentAttacks >= Doc.Intensity) + { + return ChooseAttackState; + } + return null; } } diff --git a/State/NPC/Doc/DocUnwantedFrequencyState.cs b/State/NPC/Doc/DocUnwantedFrequencyState.cs new file mode 100644 index 0000000..e2b1048 --- /dev/null +++ b/State/NPC/Doc/DocUnwantedFrequencyState.cs @@ -0,0 +1,32 @@ +using Godot; +using SupaLidlGame.Entities; + +namespace SupaLidlGame.State.NPC.Doc; + +public partial class DocUnwantedFrequencyState : DocShungiteSpikeState +{ + protected override Projectile SpawnProjectile( + Vector2 position, + Vector2 direction) + { + var projectile = _map.SpawnEntity(Projectile); + projectile.Hitbox.Faction = NPC.Faction; + projectile.GlobalPosition = position; + projectile.Direction = direction; + projectile.Delay = 1.0 / Doc.Intensity; + return projectile; + } + + protected override void Attack() + { + var player = _world.CurrentPlayer; + var playerPos = player.GlobalPosition; + var docPos = NPC.GlobalPosition; + var projectile = SpawnProjectile(docPos, docPos.DirectionTo(playerPos)) + as UnwantedFrequency; + projectile.Homing = player; + + _currentAttackDuration = 1; + _currentAttacks++; + } +} diff --git a/Utils/Physics.cs b/Utils/Physics.cs new file mode 100644 index 0000000..239532a --- /dev/null +++ b/Utils/Physics.cs @@ -0,0 +1,36 @@ +using Godot; + +namespace SupaLidlGame.Utils; + +public static class Physics +{ + /// + /// Returns the predicted position of a target after a time t at which a + /// projectile is predicted to hit a target. + /// + public static Vector2 PredictNewPosition( + Vector2 position, + float speed, + Vector2 targetPosition, + Vector2 targetVelocity, + out float time) + { + // relative velocity is sum of projectile's relative velocity when idle + // plus its relative velocity when heading towards target (as origin) + var relIdle = -targetVelocity; + var relDir = (position - targetPosition).DirectionTo(Vector2.Zero); + + var relVel = relIdle + relDir * speed; + var relSpeed = relVel.Length(); + + GD.Print("Relative velocity: " + relVel); + + // get t = time to travel + // = (|s2| - |s1|)/(|v2| - |v1|) + time = position.DistanceTo(targetPosition) / relSpeed; + GD.Print("Time: " + time); + + // predict target's position after time t + return targetPosition + targetVelocity * time; + } +} diff --git a/Utils/Trail.cs b/Utils/Trail.cs index 56c9825..b763d33 100644 --- a/Utils/Trail.cs +++ b/Utils/Trail.cs @@ -1,17 +1,48 @@ using Godot; +namespace SupaLidlGame.Utils; + public partial class Trail : Line2D { [Export] public int MaximumPoints { get; set; } [Export] - public Node2D Tracking { get; set; } + protected uint Frequency { get; set; } + + public bool IsDead { get; set; } = false; + + protected double _currentTrailSleepTime = 0; + protected double _trailSleepTime = 0; + protected Node2D _parent; + + public override void _Ready() + { + _trailSleepTime = 1.0 / Frequency; + _parent = GetParent() as Node2D; + } public override void _Process(double delta) { - Vector2 point = Tracking.Position; - AddPoint(point); + if (IsDead && Points.Length > 0) + { + RemovePoint(0); + return; + } + + //Vector2 point = GlobalPosition; + if ((_currentTrailSleepTime -= delta) > 0) + { + if (Points.Length > 0) + { + SetPointPosition(Points.Length - 1, _parent.GlobalPosition); + } + return; + } + + _currentTrailSleepTime = _trailSleepTime; + + AddPoint(_parent.GlobalPosition); while (Points.Length > MaximumPoints) { diff --git a/Utils/Trail.tscn b/Utils/Trail.tscn index 69af05e..92f4bbd 100644 --- a/Utils/Trail.tscn +++ b/Utils/Trail.tscn @@ -4,5 +4,6 @@ [node name="Trail" type="Line2D"] show_behind_parent = true +top_level = true script = ExtResource("1_t42kk") MaximumPoints = 16 diff --git a/Utils/World.cs b/Utils/World.cs index 8e426d7..7278e8c 100644 --- a/Utils/World.cs +++ b/Utils/World.cs @@ -38,6 +38,7 @@ public partial class World : Node2D public override void _Ready() { + Godot.RenderingServer.SetDefaultClearColor(Godot.Colors.Black); if (StartingArea is not null) { LoadScene(StartingArea);