Files
LuaCsForBarotraumaEP/Barotrauma/BarotraumaShared/Source/Items/Components/Signal/MotionSensor.cs
Joonas Rikkonen 044fd3344b 2f107db...5202af9
2019-03-18 21:42:26 +02:00

151 lines
4.6 KiB
C#

using FarseerPhysics;
using Microsoft.Xna.Framework;
using System;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
partial class MotionSensor : ItemComponent
{
private const float UpdateInterval = 0.1f;
private string output, falseOutput;
private bool motionDetected;
private float rangeX, rangeY;
private Vector2 detectOffset;
private float updateTimer;
[Serialize(false, false)]
public bool MotionDetected
{
get { return motionDetected; }
set { motionDetected = value; }
}
[Serialize(false, true), Editable]
public bool OnlyHumans
{
get;
set;
}
[InGameEditable, Serialize(0.0f, true)]
public float RangeX
{
get { return rangeX; }
set
{
rangeX = MathHelper.Clamp(value, 0.0f, 1000.0f);
}
}
[InGameEditable, Serialize(0.0f, true)]
public float RangeY
{
get { return rangeY; }
set
{
rangeY = MathHelper.Clamp(value, 0.0f, 1000.0f);
}
}
[Serialize("0,0", true), Editable(ToolTip = "The position to detect the movement at relative to the item. For example, 0,100 would detect movement 100 units above the item.")]
public Vector2 DetectOffset
{
get { return detectOffset; }
set
{
detectOffset = value;
detectOffset.X = MathHelper.Clamp(value.X, -rangeX, rangeX);
detectOffset.Y = MathHelper.Clamp(value.Y, -rangeY, rangeY);
}
}
[InGameEditable, Serialize("1", true)]
public string Output
{
get { return output; }
set { output = value; }
}
[InGameEditable, Serialize("", true)]
public string FalseOutput
{
get { return falseOutput; }
set { falseOutput = value; }
}
[Editable(ToolTip = "How fast the objects within the detector's range have to be moving (in m/s).", DecimalCount = 3), Serialize(0.01f, true)]
public float MinimumVelocity
{
get;
set;
}
public MotionSensor(Item item, XElement element)
: base (item, element)
{
IsActive = true;
//backwards compatibility
if (element.Attribute("range") != null)
{
rangeX = rangeY = element.GetAttributeFloat("range", 0.0f);
}
}
public override void Update(float deltaTime, Camera cam)
{
string signalOut = motionDetected ? output : falseOutput;
if (!string.IsNullOrEmpty(signalOut)) item.SendSignal(1, signalOut, "state_out", null);
updateTimer -= deltaTime;
if (updateTimer > 0.0f) return;
motionDetected = false;
updateTimer = UpdateInterval;
if (item.body != null && item.body.Enabled)
{
if (Math.Abs(item.body.LinearVelocity.X) > MinimumVelocity || Math.Abs(item.body.LinearVelocity.Y) > MinimumVelocity)
{
motionDetected = true;
}
}
Vector2 detectPos = item.WorldPosition + detectOffset;
Rectangle detectRect = new Rectangle((int)(detectPos.X - rangeX), (int)(detectPos.Y - rangeY), (int)(rangeX * 2), (int)(rangeY * 2));
float broadRangeX = Math.Max(rangeX * 2, 500);
float broadRangeY = Math.Max(rangeY * 2, 500);
foreach (Character c in Character.CharacterList)
{
if (OnlyHumans && c.ConfigPath != Character.HumanConfigFile) { continue; }
//do a rough check based on the position of the character's collider first
//before the more accurate limb-based check
if (Math.Abs(c.WorldPosition.X - detectPos.X) > broadRangeX || Math.Abs(c.WorldPosition.Y - detectPos.Y) > broadRangeY)
{
continue;
}
foreach (Limb limb in c.AnimController.Limbs)
{
if (limb.LinearVelocity.LengthSquared() <= MinimumVelocity * MinimumVelocity) continue;
if (MathUtils.CircleIntersectsRectangle(limb.WorldPosition, ConvertUnits.ToDisplayUnits(limb.body.GetMaxExtent()), detectRect))
{
motionDetected = true;
break;
}
}
}
}
}
}