Files
peggle-roguelike/Tower.cs
T

167 lines
4.6 KiB
C#

using Godot;
using System;
using System.Collections.Generic;
using System.Diagnostics;
public partial class Tower : Sprite2D
{
public bool _hovered, _aiming;
public int _launchSpeed = 1000, _arcIterations = 50;
public Vector2 _aimOffset, _arcEnd;
public List<Vector2> _arc = new();
public Marker2D _offset, _attackSpawn;
public Area2D _area;
public Commander _commander;
public override void _Ready()
{
base._Ready();
_area = GetNode<Area2D>("Area");
_offset = GetNode<Marker2D>("Offset");
_attackSpawn = GetNode<Marker2D>("AttackSpawn");
}
public override void _Process(double delta)
{
base._Process(delta);
if (_commander?._actions > 0)
{
if (_aiming)
{
if (_arcEnd != GetGlobalMousePosition())
{
DrawArc(_attackSpawn.GlobalPosition, GetGlobalMousePosition());
}
if (Input.IsActionJustPressed("rightClick"))
{
_commander.UnloadAttack();
_aiming = false;
}
else if (Input.IsActionJustPressed("leftClick"))
{
_aimOffset = CalculateLaunchAngle(_attackSpawn.GlobalPosition, GetGlobalMousePosition());
_commander.ShootCurrentAttack(_aimOffset);
ClearArc();
_aiming = false;
}
}
else if (_hovered)
{
if (Input.IsActionJustPressed("leftClick"))
{
_aiming = true;
_commander.LoadAttack(_attackSpawn.Position);
}
}
}
}
public Vector2 CalculateLaunchAngle(Vector2 START, Vector2 END, int MAX_ITERATIONS = 20)
{
Vector2 offset = END - START;
float baseAngle = offset.Angle();
float straightUpAngle = -Mathf.Pi / 2.0f;
float lowAngle = 0.0f;
float highAngle = 1.0f;
float bestAngle = baseAngle;
for (int i = 0; i < MAX_ITERATIONS; i++)
{
float averageAngle = (lowAngle + highAngle) / 2.0f;
float testAngle = Mathf.LerpAngle(baseAngle, straightUpAngle, averageAngle);
float error = EvaluateSimulationError(testAngle, START, END);
if (Mathf.Abs(error) < 0.2f)
{
bestAngle = testAngle;
break;
}
if (error > 0)
{
lowAngle = averageAngle;
}
else
{
highAngle = averageAngle;
}
bestAngle = testAngle;
}
return Vector2.FromAngle(bestAngle) * _launchSpeed;
}
public void ClearArc()
{
Path2D path = _commander._attack.GetNode<Path2D>("PredictedPath");
path.Curve.ClearPoints();
}
public void DrawArc(Vector2 START, Vector2 END, int MAX_ITERATIONS = 20)
{
CalculateLaunchAngle(START, END);
Path2D path = _commander._attack.GetNode<Path2D>("PredictedPath");
path.Curve.ClearPoints();
for (int i = 0; i < _arc.Count; i++)
{
path.Curve.AddPoint(_arc[i]);
}
}
private float EvaluateSimulationError(float ANGLE, Vector2 START, Vector2 TARGET)
{
float speed = _launchSpeed, gravity = Globals._gravity, drag = Globals._drag, delta = 1.0f / 60.0f;
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);
bool reachedTargetX = (directionSign >= 0) ? (position.X >= TARGET.X) : (position.X <= TARGET.X);
if (reachedTargetX)
{
return position.Y - TARGET.Y;
}
}
_arcEnd = _arc[^1];
return (position.Y > TARGET.Y) ? 99999f : -99999f;
}
public void StartTurn()
{
if (_commander != null)
{
_commander._actions = _commander._actionsMax;
}
}
public void OnMouseEntered(){
_hovered = true;
}
public void OnMouseExited(){
_hovered = true;
}
}