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\$
  • \$\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\$ – Chris McFarland Dec 2 '14 at 22:43
  • \$\begingroup\$ Am I missing something? Why not use AddComponent? \$\endgroup\$ – Ben Dec 3 '14 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\$ – CostelloNicho Dec 3 '14 at 18:27
  • \$\begingroup\$ @CostelloNicho Did you try Unity testing Tools? See my revised answer. \$\endgroup\$ – aggsol Dec 4 '14 at 7:57
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\$
  • 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\$ – CostelloNicho Dec 4 '14 at 18:54
  • \$\begingroup\$ @CostelloNicho ah sorry, of course you are right! I actually confused them :( \$\endgroup\$ – aggsol Dec 5 '14 at 8:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.