61 lines
3.4 KiB
C#
61 lines
3.4 KiB
C#
using UnityEngine;
|
|
|
|
namespace DepthsOfGreed.HandbookUI
|
|
{
|
|
public enum AttackCoverage { Automatic, Circle, Sector }
|
|
|
|
public static class AttackRangeGeometry
|
|
{
|
|
public static float CoverageAngle(CombatDefinition c)
|
|
{
|
|
if(c.coverage==AttackCoverage.Circle)return 360;
|
|
if(c.coverage==AttackCoverage.Sector || (c.rotation==RotationMode.Fixed && c.attackShape==AttackShape.Cone))
|
|
return Mathf.Clamp(c.coneAngle,1,360);
|
|
return 360;
|
|
}
|
|
// Shared optional targeting helper. No shots or damage are performed here.
|
|
public static bool CanReach(CombatDefinition c,Vector2 origin,Vector2 target,float baseAngleDegrees)
|
|
{
|
|
if(c==null)return false;
|
|
Vector2 delta=target-origin;float distance=delta.magnitude;
|
|
if(distance<Mathf.Max(0,c.minimumRange) || (!c.unlimitedRange && distance>Mathf.Max(0,c.range)))return false;
|
|
float coverage=CoverageAngle(c);
|
|
return coverage>=360 || distance<.0001f || Mathf.Abs(Mathf.DeltaAngle(baseAngleDegrees+c.forwardAngleOffset,Mathf.Atan2(delta.y,delta.x)*Mathf.Rad2Deg))<=coverage*.5f;
|
|
}
|
|
}
|
|
|
|
public sealed class AttackRangePreview : MonoBehaviour
|
|
{
|
|
public LineRenderer outerEdge,minimumEdge,sectorLeft,sectorRight;
|
|
public bool showRange=true;
|
|
[Min(1)] public float unlimitedDirectionLength=10;
|
|
public Color rangeColor=new Color(.25f,.75f,1f,.35f);
|
|
public void Show(HandbookTowerEntry entry)
|
|
{
|
|
GetComponent<RangeArenaClip>()?.Configure(entry);
|
|
var c=entry?entry.combat:null;
|
|
bool ability=entry && entry.use==BuildUse.Ability;
|
|
bool visible=showRange && c!=null && (ability?c.areaRadius>0:c.range>0 || c.unlimitedRange);
|
|
gameObject.SetActive(visible);if(!visible)return;
|
|
float max=ability?c.areaRadius:c.unlimitedRange?unlimitedDirectionLength:c.range;
|
|
float min=ability?0:Mathf.Clamp(c.minimumRange,0,max);
|
|
float angle=ability?360:AttackRangeGeometry.CoverageAngle(c);
|
|
float offset=ability?0:c.forwardAngleOffset;
|
|
bool unlimited=!ability && c.unlimitedRange;
|
|
outerEdge.gameObject.SetActive(!unlimited);minimumEdge.gameObject.SetActive(min>0);sectorLeft.gameObject.SetActive(angle<360);sectorRight.gameObject.SetActive(angle<360);
|
|
Arc(outerEdge,max,angle,offset);Arc(minimumEdge,min,angle,offset);
|
|
sectorLeft.loop=sectorRight.loop=false;sectorLeft.positionCount=sectorRight.positionCount=2;
|
|
sectorLeft.SetPosition(0,Point(min,offset-angle*.5f));sectorLeft.SetPosition(1,Point(max,offset-angle*.5f));
|
|
sectorRight.SetPosition(0,Point(min,offset+angle*.5f));sectorRight.SetPosition(1,Point(max,offset+angle*.5f));
|
|
foreach(var line in new[]{outerEdge,minimumEdge,sectorLeft,sectorRight})line.startColor=line.endColor=rangeColor;
|
|
}
|
|
static Vector3 Point(float radius,float angle)=>new Vector3(Mathf.Cos(angle*Mathf.Deg2Rad)*radius,Mathf.Sin(angle*Mathf.Deg2Rad)*radius,0);
|
|
static void Arc(LineRenderer line,float radius,float angle,float offset)
|
|
{
|
|
int count=97;line.loop=angle>=360;line.positionCount=angle>=360?count-1:count;
|
|
for(int i=0;i<line.positionCount;i++)line.SetPosition(i,Point(radius,offset-angle*.5f+angle*i/(count-1)));
|
|
}
|
|
}
|
|
}
|
|
|