How do you like to organize your games?

Originally my team used MVC (Model-View-Controller) because we didn’t know any better. For our current project we’ve arranged our scenes like this:

“SceneController” game object contains all objects in the scene that might need to know that the scene has started or stopped or whatever. That allows the “SceneController” to use BroadcastMessage to communicate with all of them.

Each other game object (like an enemy or health pickup) has a lot of independent scripts attached to it, and a few that work in groups. Each attached script controls a different aspect of the game object. For example, if it’s an enemy, one controls the movement, one controls shooting, one controls health level, etc. They talk to each other via BroadcastMessage when necessary.

What are your thoughts on this kind of organization? What do you use? Are there best practices?

Two more things I just remembered:

We have a DontDestroyOnLoad “GameController” game object that persists from scene to scene, loading scenes, keeping track of scores stats, and things like that.

And when an effect happens to a game object – for example an enemy catches fire briefly – we instantiate a prefab that will handle all the effects (lowering health, showing the flames, etc.), parent it to the affected game object (the enemy), and give it a reference to the parent. It executes its effects on the parent via BroadcastMessage. When it is done, it destroys itself.

Really? No replies? Maybe I should have asked this in Gossip.

I personally would favor more robust classes, and would call functions directly with references cached in start() instead of relying on messaging. That is a function of how long the object is going to stay around and how often the messages will be sent.

It’s really just understanding that neither findObject or SendMessage scale vertically at all. Or more generally that convenience usually doesn’t equate to performance.

There are no real best practices. It’s what suits the developer and the particular problem.

Take your “scene controller” for example. Some sort of game manager singleton that provides global storage and drives your game’s state machine is a common solution.

There however are a myriad of ways to implement it. Don’t destroy on load in a non reentrant scene such as a splash screen is just one. There are more programmatic solutions to singletons presented on the forums and on the wiki.

Relax Bret, you’re doing fine!

Thanks Quietus. I’m just interested in others’ approaches, since we’re kind of working in a vacuum here (and just making it up as we go).

I’m not sure what “scale vertically” means. I know that we did performance tests before starting to use BroadcastMessage. Even thousands of calls take nearly no time. Previously we’d kept instances of other scripts and called them directly, but there was no performance difference between than and BroadcastMessage. (That was pretty surprising!)

Again, anyone else who wants to chime in – even with bad or newbie examples of organization – is encouraged to post!

I wonder what sort of method you used to time that, since tests I’ve done before showed that, in artificial situations where you’re doing nothing else, SendMessage is up to hundreds of times slower than direct calling from a cached GetComponent. That doesn’t mean I never use SendMessage, because in real-world cases the difference can matter little or not at all, and it’s very useful and convenient in some situations. Especially on the desktop where you have far greater performance than mobile devices. But I wouldn’t use it in cases where performance really matters, if there’s an alternative that’s not too messy.

–Eric

Thanks Eric5h5. I’ll test it again and (if I remember) tell you what I find in the morning. BTW, you’re saying “SendMessage” and I’m saying “BroadcastMessage”, but I’m pretty sure we’re talking about the same thing.

Yeah, any of the Message functions. They have to search through a given number of objects, whereas a cached GetComponent is direct and requires no searching. (Even uncached GetComponent isn’t bad.)

–Eric

Yay! :~)
I didn’t take speed issues into consideration so far because a) I’m a newbie and b) I’m using a modern physics engine to create yet another clone of a game that celebrates it’s 25th anniversary this year, which is absurd enough as it is. I too have a central object called GameInfo that has all the top-level components needed to set the game up, shut it down, handle the gui and manage levels. My levels are just prefabs with all the geometry and entities attached as children. When I want to switch levels I tell the current level instance to unload itself and then instantiate the new one. I only built a small simple test level and didn’t have any problems with the approach so far.
When it comes to communication between objects/components I take care that it works ad-hoc and I don’t need to hard-wire much if anything. If I can’t work with in-inspector assigned references or something relatively safe like Camera.main I use my MessageCentre class, which works a bit like newgroups/email. A component can leave a message(sender, data, recipent) on a previously registered channel and other objects can fetch it later (in LateUpdate). If no recipent is given, it’s first come first serve, otherwise only the recipent can pick it up. That way components can set up ad-hoc communication like so:

  • LeaveMessage(MSGC_Instances): Hi all. I’m a spawn point instance! Would anybody like to know about the instances I’m going to spawn?
  • Reply(SpawnPoint-Instance): Hello spawn point, I’m a level instance. It is my job to destroy the instances when I have to unload myself, so please let me know what you’re doing.
  • Reply(Level-Instance): Okay!
    This is probably total overkill for a little newbie project, but I feel a lot better about the project since I implemented it because it’s a bit easier to find my own stupid newbish bugs when I can monitor all traffic by the click of a button.

You are not a noob, a messaging paradigm can be very useful. The guys at FlashBang have a very nice tutorial on it and there are a few additional examples of message classes on the wiki.

There won’t be any problem if you use messages for isolated events such as “I am destroying myself” or “Scored goal.” Nobody is saying you should never use sendmessage.

What will kill you is using it inside game loops. Keep them away from Update().

It’s no different than the various incarnations of find in the Unity api. I call them all the time, but if I were to call them within each object’s Update() instead of caching the results my game would grind to a halt.

What the Cthulhu dude said.

–Eric

Okay maybe I’m not a newbie but it seems to me that I’m utterly misguided at times :~)

That’s why I love that messaging system. By the time the first updates are called the communication partners could already have agreed upon using callback until they say otherwise.

BroadcastMessage appears quicker than a direct reference to a script function! (Unless I’m doing it wrong.) Here’s how I did my test:

Create an empty GameObject. Name it “ParentObject”.

Create another empty GameObject. Name it “ChildObject”.

In the Hierarchy, put ChildObject inside ParentObject.

Create a new Javascript named ParentScript.

Paste this script into ParentScript and resave it:

public var go_child_object : GameObject;

function Start () {
	var fl_time : float;
	var i_counter : int;
	var i_counter_max : int = 1000000;
	var sc_script;
	
	//Script reference
	sc_script = go_child_object.GetComponent("ChildScript");
	
	//Test BroadcastMessage
	fl_time = Time.realtimeSinceStartup;
	for (i_counter = 0; i_counter < i_counter_max; i_counter++) {
		BroadcastMessage("doTest", null);
	}
	Debug.Log ("BroadcastMessage took " + (Time.realtimeSinceStartup - fl_time) + " seconds");
	
	//Test direct script reference
	fl_time = Time.realtimeSinceStartup;
	for (i_counter = 0; i_counter < i_counter_max; i_counter++) {
		sc_script.doTest();
	}
	Debug.Log ("Direct reference took " + (Time.realtimeSinceStartup - fl_time) + " seconds");

}

Attach ParentScript to ParentObject.

Create another Javascript named ChildScript.

Paste this script into ChildScript and resave it:

public function doTest() {
	var i_test : int;
	i_test = 1.24124 * 0.92352; //just so this function has something to do....
}

Attach ChildScript to ChildObject.

In the Hierarchy, select ParentObject.

Drag ChildObject into the Inspector Variable go_child_object.

Run the scene.

For me, BroadcastMessage took 0.955 seconds, whereas the direct reference took 1.388 seconds. What speeds do you get?

Well, you’re testing how much slower dynamic typing is compared to static typing. :wink:

Change this:

var sc_script;

To this:

var sc_script : ChildScript;

Then re-run the test and see what sort of speed you get. (And try running it with the code removed from the “doTest” function, so you’re only timing the function call itself and not the math inside the function.) Also, this:

sc_script = go_child_object.GetComponent("ChildScript");

Should normally be this:

sc_script = go_child_object.GetComponent(ChildScript);

Not that it would make any difference in this case, but using string lookups is slower than using the type, aside from the fact that you get run-time errors with a string lookup vs compile-time errors with the type.

–Eric

Thanks Eric5h5! That makes a major difference. Now, 1 million “direct references” take only 0.05 seconds. That’s a whole lot better than BroadcastMessage.

But realistically, each BroadcastMessage only takes about a millionth of a second (since 1,000,000 of them take about 1 second). That’s still pretty fast. :wink: I won’t change my team’s current project, where we only use BroadcastMessage for sporadic events and never during Update(). But we’ll switch to static typing for future projects.

Well, only switch if it makes sense to do so…remember the bit about premature optimizing being the root of all evil. :slight_smile: There are cases where BroadcastMessage et al make your code a lot nicer.

–Eric

Regarding your comment about having prefabs that apply effects to the parent, we also use this, and I think it works great.

Currently, we have a turret.

To each ‘barrel’ of the turret, regardless of how many there are, we assign a launcher script.
This launcher script has a reference (drag n drop) to a projectile prefab.

The projectile prefab handles things like velocity, how long it lives, and the explosion prefab to create when it hits something.
The great thing about this…seperation of concerns :slight_smile: The project gets some basic info from the launcher, like its direction and such, and it’s pretty much fire and forget.
This lets us have turrets with any number of barrels, and different parts. You could have a turret with 5 barrels, one that shoots rockets (controlled by the rocket prefab), one that shoots lasers, one that shoots bubbles, etc etc.
It works great. The only concern I might have at this point is the speed of creating the prefab instances, but … meh. It hasn’t been an issue yet.

(probably famous last words eh? ) :slight_smile: