Skip to content

Commit

Permalink
feat(Collision): add proxy emitter for CollisionNotifier
Browse files Browse the repository at this point in the history
The CollisionNotifierEventProxyEmitter allows chaining together events
that emit CollisionNotifier EventData.

It's possible to restrict the proxy event based on either the forward
source of the event data or the collision source.
  • Loading branch information
thestonefox committed Apr 14, 2019
1 parent ca0c42c commit 6019a82
Show file tree
Hide file tree
Showing 8 changed files with 320 additions and 0 deletions.
8 changes: 8 additions & 0 deletions Runtime/Tracking/Collision/Event.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Runtime/Tracking/Collision/Event/Proxy.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

@@ -0,0 +1,60 @@
namespace Zinnia.Tracking.Collision.Event.Proxy
{
using UnityEngine;
using UnityEngine.Events;
using System;
using Malimbe.XmlDocumentationAttribute;
using Malimbe.PropertySerializationAttribute;
using Zinnia.Extension;
using Zinnia.Event.Proxy;

/// <summary>
/// Emits a UnityEvent with a <see cref="ActiveCollisionsContainer.EventData"/> payload whenever <see cref="SingleEventProxyEmitter{TValue,TEvent}.Receive"/> is called.
/// </summary>
public class CollisionNotifierEventProxyEmitter : RestrictableSingleEventProxyEmitter<CollisionNotifier.EventData, CollisionNotifierEventProxyEmitter.UnityEvent>
{
/// <summary>
/// The types of <see cref="GameObject"/> that can be used for the rule source.
/// </summary>
public enum RuleSourceType
{
/// <summary>
/// Use the <see cref="CollisionNotifier.EventData.ForwardSource"/> for the rule.
/// </summary>
ForwardSource,
/// <summary>
/// Use the <see cref="CollisionNotifier.EventData.ColliderData"/> containing <see cref="Transform"/> for the rule.
/// </summary>
CollidingSource
}

/// <summary>
/// The source <see cref="GameObject"/> to apply to the <see cref="RestrictableSingleEventProxyEmitter.ReceiveValidity"/>.
/// </summary>
[Serialized]
[field: DocumentedByXml]
public RuleSourceType RuleSource { get; set; }

/// <summary>
/// Defines the event with the specified state.
/// </summary>
[Serializable]
public class UnityEvent : UnityEvent<CollisionNotifier.EventData>
{
}

/// <inheritdoc />
protected override object GetTargetToCheck()
{
switch (RuleSource)
{
case RuleSourceType.ForwardSource:
return Payload.ForwardSource.gameObject;
case RuleSourceType.CollidingSource:
Transform containingTransform = Payload.ColliderData.GetContainingTransform();
return containingTransform != null ? containingTransform.gameObject : null;
}
return null;
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Tests/Editor/Tracking/Collision/Event.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Tests/Editor/Tracking/Collision/Event/Proxy.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

@@ -0,0 +1,206 @@
using Zinnia.Tracking.Collision.Event.Proxy;
using Zinnia.Rule;
using Zinnia.Tracking.Collision;
using Zinnia.Data.Collection.List;

namespace Test.Zinnia.Tracking.Collision.Event.Proxy
{
using UnityEngine;
using NUnit.Framework;
using Test.Zinnia.Utility.Mock;

public class CollisionNotifierEventProxyEmitterTest
{
private GameObject containingObject;
private CollisionNotifierEventProxyEmitter subject;

[SetUp]
public void SetUp()
{
containingObject = new GameObject();
subject = containingObject.AddComponent<CollisionNotifierEventProxyEmitter>();
}

[TearDown]
public void TearDown()
{
Object.DestroyImmediate(containingObject);
}

[Test]
public void Receive()
{
GameObject forwardSource = new GameObject();
GameObject collisionSource = new GameObject();
Collider collider = collisionSource.AddComponent<BoxCollider>();

UnityEventListenerMock emittedMock = new UnityEventListenerMock();
subject.Emitted.AddListener(emittedMock.Listen);

CollisionNotifier.EventData digest = new CollisionNotifier.EventData();
digest.Set(forwardSource.GetComponent<Component>(), true, null, collider);

Assert.IsNull(subject.Payload);
Assert.IsFalse(emittedMock.Received);

subject.Receive(digest);

Assert.AreEqual(digest, subject.Payload);
Assert.IsTrue(emittedMock.Received);

Object.DestroyImmediate(forwardSource);
Object.DestroyImmediate(collisionSource);
}

[Test]
public void ReceiveWithRuleRestrictionsOnForwardSource()
{
GameObject forwardSourceValid = new GameObject();
GameObject forwardSourceInvalid = new GameObject();
GameObject collisionSource = new GameObject();
Collider collider = collisionSource.AddComponent<BoxCollider>();

ListContainsRule rule = subject.gameObject.AddComponent<ListContainsRule>();
UnityObjectObservableList objects = containingObject.AddComponent<UnityObjectObservableList>();
rule.Objects = objects;

objects.Add(forwardSourceValid);
subject.ReceiveValidity = new RuleContainer
{
Interface = rule
};

subject.RuleSource = CollisionNotifierEventProxyEmitter.RuleSourceType.ForwardSource;

UnityEventListenerMock emittedMock = new UnityEventListenerMock();
subject.Emitted.AddListener(emittedMock.Listen);

CollisionNotifier.EventData validDigest = new CollisionNotifier.EventData();
validDigest.Set(forwardSourceValid.GetComponent<Component>(), true, null, collider);
CollisionNotifier.EventData invalidDigest = new CollisionNotifier.EventData();
invalidDigest.Set(forwardSourceInvalid.GetComponent<Component>(), true, null, collider);

Assert.IsNull(subject.Payload);
Assert.IsFalse(emittedMock.Received);

subject.Receive(validDigest);

Assert.AreEqual(validDigest, subject.Payload);
Assert.IsTrue(emittedMock.Received);

emittedMock.Reset();

subject.Receive(invalidDigest);

Assert.AreEqual(validDigest, subject.Payload);
Assert.IsFalse(emittedMock.Received);

Object.DestroyImmediate(forwardSourceValid);
Object.DestroyImmediate(forwardSourceInvalid);
Object.DestroyImmediate(collisionSource);
}

[Test]
public void ReceiveWithRuleRestrictionsOnCollisionSource()
{
GameObject forwardSource = new GameObject();
GameObject collisionSourceValid = new GameObject();
Collider colliderValid = collisionSourceValid.AddComponent<BoxCollider>();
GameObject collisionSourceInvalid = new GameObject();
Collider colliderInvalid = collisionSourceInvalid.AddComponent<BoxCollider>();

ListContainsRule rule = subject.gameObject.AddComponent<ListContainsRule>();
UnityObjectObservableList objects = containingObject.AddComponent<UnityObjectObservableList>();
rule.Objects = objects;

objects.Add(collisionSourceValid);
subject.ReceiveValidity = new RuleContainer
{
Interface = rule
};

subject.RuleSource = CollisionNotifierEventProxyEmitter.RuleSourceType.CollidingSource;

UnityEventListenerMock emittedMock = new UnityEventListenerMock();
subject.Emitted.AddListener(emittedMock.Listen);

CollisionNotifier.EventData validDigest = new CollisionNotifier.EventData();
validDigest.Set(forwardSource.GetComponent<Component>(), true, null, colliderValid);
CollisionNotifier.EventData invalidDigest = new CollisionNotifier.EventData();
invalidDigest.Set(forwardSource.GetComponent<Component>(), true, null, colliderInvalid);

Assert.IsNull(subject.Payload);
Assert.IsFalse(emittedMock.Received);

subject.Receive(validDigest);

Assert.AreEqual(validDigest, subject.Payload);
Assert.IsTrue(emittedMock.Received);

emittedMock.Reset();

subject.Receive(invalidDigest);

Assert.AreEqual(validDigest, subject.Payload);
Assert.IsFalse(emittedMock.Received);

Object.DestroyImmediate(forwardSource);
Object.DestroyImmediate(collisionSourceValid);
Object.DestroyImmediate(collisionSourceInvalid);
}

[Test]
public void ReceiveInactiveGameObject()
{
GameObject forwardSource = new GameObject();
GameObject collisionSource = new GameObject();
Collider collider = collisionSource.AddComponent<BoxCollider>();

UnityEventListenerMock emittedMock = new UnityEventListenerMock();
subject.Emitted.AddListener(emittedMock.Listen);

CollisionNotifier.EventData digest = new CollisionNotifier.EventData();
digest.Set(forwardSource.GetComponent<Component>(), true, null, collider);

subject.gameObject.SetActive(false);

Assert.IsNull(subject.Payload);
Assert.IsFalse(emittedMock.Received);

subject.Receive(digest);

Assert.IsNull(subject.Payload);
Assert.IsFalse(emittedMock.Received);

Object.DestroyImmediate(forwardSource);
Object.DestroyImmediate(collisionSource);
}

[Test]
public void ReceiveInactiveComponent()
{
GameObject forwardSource = new GameObject();
GameObject collisionSource = new GameObject();
Collider collider = collisionSource.AddComponent<BoxCollider>();

UnityEventListenerMock emittedMock = new UnityEventListenerMock();
subject.Emitted.AddListener(emittedMock.Listen);

CollisionNotifier.EventData digest = new CollisionNotifier.EventData();
digest.Set(forwardSource.GetComponent<Component>(), true, null, collider);

subject.enabled = false;

Assert.IsNull(subject.Payload);
Assert.IsFalse(emittedMock.Received);

subject.Receive(digest);

Assert.IsNull(subject.Payload);
Assert.IsFalse(emittedMock.Received);

Object.DestroyImmediate(forwardSource);
Object.DestroyImmediate(collisionSource);
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 6019a82

Please sign in to comment.