rework spike attack; added unwanted frequency
parent
9dd4525fcd
commit
2979f69405
Binary file not shown.
|
@ -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
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 458 B After Width: | Height: | Size: 818 B |
|
@ -80,7 +80,6 @@ public partial class Hitbox : BoundingBox
|
||||||
{
|
{
|
||||||
if (area is BoundingBox box)
|
if (area is BoundingBox box)
|
||||||
{
|
{
|
||||||
GD.Print("hit");
|
|
||||||
// we don't want to hurt teammates
|
// we don't want to hurt teammates
|
||||||
if (Faction != box.Faction)
|
if (Faction != box.Faction)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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="Script" path="res://Characters/Doc.cs" id="2_3elet"]
|
||||||
[ext_resource type="Shader" path="res://Shaders/Flash.gdshader" id="2_5jxom"]
|
[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="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/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/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"]
|
[sub_resource type="ShaderMaterial" id="ShaderMaterial_7n7iy"]
|
||||||
resource_local_to_scene = true
|
resource_local_to_scene = true
|
||||||
|
@ -257,10 +259,20 @@ ChooseAttackState = NodePath("../ChooseAttack")
|
||||||
Doc = NodePath("../..")
|
Doc = NodePath("../..")
|
||||||
NPC = 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")
|
script = ExtResource("12_45x13")
|
||||||
DartState = NodePath("../Dart")
|
DartState = NodePath("../Dart")
|
||||||
SpikeState = NodePath("../Spike")
|
SpikeState = NodePath("../Spike")
|
||||||
|
UnwantedFrequencyState = NodePath("../UnwantedFrequency")
|
||||||
ExitState = NodePath("../Exit")
|
ExitState = NodePath("../Exit")
|
||||||
NPC = NodePath("../..")
|
NPC = NodePath("../..")
|
||||||
|
|
||||||
|
|
|
@ -84,6 +84,25 @@ public sealed partial class Player : Character
|
||||||
// TODO: implement visual effects for stun
|
// 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()
|
public override void Die()
|
||||||
{
|
{
|
||||||
GD.Print("died");
|
GD.Print("died");
|
||||||
|
|
|
@ -8,6 +8,9 @@ public partial class Projectile : RigidBody2D
|
||||||
{
|
{
|
||||||
public Vector2 Velocity => Direction * Speed;
|
public Vector2 Velocity => Direction * Speed;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public string ProjectileName { get; set; }
|
||||||
|
|
||||||
[Export]
|
[Export]
|
||||||
public float Speed { get; set; }
|
public float Speed { get; set; }
|
||||||
|
|
||||||
|
@ -25,6 +28,8 @@ public partial class Projectile : RigidBody2D
|
||||||
|
|
||||||
public Character Character { get; set; }
|
public Character Character { get; set; }
|
||||||
|
|
||||||
|
public bool IsDead { get; set; }
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
Hitbox.Hit += OnHit;
|
Hitbox.Hit += OnHit;
|
||||||
|
@ -35,15 +40,26 @@ public partial class Projectile : RigidBody2D
|
||||||
if (Delay > 0)
|
if (Delay > 0)
|
||||||
{
|
{
|
||||||
Delay -= delta;
|
Delay -= delta;
|
||||||
|
if (Delay <= 0)
|
||||||
|
{
|
||||||
|
OnDelayEnd();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ((Lifetime -= delta) <= 0)
|
if ((Lifetime -= delta) <= 0)
|
||||||
{
|
{
|
||||||
QueueFree();
|
if (!IsDead)
|
||||||
|
{
|
||||||
|
Die();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _PhysicsProcess(double delta)
|
public override void _PhysicsProcess(double delta)
|
||||||
{
|
{
|
||||||
|
if (IsDead)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
Vector2 velocity = Delay <= 0 ? Velocity : Vector2.Zero;
|
Vector2 velocity = Delay <= 0 ? Velocity : Vector2.Zero;
|
||||||
MoveAndCollide(velocity * (float)delta);
|
MoveAndCollide(velocity * (float)delta);
|
||||||
}
|
}
|
||||||
|
@ -60,4 +76,14 @@ public partial class Projectile : RigidBody2D
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual void Die()
|
||||||
|
{
|
||||||
|
QueueFree();
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void OnDelayEnd()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -277,8 +277,10 @@ _data = {
|
||||||
|
|
||||||
[node name="ShungiteDart" type="RigidBody2D" node_paths=PackedStringArray("Hitbox")]
|
[node name="ShungiteDart" type="RigidBody2D" node_paths=PackedStringArray("Hitbox")]
|
||||||
script = ExtResource("1_jbgb8")
|
script = ExtResource("1_jbgb8")
|
||||||
|
ProjectileName = "Shungite Dart"
|
||||||
Speed = 256.0
|
Speed = 256.0
|
||||||
Hitbox = NodePath("Hitbox")
|
Hitbox = NodePath("Hitbox")
|
||||||
|
Lifetime = 5.0
|
||||||
Delay = 1.0
|
Delay = 1.0
|
||||||
|
|
||||||
[node name="Sprite2D" type="AnimatedSprite2D" parent="."]
|
[node name="Sprite2D" type="AnimatedSprite2D" parent="."]
|
||||||
|
@ -290,7 +292,7 @@ speed_scale = 4.0
|
||||||
|
|
||||||
[node name="Hitbox" parent="." instance=ExtResource("3_gdyk8")]
|
[node name="Hitbox" parent="." instance=ExtResource("3_gdyk8")]
|
||||||
Damage = 25.0
|
Damage = 25.0
|
||||||
Knockback = 128.0
|
Knockback = 64.0
|
||||||
|
|
||||||
[node name="CollisionShape2D" parent="Hitbox" index="0"]
|
[node name="CollisionShape2D" parent="Hitbox" index="0"]
|
||||||
shape = SubResource("RectangleShape2D_fa7yf")
|
shape = SubResource("RectangleShape2D_fa7yf")
|
||||||
|
|
|
@ -9,9 +9,6 @@ public partial class ShungiteSpike : Projectile
|
||||||
[Export]
|
[Export]
|
||||||
public PackedScene Dart { get; set; }
|
public PackedScene Dart { get; set; }
|
||||||
|
|
||||||
[Export]
|
|
||||||
public double ExplodeTime { get; set; } = 6;
|
|
||||||
|
|
||||||
[Export]
|
[Export]
|
||||||
public BoundingBoxes.Hurtbox Hurtbox { get; set; }
|
public BoundingBoxes.Hurtbox Hurtbox { get; set; }
|
||||||
|
|
||||||
|
@ -21,18 +18,44 @@ public partial class ShungiteSpike : Projectile
|
||||||
[Export]
|
[Export]
|
||||||
public AnimationPlayer AnimationPlayer { get; set; }
|
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 _currentExplodeTime;
|
||||||
|
private double _freezeTime;
|
||||||
|
private double _currentFreezeTime;
|
||||||
|
private bool _hasFrozen = false;
|
||||||
|
private bool _hasExploded = false;
|
||||||
|
|
||||||
private Scenes.Map _map;
|
private Scenes.Map _map;
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
|
_currentFreezeTime = FreezeTime;
|
||||||
_currentExplodeTime = ExplodeTime;
|
_currentExplodeTime = ExplodeTime;
|
||||||
_map = this.GetAncestor<Scenes.Map>();
|
_map = this.GetAncestor<Scenes.Map>();
|
||||||
|
|
||||||
Hurtbox.ReceivedDamage += OnReceivedDamage;
|
Hurtbox.ReceivedDamage += OnReceivedDamage;
|
||||||
AnimationPlayer.Play("spin");
|
AnimationPlayer.Play("spin");
|
||||||
|
|
||||||
|
AnimationPlayer.AnimationFinished += (StringName anim) =>
|
||||||
|
{
|
||||||
|
if (anim == "explode")
|
||||||
|
{
|
||||||
|
QueueFree();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
base._Ready();
|
base._Ready();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,8 +66,21 @@ public partial class ShungiteSpike : Projectile
|
||||||
Vector2 knockbackOrigin = default,
|
Vector2 knockbackOrigin = default,
|
||||||
Vector2 knockbackVector = 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();
|
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)
|
public override void _Process(double delta)
|
||||||
{
|
{
|
||||||
if ((_currentExplodeTime -= delta) <= 0)
|
if ((_currentFreezeTime -= delta) <= 0)
|
||||||
{
|
{
|
||||||
CreateDart(Vector2.Up);
|
if (!_hasFrozen)
|
||||||
CreateDart(Vector2.Down);
|
{
|
||||||
CreateDart(Vector2.Left);
|
Speed = 0;
|
||||||
CreateDart(Vector2.Right);
|
_hasFrozen = true;
|
||||||
QueueFree();
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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="Script" path="res://Entities/ShungiteSpike.cs" id="1_pclpe"]
|
||||||
[ext_resource type="PackedScene" uid="uid://djaljmco3xo4g" path="res://Entities/ShungiteDart.tscn" id="2_hinxt"]
|
[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="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"]
|
[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"]
|
[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"]
|
[sub_resource type="Animation" id="Animation_dlpaa"]
|
||||||
resource_name = "spin"
|
resource_name = "spin"
|
||||||
|
@ -29,46 +109,34 @@ tracks/0/keys = {
|
||||||
"values": [0.0, 6.28319]
|
"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"]
|
[sub_resource type="AnimationLibrary" id="AnimationLibrary_jj1qe"]
|
||||||
_data = {
|
_data = {
|
||||||
"RESET": SubResource("Animation_0vfvo"),
|
"RESET": SubResource("Animation_0vfvo"),
|
||||||
|
"explode": SubResource("Animation_0a85j"),
|
||||||
"spin": SubResource("Animation_dlpaa")
|
"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")
|
script = ExtResource("1_pclpe")
|
||||||
Dart = ExtResource("2_hinxt")
|
Dart = ExtResource("2_hinxt")
|
||||||
Hurtbox = NodePath("Hurtbox")
|
Hurtbox = NodePath("Hurtbox")
|
||||||
HitSound = NodePath("AudioStreamPlayer2D")
|
HitSound = NodePath("AudioStreamPlayer2D")
|
||||||
|
AnimationPlayer = NodePath("AnimationPlayer")
|
||||||
|
ProjectileName = "Shungite Spike"
|
||||||
|
Speed = 96.0
|
||||||
Hitbox = NodePath("Hitbox")
|
Hitbox = NodePath("Hitbox")
|
||||||
|
|
||||||
[node name="Sprite2D" type="Sprite2D" parent="."]
|
[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_filter = 1
|
||||||
texture = ExtResource("2_klp8v")
|
texture = ExtResource("2_klp8v")
|
||||||
|
hframes = 5
|
||||||
|
|
||||||
[node name="Hitbox" parent="." instance=ExtResource("3_kojrj")]
|
[node name="Hitbox" parent="." instance=ExtResource("3_kojrj")]
|
||||||
Damage = 10.0
|
Damage = 14.0
|
||||||
Knockback = 256.0
|
Knockback = 200.0
|
||||||
|
|
||||||
[node name="CollisionShape2D" parent="Hitbox" index="0"]
|
[node name="CollisionShape2D" parent="Hitbox" index="0"]
|
||||||
shape = SubResource("RectangleShape2D_konb7")
|
shape = SubResource("CircleShape2D_hrev2")
|
||||||
|
|
||||||
[node name="Hurtbox" parent="." instance=ExtResource("4_d8dl4")]
|
[node name="Hurtbox" parent="." instance=ExtResource("4_d8dl4")]
|
||||||
|
|
||||||
|
|
|
@ -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<Node2D>("TrailRotation");
|
||||||
|
TrailPosition = TrailRotation.GetNode<Node2D>("TrailPosition");
|
||||||
|
Trail = TrailPosition.GetNode<Utils.Trail>("Trail");
|
||||||
|
DeferDeathTimer = GetNode<Timer>("DeferDeath");
|
||||||
|
DeathParticles = GetNode<GpuParticles2D>("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<AudioStreamPlayer2D>("Sound").Stop();
|
||||||
|
GetNode<AnimationPlayer>("AnimationPlayer").Play("death");
|
||||||
|
}
|
||||||
|
}
|
|
@ -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_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="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="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"]
|
|
@ -377,12 +377,11 @@ environment = SubResource("Environment_72txp")
|
||||||
y_sort_enabled = true
|
y_sort_enabled = true
|
||||||
rotation = -1.5708
|
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)
|
position = Vector2(2.40734, -0.55655)
|
||||||
rotation = 0.945464
|
rotation = 0.945464
|
||||||
width_curve = SubResource("Curve_4cxtp")
|
width_curve = SubResource("Curve_4cxtp")
|
||||||
gradient = SubResource("Gradient_2ablm")
|
gradient = SubResource("Gradient_2ablm")
|
||||||
Tracking = NodePath("../Node2D/Sprite2D")
|
|
||||||
|
|
||||||
[node name="Node2D" type="Node2D" parent="Anchor"]
|
[node name="Node2D" type="Node2D" parent="Anchor"]
|
||||||
y_sort_enabled = true
|
y_sort_enabled = true
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
[ext_resource type="PackedScene" uid="uid://clwv2owvk6abe" path="res://Scenes/BaseMap.tscn" id="1_ifiic"]
|
[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://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="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="Shader" path="res://Shaders/Flash.gdshader" id="5_aevwf"]
|
||||||
|
|
||||||
[sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_8jil2"]
|
[sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_8jil2"]
|
||||||
|
@ -252,7 +252,7 @@ physics_layer_0/collision_layer = 1
|
||||||
sources/2 = SubResource("TileSetAtlasSource_5yxvt")
|
sources/2 = SubResource("TileSetAtlasSource_5yxvt")
|
||||||
sources/0 = SubResource("TileSetAtlasSource_fcd6d")
|
sources/0 = SubResource("TileSetAtlasSource_fcd6d")
|
||||||
|
|
||||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_4g4ap"]
|
[sub_resource type="ShaderMaterial" id="ShaderMaterial_h6m08"]
|
||||||
resource_local_to_scene = true
|
resource_local_to_scene = true
|
||||||
shader = ExtResource("5_aevwf")
|
shader = ExtResource("5_aevwf")
|
||||||
shader_parameter/color = Quaternion(1, 1, 1, 1)
|
shader_parameter/color = Quaternion(1, 1, 1, 1)
|
||||||
|
@ -268,6 +268,6 @@ layer_4/tile_data = PackedInt32Array(-524296, 327680, 0, -589818, 262144, 0, -58
|
||||||
color = Color(0.753984, 0.753984, 0.753984, 1)
|
color = Color(0.753984, 0.753984, 0.753984, 1)
|
||||||
|
|
||||||
[node name="Doc" parent="Entities" index="0" instance=ExtResource("4_c0csw")]
|
[node name="Doc" parent="Entities" index="0" instance=ExtResource("4_c0csw")]
|
||||||
material = SubResource("ShaderMaterial_4g4ap")
|
material = SubResource("ShaderMaterial_h6m08")
|
||||||
PreferredWeightDistance = 256.0
|
PreferredWeightDistance = 256.0
|
||||||
MaxWeightDistance = 32.0
|
MaxWeightDistance = 32.0
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Godot;
|
using Godot;
|
||||||
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace SupaLidlGame.State.NPC.Doc;
|
namespace SupaLidlGame.State.NPC.Doc;
|
||||||
|
@ -11,22 +12,31 @@ public partial class DocChooseAttackState : NPCState
|
||||||
[Export]
|
[Export]
|
||||||
public DocShungiteSpikeState SpikeState { get; set; }
|
public DocShungiteSpikeState SpikeState { get; set; }
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public DocUnwantedFrequencyState UnwantedFrequencyState { get; set; }
|
||||||
|
|
||||||
[Export]
|
[Export]
|
||||||
public DocExitState ExitState { get; set; }
|
public DocExitState ExitState { get; set; }
|
||||||
|
|
||||||
public Characters.Doc Doc => NPC as Characters.Doc;
|
public Characters.Doc Doc => NPC as Characters.Doc;
|
||||||
|
|
||||||
private List<NPCState> _states = new List<NPCState>();
|
private HashSet<NPCState> _possibleStates = new HashSet<NPCState>();
|
||||||
|
|
||||||
private int _consecutiveAttacks = 0;
|
private int _consecutiveAttacks = 0;
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
_states.Add(DartState);
|
ResetStates();
|
||||||
_states.Add(SpikeState);
|
|
||||||
base._Ready();
|
base._Ready();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ResetStates()
|
||||||
|
{
|
||||||
|
//_possibleStates.Add(DartState);
|
||||||
|
//_possibleStates.Add(SpikeState);
|
||||||
|
_possibleStates.Add(UnwantedFrequencyState);
|
||||||
|
}
|
||||||
|
|
||||||
public override NPCState Enter(IState<NPCState> previous)
|
public override NPCState Enter(IState<NPCState> previous)
|
||||||
{
|
{
|
||||||
if (previous is not DocTelegraphState)
|
if (previous is not DocTelegraphState)
|
||||||
|
@ -44,8 +54,16 @@ public partial class DocChooseAttackState : NPCState
|
||||||
return ExitState;
|
return ExitState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_possibleStates.Count == 0)
|
||||||
|
{
|
||||||
|
ResetStates();
|
||||||
|
}
|
||||||
|
|
||||||
// choose random attack
|
// choose random attack
|
||||||
var random = new System.Random();
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,8 +47,6 @@ public partial class DocShungiteDartState : DocAttackState
|
||||||
{
|
{
|
||||||
var projectile = _map.SpawnEntity<Projectile>(Projectile);
|
var projectile = _map.SpawnEntity<Projectile>(Projectile);
|
||||||
projectile.Hitbox.Faction = NPC.Faction;
|
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.GlobalPosition = position;
|
||||||
projectile.Direction = direction;
|
projectile.Direction = direction;
|
||||||
projectile.GlobalRotation = direction.Angle();
|
projectile.GlobalRotation = direction.Angle();
|
||||||
|
@ -60,6 +58,8 @@ public partial class DocShungiteDartState : DocAttackState
|
||||||
{
|
{
|
||||||
var player = _world.CurrentPlayer;
|
var player = _world.CurrentPlayer;
|
||||||
var playerPos = player.GlobalPosition;
|
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 position1 = 2 * NPC.GlobalPosition - playerPos;
|
||||||
Vector2 position2 = 2 * playerPos - NPC.GlobalPosition;
|
Vector2 position2 = 2 * playerPos - NPC.GlobalPosition;
|
||||||
Vector2 direction1 = position1.DirectionTo(playerPos);
|
Vector2 direction1 = position1.DirectionTo(playerPos);
|
||||||
|
|
|
@ -5,12 +5,12 @@ namespace SupaLidlGame.State.NPC.Doc;
|
||||||
|
|
||||||
public partial class DocShungiteSpikeState : DocShungiteDartState
|
public partial class DocShungiteSpikeState : DocShungiteDartState
|
||||||
{
|
{
|
||||||
private float _intensity = 1;
|
protected int _currentAttacks = 0;
|
||||||
|
|
||||||
public override NPCState Enter(IState<NPCState> previous)
|
public override NPCState Enter(IState<NPCState> previous)
|
||||||
{
|
{
|
||||||
// subtract from total state time by intensity
|
_currentAttacks = 0;
|
||||||
Duration = _currentDuration = 9 - 2 * Doc.Intensity;
|
_currentAttackDuration = 1;
|
||||||
return base.Enter(previous);
|
return base.Enter(previous);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,6 @@ public partial class DocShungiteSpikeState : DocShungiteDartState
|
||||||
as ShungiteSpike;
|
as ShungiteSpike;
|
||||||
projectile.GlobalRotation = 0;
|
projectile.GlobalRotation = 0;
|
||||||
projectile.Delay = 0;
|
projectile.Delay = 0;
|
||||||
projectile.ExplodeTime = 6 - 2 * Doc.Intensity;
|
|
||||||
projectile.Hitbox.Faction = projectile.Hurtbox.Faction = Doc.Faction;
|
projectile.Hitbox.Faction = projectile.Hurtbox.Faction = Doc.Faction;
|
||||||
return projectile;
|
return projectile;
|
||||||
}
|
}
|
||||||
|
@ -31,31 +30,37 @@ public partial class DocShungiteSpikeState : DocShungiteDartState
|
||||||
{
|
{
|
||||||
var player = _world.CurrentPlayer;
|
var player = _world.CurrentPlayer;
|
||||||
var playerPos = player.GlobalPosition;
|
var playerPos = player.GlobalPosition;
|
||||||
Vector2 left = playerPos + Vector2.Left * 64;
|
var docPos = NPC.GlobalPosition;
|
||||||
Vector2 right = playerPos + Vector2.Right * 64;
|
var projectile = SpawnProjectile(docPos, Vector2.Zero) as ShungiteSpike;
|
||||||
Vector2 up = playerPos + Vector2.Up * 64;
|
var projectileSpeed = projectile.Speed = 96;
|
||||||
Vector2 down = playerPos + Vector2.Down * 64;
|
|
||||||
SpawnProjectile(left, Vector2.Zero);
|
|
||||||
SpawnProjectile(right, Vector2.Zero);
|
|
||||||
SpawnProjectile(up, Vector2.Zero);
|
|
||||||
SpawnProjectile(down, Vector2.Zero);
|
|
||||||
|
|
||||||
// only attack once and stop (but keep in this state for 8 seconds)
|
// predict to player's position
|
||||||
_currentAttackDuration += 8;
|
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)
|
public override NPCState Process(double delta)
|
||||||
{
|
{
|
||||||
if ((_currentDuration -= delta) <= 0)
|
|
||||||
{
|
|
||||||
return ChooseAttackState;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((_currentAttackDuration -= delta) <= 0)
|
if ((_currentAttackDuration -= delta) <= 0)
|
||||||
{
|
{
|
||||||
Attack();
|
Attack();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_currentAttacks >= Doc.Intensity)
|
||||||
|
{
|
||||||
|
return ChooseAttackState;
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<UnwantedFrequency>(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++;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace SupaLidlGame.Utils;
|
||||||
|
|
||||||
|
public static class Physics
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the predicted position of a target after a time t at which a
|
||||||
|
/// projectile is predicted to hit a target.
|
||||||
|
/// </summary>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,17 +1,48 @@
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
|
namespace SupaLidlGame.Utils;
|
||||||
|
|
||||||
public partial class Trail : Line2D
|
public partial class Trail : Line2D
|
||||||
{
|
{
|
||||||
[Export]
|
[Export]
|
||||||
public int MaximumPoints { get; set; }
|
public int MaximumPoints { get; set; }
|
||||||
|
|
||||||
[Export]
|
[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)
|
public override void _Process(double delta)
|
||||||
{
|
{
|
||||||
Vector2 point = Tracking.Position;
|
if (IsDead && Points.Length > 0)
|
||||||
AddPoint(point);
|
{
|
||||||
|
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)
|
while (Points.Length > MaximumPoints)
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,5 +4,6 @@
|
||||||
|
|
||||||
[node name="Trail" type="Line2D"]
|
[node name="Trail" type="Line2D"]
|
||||||
show_behind_parent = true
|
show_behind_parent = true
|
||||||
|
top_level = true
|
||||||
script = ExtResource("1_t42kk")
|
script = ExtResource("1_t42kk")
|
||||||
MaximumPoints = 16
|
MaximumPoints = 16
|
||||||
|
|
Loading…
Reference in New Issue