171 lines
5.1 KiB
C#
171 lines
5.1 KiB
C#
using Chickensoft.AutoInject;
|
|
using Chickensoft.Introspection;
|
|
using Godot;
|
|
using System.Linq;
|
|
|
|
namespace Zennysoft.Game.Ma;
|
|
[Meta(typeof(IAutoNode))]
|
|
public partial class EnemyModelView2D : EnemyModelView, IEnemyModelView
|
|
{
|
|
private readonly string _idleName = "Idle";
|
|
private readonly string _walkingName = "Walking";
|
|
private readonly string _primaryAttackName = "Primary Attack";
|
|
private readonly string _secondaryAttackName = "Secondary Attack";
|
|
private readonly string _activateName = "Activate";
|
|
|
|
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 Area3D Hitbox { get; set; } = default!;
|
|
|
|
[Node] public AnimationPlayer AnimationPlayer { get; set; } = default!;
|
|
|
|
[Node] public AnimationTree AnimationTree { get; set; } = default!;
|
|
|
|
[ExportGroup("Enemy Model Properties")]
|
|
[Export(PropertyHint.Range, "0.0, 1.0")]
|
|
private float _upperThreshold { get; set; } = 0.5f;
|
|
[Export(PropertyHint.Range, "-1.0, 0.0")]
|
|
private float _lowerThreshold { get; set; } = -0.5f;
|
|
|
|
EnemyDirection _enemyDirection { get; set; } = EnemyDirection.Forward;
|
|
|
|
private AnimationNodeStateMachinePlayback _stateMachine;
|
|
|
|
public void OnReady()
|
|
{
|
|
_stateMachine = (AnimationNodeStateMachinePlayback)AnimationTree.Get("parameters/playback");
|
|
Hitbox.BodyEntered += Hitbox_BodyEntered;
|
|
}
|
|
|
|
private void Hitbox_BodyEntered(Node3D body) => EmitSignal(SignalName.HitPlayer);
|
|
|
|
public void SetCurrentDirection(Basis enemyBasis, Vector3 cameraDirection) => _enemyDirection = GetEnemyDirection(enemyBasis, cameraDirection, _upperThreshold, _lowerThreshold);
|
|
|
|
public void PlayPrimaryAttackAnimation() => _stateMachine.Travel(_primaryAttackName);
|
|
|
|
public void PlaySecondaryAttackAnimation() => _stateMachine.Travel(_secondaryAttackName);
|
|
|
|
public void PlayPrimarySkillAnimation() => _stateMachine.Travel("Primary Skill");
|
|
|
|
public void PlayIdleAnimation() => _stateMachine.Travel(_idleName);
|
|
|
|
public void PlayWalkAnimation() => _stateMachine.Travel(_walkingName);
|
|
|
|
public void PlayActivateAnimation()
|
|
{
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
private EnemyDirection 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 < _lowerThreshold)
|
|
{
|
|
SetForward();
|
|
return EnemyDirection.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)
|
|
{
|
|
SetBack();
|
|
return EnemyDirection.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 < _lowerThreshold)
|
|
{
|
|
SetRight();
|
|
return EnemyDirection.Left;
|
|
}
|
|
|
|
// 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 (leftDotProduct > rotateUpperThreshold)
|
|
{
|
|
SetLeft();
|
|
return EnemyDirection.Right;
|
|
}
|
|
}
|
|
|
|
return _enemyDirection;
|
|
}
|
|
|
|
private void LoadShader(string shaderPath)
|
|
{
|
|
var shader = GD.Load<Shader>(shaderPath);
|
|
var sprites = FindChildren("*", "AnimatedSprite2D", true).Cast<AnimatedSprite2D>();
|
|
foreach (var sprite in sprites)
|
|
{
|
|
sprite.Material = new ShaderMaterial();
|
|
var shaderMaterial = (ShaderMaterial)sprite.Material;
|
|
shaderMaterial.Shader = shader;
|
|
}
|
|
}
|
|
|
|
private void SetShaderValue(float shaderValue)
|
|
{
|
|
var sprites = FindChildren("*", "AnimatedSprite2D", true).Cast<AnimatedSprite2D>();
|
|
foreach (var sprite in sprites)
|
|
{
|
|
var shaderMaterial = (ShaderMaterial)sprite.Material;
|
|
shaderMaterial.SetShaderParameter("progress", shaderValue);
|
|
}
|
|
}
|
|
|
|
private void SetForward()
|
|
{
|
|
_enemyDirection = EnemyDirection.Forward;
|
|
}
|
|
|
|
private void SetLeft()
|
|
{
|
|
_enemyDirection = EnemyDirection.Left;
|
|
}
|
|
|
|
private void SetRight()
|
|
{
|
|
_enemyDirection = EnemyDirection.Right;
|
|
}
|
|
|
|
private void SetBack()
|
|
{
|
|
_enemyDirection = EnemyDirection.Backward;
|
|
}
|
|
|
|
private enum EnemyDirection
|
|
{
|
|
Left,
|
|
Right,
|
|
Forward,
|
|
Backward
|
|
}
|
|
}
|