Files
RobustToolbox/CGO/Component/Collidable/CollidableComponent.cs
volundr- 6c85d8cd15 Adds debug visualizer for hitboxes
Summary:
Adds debug visualizer to render Collider and CollidableComponents.  You can choose their color in the entity defition even.
Tweaked how HitboxComponent stores its AABB, for performance. (Forgive me, I lost control!)
Fixed hitbox calculation that was shifting them down and to the right.

Collidables still seem to prefer going by the sprite size instead of looking for a HitboxComponent.  That will need to be fixed later.  As will the offset of the player sprite.

Test Plan: Hit F4 and caress the table.

Reviewers: #ss14_developers, volundr-

Reviewed By: #ss14_developers, volundr-

Projects: #space_station_14

Differential Revision: http://phab.nexisonline.net/D40
2015-01-22 16:42:24 -05:00

236 lines
7.6 KiB
C#

using System;
using System.Drawing;
using ClientInterfaces.Collision;
using GameObject;
using GorgonLibrary;
using Lidgren.Network;
using SS13.IoC;
using SS13_Shared.GO;
using SS13_Shared.GO.Component.Collidable;
namespace CGO
{
public class CollidableComponent : Component, ICollidable
{
public Color DebugColor { get; set; }
private bool collisionEnabled = true;
private RectangleF currentAABB;
protected bool isHardCollidable = true;
/// <summary>
/// X - Top | Y - Right | Z - Bottom | W - Left
/// </summary>
private Vector4D tweakAABB;
public CollidableComponent()
{
Family = ComponentFamily.Collidable;
DebugColor = Color.Red;
tweakAABB = new Vector4D(0,0,0,0);
}
public override Type StateType
{
get { return typeof (CollidableComponentState); }
}
private Vector4D TweakAABB
{
get { return tweakAABB; }
set { tweakAABB = value; }
}
private RectangleF OffsetAABB
{
get
{
// Return tweaked AABB
if (currentAABB != null)
return
new RectangleF(
currentAABB.Left +
Owner.GetComponent<TransformComponent>(ComponentFamily.Transform).Position.X -
(currentAABB.Width/2) + tweakAABB.W,
currentAABB.Top +
Owner.GetComponent<TransformComponent>(ComponentFamily.Transform).Position.Y -
(currentAABB.Height/2) + tweakAABB.X,
currentAABB.Width - (tweakAABB.W - tweakAABB.Y),
currentAABB.Height - (tweakAABB.X - tweakAABB.Z));
else
return RectangleF.Empty;
}
}
#region ICollidable Members
public RectangleF AABB
{
get { return OffsetAABB; }
}
/// <summary>
/// Called when the collidable is bumped into by someone/something
/// </summary>
public void Bump(Entity ent)
{
if (OnBump != null)
OnBump(this, new EventArgs());
Owner.SendMessage(this, ComponentMessageType.Bumped, ent);
Owner.SendComponentNetworkMessage(this, NetDeliveryMethod.ReliableUnordered, ComponentMessageType.Bumped,
ent.Uid);
}
public bool IsHardCollidable
{
get { return isHardCollidable; }
}
#endregion
public event EventHandler OnBump;
/// <summary>
/// OnAdd override -- gets the AABB from the sprite component and sends it to the collision manager.
/// </summary>
/// <param name="owner"></param>
public override void OnAdd(Entity owner)
{
base.OnAdd(owner);
GetAABB();
var cm = IoCManager.Resolve<ICollisionManager>();
cm.AddCollidable(this);
}
/// <summary>
/// OnRemove override -- removes the AABB from the collisionmanager.
/// </summary>
public override void OnRemove()
{
var cm = IoCManager.Resolve<ICollisionManager>();
cm.RemoveCollidable(this);
base.OnRemove();
}
/// <summary>
/// Message handler --
/// SpriteChanged means the spritecomponent changed the current sprite.
/// </summary>
/// <param name="sender"></param>
/// <param name="type"></param>
/// <param name="reply"></param>
/// <param name="list"></param>
public override ComponentReplyMessage RecieveMessage(object sender, ComponentMessageType type,
params object[] list)
{
ComponentReplyMessage reply = base.RecieveMessage(sender, type, list);
if (sender == this) //Don't listen to our own messages!
return ComponentReplyMessage.Empty;
switch (type)
{
case ComponentMessageType.SpriteChanged:
if (collisionEnabled)
{
GetAABB();
var cm = IoCManager.Resolve<ICollisionManager>();
cm.UpdateCollidable(this);
}
break;
case ComponentMessageType.DisableCollision:
DisableCollision();
break;
case ComponentMessageType.EnableCollision:
EnableCollision();
break;
}
return reply;
}
/// <summary>
/// Parameter Setting
/// Settable params:
/// TweakAABB - Vector4D
/// </summary>
/// <param name="parameter"></param>
public override void SetParameter(ComponentParameter parameter)
{
base.SetParameter(parameter);
switch (parameter.MemberName)
{
case "TweakAABB":
TweakAABB = parameter.GetValue<Vector4D>();
break;
case "TweakAABBtop":
tweakAABB.X = parameter.GetValue<float>();
break;
case "TweakAABBright":
tweakAABB.Y = parameter.GetValue<float>();
break;
case "TweakAABBbottom":
tweakAABB.Z = parameter.GetValue<float>();
break;
case "TweakAABBleft":
tweakAABB.W = parameter.GetValue<float>();
break;
case "DebugColor":
var color = ColorTranslator.FromHtml(parameter.GetValue<string>());
if (!color.IsEmpty)
DebugColor = color;
break;
}
}
/// <summary>
/// Enables collidable
/// </summary>
private void EnableCollision()
{
collisionEnabled = true;
var cm = IoCManager.Resolve<ICollisionManager>();
cm.AddCollidable(this);
}
/// <summary>
/// Disables Collidable
/// </summary>
private void DisableCollision()
{
collisionEnabled = false;
var cm = IoCManager.Resolve<ICollisionManager>();
cm.RemoveCollidable(this);
}
/// <summary>
/// Gets the current AABB from the sprite component.
/// </summary>
private void GetAABB()
{
ComponentReplyMessage reply = Owner.SendMessage(this, ComponentFamily.Renderable,
ComponentMessageType.GetAABB);
if (reply.MessageType == ComponentMessageType.CurrentAABB)
{
currentAABB = (RectangleF) reply.ParamsList[0];
}
else
return;
}
public override void HandleComponentState(dynamic state)
{
if (state.CollisionEnabled != collisionEnabled)
{
if (state.CollisionEnabled)
EnableCollision();
else
DisableCollision();
}
}
}
}