187 lines
7.2 KiB
C#
187 lines
7.2 KiB
C#
using Chickensoft.AutoInject;
|
|
using Chickensoft.Introspection;
|
|
using Godot;
|
|
|
|
namespace Zennysoft.Game.Ma;
|
|
[Meta(typeof(IAutoNode))]
|
|
public partial class EnemyModelView2D : Node3D, IEnemyModelView
|
|
{
|
|
protected const string PRIMARY_ATTACK = "primary_attack";
|
|
protected const string PRIMARY_ATTACK_LEFT = "primary_attack_left";
|
|
protected const string PRIMARY_ATTACK_RIGHT = "primary_attack_right";
|
|
protected const string PRIMARY_ATTACK_BACK = "primary_attack_back";
|
|
protected const string SECONDARY_ATTACK = "secondary_attack";
|
|
protected const string SECONDARY_ATTACK_LEFT = "secondary_attack_left";
|
|
protected const string SECONDARY_ATTACK_RIGHT = "secondary_attack_right";
|
|
protected const string SECONDARY_ATTACK_BACK = "secondary_attack_back";
|
|
protected const string PRIMARY_SKILL = "primary_skill";
|
|
protected const string IDLE_FORWARD = "idle_front";
|
|
protected const string IDLE_LEFT = "idle_left";
|
|
protected const string IDLE_RIGHT = "idle_right";
|
|
protected const string IDLE_BACK = "idle_back";
|
|
protected const string IDLE_FORWARD_WALK = "idle_front_walk";
|
|
protected const string IDLE_LEFT_WALK = "idle_left_walk";
|
|
protected const string IDLE_RIGHT_WALK = "idle_right_walk";
|
|
protected const string IDLE_BACK_WALK = "idle_back_walk";
|
|
protected const string PARAMETERS_PLAYBACK = "parameters/playback";
|
|
|
|
public override void _Notification(int what) => this.Notify(what);
|
|
|
|
[Export] public EnemyLoreInfo EnemyLoreInfo { get; set; } = default!;
|
|
|
|
[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!;
|
|
|
|
protected DirectionType _currentDirection = DirectionType.FORWARD;
|
|
|
|
public void SetCurrentDirection(Basis enemyBasis, Vector3 cameraDirection) => _currentDirection = GetEnemyDirection(enemyBasis, cameraDirection, 0.55f, 0.45f);
|
|
|
|
public void PlayPrimaryAttackAnimation()
|
|
{
|
|
switch (_currentDirection)
|
|
{
|
|
case DirectionType.FORWARD:
|
|
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(PRIMARY_ATTACK);
|
|
break;
|
|
case DirectionType.RIGHT:
|
|
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(PRIMARY_ATTACK_RIGHT);
|
|
break;
|
|
case DirectionType.LEFT:
|
|
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(PRIMARY_ATTACK_LEFT);
|
|
break;
|
|
case DirectionType.BACKWARD:
|
|
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(PRIMARY_ATTACK_BACK);
|
|
break;
|
|
}
|
|
}
|
|
|
|
public void PlaySecondaryAttackAnimation()
|
|
{
|
|
switch (_currentDirection)
|
|
{
|
|
case DirectionType.FORWARD:
|
|
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(SECONDARY_ATTACK);
|
|
break;
|
|
case DirectionType.RIGHT:
|
|
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(SECONDARY_ATTACK_RIGHT);
|
|
break;
|
|
case DirectionType.LEFT:
|
|
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(SECONDARY_ATTACK_LEFT);
|
|
break;
|
|
case DirectionType.BACKWARD:
|
|
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(SECONDARY_ATTACK_BACK);
|
|
break;
|
|
}
|
|
}
|
|
|
|
public void PlayPrimarySkillAnimation()
|
|
{
|
|
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(PRIMARY_SKILL);
|
|
}
|
|
|
|
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 virtual void PlayIdleAnimation()
|
|
{
|
|
switch (_currentDirection)
|
|
{
|
|
case DirectionType.FORWARD:
|
|
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(IDLE_FORWARD);
|
|
break;
|
|
case DirectionType.RIGHT:
|
|
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(IDLE_RIGHT);
|
|
break;
|
|
case DirectionType.LEFT:
|
|
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(IDLE_LEFT);
|
|
break;
|
|
case DirectionType.BACKWARD:
|
|
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(IDLE_BACK);
|
|
break;
|
|
}
|
|
}
|
|
|
|
public virtual void PlayWalkAnimation()
|
|
{
|
|
switch (_currentDirection)
|
|
{
|
|
case DirectionType.FORWARD:
|
|
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(IDLE_FORWARD_WALK);
|
|
break;
|
|
case DirectionType.RIGHT:
|
|
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(IDLE_RIGHT_WALK);
|
|
break;
|
|
case DirectionType.LEFT:
|
|
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(IDLE_LEFT_WALK);
|
|
break;
|
|
case DirectionType.BACKWARD:
|
|
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(IDLE_BACK_WALK);
|
|
break;
|
|
}
|
|
}
|
|
|
|
private DirectionType GetEnemyDirection(
|
|
Basis enemyBasis,
|
|
Vector3 cameraDirection,
|
|
float rotateUpperThreshold,
|
|
float rotateLowerThreshold)
|
|
{
|
|
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)
|
|
return DirectionType.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)
|
|
return DirectionType.BACKWARD;
|
|
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).
|
|
if (leftDotProduct > 0)
|
|
return DirectionType.RIGHT;
|
|
|
|
// 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)
|
|
return DirectionType.LEFT;
|
|
}
|
|
|
|
return _currentDirection;
|
|
}
|
|
|
|
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 SetShaderValue(float shaderValue)
|
|
{
|
|
var shaderMaterial = (ShaderMaterial)AnimatedSprite.Material;
|
|
shaderMaterial.SetShaderParameter("progress", shaderValue);
|
|
}
|
|
}
|