Change all enemy types to CharacterBody3D
This commit is contained in:
@@ -30,6 +30,9 @@ public partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLogic>
|
||||
|
||||
#region Exports
|
||||
[Export] protected EnemyStatResource _enemyStatResource { get; set; } = default!;
|
||||
|
||||
[Export]
|
||||
private float _movementSpeed = 2f;
|
||||
#endregion
|
||||
|
||||
#region Node Dependencies
|
||||
@@ -60,6 +63,7 @@ public partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLogic>
|
||||
|
||||
private Timer _thinkTimer;
|
||||
|
||||
#region Godot methods
|
||||
public void Setup()
|
||||
{
|
||||
_enemyLogic = new EnemyLogic();
|
||||
@@ -81,93 +85,6 @@ public partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLogic>
|
||||
_thinkTimer.Start();
|
||||
}
|
||||
|
||||
private void NavAgent_TargetReached()
|
||||
{
|
||||
NavAgent.TargetPosition = _currentTarget;
|
||||
}
|
||||
|
||||
private void NavAgent_VelocityComputed(Vector3 safeVelocity)
|
||||
{
|
||||
if (CurrentHP <= 0)
|
||||
return;
|
||||
|
||||
_knockbackStrength = _knockbackStrength * 0.9f;
|
||||
Velocity = safeVelocity + (_knockbackDirection * _knockbackStrength);
|
||||
MoveAndSlide();
|
||||
}
|
||||
|
||||
public void SetTarget(Vector3 target)
|
||||
{
|
||||
Task.Delay(TimeSpan.FromSeconds(1.5)).ContinueWith(_ => _currentTarget = new Vector3(target.X, -1.75f, target.Z));
|
||||
}
|
||||
|
||||
public void TakeDamage(double damage, ElementType elementType, bool isCriticalHit = false, bool ignoreDefense = false, bool ignoreElementalResistance = false)
|
||||
{
|
||||
if (_currentHP.Value > 0)
|
||||
{
|
||||
if (!ignoreElementalResistance)
|
||||
damage = CalculateElementalResistance(damage, elementType);
|
||||
if (!ignoreDefense)
|
||||
damage = CalculateDefenseResistance(damage);
|
||||
if (isCriticalHit)
|
||||
damage *= 2;
|
||||
GD.Print($"Enemy Hit for {damage} damage.");
|
||||
_currentHP.OnNext(_currentHP.Value - damage);
|
||||
GD.Print("Current HP: " + _currentHP.Value);
|
||||
|
||||
if (_currentHP.Value <= 0)
|
||||
return;
|
||||
|
||||
EnemyModelView.PlayHitAnimation();
|
||||
_enemyLogic.Input(new EnemyLogic.Input.Alerted());
|
||||
NavAgent_TargetReached();
|
||||
|
||||
if (Player.EquippedWeapon.Value.WeaponTags.Contains(WeaponTag.SelfDamage))
|
||||
Player.Stats.SetCurrentHP(Player.Stats.CurrentHP.Value - 5);
|
||||
}
|
||||
}
|
||||
|
||||
public override void _PhysicsProcess(double delta)
|
||||
{
|
||||
if (CurrentHP <= 0)
|
||||
return;
|
||||
|
||||
if (_enemyLogic.Value is EnemyLogic.State.Attacking)
|
||||
SetTarget(GlobalPosition);
|
||||
|
||||
var nextPathPosition = NavAgent.GetNextPathPosition();
|
||||
|
||||
var newVelocity = GlobalPosition.DirectionTo(nextPathPosition) * 2f;
|
||||
if (NavAgent.AvoidanceEnabled)
|
||||
NavAgent.Velocity = newVelocity;
|
||||
else
|
||||
NavAgent_VelocityComputed(newVelocity);
|
||||
|
||||
var lookDir = GlobalPosition + Velocity;
|
||||
if (_enemyLogic.Value is not EnemyLogic.State.Attacking && (!lookDir.IsEqualApprox(GlobalPosition) || !Velocity.IsZeroApprox()))
|
||||
LookAt(lookDir, Vector3.Up, true);
|
||||
|
||||
var isWalking = _enemyLogic.Value is EnemyLogic.State.Patrolling or EnemyLogic.State.FollowPlayer;
|
||||
EnemyModelView.RotateModel(GlobalTransform.Basis, -Player.CurrentBasis.Z, isWalking);
|
||||
}
|
||||
|
||||
public void Knockback(float impulse, Vector3 direction)
|
||||
{
|
||||
_knockbackDirection = direction;
|
||||
_knockbackStrength = 0.3f;
|
||||
}
|
||||
|
||||
public void Die()
|
||||
{
|
||||
_enemyLogic.Input(new EnemyLogic.Input.EnemyDefeated());
|
||||
CollisionShape.SetDeferred("disabled", true);
|
||||
EnemyModelView.PlayDeathAnimation();
|
||||
var tweener = GetTree().CreateTween();
|
||||
tweener.TweenInterval(1.0f);
|
||||
tweener.TweenCallback(Callable.From(QueueFree));
|
||||
GameEventDepot.OnEnemyDefeated(GlobalPosition, _enemyStatResource);
|
||||
}
|
||||
|
||||
public void OnResolved()
|
||||
{
|
||||
EnemyBinding = _enemyLogic.Bind();
|
||||
@@ -194,10 +111,77 @@ public partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLogic>
|
||||
PatrolTimer.WaitTime = rng.RandfRange(7.0f, 15.0f);
|
||||
}
|
||||
|
||||
public void OnExitTree()
|
||||
public override void _PhysicsProcess(double delta)
|
||||
{
|
||||
_enemyLogic.Stop();
|
||||
EnemyBinding.Dispose();
|
||||
CalculateVelocity();
|
||||
}
|
||||
#endregion
|
||||
|
||||
public virtual void TakeAction()
|
||||
{
|
||||
}
|
||||
|
||||
public void SetTarget(Vector3 target)
|
||||
{
|
||||
Task.Delay(TimeSpan.FromSeconds(1.5)).ContinueWith(_ => _currentTarget = new Vector3(target.X, -1.75f, target.Z));
|
||||
}
|
||||
|
||||
public virtual void TakeDamage(double damage, ElementType elementType, bool isCriticalHit = false, bool ignoreDefense = false, bool ignoreElementalResistance = false)
|
||||
{
|
||||
if (_currentHP.Value > 0)
|
||||
{
|
||||
if (!ignoreElementalResistance)
|
||||
damage = CalculateElementalResistance(damage, elementType);
|
||||
if (!ignoreDefense)
|
||||
damage = CalculateDefenseResistance(damage);
|
||||
if (isCriticalHit)
|
||||
damage *= 2;
|
||||
GD.Print($"Enemy Hit for {damage} damage.");
|
||||
_currentHP.OnNext(_currentHP.Value - damage);
|
||||
GD.Print("Current HP: " + _currentHP.Value);
|
||||
|
||||
if (_currentHP.Value <= 0)
|
||||
return;
|
||||
|
||||
EnemyModelView.PlayHitAnimation();
|
||||
_enemyLogic.Input(new EnemyLogic.Input.Alerted());
|
||||
NavAgent_TargetReached();
|
||||
|
||||
if (Player.EquippedWeapon.Value.WeaponTags.Contains(WeaponTag.SelfDamage))
|
||||
Player.Stats.SetCurrentHP(Player.Stats.CurrentHP.Value - 5);
|
||||
}
|
||||
}
|
||||
|
||||
public void Knockback(float impulse, Vector3 direction)
|
||||
{
|
||||
_knockbackDirection = direction;
|
||||
_knockbackStrength = 0.3f;
|
||||
}
|
||||
|
||||
public void Die()
|
||||
{
|
||||
_enemyLogic.Input(new EnemyLogic.Input.EnemyDefeated());
|
||||
CollisionShape.SetDeferred("disabled", true);
|
||||
EnemyModelView.PlayDeathAnimation();
|
||||
var tweener = GetTree().CreateTween();
|
||||
tweener.TweenInterval(1.0f);
|
||||
tweener.TweenCallback(Callable.From(QueueFree));
|
||||
GameEventDepot.OnEnemyDefeated(GlobalPosition, _enemyStatResource);
|
||||
}
|
||||
|
||||
private void NavAgent_TargetReached()
|
||||
{
|
||||
NavAgent.TargetPosition = _currentTarget;
|
||||
}
|
||||
|
||||
private void NavAgent_VelocityComputed(Vector3 safeVelocity)
|
||||
{
|
||||
if (CurrentHP <= 0)
|
||||
return;
|
||||
|
||||
_knockbackStrength = _knockbackStrength * 0.9f;
|
||||
Velocity = safeVelocity + (_knockbackDirection * _knockbackStrength);
|
||||
MoveAndSlide();
|
||||
}
|
||||
|
||||
private void OnPatrolTimeout()
|
||||
@@ -221,6 +205,30 @@ public partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLogic>
|
||||
|
||||
}
|
||||
|
||||
private void CalculateVelocity()
|
||||
{
|
||||
if (CurrentHP <= 0)
|
||||
return;
|
||||
|
||||
if (_enemyLogic.Value is EnemyLogic.State.Attacking)
|
||||
SetTarget(GlobalPosition);
|
||||
|
||||
var nextPathPosition = NavAgent.GetNextPathPosition();
|
||||
|
||||
var newVelocity = GlobalPosition.DirectionTo(nextPathPosition) * 2f;
|
||||
if (NavAgent.AvoidanceEnabled)
|
||||
NavAgent.Velocity = newVelocity;
|
||||
else
|
||||
NavAgent_VelocityComputed(newVelocity);
|
||||
|
||||
var lookDir = GlobalPosition + Velocity;
|
||||
if (_enemyLogic.Value is not EnemyLogic.State.Attacking && (!lookDir.IsEqualApprox(GlobalPosition) || !Velocity.IsZeroApprox()))
|
||||
LookAt(lookDir, Vector3.Up, true);
|
||||
|
||||
var isWalking = _enemyLogic.Value is EnemyLogic.State.Patrolling or EnemyLogic.State.FollowPlayer;
|
||||
EnemyModelView.RotateModel(GlobalTransform.Basis, -Player.CurrentBasis.Z, isWalking);
|
||||
}
|
||||
|
||||
private void OnAttackTimeout()
|
||||
{
|
||||
if (GlobalPosition.DistanceTo(Player.CurrentPosition) > 5f)
|
||||
@@ -284,7 +292,9 @@ public partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLogic>
|
||||
return Mathf.Max(incomingDamage - _enemyStatResource.CurrentDefense, 0.0);
|
||||
}
|
||||
|
||||
public virtual void TakeAction()
|
||||
public void OnExitTree()
|
||||
{
|
||||
_enemyLogic.Stop();
|
||||
EnemyBinding.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user