Custom Collision Responses
by Nicholas Slowes · in Torque X 2D · 09/20/2007 (1:53 pm) · 3 replies
I am trying to create a region component that will track which objects are contained in a region by using a scene object with collisions enabled and custom collision delegates. I set the player object ResolveCollision delegate to a function that checks first to see if the object it is colliding with is a region, and if it is not it calls collision response from the T2DPhysicsComponent. I set the region ResolveCollision delegate to add objects to a list to keep track of who is inside the region. Collisions are enabled on both objects, without which they won't register collisions.
What I don't understand is that after slightly penetrating the region, the player object is stopped, and if you stop moving it is pushed back out of the region. Some sort of physics response is still preventing the player from freely moving over the region, but I have no idea what since both objects collision responses have been overridden.
Here is the code for my region component:
Suggestions are appreciated, including alternative approaches to producing the same functionality, if there is a simpler way to get this done.
What I don't understand is that after slightly penetrating the region, the player object is stopped, and if you stop moving it is pushed back out of the region. Some sort of physics response is still preventing the player from freely moving over the region, but I have no idea what since both objects collision responses have been overridden.
Here is the code for my region component:
public class RegionComponent : TorqueComponent, ITickObject
{
public delegate void EnterRegionDelegate(T2DSceneObject enteringObject);
public delegate void ExitRegionDelegate(T2DSceneObject exitingObject);
public delegate void TickInRegionDelegate(T2DSceneObject insideObject, float dt);
public event EnterRegionDelegate OnEnterRegion;
public event ExitRegionDelegate OnExitRegion;
public event TickInRegionDelegate OnTickInRegion;
public T2DSceneObject SceneObject
{
get { return Owner as T2DSceneObject; }
}
public virtual void ProcessTick(Move move, float dt)
{
// call exit for members no longer inside the region
foreach (T2DSceneObject obj in lastTickList)
{
if (!nextTickList.Contains(obj))
{
this.OnExitRegion.Invoke(obj);
}
}
//update inside region list
lastTickList = nextTickList;
nextTickList = new List<T2DSceneObject>();
//perform tick event for every object inside the region
foreach (T2DSceneObject obj in lastTickList)
{
this.OnTickInRegion.Invoke(obj, dt);
}
}
public virtual void InterpolateTick(float k)
{
// todo: interpolate between ticks as needed here
}
public void ResolveCollision(T2DSceneObject ours, T2DSceneObject theirs, ref T2DCollisionInfo info, T2DCollisionMaterial material, bool handleBoth)
{
//add object to region list
this.nextTickList.Add(theirs);
if(!this.lastTickList.Contains(theirs))
this.OnEnterRegion.Invoke(theirs);
}
protected override bool _OnRegister(TorqueObject owner)
{
if (!base._OnRegister(owner) || !(owner is T2DSceneObject))
return false;
// todo: perform initialization for the component
lastTickList = new List<T2DSceneObject>();
nextTickList = new List<T2DSceneObject>();
// set up collision delegate
T2DResolveCollisionDelegate resolve = new T2DResolveCollisionDelegate(this.ResolveCollision);
// safely cast to scene object, since it is checked at the beginning of the method
T2DSceneObject regionObject = (T2DSceneObject)owner;
// apply collision delegate and make sure collisions are enabled
regionObject.Collision.ResolveCollision = resolve;
regionObject.Collision.OnCollision = null;
regionObject.CollisionsEnabled = true;
ProcessList.Instance.AddTickCallback(Owner, this);
// todo: look up interfaces exposed by other components
// E.g.,
// _theirInterface = Owner.Components.GetInterface<ValueInterface<float>>("float", "their interface name");
return true;
}
private List<T2DSceneObject> lastTickList;
private List<T2DSceneObject> nextTickList;
}Suggestions are appreciated, including alternative approaches to producing the same functionality, if there is a simpler way to get this done.
About the author
#2
09/20/2007 (2:38 pm)
Thanks! Setting SolveOverlap to false on the region object worked perfectly. Why does it only need to be disabled on one object? Does it only take effect when both intersecting objects have SolveOverlap set to true?
#3
Mount a trigger object instead of using a component (or the component could create and mount the trigger object in onregister).
Don't use collisions at all, use scenegraph.instance.findobject (or whatever the syntax is, to find objects in a rect or radius).
09/20/2007 (4:31 pm)
Heres two ideas which seems much simpler to me:Mount a trigger object instead of using a component (or the component could create and mount the trigger object in onregister).
Don't use collisions at all, use scenegraph.instance.findobject (or whatever the syntax is, to find objects in a rect or radius).
Torque Owner Frederic
Note that the collision detection seems to happen multiple times per tick. You will have to change ResolveCollision to check if the T2DSceneObject has already been added to the nextTickList. Otherwise the OnEnterRegion.Invoke method will be called multiple times, and the T2DSceneObject will be added multiple times to the nextTickList.