Adventures in Unity3d 1: A simple event scheduling system and sound manager

Forget the cloth physics, kid

So I’m learning Unity and figured it couldn’t hurt to blog about my experiences while still fresh.

After doing a few of the sexy terrain and physics tutorials which instantly let me do amazing things with a few clicks, I realized I probably couldn’t even write tic tac toe.

OH YEAH?!  Be amazed:

[unity src=”1702″]

Fine, it sucks.  But that wasn’t the point, it forced me to come to grips with how objects, scripting and using classes together all worked in Unity and C#.

(And yes, the enemy “ai” is actually Board.GetRandomEmptyCell() … busted! )

Source is here as a zip.  (Requires Unity 4.3, despite the intense graphics it doesn’t require pro)

A common trait of programmer-centric devs is are constantly thinking about projects on a “shared” and “app specific” level.  They are organizing code into two places, with the more generic stuff meant to be reused.  We just can’t help it!  It’s why we always end up with engines and middleware.

So in case it’s useful to anybody else, here are some general utilities I wrote and an explanation of why they are useful.

You can download them as a unity package here:  rt.unitypackage (they are also in the tic tac toe source above)

RTAudioManager

I didn’t see a simple way to play a “crap.wav” filename from script (you have to create an object and attach a sound and ..) , so this is a very basic class that takes care of stuff like that.

You add an audio file under Assets/Resources (uncheck 3d sound source on the file in Unity – That one confused me, as there is no error, you just don’t hear anything…) and can play it from anywhere like this:

[code language=”csharp”]
//don’t add the .wav or .mp3 at the end, it’s automatic
RTAudioManager.Get().Play("scream");
[/code]

Or to get fancier:

[code language=”csharp”]
//Play at 1.0f volume and a pitch mod of 2 (twice as fast)
RTAudioManager.Get().PlayEx("scream", 1.0f, 2.0f);
[/code]

To play a song (will kill any current song playing)

[code language=”csharp”]
//plays mysong.ogg or mp3 etc at 1.0f volume and 1.0f pitch mod, looping
RTAudioManager.Get().PlayMusic("mysong", 1.0f, 1.0f, true);
[/code]

To set it up in a project is easy, just add RTAudioManager.cs to an empty GameObject somewhere.  (It will rename the gameobject RTAudioManager if it isn’t already)  It uses a singleton style .Get() to give the same instance to everybody.

RTEventManager

One of the first things I do in a new programming environment is figure out how to call any function in N seconds with any number of parms .

Even in the crappy Tic Tac Toe above, the difference between everything happening at once and instead using subtle delays (for instance, a delay before the AI moves) makes a huge difference.

If interesting timing is simple to add and tweak in your game, you’re much more like to do it, if you’re as lazy as I am.

Coroutines and other schedulers I found didn’t quite fit my requirements.. plus, I like to waste time re-inventing everything anyway!

Same as RTAudioManager, to set it up you just add it to an empty GameObject in your scene.  There is no other setup needed to just start using it.

It uses SendMessage internally and things it sends to must have a unique GameObject name.

Let’s say you want to use the above RTAudioManager to play “pain”(.wav) in 1 second instead of instantly.  No need to build a special timer, just use RTEventManager like this:

[code language=”csharp”]
//schedule the function "Play" to be called in one second, sending a string variable to it.
RTEventManager.Get().Schedule(RTAudioManager.GetName(), "Play", 1.0f, "pain");
[/code]

It’s a little ugly, but not too bad to understand.  The .GetName() is just a function I added to the RTAudioManager class to make it easy to get the GameObject name its attached to, but a string of “RTAudioManager” would have worked just as well, you just have to be sure you know what stuff is named.

Want to call a function called Respawn that is in an attached script on your player GameObject (which is named “Player”) in 5 seconds with no parms?

[code language=”csharp”]
//note that you don’t have to send that extra parm
RTEventManager.Get().Schedule("Player", "Respawn", 5.0);
[/code]

But what about RTAudioManager.Get().PlayEx(“fileName”, 1.0f, 2.0f);  from above? What if we want that to happen in 5 seconds?  That needs three parms, how can we schedule that?

Well, I couldn’t figure out a great way, but because the scheduler’s single parm can be of any object type we can work around the problem.  One way would be to send a custom class, but I’m far too lazy to be creating classes everywhere so here’s what I came up with instead:

[code language=”csharp”]
//will play in 5 seconds
RTEventManager.Get().Schedule(RTAudioManager.GetName(),
"PlayEx",  5.0f, new RTDB("fileName", "scream",
"volume", 1.0f, "pitch", 2.0f));
[/code]

What’s going on here?  RTDB is a simple database key/value (which can be any object type) system that can be created and sent inline with a flexible number of parms.  Key “fileName” is a string, key “volume” is a float and so on.

Unfortunately, when doing this, the receiving end must expect what is coming and know the keyname(s) to extract the data.  RTAudioManager’s code to receive it looks like this:

[code language=”csharp”]
public void PlayEx(RTDB db)
{
PlayEx(db.GetString("fileName"),</pre>
db.GetFloatWithDefault("volume", 1.0f),
db.GetFloatWithDefault("pitch", 1.0f)
);
}
[/code]

It’s just a front end for calling the real function.  It will warn if sent the wrong type.  If a parm is left out, it will use a default value so it still works. (filename is the only thing absolutely required)

On the bright side, you can easily add support for more parameters without breaking backwards compatibility in places you’ve already used it.

Speed considerations

Now, you may be worried about the costs of using SendMessage internally, the name lookups, and inline initializing and usage of RTDB and the like.  Well, unless you’re sending 25+ messages a second I wouldn’t worry about it.  It’s mostly for controlling program flow and timing, if you’re sending 1000 messages a frame (for instance, trying to control a sprites x/y animation with it)  it’s definitely the wrong tool for the job.

One click build and upload

Oh, also included in the zip above is a windows .bat file that builds and uploads the web version of the game.  You’d have to edit it a bit, but here it is:

[code language=”csharp”]
call app_info_setup.bat
REM get our ftp logon info
call d:\projects\SetFTPLogonInfoTanked.bat

:Actually do the unity build
rmdir build\web /S /Q
mkdir build\web

echo Building project…
%UNITY_EXE% -quit -batchmode -buildWebPlayer build/web .
echo Finished building.

rmdir temp /S /Q
mkdir temp
mkdir temp\%FILENAME%

xcopy build\web temp\%FILENAME%\ /E /F /Y

rename temp\%FILENAME%\web.html index.html

if not exist temp\%FILENAME%\index.html beeper.exe /p
if not exist temp\%FILENAME%\web.unity3d beeper.exe /p

ncftpput -u %_FTP_USER_% -p %_FTP_PASS_% -R %_FTP_SITE_% /www/ temp\*

echo File uploaded: http://www.%_FTP_SITE_%/%FILENAME%

:Let’s go ahead an open a browser to test it
start http://www.%_FTP_SITE_%/%FILENAME%
pause
[/code]

It requires ncftp to be installed.

Oh, app_info_setup.bat sets the app name, but it also would need to setup the ftp site and password data. Basically you need this somewhere, could even cut and paste it to the top of the .bat:

[code]
SET FILENAME=breakout
SET UNITY_EXE=A:\pro\Unity\Unity.exe
SET _FTP_SITE_=mydomainname.com
SET _FTP_USER_=username
SET _FTP_PASS_=mypassword
[/code]

Breakout test

To get slightly more graphical, here’s a “throwaway breakout” I whipped up (using the old 3d physics, not the new box2d stuff)  (Maximize to look slightly less ass, use arrow keys to control):

[unity src=”1711″]

Was watching the Unite keynote (woah, Richard Garriott!)  and believe I heard that 10% of all downloads happening on iOS are now Unity based.  That’s just.. wow.

Why Unity and C#?  Aren’t you that hardcore C++ guy who made Proton SDK?

Yeah, but that doesn’t mean I have to use C++ for everything.  I still use Proton (ahem, Growtopia) and it’s my go-to weapon if I have to port an existing C++ product to mobile. (as with Dink Smallwood)

But let’s face it, supporting the newer graphic technologies on the plethora of platforms and graphics chips out there is a losing battle for a one-person developer.  Especially if I’d like to actually make games too.

(Note: Others are still adding new features such as GLES2 support  to Proton in separate distributions, which is fine with me)

One thought on “Adventures in Unity3d 1: A simple event scheduling system and sound manager

  1. Zaxuhe

    Hey Seth, thank you for the post, just wanted to clarify about the 3d sound source, you set a position to it and if the camera is within a radius you will listen to it (with less strength if you are far from it), it is there to add audio effects to objects and listen to them only if you are near enough

Leave a Reply

Your email address will not be published. Required fields are marked *