Today's lesson in MMF architecture is a fairly mundane one, but it has a lot of useful applications. PLUS, I'll teach you why your program has that one bug where when the game has a lot of objects, stuff starts getting Glitchy, objects start jumping around the screen or looking like each other.
The answer is, Object Scope.
Object Scope is a list of all the objects that the runtime keeps while running through your code. This is a list which is every single active object in the screen, which can be removed from inside the Conditions (left-side commands like Pick all objects with Value A = 0), and is then used to tell the application which objects to run the events on during runtime.
Heres how it works. Every time the game reads a single line of code, before it checks the conditions, it creates a new List. Inside this is every single active object in the game. So if you have 100 Enemy objects, and 1 Player object, you'll have a list of length 101.
Now, before it reads the conditions, this list has every object in it. When it runs through the conditions, it starts REMOVING objects from the list. A couple of actions can ADD to the list, but this is rather uncommon. The way this works is a lot simpler than it sounds. The game reads the conditions on each event from top to bottom. When it reads a condition like:
Enemy's Alterable Value A < 50
what it will do is read through this list of active objects, and for every single Enemy in the list, it will check if that Enemy object has a value of below 50. If it DOESN'T, it will remove its name from the list. It if DOES, it will stay in the list.
Now lets take a hypothetical set of conditions, as:
Start of Frame
Enemy's Alterable Value A < 50
Enemy Flag 0 is On
Pick an Enemy at random
(with this action
=Destroy Enemy
here is how it will read through this code. First, it reads the Start of Frame condition. If this is the first frame of gameplay drawn, it will return TRUE, if it is not, it will return FALSE. All of the conditions must be TRUE or the events will not execute. If even one of them is FALSE, the game will skip all the events and go to the next line. This particular condition, Start of Frame has no effect on the Object Scope list. It will not remove any objects from the list.
The second line, 'Enemy's Alterable Value A < 50', will execute like we talked about before. The game will run through the list of scoped objects. For each one that is an Enemy, it will check that its alterable value is below 50. If it IS, it will make the condition TRUE. If it ISNT, it removes its name from the object scope list. If none of objects returned TRUE (none of the enemies had a value below 50), then the game will count the condition as FALSE, and the events will not execute.
So after that condition, only objects whos Value A was below 50 will be left on the scope list. THEN, it reads the next line, 'Enemy Flag 0 is On'. Now, it runs just like the previous condition. It runs through the Object Scope list, and for every Enemy on it, it checks if its Flag 0 is on. But heres the catch; this time through the list, none of the objects who had their Value A above 50 will be checked. It will only check the objects that returned true for the previous step.
So if there exists an object with Value A = 60, and Flag 0 is On, but its the only one with Flag 0 is on, this condition will return FALSE, even though an object existed with its Flag 0 is on. So after the list is run through this time, the only remaining Enemy objects on it, must have BOTH their value below 50, and their Flag 0 on. Any objects either EITHER of these as false, will be removed from the list at this point.
Now, the game reads a Pick an Enemy at random condition. What this condition does, is erase all but one of the remaining objects on the scope list of that object type. So of all the Enemy objects with both Value A below 50 & Flag 0 on, it now chooses one. It WILL NOT choose any of the objects we took off the list before. It only picks at random from the objects still on the list. If there was only 1 remaining object, it will always be that one.
Now heres the kicker. All the previous steps had no effect on OTHER objects on the scope list. These conditions will only affect the Enemy objects on the list. All the other objects will be at FULL SCOPE, ie; all of them are still on the list, for all other objects.
Now heres how the scope list is APPLIED (what it does):
Now, the game has read all of the conditions. In this case, they were TRUE, and theres 1 Enemy on the scope list. When the game reads the Destroy Enemy action, it now applies this action to ALL OBJECTS ON THE SCOPE LIST. In this case, we started with 100 enemies & 1 player object in the game. After all the conditions, theres 1 Enemy & 1 Player. Since the command is
Destroy Enemy
it will destroy ALL of the objects on the list, with objecttype = enemy
which is, in other words, just that one object (not the player).
If we had gotten rid of our Pick an Enemy at random line, it would have destroyed ALL enemies matching those conditions. So what does all of this mean to us? Well, Scope is important to remember. Think visually, as you go down your conditions, that each following condition will only affect the objects that rang true for the previous ones.
Now, heres where I address that Created too many objects, now my games glitchy issue:
The Create an Object action is special. When you create a new object, the game will ERASE all objects of that type from the scope list, and then add ONLY that new copy, back onto the list. So for all actions AFTER the Create an Object action, it will only reference THAT specific copy of the objects, not any of the ones defined in the conditions.
So say our conditions brought the list down to 5 Enemy objects, then we ran these two actions:
Create a new Enemy
Destroy Enemy
It would create a new enemy object, and then change the scope list to no longer hold those other 5 objects, just the new one. Then, it would read Destroy Enemy, and would destroy the only enemy left on the list; the one we just created. So this Create enemy, destroy enemy line would do pretty much nothing
Yet, if we did them in reverse order:
Destroy Enemy
Create a new Enemy
first, it would destroy all 5 of those specified objects, then it would create a new one.
So why does this matter? Well, this is where it gets interesting.
When the game attempts to create a new object, but you already have too many objects on the field (you've hit your active object limit, around 256 for TGF, 10000 for MMF2), the game will realize it CANNOT create a new object. So [b]it will skip the create object line[/b].
But you should realize the side effect of this! It will NOT change the scope list, whereas if it HAD created the new object, it would have changed the scope of all following actions to JUST that object. This is a very dangerous bug. IMO, Clickteam should make it so the scope list removes all objects of that type in a failed create object command. But it doesn't right now.
So say we have this line of code:
Upon Pressing Space Bar:
Create a Laser Beam object at (256,256)
Set Laser Beam Value A to (Random(10))
Set Animation of Laser Beam (Value A of Laser Beam)
In this case, we have 10 different laser beam animations, which are picked from Value A. When we create a new one, it chooses an animation at random and plays it. Now, if there are too many active objects when we run this code, this is what happens:
First, the game checks if you hit the space bar. If you did, it attempts to create a new object. But it can't, so it throws out that line of code. It does not change the scope list; it still has all Laser Beam objects in it, not just the new one (because there isn't a new one). Then, it takes all the laser beam objects, and sets their value A to random(10), and then sets their animation to this value.
The end result is, ALL the existing lasers onscreen start playing a single animation. If we had positioned the new object after creating it, they ALL would have been put to this position. If we had destroyed the object after creating it, they ALL would have been destroyed. Effectively, are code is exactly like this:
Upon Pressing Space Bar:
Set Laser Beam Value A to (Random(10))
Set Animation of Laser Beam (Value A of Laser Beam)
So thats why the game gets all glitchy. The solution is simple; DONT HAVE THAT MANY OBJECTS AT A TIME. Keep your active object # below the limit. Or else, make sure your Create Object lines of code don't do anything after creating, or yell at yves or jeff or someone until clickteam fixes it.
|