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)
|
||||
{
|
||||
GD.Print("hit");
|
||||
// we don't want to hurt teammates
|
||||
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="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("../..")
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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<Scenes.Map>();
|
||||
|
||||
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 ((_currentFreezeTime -= delta) <= 0)
|
||||
{
|
||||
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);
|
||||
QueueFree();
|
||||
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="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")]
|
||||
|
||||
|
|
|
@ -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
|
||||
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
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
[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"]
|
||||
|
||||
[sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_8jil2"]
|
||||
|
@ -252,7 +252,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_h6m08"]
|
||||
resource_local_to_scene = true
|
||||
shader = ExtResource("5_aevwf")
|
||||
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)
|
||||
|
||||
[node name="Doc" parent="Entities" index="0" instance=ExtResource("4_c0csw")]
|
||||
material = SubResource("ShaderMaterial_4g4ap")
|
||||
material = SubResource("ShaderMaterial_h6m08")
|
||||
PreferredWeightDistance = 256.0
|
||||
MaxWeightDistance = 32.0
|
||||
|
|
|
@ -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<NPCState> _states = new List<NPCState>();
|
||||
private HashSet<NPCState> _possibleStates = new HashSet<NPCState>();
|
||||
|
||||
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<NPCState> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,8 +47,6 @@ public partial class DocShungiteDartState : DocAttackState
|
|||
{
|
||||
var projectile = _map.SpawnEntity<Projectile>(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);
|
||||
|
|
|
@ -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<NPCState> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -4,5 +4,6 @@
|
|||
|
||||
[node name="Trail" type="Line2D"]
|
||||
show_behind_parent = true
|
||||
top_level = true
|
||||
script = ExtResource("1_t42kk")
|
||||
MaximumPoints = 16
|
||||
|
|
Loading…
Reference in New Issue