Refactor enemy view model for data viewer project

This commit is contained in:
2024-12-05 22:45:13 -08:00
parent 270ded8ef7
commit 8068f33302
10 changed files with 1270 additions and 1207 deletions

108
src/enemy/EnemyModelView.cs Normal file
View File

@@ -0,0 +1,108 @@
using Chickensoft.AutoInject;
using Chickensoft.GodotNodeInterfaces;
using Chickensoft.Introspection;
using GameJamDungeon;
using Godot;
public interface IEnemyModelView : INode3D
{
public void PlayAttackAnimation();
public void PlayHitAnimation();
public void PlayDeathAnimation();
public void RotateModel(Basis enemyBasis, Vector3 cameraDirection);
}
[Meta(typeof(IAutoNode))]
public partial class EnemyModelView : Node3D, IEnemyModelView
{
private const string ATTACK = "attack";
private const string IDLE_FORWARD = "idle_front_walk";
private const string IDLE_LEFT = "idle_left_walk";
private const string IDLE_BACK = "idle_back_walk";
private const string PARAMETERS_PLAYBACK = "parameters/playback";
public override void _Notification(int what) => this.Notify(what);
[Node] public AnimatedSprite2D AnimatedSprite { get; set; } = default!;
[Node] public IHitbox Hitbox { get; set; } = default!;
[Node] public AnimationPlayer AnimationPlayer { get; set; } = default!;
[Node] public AnimationTree AnimationTree { get; set; } = default!;
public void Setup()
{
AnimationTree.AnimationFinished += AnimationTree_AnimationFinished;
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Start(IDLE_FORWARD);
}
public void PlayAttackAnimation()
{
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(ATTACK);
}
public void PlayHitAnimation()
{
LoadShader("res://src/vfx/shaders/DamageHit.gdshader");
var tweener = GetTree().CreateTween();
tweener.TweenMethod(Callable.From((float x) => SetShaderValue(x)), 0.0f, 1.0f, 1.0f);
}
public void PlayDeathAnimation()
{
LoadShader("res://src/vfx/shaders/PixelMelt.gdshader");
var tweener = GetTree().CreateTween();
tweener.TweenMethod(Callable.From((float x) => SetShaderValue(x)), 0.0f, 1.0f, 0.8f);
tweener.TweenCallback(Callable.From(QueueFree));
}
public void RotateModel(Basis enemyBasis, Vector3 cameraDirection)
{
var rotateUpperThreshold = 0.85f;
var rotateLowerThreshold = 0.3f;
var enemyForwardDirection = enemyBasis.Z;
var enemyLeftDirection = enemyBasis.X;
var leftDotProduct = enemyLeftDirection.Dot(cameraDirection);
var forwardDotProduct = enemyForwardDirection.Dot(cameraDirection);
// Check if forward facing. If the dot product is -1, the enemy is facing the camera.
if (forwardDotProduct < -rotateUpperThreshold)
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(IDLE_FORWARD);
// Check if backward facing. If the dot product is 1, the enemy is facing the same direction as the camera.
else if (forwardDotProduct > rotateUpperThreshold)
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(IDLE_BACK);
else
{
// If the dot product of the perpendicular direction is positive (up to 1), the enemy is facing to the left (since it's mirrored).
AnimatedSprite.FlipH = leftDotProduct > 0;
// Check if side facing. If the dot product is close to zero in the positive or negative direction, its close to the threshold for turning.
if (Mathf.Abs(forwardDotProduct) < rotateLowerThreshold)
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(IDLE_LEFT);
}
}
private void LoadShader(string shaderPath)
{
var shader = GD.Load<Shader>(shaderPath);
AnimatedSprite.Material = new ShaderMaterial();
var shaderMaterial = (ShaderMaterial)AnimatedSprite.Material;
shaderMaterial.Shader = shader;
}
private void AnimationTree_AnimationFinished(StringName animName)
{
if (animName == "attack")
AnimationTree.Get("parameters/playback").As<AnimationNodeStateMachinePlayback>().Travel(IDLE_FORWARD);
}
private void SetShaderValue(float shaderValue)
{
var shaderMaterial = (ShaderMaterial)AnimatedSprite.Material;
shaderMaterial.SetShaderParameter("progress", shaderValue);
}
}