5
\$\begingroup\$

Problem:

I'm trying to set up some tests with mock collision objects, but i cannot construct collisions with custom objects. What I'm trying to do:

Collision2D col = new Collision2D();
col.gameObject = this.gameObject;

There seems to be no way to do this as col.gameObject has no visible setter. Is there a way to do this? I would like to script the passing of a collision to a mono-behavior via an event that gets handled by the OnCollisionEnter2D(Collision2D collision) inherited from mono-behaviors. Thanks for your time.

\$\endgroup\$
4
  • \$\begingroup\$ Maybe call Rect.Overlaps continuously to see if one collider's Rect overlaps another collider's Rect? docs.unity3d.com/ScriptReference/Rect.Overlaps.html \$\endgroup\$ Dec 2, 2014 at 22:43
  • \$\begingroup\$ Am I missing something? Why not use AddComponent? \$\endgroup\$
    – Ben
    Dec 3, 2014 at 8:49
  • \$\begingroup\$ I'm trying to run tests on the collision handling of mono behaviors. Instead of actually making them collide with other objects, which would be less customizable, I want to be able to create a fake collision in code (no actual collision between colliders just a new Collision2D object). \$\endgroup\$ Dec 3, 2014 at 18:27
  • \$\begingroup\$ @CostelloNicho Did you try Unity testing Tools? See my revised answer. \$\endgroup\$
    – aggsol
    Dec 4, 2014 at 7:57

2 Answers 2

2
\$\begingroup\$

This looks like a job for reflection:

public T MockType<T>(Dictionary<string,object> fieldValues, params object[] consParams)
{
    var type = typeof (T);
    var cons = type.GetConstructor(BindingFlags.NonPublic,
                                   Type.DefaultBinder,
                                   consParams.Select(p => p.GetType()).ToArray(),
                                   null);
    var result = (T)cons.Invoke(consParams ?? new object[0]); // invoke non-public constructor
    foreach (var fieldValue in fieldValues)
    {
        var field = type.GetField(fieldValue.Key, BindingFlags.NonPublic)
        field.SetValue(result, fieldValue.Value); // Set non-public field
    }
    return result;
}


// Example method demonstrating use:
public Collision2D MockCollision2D(Rigidbody2D rigidbody,
                                   Collider2D collider,
                                   Vector2 relativeVelocity,
                                   ContactPoint2D[] contacts)
{
    return MockType<Collision2D>(new Dictionary<string, object>
                                     {
// Use a decompiler like ILSpy to find out what the internal fields' names are:
                                         {"m_Rigidbody", rigidbody},
                                         {"m_Collider", collider},
                                         {"m_RelativeVelocity", relativeVelocity},
                                         {"m_Contacts", contacts}
                                     },
                                 new object[0]
        );
}

I haven't tested this, so it might need some tweaks. The game object the collision refers to is drawn from the collider field.

\$\endgroup\$
-2
\$\begingroup\$

Do not new MonoBehaviour just add them as components. Your approach won't work.

EDIT: I still advise you against breaking the component and Monobehaviour approach. If you want testing then have a look at the Unity Testing Tools. They will provide you with everything you need including mocks and stubs for unit and integration tests.

Asset Store

Documentation

\$\endgroup\$
2
  • 1
    \$\begingroup\$ I think you are confusing a collision with a collider. A collider is a component of a Monobehviour while a collision is : "information passed to Collider.OnCollisionEnter, Collider.OnCollisionStay and Collider.OnCollisionExit events." \$\endgroup\$ Dec 4, 2014 at 18:54
  • \$\begingroup\$ @CostelloNicho ah sorry, of course you are right! I actually confused them :( \$\endgroup\$
    – aggsol
    Dec 5, 2014 at 8:09

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .