Files
OpenRA/OpenRA.Mods.Common/HitShapes/Capsule.cs
reaperrr bc5eb66088 Add OuterRadius debug overlay to Rectangle and Capsule
Circle obviously doesn't need it now (might change with the introduction of offsets, but we can still add it when that happens).
2017-05-29 07:41:20 -05:00

126 lines
4.2 KiB
C#

#region Copyright & License Information
/*
* Copyright 2007-2017 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using System;
using System.Drawing;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Graphics;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.HitShapes
{
public class CapsuleShape : IHitShape
{
public WDist OuterRadius { get; private set; }
[FieldLoader.Require]
public readonly int2 PointA;
[FieldLoader.Require]
public readonly int2 PointB;
public readonly WDist Radius = new WDist(426);
[Desc("Defines the top offset relative to the actor's target point.")]
public readonly int VerticalTopOffset = 0;
[Desc("Defines the bottom offset relative to the actor's target point.")]
public readonly int VerticalBottomOffset = 0;
int2 ab;
int abLenSq;
public CapsuleShape() { }
public CapsuleShape(int2 a, int2 b, WDist radius)
{
PointA = a;
PointB = b;
Radius = radius;
}
public void Initialize()
{
ab = PointB - PointA;
abLenSq = ab.LengthSquared / 1024;
if (abLenSq == 0)
throw new YamlException("This Capsule describes a circle. Use a Circle HitShape instead.");
if (VerticalTopOffset < VerticalBottomOffset)
throw new YamlException("VerticalTopOffset must be equal to or higher than VerticalBottomOffset.");
OuterRadius = Radius + new WDist(Math.Max(PointA.Length, PointB.Length));
}
public WDist DistanceFromEdge(WVec v)
{
var p = new int2(v.X, v.Y);
var t = int2.Dot(p - PointA, ab) / abLenSq;
if (t < 0)
return new WDist(Math.Max(0, (PointA - p).Length - Radius.Length));
if (t > 1024)
return new WDist(Math.Max(0, (PointB - p).Length - Radius.Length));
var projection = PointA + new int2(
(ab.X * t) / 1024,
(ab.Y * t) / 1024);
var distance = (projection - p).Length;
return new WDist(Math.Max(0, distance - Radius.Length));
}
public WDist DistanceFromEdge(WPos pos, Actor actor)
{
var actorPos = actor.CenterPosition;
if (pos.Z > actorPos.Z + VerticalTopOffset)
return DistanceFromEdge((pos - (actorPos + new WVec(0, 0, VerticalTopOffset))).Rotate(-actor.Orientation));
if (pos.Z < actorPos.Z + VerticalBottomOffset)
return DistanceFromEdge((pos - (actorPos + new WVec(0, 0, VerticalBottomOffset))).Rotate(-actor.Orientation));
return DistanceFromEdge((pos - new WPos(actorPos.X, actorPos.Y, pos.Z)).Rotate(-actor.Orientation));
}
public void DrawCombatOverlay(WorldRenderer wr, RgbaColorRenderer wcr, Actor actor)
{
var actorPos = actor.CenterPosition;
var a = actorPos + new WVec(PointA.X, PointA.Y, VerticalTopOffset).Rotate(actor.Orientation);
var b = actorPos + new WVec(PointB.X, PointB.Y, VerticalTopOffset).Rotate(actor.Orientation);
var aa = actorPos + new WVec(PointA.X, PointA.Y, VerticalBottomOffset).Rotate(actor.Orientation);
var bb = actorPos + new WVec(PointB.X, PointB.Y, VerticalBottomOffset).Rotate(actor.Orientation);
var offset1 = new WVec(a.Y - b.Y, b.X - a.X, 0);
offset1 = offset1 * Radius.Length / offset1.Length;
var offset2 = new WVec(aa.Y - bb.Y, bb.X - aa.X, 0);
offset2 = offset2 * Radius.Length / offset2.Length;
var c = Color.Yellow;
RangeCircleRenderable.DrawRangeCircle(wr, a, Radius, 1, c, 0, c);
RangeCircleRenderable.DrawRangeCircle(wr, b, Radius, 1, c, 0, c);
wcr.DrawLine(new[] { wr.Screen3DPosition(a - offset1), wr.Screen3DPosition(b - offset1) }, 1, c);
wcr.DrawLine(new[] { wr.Screen3DPosition(a + offset1), wr.Screen3DPosition(b + offset1) }, 1, c);
RangeCircleRenderable.DrawRangeCircle(wr, aa, Radius, 1, c, 0, c);
RangeCircleRenderable.DrawRangeCircle(wr, bb, Radius, 1, c, 0, c);
wcr.DrawLine(new[] { wr.Screen3DPosition(aa - offset2), wr.Screen3DPosition(bb - offset2) }, 1, c);
wcr.DrawLine(new[] { wr.Screen3DPosition(aa + offset2), wr.Screen3DPosition(bb + offset2) }, 1, c);
RangeCircleRenderable.DrawRangeCircle(wr, actorPos, OuterRadius, 1, Color.LimeGreen, 0, Color.LimeGreen);
}
}
}