Posts Tagged C#

Timer Manager for Unity3D

It’s been a nearly a month since my last blog entry. Typically people disappear for long periods of time because they’ve either just begun a romantic charade or they just became insanely busy with work. Well in my case, I’m already happily married with a sweet little daughter so it’s clearly a work issue. If you haven’t guessed it yet from this site, I’m actually starting a new company named Monkey Prism. At Monkey Prism we’re in the midst of an up and coming Unity 3D iOS release. During our development cycle we were in need of a basic timer object. This example really serves as an object to learn from on how to use Time.time in your code to create a basic timer. Feel free to use this code in anyway that you like!

Here is how you call this MPTimer object.
Example 1

View Code CSHARP
//Example 1:
private MPTimer monkeyPrismTimer;
 
void Start() {
   /*
   Creates a timer object that will wait 5 seconds before calling 
   the ToggleExample method.  The false flag signifies that this object
   will not start the timer until the 
      monkeyPrismTimer.Active = true;
   has been set.
   */
   monkeyPrismTimer = new MPTimer(
      new MPTimerObject(gameObject, "ToggleExample", 5.0f), false);
}
 
public void ToggleExample() {
   Debug.Log("ToggleExample() called!");
}
 
void Update() {
   //daisy chain the timer running.  Every time it inactivates, we'll re-activate it.
   if (!monkeyPrismTimer.Active) {
      Debug.Log("Enabling the timer!");
      monkeyPrismTimer.Active = true;
   }
 
   //drive the timer
   monkeyPrismTimer.DoTimer();
}

Example 2 (auto-start the timer)

View Code CSHARP
private MPTimer monkeyPrismTimer;
 
void Start() {
   //create a 3 second timer that repeats 10 times.
   MPTimerObject mpTimerObject = new MPTimerObject(gameObject, "ToggleExample", 3.0f);
   mpTimerObject.repeatCount = 10;  // repeat it 10 times.
 
   //creates a timer object without auto-starting it.
   monkeyPrismTimer = new MPTimer(mpTimerObject, true);
}
 
public void ToggleExample() {
   Debug.Log("ToggleExample() called!");
}
 
void Update() {
   //drive the timer
   monkeyPrismTimer.DoTimer();
}

The file on my system is named: “MPTimer.cs“. Here it is! The meat and potatoes we’ve been talking about!

Download MPTimer.cs
using System;
using UnityEngine;
 
/// <summary>
/// A timer object that will be passed into the MPTimer class.
/// </summary>
public class MPTimerObject
{
	/// <summary>
	/// The target GameObject that contains the onCompleteMethod specified.
	/// </summary>
	public GameObject target;
	/// <summary>
	/// A string representing the method to call when the timer expires.
	/// </summary>
	public String onCompleteMethod;
	/// <summary>
	/// A float value in seconds representing how often you would like the timer to trigger.
	/// </summary>
	public float runForSeconds;
	/// <summary>
	/// An integer value representing the number of times you would like this timer to trigger before becoming inactive.
	/// </summary>
	public int repeatCount;
 
	public MPTimerObject() { }
 
	/// <summary>
	/// Creates a basic Monkey Prism timer object.
	/// </summary>
	/// <param name="targetCompleteMethodObject">
	/// A <see cref="GameObject"/> that is the targeted object that contains the "completeMethod" string parameter.
	/// </param>
	/// <param name="completeMethod">
	/// A <see cref="String"/> representing a method named contained within the GameObject specified.  Example:  "myMethod"
	/// </param>
	/// <param name="triggerTime">
	/// A <see cref="System.Single"/> float value in seconds.  5.0f would be 5 seconds.  This tells the timer to trigger in 5 seconds.
	/// </param>
	public MPTimerObject(GameObject targetCompleteMethodObject, String completeMethod, float triggerTime)
	{
		Init(targetCompleteMethodObject, completeMethod, triggerTime, 1);
	}
 
	private void Init(GameObject targetCompleteMethodObject, String completeMethod, float runForSeconds, int repeatCount)
	{
		this.target = targetCompleteMethodObject;
		onCompleteMethod = completeMethod;
		this.runForSeconds = runForSeconds;
		this.repeatCount = repeatCount;
	}
}
 
/// <summary>
/// A Monkey Prism timer object that allows for a user to trigger a method based on a time specified.
/// </summary>
public class MPTimer
{
	private MPTimerObject timerObject;
	private float startTime;
	private float endTime;
	private bool active;
	private int count;
 
	/// <summary>
	/// Create a new MPTimer object.
	/// </summary>
	/// <param name="mpTimerObject">
	/// A <see cref="MPTimerObject"/>
	/// </param>
	public MPTimer(MPTimerObject mpTimerObject)
	{
		Init(mpTimerObject, true);
	}
 
	/// <summary>
	/// Create a new MPTimer object.
	/// </summary>
	/// <param name="mpTimerObject">
	/// A <see cref="MPTimerObject"/>
	/// </param>
	/// <param name="activeState">
	/// A <see cref="System.Boolean"/> representing whether to start the timer immediately or to wait.  If true, the timer will kick-off immediately.
	/// </param>
	public MPTimer(MPTimerObject mpTimerObject, bool activeState)
	{
		Init(mpTimerObject, activeState);
	}
 
	private void Init(MPTimerObject mpTimerObject, bool activeState)
	{
		if (mpTimerObject == null || 
		    mpTimerObject.onCompleteMethod == null || mpTimerObject.target == null) {
			Debug.LogError("MPTimer Error: Invalid MPTimerObject specified.");
		}
		timerObject = mpTimerObject;
		Active = activeState;
	}
 
	/// <summary>
	/// The MPTimerObject get/set helper.  Setting a new timer object will inactivate the current timer.
	/// </summary>
	public MPTimerObject TimerObject
	{
		get { return timerObject; }
		set {
			active = false;
			timerObject = value;
		}
	}
 
	/// <summary>
	/// The Active get/set helper.  By setting this to "Active" you will instantly cause this method to be called.
	/// </summary>
	public bool Active
	{
		get { return active; }
		set { 
			if (value != active) 
				count = 0;
			active = value; 
			if (active) {
				startTime = Time.time;
				endTime = startTime + timerObject.runForSeconds;
				//Debug.Log("Start= " + startTime + ", End= " + endTime);
			}
		}
	}
 
	/// <summary>
	/// A method used for the "Update" call in your calling library.  If this method is not called, the timer is not automatically driven.
	/// </summary>
	public void DoTimer()
	{
		if (!active) return;
 
		if (Time.time >= endTime) {
			//Debug.Log("timer fired!");
			timerObject.target.SendMessage(timerObject.onCompleteMethod);
			if (++count >= timerObject.repeatCount)
				active = false; //toggle off.
		}
	}
}

, , , , ,

No Comments

Unity 3D JavaScript and C# Scoping/Compiling Issue

This is a quick write-up regarding something as simple as getting JavaScript to interoperate properly with C# scripts in your Unity projects.

I ran into such an issue after purchasing EZ Gui via the Unity Asset Store.  Immediately upon purchasing you are prompted to “import” the project into your codebase.  I did this without issue.  Everything worked fine and dandy until my JavaScript code required referencing a SpriteText object.  This is when the following issue began happening:

Unity BCE0018: The name ‘SpriteText’ does not denote a valid type (‘not found’).

My folder structure was simply the following:

/scripts/myCameraScript.js  <– trying to reference the SpriteText

 

View Code JAVASCRIPT
var test : SpriteText;  //this line was throwing the error.

 

/EZ GUI/ <– default after purchasing and importing from the Unity Asset store.

I sat and read Unity compiling and scoping rules over and over located here.  On point 4, the statement reads “All scripts that are compiled in this step have access to all scripts in the first group (“Standard Assets”, “Pro Standard Assets” or “Plugins”).”

The solution is simple here. Take the EZ Gui code located in the “Plugins” folder and move it to the root.

/EZ Gui/Plugins/ <– move this to:

/Plugins/

Done. It works. Super simple.

Bonus Play, Rule of thumb (kind of no brainers really):

  1. Place all your plugins in the /Plugins/ folder.
  2. Place all your C# Code into the /Standard Assets/ folder.
  3. Place all your JavaScript code into /Scripts/ or any folder that is NOT named (“Standard Assets”, “Pro Standard Assets” or “Plugins”)

This will lead to success and less headaches.

, , , , ,

No Comments

.Net C Sharp Date Range Check Method

This function is a trivial example of how to do a basic date range check in .Net. I do a few silly conversions from string to timestamp only to serve as an example.

View Code CSHARP
/*
Assumes the local culture.  
Does a check to see if the current time is within the range 
  of 7 AM and 1 PM.  If so, returns true.
*/
if (IsCurrentDateInRange("7:00", "13:00")) {
   //The current date is in range.
} else {
  //The current date is out of range.
}
View Code CSHARP
using System;
/*
startTime should be in the format HH:mm such as 09:45
endTime should be in the format HH:mm such as 18:45
The culture is assumed to be the local one which can be 
troubling in applications that extend themselves internationally.
*/
public bool IsCurrentDateInRange(string startTime, string endTime) {
  DateTime dtNow = DateTime.Now;
  DateTime dtStart, dtEnd;
  int hour = 0, minute = 0;
 
  string[] strDt = startTime.Split(new char[] { ':' });
  if (strDt.Length > 1)
  {
     Int32.TryParse(strDt[0], out hour);
     Int32.TryParse(strDt[1], out minute);
 
     dtStart = new DateTime(dtNow.Year, dtNow.Month, dtNow.Day, hour, minute, 0);
  }
  else
  {
     //TODO: log an error in formatting.
     return false;
  }               
 
  strDt = endTime.Split(new char[] { ':' });
  if (strDt.Length > 1)
  {
     hour = minute = 0;
     Int32.TryParse(strDt[0], out hour);
     Int32.TryParse(strDt[1], out minute);
 
     dtEnd = new DateTime(dtNow.Year, dtNow.Month, dtNow.Day, hour, minute, 0);
  }
  else
  {
     //TODO: log an error in formatting.
    return false;
  }
 
  TimeSpan tsEndDiff = dtEnd - dtNow;
  TimeSpan tsStartDiff = dtNow - dtStart;
  if (tsStartDiff.TotalSeconds >= 0 && tsEndDiff.TotalSeconds >= 0)
  {
     return true;
  }
  else 
     return false;
}

, , ,

No Comments