134 lines
4.7 KiB
C#
134 lines
4.7 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
public class AimTower : Tower
|
|
{
|
|
[SerializeField] protected Barrel barrel;
|
|
[SerializeField] protected EditableArc horizontalArc;
|
|
[SerializeField] protected EditableArc verticalArc;
|
|
|
|
[Header("Trajectory")]
|
|
[SerializeField] private float spaceBetweenGhosts = 0.5f;
|
|
[SerializeField] private int trajectoryBounces = 3;
|
|
private const float k_trajectory_maxdist = 100f;
|
|
private List<GameObject> ghosts = new();
|
|
[SerializeField] private GameObject ghostPrefab;
|
|
[SerializeField] private LineRenderer trajectoryLine;
|
|
[SerializeField] private int trajectoryObjectPoolSize = 25;
|
|
[SerializeField] private LayerMask wallMask;
|
|
private int poolIdx = 0;
|
|
|
|
public Vector3 AimDirection => barrel.transform.forward;
|
|
public Vector2 HorizontalRotationMinMax => horizontalArc.RotationMinMax;
|
|
public Vector2 VerticalRotationMinMax => verticalArc.RotationMinMax;
|
|
public float HorizontalRotation => horizontalArc.Value;
|
|
public float VerticalRotation => verticalArc.Value;
|
|
|
|
public override void Placed()
|
|
{
|
|
base.Placed();
|
|
|
|
horizontalArc.Value.AddListener(UpdateBarrelRotation);
|
|
verticalArc.Value.AddListener(UpdateBarrelRotation);
|
|
|
|
horizontalArc.Value.AddListener(UpdateTrajectory);
|
|
verticalArc.Value.AddListener(UpdateTrajectory);
|
|
|
|
horizontalArc.Value.AddListener(SnapVerticalToHorizontal);
|
|
|
|
UpdateTrajectory();
|
|
UpdateBarrelRotation();
|
|
}
|
|
|
|
public override void TowerSelected(bool selected)
|
|
{
|
|
base.TowerSelected(selected);
|
|
|
|
horizontalArc.gameObject.SetActive(selected);
|
|
verticalArc.gameObject.SetActive(selected);
|
|
trajectoryLine.gameObject.SetActive(selected);
|
|
UpdateTrajectory();
|
|
}
|
|
|
|
protected override void OnDestroy()
|
|
{
|
|
horizontalArc.Value.RemoveListener(UpdateBarrelRotation);
|
|
verticalArc.Value.RemoveListener(UpdateBarrelRotation);
|
|
horizontalArc.Value.RemoveListener(SnapVerticalToHorizontal);
|
|
}
|
|
|
|
private void UpdateBarrelRotation(float unused) => UpdateBarrelRotation();
|
|
|
|
// Rotate barrel to match rotation
|
|
private void UpdateBarrelRotation()
|
|
{
|
|
barrel.transform.localRotation = Quaternion.Euler(-verticalArc.Value, horizontalArc.Value, 0f);
|
|
}
|
|
|
|
private void SnapVerticalToHorizontal(float horizontalAngle)
|
|
{
|
|
verticalArc.transform.rotation = Quaternion.Euler(verticalArc.transform.rotation.eulerAngles.x, horizontalAngle, verticalArc.transform.rotation.eulerAngles.z);
|
|
}
|
|
|
|
private void UpdateTrajectory(float unused) => UpdateTrajectory();
|
|
|
|
private void UpdateTrajectory()
|
|
{
|
|
foreach (var ghost in ghosts)
|
|
{
|
|
ghost.SetActive(false);
|
|
}
|
|
if (!this.selected) return;
|
|
|
|
Vector3 origin = barrel.Tip.position;
|
|
Vector3 dir = barrel.transform.forward;
|
|
List<Vector3> pointsInTrajectory = new();
|
|
pointsInTrajectory.Add(origin);
|
|
for (int i = 0; i < trajectoryBounces; i++)
|
|
{
|
|
Debug.DrawRay(origin, dir.normalized * k_trajectory_maxdist, Color.red, 5f);
|
|
RaycastHit hit;
|
|
if (!Physics.Raycast(origin, dir, out hit, k_trajectory_maxdist, wallMask))
|
|
break;
|
|
|
|
pointsInTrajectory.Add(hit.point);
|
|
dir = Vector3.Reflect(dir, hit.normal);
|
|
origin = hit.point;
|
|
}
|
|
|
|
trajectoryLine.positionCount = pointsInTrajectory.Count;
|
|
trajectoryLine.SetPositions(pointsInTrajectory.ToArray());
|
|
|
|
// Build trajectory
|
|
for (int i = 0; i < pointsInTrajectory.Count - 1; i++)
|
|
{
|
|
Vector3 point1 = pointsInTrajectory[i];
|
|
Vector3 point2 = pointsInTrajectory[i + 1];
|
|
|
|
Vector3 trajDir = (point2 - point1).normalized;
|
|
float dist = Vector3.Distance(point1, point2);
|
|
for (float j = 0; j < dist; j += spaceBetweenGhosts)
|
|
{
|
|
Vector3 ghostPos = point1 + trajDir * j;
|
|
|
|
// Use object pool or spawn new
|
|
if (ghosts.Count >= trajectoryObjectPoolSize)
|
|
{
|
|
ghosts[poolIdx].transform.position = ghostPos;
|
|
ghosts[poolIdx].SetActive(true);
|
|
poolIdx = (poolIdx + 1) % trajectoryObjectPoolSize;
|
|
}
|
|
else
|
|
{
|
|
var ghost = Instantiate(ghostPrefab);
|
|
ghost.transform.position = ghostPos;
|
|
ghost.transform.parent = transform;
|
|
ghosts.Add(ghost);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|