From 90d2a95fa89b128ec2d3bbbb67b1bf5f1ce1f146 Mon Sep 17 00:00:00 2001 From: Marco Date: Tue, 18 Feb 2025 17:40:33 +0100 Subject: [PATCH] Bad tank movement --- Scenes/Actors/ActorEnemyTest.tscn | 245 ++++++++++++++++++ Scenes/test.tscn | 6 +- Scripts/Components/Actors/Actor.cs | 17 +- .../Components/Actors/ActorFreeMovement.cs | 22 +- .../Components/Actors/ActorTankMovement.cs | 112 ++++++++ Scripts/Components/Actors/AnimationHandler.cs | 60 +++++ Scripts/Components/Actors/InputProvider.cs | 8 + .../Actors/KeyboardInputProvider.cs | 11 + Scripts/Components/Actors/MovementHandler.cs | 29 ++- Scripts/Tools.cs | 12 + 10 files changed, 514 insertions(+), 8 deletions(-) create mode 100644 Scenes/Actors/ActorEnemyTest.tscn create mode 100644 Scripts/Components/Actors/ActorTankMovement.cs create mode 100644 Scripts/Components/Actors/AnimationHandler.cs create mode 100644 Scripts/Components/Actors/InputProvider.cs create mode 100644 Scripts/Components/Actors/KeyboardInputProvider.cs diff --git a/Scenes/Actors/ActorEnemyTest.tscn b/Scenes/Actors/ActorEnemyTest.tscn new file mode 100644 index 00000000..ebaa0892 --- /dev/null +++ b/Scenes/Actors/ActorEnemyTest.tscn @@ -0,0 +1,245 @@ +[gd_scene load_steps=32 format=3 uid="uid://bqjcwxene73l2"] + +[ext_resource type="Script" path="res://Scripts/Components/Actors/Actor.cs" id="1_k5cyk"] +[ext_resource type="Texture2D" uid="uid://hukxr2e63gky" path="res://Sprites/Actors/Robot3.png" id="2_wt8wl"] +[ext_resource type="Script" path="res://Scripts/Components/Actors/ActorTankMovement.cs" id="3_738kr"] +[ext_resource type="Script" path="res://Scripts/Components/Actors/KeyboardInputProvider.cs" id="4_8bcq6"] +[ext_resource type="Script" path="res://Scripts/Components/Actors/AnimationHandler.cs" id="5_c7ovk"] + +[sub_resource type="AtlasTexture" id="AtlasTexture_spe0p"] +atlas = ExtResource("2_wt8wl") +region = Rect2(0, 0, 16, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_wjwtx"] +atlas = ExtResource("2_wt8wl") +region = Rect2(16, 0, 16, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_3ip5h"] +atlas = ExtResource("2_wt8wl") +region = Rect2(32, 0, 16, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_48rwl"] +atlas = ExtResource("2_wt8wl") +region = Rect2(0, 224, 16, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_t3srr"] +atlas = ExtResource("2_wt8wl") +region = Rect2(16, 224, 16, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_rfyhw"] +atlas = ExtResource("2_wt8wl") +region = Rect2(32, 224, 16, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_vwjtc"] +atlas = ExtResource("2_wt8wl") +region = Rect2(0, 32, 16, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_synp8"] +atlas = ExtResource("2_wt8wl") +region = Rect2(16, 32, 16, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_qwhd0"] +atlas = ExtResource("2_wt8wl") +region = Rect2(32, 32, 16, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_ue6d2"] +atlas = ExtResource("2_wt8wl") +region = Rect2(0, 192, 16, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_0ofyy"] +atlas = ExtResource("2_wt8wl") +region = Rect2(16, 192, 16, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_36xaf"] +atlas = ExtResource("2_wt8wl") +region = Rect2(32, 192, 16, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_q325s"] +atlas = ExtResource("2_wt8wl") +region = Rect2(0, 64, 16, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_0ao0j"] +atlas = ExtResource("2_wt8wl") +region = Rect2(16, 64, 16, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_7gqg8"] +atlas = ExtResource("2_wt8wl") +region = Rect2(32, 64, 16, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_qjdm5"] +atlas = ExtResource("2_wt8wl") +region = Rect2(0, 128, 16, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_w72lm"] +atlas = ExtResource("2_wt8wl") +region = Rect2(16, 128, 16, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_p3mq3"] +atlas = ExtResource("2_wt8wl") +region = Rect2(32, 128, 16, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_p7tp3"] +atlas = ExtResource("2_wt8wl") +region = Rect2(0, 160, 16, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_lvaxr"] +atlas = ExtResource("2_wt8wl") +region = Rect2(16, 160, 16, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_y3l85"] +atlas = ExtResource("2_wt8wl") +region = Rect2(32, 160, 16, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_v1l62"] +atlas = ExtResource("2_wt8wl") +region = Rect2(0, 96, 16, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_b8g6v"] +atlas = ExtResource("2_wt8wl") +region = Rect2(16, 96, 16, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_ykxak"] +atlas = ExtResource("2_wt8wl") +region = Rect2(32, 96, 16, 32) + +[sub_resource type="SpriteFrames" id="SpriteFrames_ix17a"] +animations = [{ +"frames": [{ +"duration": 1.0, +"texture": SubResource("AtlasTexture_spe0p") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_wjwtx") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_3ip5h") +}], +"loop": true, +"name": &"walk_down", +"speed": 5.0 +}, { +"frames": [{ +"duration": 1.0, +"texture": SubResource("AtlasTexture_48rwl") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_t3srr") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_rfyhw") +}], +"loop": true, +"name": &"walk_down_left", +"speed": 5.0 +}, { +"frames": [{ +"duration": 1.0, +"texture": SubResource("AtlasTexture_vwjtc") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_synp8") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_qwhd0") +}], +"loop": true, +"name": &"walk_down_right", +"speed": 5.0 +}, { +"frames": [{ +"duration": 1.0, +"texture": SubResource("AtlasTexture_ue6d2") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_0ofyy") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_36xaf") +}], +"loop": true, +"name": &"walk_left", +"speed": 5.0 +}, { +"frames": [{ +"duration": 1.0, +"texture": SubResource("AtlasTexture_q325s") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_0ao0j") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_7gqg8") +}], +"loop": true, +"name": &"walk_right", +"speed": 5.0 +}, { +"frames": [{ +"duration": 1.0, +"texture": SubResource("AtlasTexture_qjdm5") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_w72lm") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_p3mq3") +}], +"loop": true, +"name": &"walk_up", +"speed": 5.0 +}, { +"frames": [{ +"duration": 1.0, +"texture": SubResource("AtlasTexture_p7tp3") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_lvaxr") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_y3l85") +}], +"loop": true, +"name": &"walk_up_left", +"speed": 5.0 +}, { +"frames": [{ +"duration": 1.0, +"texture": SubResource("AtlasTexture_v1l62") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_b8g6v") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_ykxak") +}], +"loop": true, +"name": &"walk_up_right", +"speed": 5.0 +}] + +[sub_resource type="CircleShape2D" id="CircleShape2D_2b36v"] +radius = 5.0 + +[node name="ActorEnemyTest" type="CharacterBody2D"] +collision_layer = 16 +collision_mask = 115 +script = ExtResource("1_k5cyk") +MovementSpeed = 40.0 + +[node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="."] +position = Vector2(0, 4) +sprite_frames = SubResource("SpriteFrames_ix17a") +animation = &"walk_down" + +[node name="MovementProvider" type="Node2D" parent="."] +script = ExtResource("3_738kr") + +[node name="InputProvider" type="Node2D" parent="MovementProvider"] +script = ExtResource("4_8bcq6") + +[node name="CollisionShape2D" type="CollisionShape2D" parent="."] +shape = SubResource("CircleShape2D_2b36v") + +[node name="AnimationHandler" type="Node2D" parent="." node_paths=PackedStringArray("_animatedSprite")] +script = ExtResource("5_c7ovk") +_animatedSprite = NodePath("../AnimatedSprite2D") diff --git a/Scenes/test.tscn b/Scenes/test.tscn index 12ee00c2..f9634845 100644 --- a/Scenes/test.tscn +++ b/Scenes/test.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=69 format=4 uid="uid://bv451a8wgty4u"] +[gd_scene load_steps=70 format=4 uid="uid://bv451a8wgty4u"] [ext_resource type="Script" path="res://Scripts/GameManager.cs" id="1_8tmoj"] [ext_resource type="PackedScene" uid="uid://bghghp5ep4w2j" path="res://Scenes/player.tscn" id="2_8mh54"] @@ -59,6 +59,7 @@ [ext_resource type="PackedScene" uid="uid://cd36ch65jijg0" path="res://Scenes/Activable/BulletEmitter.tscn" id="49_64oga"] [ext_resource type="PackedScene" uid="uid://c5fiv1nioghfb" path="res://Scenes/Actors/Marisa.tscn" id="50_mp5ma"] [ext_resource type="Script" path="res://Scripts/Resources/Events/ControlEnemyEvent.cs" id="52_5m7td"] +[ext_resource type="PackedScene" uid="uid://bqjcwxene73l2" path="res://Scenes/Actors/ActorEnemyTest.tscn" id="55_chha6"] [sub_resource type="CircleShape2D" id="CircleShape2D_8wuck"] @@ -515,6 +516,9 @@ offset_bottom = 2.0 text = "Briefing Test" label_settings = ExtResource("14_c4c20") +[node name="ActorEnemyTest" parent="Computer4" instance=ExtResource("55_chha6")] +position = Vector2(100, 104) + [node name="Ammo1" parent="." instance=ExtResource("34_17pjh")] position = Vector2(-792, -396) diff --git a/Scripts/Components/Actors/Actor.cs b/Scripts/Components/Actors/Actor.cs index ddb4ec06..60975d42 100644 --- a/Scripts/Components/Actors/Actor.cs +++ b/Scripts/Components/Actors/Actor.cs @@ -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 _movementHandlers = new(); + + private List _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); + } } } \ No newline at end of file diff --git a/Scripts/Components/Actors/ActorFreeMovement.cs b/Scripts/Components/Actors/ActorFreeMovement.cs index 3b330749..1a2960e7 100644 --- a/Scripts/Components/Actors/ActorFreeMovement.cs +++ b/Scripts/Components/Actors/ActorFreeMovement.cs @@ -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(); - } } \ No newline at end of file diff --git a/Scripts/Components/Actors/ActorTankMovement.cs b/Scripts/Components/Actors/ActorTankMovement.cs new file mode 100644 index 00000000..4a02f636 --- /dev/null +++ b/Scripts/Components/Actors/ActorTankMovement.cs @@ -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(); + } + +} \ No newline at end of file diff --git a/Scripts/Components/Actors/AnimationHandler.cs b/Scripts/Components/Actors/AnimationHandler.cs new file mode 100644 index 00000000..c9a1a347 --- /dev/null +++ b/Scripts/Components/Actors/AnimationHandler.cs @@ -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"; + } +} \ No newline at end of file diff --git a/Scripts/Components/Actors/InputProvider.cs b/Scripts/Components/Actors/InputProvider.cs new file mode 100644 index 00000000..896154a9 --- /dev/null +++ b/Scripts/Components/Actors/InputProvider.cs @@ -0,0 +1,8 @@ +using Godot; + +namespace Cirno.Scripts.Components.Actors; + +public abstract partial class InputProvider : Node2D +{ + public abstract Vector2 GetMovementInput(); +} \ No newline at end of file diff --git a/Scripts/Components/Actors/KeyboardInputProvider.cs b/Scripts/Components/Actors/KeyboardInputProvider.cs new file mode 100644 index 00000000..2e6a22c7 --- /dev/null +++ b/Scripts/Components/Actors/KeyboardInputProvider.cs @@ -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"); + } +} \ No newline at end of file diff --git a/Scripts/Components/Actors/MovementHandler.cs b/Scripts/Components/Actors/MovementHandler.cs index 618b2edf..d27c36fa 100644 --- a/Scripts/Components/Actors/MovementHandler.cs +++ b/Scripts/Components/Actors/MovementHandler.cs @@ -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 _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); diff --git a/Scripts/Tools.cs b/Scripts/Tools.cs index 258536f9..ad6e13a1 100644 --- a/Scripts/Tools.cs +++ b/Scripts/Tools.cs @@ -77,4 +77,16 @@ public static class Tools { return node.GetNodeOrNull("/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(); + } }