Bad tank movement

This commit is contained in:
Marco 2025-02-18 17:40:33 +01:00
commit 90d2a95fa8
10 changed files with 514 additions and 8 deletions

View file

@ -1,5 +1,6 @@
using System.Collections.Generic;
using Cirno.Scripts;
using Cirno.Scripts.Components.Actors;
using Godot;
public partial class Actor : CharacterBody2D
@ -7,12 +8,15 @@ public partial class Actor : CharacterBody2D
[Export]
public float MovementSpeed { get; private set; }
public Vector2 MovementDirection { get; set; }
public Vector2 FacingDirection { get; set; }
private GameManager _gameManager;
private List<MovementHandler> _movementHandlers = new();
private List<AnimationHandler> _animationHandlers = new();
public override void _Ready()
{
@ -23,6 +27,12 @@ public partial class Actor : CharacterBody2D
if (child is MovementHandler movementHandler)
{
_movementHandlers.Add(movementHandler);
movementHandler.Init(this);
}
else if (child is AnimationHandler animationHandler)
{
_animationHandlers.Add(animationHandler);
animationHandler.Init(this);
}
}
}
@ -33,6 +43,11 @@ public partial class Actor : CharacterBody2D
{
handler.Move(delta);
}
foreach (var handler in _animationHandlers)
{
handler.Update(delta);
}
}
}

View file

@ -1,23 +1,37 @@
using System.Collections.Generic;
using System.Linq;
using Cirno.Scripts.Components.Actors;
using Godot;
public partial class ActorFreeMovement : MovementHandler
{
public override Vector2 FacingDirection
{
get => _parent.FacingDirection;
set => _parent.FacingDirection = value;
}
private Actor _parent;
public override Vector2 MovementDirection
{
get => _parent.MovementDirection;
set => _parent.MovementDirection = value;
}
public override void Init(Actor parent)
{
_parent = parent;
base.Init(parent);
MovementDirection = Vector2.Zero;
_parent.FacingDirection = Vector2.Down;
FacingDirection = Vector2.Down;
}
public override void Move(double delta)
{
MovementDirection = AggregateInputProviders();
_parent.Velocity = MovementDirection * _parent.MovementSpeed;
_parent.MoveAndSlide();
}
}

View file

@ -0,0 +1,112 @@
using Godot;
namespace Cirno.Scripts.Components.Actors;
public partial class ActorTankMovement : MovementHandler
{
public override Vector2 FacingDirection
{
get => _parent.FacingDirection;
set => _parent.FacingDirection = value;
}
public override Vector2 MovementDirection
{
get => _parent.MovementDirection;
set => _parent.MovementDirection = value;
}
[Export] public float TurnSpeed = 4.0f; // Speed of turning
[Export] public float Acceleration = 30f;
[Export] public float Deceleration = 50f;
private float _currentTurnProgress = 0;
private Vector2 _targetFacingDirection = Vector2.Up;
private float _currentSpeed = 0;
private AnimatedSprite2D _animatedSprite;
public override void Init(Actor parent)
{
base.Init(parent);
MovementDirection = Vector2.Zero;
FacingDirection = Vector2.Down;
}
public override void Move(double delta)
{
var inputDirection = AggregateInputProviders();
// Handle Turning
HandleTurning(_parent, inputDirection, delta);
// Handle Movement (forward/backward)
HandleMovement(_parent, inputDirection, delta);
// Set Animation
//UpdateAnimation(actor);
}
private void HandleTurning(Actor actor, Vector2 input, double delta)
{
// Only rotate if there is input and not currently turning
if (input.Length() > 0.1f && _currentTurnProgress <= 0)
{
// Snap to the closest 8-direction vector
_targetFacingDirection = GetSnappedDirection(input);
_currentTurnProgress = 1.0f; // Start turn animation
}
// Simulate turning delay
if (_currentTurnProgress > 0)
{
_currentTurnProgress -= (float)(TurnSpeed * delta);
if (_currentTurnProgress <= 0)
{
actor.FacingDirection = _targetFacingDirection;
}
}
}
private Vector2 GetSnappedDirection(Vector2 input)
{
// Get angle and snap to 45-degree increments
float angle = input.Angle();
float snappedAngle = Mathf.Round(angle / (Mathf.Pi / 4)) * (Mathf.Pi / 4); // 45° increments
return Vector2.Right.Rotated(snappedAngle).Normalized();
}
private void HandleMovement(Actor actor, Vector2 input, double delta)
{
// If turning, no movement
if (_currentTurnProgress > 0)
{
actor.Velocity = Vector2.Zero;
return;
}
// Move forward/backward based on facing direction
if (input.Y < 0) // Forward
{
_currentSpeed = Mathf.MoveToward(_currentSpeed, actor.MovementSpeed, Acceleration * (float)delta);
}
else if (input.Y > 0) // Backward
{
_currentSpeed = Mathf.MoveToward(_currentSpeed, -actor.MovementSpeed / 2, Acceleration * (float)delta);
}
else
{
_currentSpeed = Mathf.MoveToward(_currentSpeed, 0, Deceleration * (float)delta);
}
// Set velocity
actor.Velocity = actor.FacingDirection * _currentSpeed;
actor.MoveAndSlide();
}
}

View file

@ -0,0 +1,60 @@
using Godot;
namespace Cirno.Scripts.Components.Actors;
public partial class AnimationHandler : Node2D
{
[Export]
public AnimatedSprite2D _animatedSprite { get; protected set; }
protected Actor _parent;
public virtual void Init(Actor parent)
{
_parent = parent;
// var children = GetChildren();
// foreach (var child in children) {
// if (child is InputProvider inputProvider)
// {
// _inputProviders.Add(inputProvider);
// }
// }
}
public virtual void Update(double delta)
{
var direction = _parent.FacingDirection; //GetSnappedDirection();
if (_parent.Velocity.Length() > 0)
{
_animatedSprite.Play("walk_" + DirectionToString(direction));
_animatedSprite.SpeedScale = 1;
}
else
{
//_animatedSprite.Play("idle_" + DirectionToString(direction));
_animatedSprite.Play("walk_" + DirectionToString(direction));
_animatedSprite.SpeedScale = 0;
}
}
private string DirectionToString(Vector2 direction)
{
var angle = Mathf.RadToDeg(direction.Angle());
angle = Mathf.PosMod(angle, 360);
if (angle >= 337.5 || angle < 22.5) return "right";
if (angle >= 22.5 && angle < 67.5) return "up_right";
if (angle >= 67.5 && angle < 112.5) return "up";
if (angle >= 112.5 && angle < 157.5) return "up_left";
if (angle >= 157.5 && angle < 202.5) return "left";
if (angle >= 202.5 && angle < 247.5) return "down_left";
if (angle >= 247.5 && angle < 292.5) return "down";
if (angle >= 292.5 && angle < 337.5) return "down_right";
return "up";
}
}

View file

@ -0,0 +1,8 @@
using Godot;
namespace Cirno.Scripts.Components.Actors;
public abstract partial class InputProvider : Node2D
{
public abstract Vector2 GetMovementInput();
}

View file

@ -0,0 +1,11 @@
using Godot;
namespace Cirno.Scripts.Components.Actors;
public partial class KeyboardInputProvider : InputProvider
{
public override Vector2 GetMovementInput()
{
return Input.GetVector("left", "right", "up", "down");
}
}

View file

@ -1,10 +1,35 @@
using System.Collections.Generic;
using System.Linq;
using Cirno.Scripts.Components.Actors;
using Godot;
public abstract partial class MovementHandler : Node2D
{
public Vector2 MovementDirection { get; set; }
protected Actor _parent;
public abstract Vector2 MovementDirection { get; set; }
public abstract Vector2 FacingDirection { get; set; }
public abstract void Init(Actor parent);
protected readonly List<InputProvider> _inputProviders = new();
public virtual void Init(Actor parent)
{
_parent = parent;
var children = GetChildren();
foreach (var child in children) {
if (child is InputProvider inputProvider)
{
_inputProviders.Add(inputProvider);
}
}
}
public virtual Vector2 AggregateInputProviders()
{
return _inputProviders.Aggregate(Vector2.Zero, (current, inputProvider) => current + inputProvider.GetMovementInput().Normalized());
}
public abstract void Move(double delta);

View file

@ -77,4 +77,16 @@ public static class Tools
{
return node.GetNodeOrNull<InventoryManager>("/root/GameScene/InventoryManager");
}
public static Vector2 GetSnappedDirection(Vector2 direction)
{
// Snap to one of 8 directions
var angles = new[]
{
Vector2.Up, Vector2.Up + Vector2.Right, Vector2.Right, Vector2.Right + Vector2.Down,
Vector2.Down, Vector2.Down + Vector2.Left, Vector2.Left, Vector2.Left + Vector2.Up
};
return angles[Mathf.PosMod((int)(direction.X + 4), 8)].Normalized();
}
}