Hit shader

This commit is contained in:
2024-09-15 17:12:18 -07:00
parent 470b853916
commit 4a1fdd94f8
19 changed files with 528 additions and 257 deletions

View File

@@ -1,44 +1,4 @@
[gd_resource type="ShaderMaterial" load_steps=2 format=3 uid="uid://pq2fqq4ophsy"]
[sub_resource type="Shader" id="Shader_xtf8b"]
resource_local_to_scene = true
code = "shader_type spatial;
render_mode unshaded, cull_disabled, depth_draw_always, depth_test_disabled;
uniform vec3 color = vec3(0.0, 1.0, 0.0);
uniform float line_width : hint_range(0.0, 10.0) = 0.85;
varying vec3 barycentric;
void vertex() {
vec3 b_coords[3] = vec3[](vec3(1, 0, 0), vec3(0, 1, 0), vec3(0, 0, 1));
int vertex_id = int(VERTEX_ID) % 3;
barycentric = b_coords[vertex_id];
}
void fragment() {
// Calculate the screen-space derivatives of the barycentric coordinates
vec3 dFdx_barycentric = dFdx(barycentric);
vec3 dFdy_barycentric = dFdy(barycentric);
// Calculate the minimum barycentric coordinate value
float min_bary = min(min(barycentric.x, barycentric.y), barycentric.z);
// Calculate the screen-space line width
float screen_line_width = line_width * length(vec2(dFdx_barycentric.x, dFdy_barycentric.x));
// Draw the line based on the calculated screen-space line width
if (min_bary < screen_line_width) {
ALBEDO = color;
} else {
discard;
}
}
"
[gd_resource type="ShaderMaterial" format=3 uid="uid://pq2fqq4ophsy"]
[resource]
resource_local_to_scene = true
render_priority = 0
shader = SubResource("Shader_xtf8b")
shader_parameter/color = Vector3(0, 1, 0)
shader_parameter/line_width = 0.85

View File

@@ -34,6 +34,8 @@ public partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLogic>
[Dependency] IGameRepo GameRepo => this.DependOn<IGameRepo>();
[Dependency] IGameEventDepot GameEventDepot => this.DependOn<IGameEventDepot>();
[Export]
public EnemyStatResource EnemyStatResource { get; set; } = default!;
@@ -51,10 +53,12 @@ public partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLogic>
[Node] public Timer AttackTimer { get; set; } = default!;
[Node] public AnimatedSprite3D AnimatedSprite { get; set; } = default!;
[Node] public AnimatedSprite2D AnimatedSprite { get; set; } = default!;
[Node] public RayCast3D Raycast { get; set; } = default!;
[Node] public AnimationPlayer AnimationPlayer { get; set; } = default!;
private const string IDLE_FORWARD = "idle_front_walk";
private const string IDLE_LEFT = "idle_left_walk";
private const string IDLE_BACK = "idle_back_walk";
@@ -67,17 +71,93 @@ public partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLogic>
EnemyLogic.Set(EnemyStatResource);
EnemyLogic.Set(this as IEnemy);
EnemyLogic.Set(GameRepo);
AnimationPlayer.AnimationFinished += AnimationPlayer_AnimationFinished;
}
public void OnReady()
{
SetPhysicsProcess(true);
CollisionDetector = CollisionDetectorScene.Instantiate<Area3D>();
CollisionDetector.AreaEntered += OnPlayerHitboxEntered;
AddChild(CollisionDetector);
}
public void OnResolved()
{
EnemyBinding = EnemyLogic.Bind();
EnemyBinding
.Handle((in EnemyLogic.Output.MovementComputed output) =>
{
MoveAndSlide();
})
.Handle((in EnemyLogic.Output.HitByPlayer output) =>
{
if (CurrentHP.Value > 0)
AnimationPlayer.Play("hit");
// TODO: Make this an event to notify game that player hit someone
if (GameRepo.PlayerData.Inventory.EquippedWeapon.Value.WeaponStats.WeaponTags.Contains(WeaponTag.SelfDamage))
GameRepo.PlayerData.SetCurrentHP(GameRepo.PlayerData.CurrentHP.Value - 5);
})
.Handle((in EnemyLogic.Output.Defeated output) =>
{
AnimationPlayer.Play("defeated");
});
this.Provide();
EnemyLogic.Start();
CurrentHP = new AutoProp<double>(EnemyStatResource.MaximumHP);
CurrentHP.Sync += OnHPChanged;
LineOfSight.BodyEntered += LineOfSight_BodyEntered;
PatrolTimer.Timeout += OnPatrolTimeout;
AttackTimer.Timeout += OnAttackTimeout;
var rng = new RandomNumberGenerator();
rng.Randomize();
PatrolTimer.WaitTime = rng.RandfRange(7.0f, 15.0f);
}
public void OnExitTree()
{
EnemyLogic.Stop();
EnemyBinding.Dispose();
}
private void OnPatrolTimeout()
{
var rng = new RandomNumberGenerator();
rng.Randomize();
var randomizedSpot = new Vector3(rng.RandfRange(-3.0f, 3.0f), 0, rng.RandfRange(-3.0f, 3.0f));
var randomizedSpot = new Vector3(rng.RandfRange(-7.0f, 7.0f), 0, rng.RandfRange(-7.0f, 7.0f));
EnemyLogic.Input(new EnemyLogic.Input.PatrolToRandomSpot(GlobalPosition + randomizedSpot));
PatrolTimer.WaitTime = rng.RandfRange(7.0f, 15.0f);
}
public void OnPhysicsProcess(double delta)
{
EnemyLogic.Input(new EnemyLogic.Input.PhysicsTick(delta));
RotateEnemy(-GameRepo.PlayerGlobalTransform.Value.Basis.Z);
}
public void OnPlayerHitboxEntered(Area3D body)
{
if (body is IHitbox hitBox)
{
if (CurrentHP.Value > 0)
{
var isCriticalHit = false;
var rng = new RandomNumberGenerator();
rng.Randomize();
var roll = rng.Randf();
if (roll <= GameRepo.PlayerData.Inventory.EquippedWeapon.Value.WeaponStats.Luck)
isCriticalHit = true;
var damage = DamageCalculator.CalculatePlayerDamage(GameRepo.PlayerData.CurrentAttack.Value + GameRepo.PlayerData.BonusAttack, EnemyStatResource, GameRepo.PlayerData.Inventory.EquippedWeapon.Value.WeaponStats, isCriticalHit);
GD.Print($"Enemy Hit for {damage} damage.");
EnemyLogic.Input(new EnemyLogic.Input.HitByPlayer(damage));
}
}
}
private void OnAttackTimeout()
{
if (GlobalPosition.DistanceTo(GameRepo.PlayerGlobalPosition.Value) > 2.5f)
@@ -92,54 +172,20 @@ public partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLogic>
private void LineOfSight_BodyEntered(Node3D body)
{
var overlappingBodies = LineOfSight.GetOverlappingBodies();
//foreach (var overlap in overlappingBodies)
//{
// Raycast.LookAt(GameRepo.PlayerGlobalPosition.Value, Vector3.Up);
// Raycast.ForceRaycastUpdate();
// if (Raycast.IsColliding())
// {
// var collider = Raycast.GetCollider();
// if (collider is IPlayer player)
// {
// Raycast.DebugShapeCustomColor = Color.FromString("Purple", Colors.Purple);
// EnemyLogic.Input(new EnemyLogic.Input.Alerted());
// }
// }
//}
}
public void OnResolved()
{
EnemyBinding = EnemyLogic.Bind();
EnemyBinding
.Handle((in EnemyLogic.Output.MovementComputed output) =>
foreach (var overlap in overlappingBodies)
{
Raycast.LookAt(GameRepo.PlayerGlobalPosition.Value, Vector3.Up);
Raycast.ForceRaycastUpdate();
if (Raycast.IsColliding())
{
MoveAndSlide();
})
.Handle((in EnemyLogic.Output.Die output) =>
{
QueueFree();
})
.Handle((in EnemyLogic.Output.HitByPlayer output) =>
{
// TODO: Make this an event to notify game that player hit someone
if (GameRepo.PlayerData.Inventory.EquippedWeapon.Value.WeaponStats.WeaponTags.Contains(WeaponTag.SelfDamage))
GameRepo.PlayerData.SetCurrentHP(GameRepo.PlayerData.CurrentHP.Value - 5);
});
this.Provide();
EnemyLogic.Start();
CurrentHP = new AutoProp<double>(EnemyStatResource.MaximumHP);
CurrentHP.Sync += OnHPChanged;
LineOfSight.BodyEntered += LineOfSight_BodyEntered;
PatrolTimer.Timeout += OnPatrolTimeout;
AttackTimer.Timeout += OnAttackTimeout;
var rng = new RandomNumberGenerator();
rng.Randomize();
PatrolTimer.WaitTime = rng.RandfRange(7.0f, 15.0f);
var collider = Raycast.GetCollider();
if (collider is IPlayer player)
{
Raycast.DebugShapeCustomColor = Color.FromString("Purple", Colors.Purple);
EnemyLogic.Input(new EnemyLogic.Input.Alerted());
}
}
}
}
private void RotateEnemy(Vector3 cameraDirection)
@@ -169,58 +215,18 @@ public partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLogic>
}
}
public void OnPhysicsProcess(double delta)
{
EnemyLogic.Input(new EnemyLogic.Input.PhysicsTick(delta));
RotateEnemy(-GameRepo.PlayerGlobalTransform.Value.Basis.Z);
}
public void OnPlayerHitboxEntered(Area3D body)
{
if (body is IHitbox hitBox)
{
if (CurrentHP.Value > 0)
{
var isCriticalHit = false;
var rng = new RandomNumberGenerator();
rng.Randomize();
var roll = rng.Randf();
if (roll <= GameRepo.PlayerData.Inventory.EquippedWeapon.Value.WeaponStats.Luck)
isCriticalHit = true;
var damage = DamageCalculator.CalculatePlayerDamage(GameRepo.PlayerData.CurrentAttack.Value + GameRepo.PlayerData.BonusAttack, EnemyStatResource, GameRepo.PlayerData.Inventory.EquippedWeapon.Value.WeaponStats, isCriticalHit);
GD.Print($"Enemy Hit for {damage} damage.");
EnemyLogic.Input(new EnemyLogic.Input.HitByPlayer(damage));
}
}
}
private void OnHPChanged(double newHP)
{
if (newHP <= 0)
{
EnemyLogic.Input(new EnemyLogic.Input.Killed());
EnemyLogic.Input(new EnemyLogic.Input.EnemyDefeated());
GameEventDepot.OnEnemyDefeated(EnemyStatResource);
}
}
public void OnReady()
private void AnimationPlayer_AnimationFinished(StringName animName)
{
SetPhysicsProcess(true);
CollisionDetector = CollisionDetectorScene.Instantiate<Area3D>();
CollisionDetector.AreaEntered += OnPlayerHitboxEntered;
AddChild(CollisionDetector);
}
public void OnExitTree()
{
EnemyLogic.Stop();
EnemyBinding.Dispose();
if (animName == "defeated")
QueueFree();
}
}
public enum WeaponTag
{
SelfDamage,
IgnoreAffinity,
Knockback,
BreaksOnChange
}

9
src/enemy/WeaponTag.cs Normal file
View File

@@ -0,0 +1,9 @@
namespace GameJamDungeon;
public enum WeaponTag
{
SelfDamage,
IgnoreAffinity,
Knockback,
BreaksOnChange
}

View File

@@ -1,10 +1,13 @@
[gd_scene load_steps=81 format=3 uid="uid://dcgj5i52i76gj"]
[gd_scene load_steps=87 format=3 uid="uid://dcgj5i52i76gj"]
[ext_resource type="Script" path="res://src/enemy/Enemy.cs" id="1_a6wro"]
[ext_resource type="Script" path="res://src/enemy/EnemyStatResource.cs" id="2_x4pjh"]
[ext_resource type="Script" path="res://src/hitbox/Hitbox.cs" id="3_aiftp"]
[ext_resource type="Shader" path="res://src/vfx/shaders/DamageHit.gdshader" id="3_ekj3e"]
[ext_resource type="Material" uid="uid://c0gpeve05njqq" path="res://src/vfx/shaders/DamageHit.tres" id="4_01npl"]
[ext_resource type="Texture2D" uid="uid://clpqh2pyqljkn" path="res://src/enemy/enemy_types/michael/animations/IDLE_WALK/BACK/Michael_Walk_Idle_Back (1).png" id="4_7kurm"]
[ext_resource type="Texture2D" uid="uid://b0dec8ak2bo5t" path="res://src/enemy/enemy_types/michael/animations/IDLE_WALK/BACK/Michael_Walk_Idle_Back (2).png" id="5_1a1hr"]
[ext_resource type="Shader" path="res://src/vfx/shaders/PixelMelt.gdshader" id="5_lw20o"]
[ext_resource type="Texture2D" uid="uid://tnmyksd68vmv" path="res://src/enemy/enemy_types/michael/animations/IDLE_WALK/BACK/Michael_Walk_Idle_Back (3).png" id="6_p47tl"]
[ext_resource type="Texture2D" uid="uid://duwipvc2kl6xa" path="res://src/enemy/enemy_types/michael/animations/IDLE_WALK/BACK/Michael_Walk_Idle_Back (4).png" id="7_efmib"]
[ext_resource type="Texture2D" uid="uid://dcd4v7jjxr8x2" path="res://src/enemy/enemy_types/michael/animations/IDLE_WALK/BACK/Michael_Walk_Idle_Back (5).png" id="8_ujyav"]
@@ -111,6 +114,42 @@ tracks/0/keys = {
"update": 1,
"values": [true]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("Sprite3D/SubViewport/AnimatedSprite:material")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [null]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("Sprite3D/SubViewport/AnimatedSprite:material:shader")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [ExtResource("3_ekj3e")]
}
tracks/3/type = "value"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath("Sprite3D/SubViewport/AnimatedSprite:material:shader_parameter/progress")
tracks/3/interp = 1
tracks/3/loop_wrap = true
tracks/3/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [-1.0]
}
[sub_resource type="Animation" id="Animation_ce86e"]
resource_name = "attack"
@@ -128,16 +167,102 @@ tracks/0/keys = {
"values": [true, false, true]
}
[sub_resource type="Animation" id="Animation_8p0l1"]
resource_name = "defeated"
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Sprite3D/SubViewport/AnimatedSprite:material")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [ExtResource("4_01npl")]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("Sprite3D/SubViewport/AnimatedSprite:material:shader")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [ExtResource("5_lw20o")]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("Sprite3D/SubViewport/AnimatedSprite:material:shader_parameter/progress")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0, 1),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [0.0, 1.0]
}
[sub_resource type="Animation" id="Animation_swr3w"]
resource_name = "hit"
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Sprite3D/SubViewport/AnimatedSprite:material")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 1),
"transitions": PackedFloat32Array(1, 1),
"update": 1,
"values": [ExtResource("4_01npl"), ExtResource("4_01npl")]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("Sprite3D/SubViewport/AnimatedSprite:material:shader")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0, 1),
"transitions": PackedFloat32Array(1, 1),
"update": 1,
"values": [ExtResource("3_ekj3e"), null]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("Sprite3D/SubViewport/AnimatedSprite:material:shader_parameter/progress")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0, 1),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [0.0, 1.0]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_346xs"]
_data = {
"RESET": SubResource("Animation_kr7ax"),
"attack": SubResource("Animation_ce86e")
"attack": SubResource("Animation_ce86e"),
"defeated": SubResource("Animation_8p0l1"),
"hit": SubResource("Animation_swr3w")
}
[sub_resource type="BoxShape3D" id="BoxShape3D_0yire"]
size = Vector3(1, 0.564941, 1.14453)
[sub_resource type="SpriteFrames" id="SpriteFrames_x7baa"]
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_cwfph"]
height = 1.0
[sub_resource type="ViewportTexture" id="ViewportTexture_57rcc"]
viewport_path = NodePath("Sprite3D/SubViewport")
[sub_resource type="SpriteFrames" id="SpriteFrames_8xwq0"]
animations = [{
"frames": [{
"duration": 1.0,
@@ -362,9 +487,6 @@ animations = [{
"speed": 12.0
}]
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_cwfph"]
height = 1.0
[node name="Michael" type="CharacterBody3D"]
process_mode = 1
collision_layer = 10
@@ -413,18 +535,9 @@ disabled = true
[node name="Raycast" type="RayCast3D" parent="."]
unique_name_in_owner = true
transform = Transform3D(-1, 0, -8.74228e-08, 0, 1, 0, 8.74228e-08, 0, -1, 0, 0, 0)
visible = false
target_position = Vector3(0, 0, -3)
collision_mask = 3
[node name="AnimatedSprite" type="AnimatedSprite3D" parent="."]
unique_name_in_owner = true
billboard = 2
double_sided = false
texture_filter = 0
sprite_frames = SubResource("SpriteFrames_x7baa")
animation = &"idle_back_walk"
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
transform = Transform3D(-1, 0, -8.74228e-08, 0, 1, 0, 8.74228e-08, 0, -1, 0, 0, 0)
shape = SubResource("CapsuleShape3D_cwfph")
@@ -434,3 +547,17 @@ unique_name_in_owner = true
avoidance_enabled = true
debug_enabled = true
debug_path_custom_color = Color(1, 0, 0, 1)
[node name="Sprite3D" type="Sprite3D" parent="."]
billboard = 2
texture = SubResource("ViewportTexture_57rcc")
[node name="SubViewport" type="SubViewport" parent="Sprite3D"]
transparent_bg = true
size = Vector2i(95, 95)
[node name="AnimatedSprite" type="AnimatedSprite2D" parent="Sprite3D/SubViewport"]
unique_name_in_owner = true
position = Vector2(45, 45)
sprite_frames = SubResource("SpriteFrames_8xwq0")
animation = &"idle_front_walk"

View File

@@ -1,6 +1,4 @@
using GameJamDungeon;
using Godot;
using System;
public partial class RotationTest : CharacterBody3D
{

View File

@@ -1,18 +1,9 @@
[gd_scene load_steps=67 format=3 uid="uid://bksq62muhk3h5"]
[gd_scene load_steps=63 format=3 uid="uid://bksq62muhk3h5"]
[ext_resource type="Script" path="res://src/enemy/Enemy.cs" id="1_7tinp"]
[ext_resource type="Script" path="res://src/enemy/EnemyStatResource.cs" id="2_j3knd"]
[ext_resource type="Script" path="res://src/hitbox/Hitbox.cs" id="3_usw2d"]
[ext_resource type="Texture2D" uid="uid://dd0ia6isdqg61" path="res://src/enemy/enemy_types/sproingy/animations/ATTACK/Layer 1.png" id="4_f5aht"]
[ext_resource type="Texture2D" uid="uid://bs4ico5ouo5d3" path="res://src/enemy/enemy_types/sproingy/animations/ATTACK/Layer 2.png" id="5_cla00"]
[ext_resource type="Texture2D" uid="uid://85ki5mc4h0vs" path="res://src/enemy/enemy_types/sproingy/animations/ATTACK/Layer 3.png" id="6_d23kt"]
[ext_resource type="Texture2D" uid="uid://bwt1m2frb3r0e" path="res://src/enemy/enemy_types/sproingy/animations/ATTACK/Layer 4.png" id="7_1s02c"]
[ext_resource type="Texture2D" uid="uid://ckssl1np6vnlu" path="res://src/enemy/enemy_types/sproingy/animations/ATTACK/Layer 5.png" id="8_nxv3t"]
[ext_resource type="Texture2D" uid="uid://c4sqc6i3xcfac" path="res://src/enemy/enemy_types/sproingy/animations/ATTACK/Layer 6.png" id="9_l4m8n"]
[ext_resource type="Texture2D" uid="uid://cawexe4wkosc8" path="res://src/enemy/enemy_types/sproingy/animations/ATTACK/Layer 7.png" id="10_l11ks"]
[ext_resource type="Texture2D" uid="uid://d0j1vrx7xdnxl" path="res://src/enemy/enemy_types/sproingy/animations/ATTACK/Layer 8.png" id="11_1h5et"]
[ext_resource type="Texture2D" uid="uid://d0qhndaukki7c" path="res://src/enemy/enemy_types/sproingy/animations/ATTACK/Layer 9.png" id="12_iu7dx"]
[ext_resource type="Texture2D" uid="uid://cnd08q34wa7ww" path="res://src/enemy/enemy_types/sproingy/animations/ATTACK/Layer 10.png" id="13_vbxxn"]
[ext_resource type="Material" uid="uid://c0gpeve05njqq" path="res://src/vfx/shaders/DamageHit.tres" id="4_0urvb"]
[ext_resource type="Texture2D" uid="uid://b8ntr7hh6rr5h" path="res://src/enemy/enemy_types/sproingy/animations/IDLE_WALK_BACK/Layer 1.png" id="14_xn75i"]
[ext_resource type="Texture2D" uid="uid://csgthlou2tnvb" path="res://src/enemy/enemy_types/sproingy/animations/IDLE_WALK_BACK/Layer 2.png" id="15_rgyxs"]
[ext_resource type="Texture2D" uid="uid://cfyxuk85350gn" path="res://src/enemy/enemy_types/sproingy/animations/IDLE_WALK_BACK/Layer 3.png" id="16_nr3ob"]
@@ -49,8 +40,10 @@
[ext_resource type="Texture2D" uid="uid://dlbt7lj5ryl0v" path="res://src/enemy/enemy_types/sproingy/animations/IDLE_WALK_SIDE/Layer 4.png" id="47_1j2ir"]
[ext_resource type="Texture2D" uid="uid://bkhn4ck7bx6tt" path="res://src/enemy/enemy_types/sproingy/animations/IDLE_WALK_SIDE/Layer 5.png" id="48_864dg"]
[ext_resource type="Texture2D" uid="uid://c8uw6qdsi1720" path="res://src/enemy/enemy_types/sproingy/animations/IDLE_WALK_SIDE/Layer 6.png" id="49_2r4d5"]
[ext_resource type="Shader" path="res://src/vfx/shaders/DamageHit.gdshader" id="49_mrxyf"]
[ext_resource type="Texture2D" uid="uid://cnoouhy7p3gi3" path="res://src/enemy/enemy_types/sproingy/animations/IDLE_WALK_SIDE/Layer 7.png" id="50_m33xn"]
[ext_resource type="Texture2D" uid="uid://b1xldymngql00" path="res://src/enemy/enemy_types/sproingy/animations/IDLE_WALK_SIDE/Layer 8.png" id="51_68cc3"]
[ext_resource type="Shader" path="res://src/vfx/shaders/PixelMelt.gdshader" id="51_y2own"]
[ext_resource type="Texture2D" uid="uid://btuxhmmb6ikvf" path="res://src/enemy/enemy_types/sproingy/animations/IDLE_WALK_SIDE/Layer 9.png" id="52_2xmc3"]
[ext_resource type="Texture2D" uid="uid://dlrn3cbdubg5s" path="res://src/enemy/enemy_types/sproingy/animations/IDLE_WALK_SIDE/Layer 10.png" id="53_bgv07"]
[ext_resource type="Texture2D" uid="uid://oukshrxpgscg" path="res://src/enemy/enemy_types/sproingy/animations/IDLE_WALK_SIDE/Layer 11.png" id="54_7gaxo"]
@@ -86,85 +79,16 @@ height = 1.0
height = 3.0
radius = 1.0
[sub_resource type="Animation" id="Animation_kr7ax"]
length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Hitbox/CollisionShape3D:disabled")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [true]
}
[sub_resource type="Animation" id="Animation_ce86e"]
resource_name = "attack"
length = 0.7
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Hitbox/CollisionShape3D:disabled")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.3, 0.5),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 1,
"values": [true, false, true]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_346xs"]
_data = {
"RESET": SubResource("Animation_kr7ax"),
"attack": SubResource("Animation_ce86e")
}
[sub_resource type="BoxShape3D" id="BoxShape3D_0yire"]
size = Vector3(1, 0.564941, 1.14453)
[sub_resource type="SpriteFrames" id="SpriteFrames_x7baa"]
[sub_resource type="ViewportTexture" id="ViewportTexture_moptw"]
viewport_path = NodePath("Sprite3D/SubViewport")
[sub_resource type="SpriteFrames" id="SpriteFrames_mi16l"]
animations = [{
"frames": [{
"duration": 1.0,
"texture": ExtResource("4_f5aht")
}, {
"duration": 1.0,
"texture": ExtResource("5_cla00")
}, {
"duration": 1.0,
"texture": ExtResource("6_d23kt")
}, {
"duration": 1.0,
"texture": ExtResource("7_1s02c")
}, {
"duration": 1.0,
"texture": ExtResource("8_nxv3t")
}, {
"duration": 1.0,
"texture": ExtResource("9_l4m8n")
}, {
"duration": 1.0,
"texture": ExtResource("10_l11ks")
}, {
"duration": 1.0,
"texture": ExtResource("11_1h5et")
}, {
"duration": 1.0,
"texture": ExtResource("12_iu7dx")
}, {
"duration": 1.0,
"texture": ExtResource("13_vbxxn")
}],
"loop": true,
"name": &"attack",
"speed": 12.0
}, {
"frames": [{
"duration": 1.0,
"texture": ExtResource("14_xn75i")
}, {
"duration": 1.0,
@@ -314,6 +238,159 @@ animations = [{
"speed": 12.0
}]
[sub_resource type="Animation" id="Animation_kr7ax"]
length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Hitbox/CollisionShape3D:disabled")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [true]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("Sprite3D/SubViewport/AnimatedSprite:material")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [null]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("Sprite3D/SubViewport/AnimatedSprite:material:shader")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [ExtResource("49_mrxyf")]
}
tracks/3/type = "value"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath("Sprite3D/SubViewport/AnimatedSprite:material:shader_parameter/progress")
tracks/3/interp = 1
tracks/3/loop_wrap = true
tracks/3/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [-1.0]
}
[sub_resource type="Animation" id="Animation_ce86e"]
resource_name = "attack"
length = 0.7
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Hitbox/CollisionShape3D:disabled")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.3, 0.5),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 1,
"values": [true, false, true]
}
[sub_resource type="Animation" id="Animation_8p0l1"]
resource_name = "defeated"
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Sprite3D/SubViewport/AnimatedSprite:material")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [ExtResource("4_0urvb")]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("Sprite3D/SubViewport/AnimatedSprite:material:shader")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [ExtResource("51_y2own")]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("Sprite3D/SubViewport/AnimatedSprite:material:shader_parameter/progress")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0, 1),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [0.0, 1.0]
}
[sub_resource type="Animation" id="Animation_swr3w"]
resource_name = "hit"
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Sprite3D/SubViewport/AnimatedSprite:material")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 1),
"transitions": PackedFloat32Array(1, 1),
"update": 1,
"values": [ExtResource("4_0urvb"), ExtResource("4_0urvb")]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("Sprite3D/SubViewport/AnimatedSprite:material:shader")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0, 1),
"transitions": PackedFloat32Array(1, 1),
"update": 1,
"values": [ExtResource("49_mrxyf"), null]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("Sprite3D/SubViewport/AnimatedSprite:material:shader_parameter/progress")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0, 1),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [0.0, 1.0]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_346xs"]
_data = {
"RESET": SubResource("Animation_kr7ax"),
"attack": SubResource("Animation_ce86e"),
"defeated": SubResource("Animation_8p0l1"),
"hit": SubResource("Animation_swr3w")
}
[node name="Sproingy" type="CharacterBody3D"]
process_mode = 1
collision_layer = 10
@@ -352,12 +429,6 @@ unique_name_in_owner = true
wait_time = 1.8
autostart = true
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
unique_name_in_owner = true
libraries = {
"": SubResource("AnimationLibrary_346xs")
}
[node name="Hitbox" type="Area3D" parent="."]
transform = Transform3D(-1, 0, -8.74228e-08, 0, 1, 0, 8.74228e-08, 0, -1, 0, 0, 0)
collision_layer = 64
@@ -376,9 +447,25 @@ visible = false
target_position = Vector3(0, 0, -3)
collision_mask = 3
[node name="AnimatedSprite" type="AnimatedSprite3D" parent="."]
unique_name_in_owner = true
[node name="Sprite3D" type="Sprite3D" parent="."]
transform = Transform3D(1.5, 0, 0, 0, 1.5, 0, 0, 0, 1.5, 0, 0, 0)
flip_v = true
billboard = 2
texture_filter = 0
sprite_frames = SubResource("SpriteFrames_x7baa")
animation = &"attack"
texture = SubResource("ViewportTexture_moptw")
[node name="SubViewport" type="SubViewport" parent="Sprite3D"]
transparent_bg = true
size = Vector2i(95, 95)
[node name="AnimatedSprite" type="AnimatedSprite2D" parent="Sprite3D/SubViewport"]
unique_name_in_owner = true
position = Vector2(45, 45)
sprite_frames = SubResource("SpriteFrames_mi16l")
animation = &"idle_left_walk"
flip_v = true
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
unique_name_in_owner = true
libraries = {
"": SubResource("AnimationLibrary_346xs")
}

View File

@@ -15,7 +15,7 @@ namespace GameJamDungeon
public readonly record struct HitByPlayer(double Damage);
public readonly record struct Killed();
public readonly record struct EnemyDefeated();
public readonly record struct PatrolToRandomSpot(Vector3 PatrolTarget);

View File

@@ -12,7 +12,7 @@ namespace GameJamDungeon
public readonly record struct HitByPlayer(double CurrentHP);
public readonly record struct Die();
public readonly record struct Defeated();
}
}
}

View File

@@ -7,6 +7,7 @@ state "EnemyLogic State" as GameJamDungeon_EnemyLogic_State {
}
}
GameJamDungeon_EnemyLogic_State_Alive --> GameJamDungeon_EnemyLogic_State_Alive : EnemyDefeated
GameJamDungeon_EnemyLogic_State_Alive --> GameJamDungeon_EnemyLogic_State_Alive : HitByPlayer
GameJamDungeon_EnemyLogic_State_Alive --> GameJamDungeon_EnemyLogic_State_Attack : AttackTimer
GameJamDungeon_EnemyLogic_State_Attack --> GameJamDungeon_EnemyLogic_State_FollowPlayer : Alerted
@@ -16,6 +17,7 @@ GameJamDungeon_EnemyLogic_State_Idle --> GameJamDungeon_EnemyLogic_State_FollowP
GameJamDungeon_EnemyLogic_State_Idle --> GameJamDungeon_EnemyLogic_State_Idle : PatrolToRandomSpot
GameJamDungeon_EnemyLogic_State_Idle --> GameJamDungeon_EnemyLogic_State_Idle : PhysicsTick
GameJamDungeon_EnemyLogic_State_Alive : OnEnemyDefeated → Defeated
GameJamDungeon_EnemyLogic_State_Alive : OnHitByPlayer → HitByPlayer
GameJamDungeon_EnemyLogic_State_Idle : OnPhysicsTick → MovementComputed

View File

@@ -8,7 +8,7 @@ namespace GameJamDungeon
public partial record State
{
[Meta, Id("enemy_logic_state_alive")]
public abstract partial record Alive : State, IGet<Input.HitByPlayer>, IGet<Input.AttackTimer>
public abstract partial record Alive : State, IGet<Input.HitByPlayer>, IGet<Input.AttackTimer>, IGet<Input.EnemyDefeated>
{
public Transition On(in Input.HitByPlayer input)
{
@@ -26,6 +26,12 @@ namespace GameJamDungeon
{
return To<Attack>();
}
public Transition On(in Input.EnemyDefeated input)
{
Output(new Output.Defeated());
return ToSelf();
}
}
}
}

View File

@@ -1,4 +1,4 @@
[gd_resource type="Resource" script_class="WeaponInfo" load_steps=3 format=3 uid="uid://c1bg0o7nmu2xw"]
[gd_resource type="Resource" script_class="WeaponStats" load_steps=3 format=3 uid="uid://c1bg0o7nmu2xw"]
[ext_resource type="Texture2D" uid="uid://cil3xe3jq82r6" path="res://src/items/weapons/textures/JIBLETT.PNG" id="1_ifm43"]
[ext_resource type="Script" path="res://src/items/weapons/WeaponStats.cs" id="1_re512"]

View File

@@ -1,4 +1,4 @@
[gd_resource type="Resource" script_class="WeaponInfo" load_steps=3 format=3 uid="uid://bpdbuf0k0exb5"]
[gd_resource type="Resource" script_class="WeaponStats" load_steps=3 format=3 uid="uid://bpdbuf0k0exb5"]
[ext_resource type="Script" path="res://src/items/weapons/WeaponStats.cs" id="1_cik6n"]
[ext_resource type="Texture2D" uid="uid://cvtcsi2sagfwm" path="res://src/items/weapons/textures/SWAN SWORD.PNG" id="1_qc4eu"]
@@ -20,4 +20,4 @@ Ignores Affinity.
The blade of a thousand faced heroine."
Texture = ExtResource("1_qc4eu")
SpawnRate = 0.5
SpawnRate = 0.01

View File

@@ -1,8 +1,9 @@
[gd_scene load_steps=5 format=3 uid="uid://by67pn7fdsg1m"]
[gd_scene load_steps=6 format=3 uid="uid://by67pn7fdsg1m"]
[ext_resource type="PackedScene" uid="uid://dvnc26rebk6o0" path="res://src/map/overworld/Overworld.tscn" id="1_ope1x"]
[ext_resource type="PackedScene" uid="uid://bc1sp6xwe0j65" path="res://src/map/dungeon/floors/Floor1.tscn" id="2_merfv"]
[ext_resource type="PackedScene" uid="uid://dcgj5i52i76gj" path="res://src/enemy/enemy_types/michael/Michael.tscn" id="4_d4sw2"]
[ext_resource type="PackedScene" uid="uid://bksq62muhk3h5" path="res://src/enemy/enemy_types/sproingy/Sproingy.tscn" id="5_cvt4a"]
[ext_resource type="PackedScene" uid="uid://bjqgl5u05ia04" path="res://src/map/dungeon/Teleport.tscn" id="5_jiohg"]
[node name="Map" type="Node3D"]
@@ -27,3 +28,6 @@ disable_mode = 2
[node name="Michael" parent="." instance=ExtResource("4_d4sw2")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4.75859, 2.28929, -4.31558)
[node name="Sproingy" parent="." instance=ExtResource("5_cvt4a")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.56057, 0)

View File

@@ -1,8 +1,6 @@
using Chickensoft.AutoInject;
using Chickensoft.Collections;
using Chickensoft.GodotNodeInterfaces;
using Chickensoft.Introspection;
using Chickensoft.LogicBlocks;
using Chickensoft.SaveFileBuilder;
using Godot;

View File

@@ -285,4 +285,3 @@ position = Vector2(900, 565)
scale = Vector2(1.8, 1.8)
sprite_frames = SubResource("SpriteFrames_ywvvo")
animation = &"attack"
frame = 6

View File

@@ -0,0 +1,29 @@
shader_type canvas_item;
/**
Color to use for the shock.
*/
uniform vec3 shock_color : source_color = vec3(1.0, 0.0, 0.0);
/**
Initial amplitude of the shock. This will start at this amplitude and
gradually attenuate.
*/
uniform float amplitude = 30.0;
uniform float progress: hint_range(0.0, 1.0) = -1.0;
/**
How fast shold it move side to side, more frequency means it'll move more quickly
side to side.
*/
uniform float frequecy = 10.0;
void vertex() {
float exponent = mod(progress, 3.0);
VERTEX.x += amplitude * exp(-3.0*exponent) * sin(frequecy*exponent);
}
void fragment() {
float exponent = mod(progress, 3.0);
vec3 normal_color = texture(TEXTURE, UV).rgb;
COLOR.rgb = normal_color + shock_color * exp(-3.0*exponent);
}

View File

@@ -0,0 +1,8 @@
[gd_resource type="ShaderMaterial" load_steps=2 format=3 uid="uid://c0gpeve05njqq"]
[ext_resource type="Shader" path="res://src/vfx/shaders/PixelMelt.gdshader" id="1_uy7cv"]
[resource]
shader = ExtResource("1_uy7cv")
shader_parameter/progress = 0.0
shader_parameter/meltiness = 1.0

View File

@@ -0,0 +1,28 @@
shader_type canvas_item;
// Animate from 0 to 1
uniform float progress: hint_range(0.0, 1.0) = 0.0;
// How jagged each band of melting pixels are
uniform float meltiness: hint_range(0.0, 16.0) = 1.0;
float psuedo_rand(float x) {
return mod(x * 2048103.0 + cos(x * 1912.0), 1.0);
}
void fragment() {
vec2 uv = UV;
// Move pixels near the top faster
uv.y -= progress / UV.y;
// Created jagged edges for each pixel on the x-axis
uv.y -= progress * meltiness * psuedo_rand(UV.x - mod(UV.x, TEXTURE_PIXEL_SIZE.x));
COLOR = texture(TEXTURE, uv);
// "delete" pixels out of range
if (uv.y <= 0.0) {
COLOR.a = 0.0;
}
}

View File

@@ -0,0 +1,10 @@
[gd_resource type="ShaderMaterial" load_steps=2 format=3 uid="uid://yvt4d1xnftll"]
[ext_resource type="Shader" path="res://src/vfx/shaders/DamageHit.gdshader" id="1_a8e00"]
[resource]
shader = ExtResource("1_a8e00")
shader_parameter/shock_color = Color(1, 0, 0, 1)
shader_parameter/amplitude = 30.0
shader_parameter/progress = 0.0
shader_parameter/frequecy = 10.0