Alpha Accesswebsite_badges_steamwishlistwebsite_badges_steamwishlist

Archive

Simple behaviors with delegates and events


miniSkullI have a “Mortality” behavior that I can attach to any game object that has health and can die. This is pretty generic, so this means it can refer to a player or character, but also to destructible objects in the scene, such as barrels and plants. As I’m still learning best practices for accomplishing specific tasks in Unity, I’d like to share my approach to this behavior. Note that this is a simplified version that you can extend to meet your needs.

The main Mortality.cs script has some variables you would expect: health (int), dead (bool), etc. The key item to note here is the use of delegates and events. By declaring delegate and event combinations (such as OnDeathEvent() and OnDeath), other objects that have this Mortality behavior can register functions to be called when these events occur. The nice thing is that this is a collection, so you can add any number of functions as listeners to these events – not just one. You just have to remember to deregister the functions when the containing object is disabled or destroyed.

using UnityEngine;
using System.Collections;

public class Mortality : MonoBehaviour
{
	public int initialHealth = 5;
	public int health { get; private set; }

	// events
	public delegate void OnDeathEvent();
	public event OnDeathEvent OnDeath = delegate {};
	public delegate void OnReviveEvent();
	public event OnReviveEvent OnRevive = delegate {};
	public delegate void OnHealthDownEvent();
	public event OnHealthDownEvent OnHealthDown = delegate {};

	void Start()
	{
		// init
		Revive();
	}

	public void Revive()
	{
		health = initialHealth;
		dead = (health <= 0);
		OnRevive();
	}

	public void DecrementHealth(int amount)
	{
		health -= amount;
		OnHealthDown();

		if (health <= 0 && !dead)
		{
			dead = true;
			OnDeath();
		}
	}
}

For example, let’s say you have a Barrel.cs behavior attached to a destructible barrel game object. If you attach the Mortality.cs script to it above, then you can handle specific health and death events on the barrel like so:

using UnityEngine;
using System.Collections;

public class Barrel : MonoBehaviour 
{
	private Mortality mortality;

	void Awake()
	{
	    // store a reference to the mortality component
		mortality = GetComponent<Mortality>();
	}

	void OnEnable()
	{
	    // register this class' OnDeath() function
		mortality.OnDeath += OnDeath;
	}

	void OnDisable()
	{
	    // deregister this class' OnDeath() function
		mortality.OnDeath -= OnDeath;
	}

	void OnDeath()
	{
		// perform your specific logic here when this game object "dies"
	}
}

Better parabolic motion for bounces


bouncingDebris2.gif.32

In a previous post, I detailed a methods of using tweens to give explosion debris some bounce and life. I knew at the time that this would be expensive for a large number of particles – but it was the right look and I at least wanted the temporary solution in the game. Consider it a living mockup, waiting to be optimized.

Recently I came across this post on gamasutra by Mohan Rajagopalan describing design philosophies and techniques behind 2D jumps. Sure enough, the parabolic arc equation was exactly what I needed for my debris bounce, which could be considered debris “jumping.” Here’s the classic formula:

y(t) = v_0 + \frac{gt^2}{2}

The implementation of this as a Unity component is quite straightforward , and here’s a simple version of the Update() function of the behavior:

public void Bounce(int numberOfBounces)
{
	// init
	startTime = Time.time;
	lastYOffset = 0.0f;
	bounceNumber = numberOfBounces;
	bounceVelocity *= 0.5f;
}

void Update()
{
	// if done with bounces, stop
	if (bounceNumber <= 0)
	{
		return;
	}

	// otherwise, calculate current yoffset
	if (bounceNumber > 0)
	{
		// apply classic parabolic formula: h(t) = vt + (gt^2 / 2)
		float time = (Time.time - startTime);
		yOffset = (bounceVelocity * time) + ((gravity * time * time) / 2);
		
		// add to the current position, but subtract last y offset (additive behavior)
		// since this could be moving in the y-axis from other forces as well
		transform.position = new Vector3
		(
			transform.position.x,
			transform.position.y + yOffset - lastYOffset,
			transform.position.z
		);
		lastYOffset = yOffset;

		// if hitting the "floor", bounce again
		if (yOffset <= 0f)
		{
			BounceTimes(bounceNumber - 1);
		}
	}
}

One thing to note is that I subtract the previously calculated y-offset since I am adding the new y-offset to the current position each update. This allows this parabolic offset to be additive to any other motion the game object is already undergoing. This is perfect in my case, since the debris is being ejected by an explosive force, and I am just adding this to the y-axis to simulate bouncing in overhead 2D space. As stated in the original post, the root of all this is the simple fact that Unity doesn’t allow gravity in the z-axis for 2D projects.

©2017 Sombr Studio LLC