From cfc13d93501b023fb38cfa020750efecdf7a4bd8 Mon Sep 17 00:00:00 2001 From: cojoedmo Date: Thu, 4 Jun 2026 03:42:07 -0400 Subject: [PATCH] working on aiming --- Attack.cs | 3 +- PlayerController.cs | 3 +- Tower.cs | 126 +++++++++++++++++++++++++++++++++++++------- attack.tscn | 5 ++ 4 files changed, 115 insertions(+), 22 deletions(-) diff --git a/Attack.cs b/Attack.cs index 255b859..ba51687 100644 --- a/Attack.cs +++ b/Attack.cs @@ -22,7 +22,7 @@ public partial class Attack : RigidBody2D { base._PhysicsProcess(delta); if (_speed != Vector2.Zero){ - ApplyCentralImpulse(_speed); + LinearVelocity = _speed; _speed = Vector2.Zero; } } @@ -38,6 +38,7 @@ public partial class Attack : RigidBody2D public void Shoot(Vector2 FORCE){ _speed = FORCE; + // Set("velocity", FORCE); GravityScale = 1; } diff --git a/PlayerController.cs b/PlayerController.cs index dc71f3d..645d3c4 100644 --- a/PlayerController.cs +++ b/PlayerController.cs @@ -47,7 +47,8 @@ public partial class PlayerController : TurnController public override void StartTurn() { - _towers.Where(t=> t._commander != null).ToList().ForEach(t=>t._commander._actions = t._commander._actionsMax); + _towers.ForEach(t => t.StartTurn()); + // _towers.Where(t=> t._commander != null).ToList().ForEach(t=>t._commander._actions = t._commander._actionsMax); } } diff --git a/Tower.cs b/Tower.cs index c56744c..0b3c9f4 100644 --- a/Tower.cs +++ b/Tower.cs @@ -6,13 +6,19 @@ using System.Diagnostics; public partial class Tower : Sprite2D { public bool _hovered, _aiming; - public Vector2 _aimOffset; + public int _launchForce = 1000, _arcIterations = 50; + public float _gravity, _drag; + public Vector2 _aimOffset, _arcEnd; + public List _arc = new(); public Marker2D _offset, _attackSpawn; public Area2D _area; public Commander _commander; public override void _Ready() { base._Ready(); + _gravity = (float)ProjectSettings.GetSetting("physics/2d/default_gravity"); + _drag = (float)ProjectSettings.GetSetting("physics/2d/default_linear_damp"); + _area = GetNode("Area"); _offset = GetNode("Offset"); _attackSpawn = GetNode("AttackSpawn"); @@ -24,6 +30,11 @@ public partial class Tower : Sprite2D { if (_aiming) { + if (_arcEnd != GetGlobalMousePosition()) + { + CalculateLaunchAngle(_attackSpawn.GlobalPosition, GetGlobalMousePosition(), _launchForce, _gravity, _drag); + DrawArc(); + } if (Input.IsActionJustPressed("rightClick")) { _commander.UnloadAttack(); @@ -32,14 +43,15 @@ public partial class Tower : Sprite2D else if (Input.IsActionJustPressed("leftClick")) { - _aimOffset = GetGlobalMousePosition() - GlobalPosition; + _aimOffset = CalculateLaunchAngle(_attackSpawn.GlobalPosition, GetGlobalMousePosition(), _launchForce, _gravity, _drag); + _commander.ShootCurrentAttack(_aimOffset); _aiming = false; } } - if (Input.IsActionJustPressed("leftClick")) + else if (_hovered) { - if (_hovered) + if (Input.IsActionJustPressed("leftClick")) { _aiming = true; _commander.LoadAttack(_attackSpawn.Position); @@ -48,28 +60,102 @@ public partial class Tower : Sprite2D } } - public List PredictPath() + public Vector2 CalculateLaunchAngle(Vector2 startPos, Vector2 targetPos, float launchSpeed, float gravity, float drag, int maxIterations = 20) { - Vector2 velocity = _aimOffset; - float timeBetweenSteps = 0.05f; - Vector2 startPosition = _attackSpawn.Position; - float gravity = -(float)ProjectSettings.GetSetting("physics/2d/default_gravity", 980.0f); - float drag = (float)ProjectSettings.GetSetting("physics/2d/default_linear_damp", 0.0f); - - List points = [startPosition]; - for (int i = 0; i < 151; i++) - { - velocity.Y += gravity * timeBetweenSteps; - // GD.Print(velocity); - velocity *= (float)Math.Clamp(1.0 - drag * timeBetweenSteps, 0, 1); + Vector2 toTarget = targetPos - startPos; + float baseAngle = toTarget.Angle(); // Directly pointing at the target - points.Add(points[^1] + velocity); + // Pure vertical angle going straight up (-Y is up in Godot) + float straightUpAngle = -Mathf.Pi / 2.0f; + + // We use a normalized 0.0 to 1.0 search range to avoid radian sign confusion + float lowT = 0.0f; // 0% = pointing straight at target + float highT = 1.0f; // 100% = pointing straight up + + float bestAngle = baseAngle; + float delta = 1.0f / 60.0f; // Matches standard physics step + + for (int i = 0; i < maxIterations; i++) + { + float testT = (lowT + highT) / 2.0f; + // Interpolate smoothly between the base angle and straight up + float testAngle = Mathf.LerpAngle(baseAngle, straightUpAngle, testT); + + float error = EvaluateSimulationError(testAngle, startPos, targetPos, launchSpeed, gravity, drag, delta); + + if (Mathf.Abs(error) < 0.2f) + { + bestAngle = testAngle; + break; + } + + // error > 0 means the simulated projectile landed below the target (+Y is down) + if (error > 0) + { + // It fell short or low. We need to loft it higher up (move toward 1.0) + lowT = testT; + } + else + { + // It flew over the target. We need to lower the arc (move toward 0.0) + highT = testT; + } + + bestAngle = testAngle; } - return points; + + return Vector2.FromAngle(bestAngle) * _launchForce; } - // public Dictionary<> Ra + public void DrawArc() + { + Path2D path = _commander._attack.GetNode("PredictedPath"); + path.Curve.ClearPoints(); + for (int i = 0; i < _arc.Count; i++) + { + path.Curve.AddPoint(_arc[i]); + } + GD.Print(path.Curve.PointCount); + } + + private float EvaluateSimulationError(float angle, Vector2 start, Vector2 target, float speed, float gravity, float drag, float delta) + { + Vector2 velocity = new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)) * speed; + Vector2 position = start; + + float directionSign = Mathf.Sign(target.X - start.X); + float maxFlightTime = 6.0f; + int totalSteps = (int)(maxFlightTime / delta); + _arc = [start]; + + for (int step = 0; step < totalSteps; step++) + { + velocity.Y += gravity * delta; + velocity -= velocity * drag * delta; + position += velocity * delta; + _arc.Add(position); + + // Check if our projectile crossed the target line on the X axis + bool reachedTargetX = (directionSign >= 0) ? (position.X >= target.X) : (position.X <= target.X); + + if (reachedTargetX) + { + return position.Y - target.Y; + } + } + _arcEnd = _arc[^1]; + // If it ran out of time or hit a wall before crossing target.X, penalize it heavily + return (position.Y > target.Y) ? 99999f : -99999f; + } + + public void StartTurn() + { + if (_commander != null) + { + _commander._actions = _commander._actionsMax; + } + } public void OnMouseEntered(){ _hovered = true; diff --git a/attack.tscn b/attack.tscn index ce1181b..cae122a 100644 --- a/attack.tscn +++ b/attack.tscn @@ -3,6 +3,9 @@ [ext_resource type="Script" uid="uid://dm2gyxmgwbmg8" path="res://Attack.cs" id="1_63pi1"] [ext_resource type="Texture2D" uid="uid://nwj4n7if8kqd" path="res://Art/circle25r.png" id="2_hqc8w"] +[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_63pi1"] +bounce = 0.25 + [sub_resource type="CircleShape2D" id="CircleShape2D_7yfhp"] radius = 8.0 @@ -10,6 +13,7 @@ radius = 8.0 [node name="Attack" type="RigidBody2D" unique_id=1225359241] input_pickable = true +physics_material_override = SubResource("PhysicsMaterial_63pi1") contact_monitor = true max_contacts_reported = 100 script = ExtResource("1_63pi1") @@ -23,6 +27,7 @@ texture = ExtResource("2_hqc8w") [node name="PredictedPath" type="Path2D" parent="." unique_id=1505290715] modulate = Color(1, 0, 1, 1) +top_level = true curve = SubResource("Curve2D_63pi1") [connection signal="body_entered" from="." to="." method="TakeAction"]