Page 1 of 2

Handling Multiple Actors (using clones)

PostPosted: Thu Feb 05, 2009 5:18 pm
by DST
Sometimes handling many actors can be a bother, but you must learn to deal with CLONES in order to make successful games.

You will find, over time, that you can reduce the number of actors each time you make a game, and that doing so will reduce the complexity and difficulty in programming your game.

Here are two basic examples of cloning vs. new actor creation.

#1. Powerups.

Ok, so you got a health powerup, a weapons powerup, an ammo powerup, an extra life powerup....these should be 1 cloned actor.

Simply add an animation, 'healthp', for instance. to the powerup actor. Add another animation...'weaponp'.

Powerup>CreateActor>
Code: Select all
type=rand(2);

switch(type){

case 0:
ChangeAnimation("Event Actor", "healthp", FORWARD);
break;

case 1:
ChangeAnimation("Event Actor", "weaponp", FORWARD);
break;

}


Now player>collision>any side>powerup
Code: Select all
switch(collide.animindex){

case 0:
health+=3;
break;

case 1:
weapon+=1;
break;

}
DestroyActor("Collide Actor");


Animindex refers to the # of the animation in the animation list; the first animation you add is 0, etc. etc.
Now you have one actor for unlimited powerup types, and only 1 create actor, and only 1 collision to deal with.

Much much much easier than having multiple powerup actors!!!!!!!


#2. Text Meters.

You might have a text actor displaying a variables, such as score.
textactor>DrawActor>
Code: Select all
textNumber=score;


You can reuse that actor too! Try cloning it and:
textactor>DrawActor>
Code: Select all
switch(cloneindex){

case 0:
textNumber=score;
break;

case 1:
textNumber=lives;
break;

case 2:
textNumber=time;
break;

}

Also, when you create text, DO NOT USE COLORS. Make text WHITE, then on textactor>createactor, set the rgb values. In this way you can make an unlimited number of colors with only 1 font! The more fonts you use, the more likely you are to experience errors.
Using these methods will greaty increase the running speed of your game, the ease of programming/changing script, and as well the handling of other variables(like ZDEPTH).

If the coding involved in the case switch seems like a pain when you're a beginner, you'll soon find that the amount of time it saves and the amount of power and flexibility it offers is more than worth it. Take time to familiarize yourself with the case switch, it is vital to making complex games.

If you've never used a case switch, here is the syntax:

Code: Select all
switch (variablenametobechecked){
case 0:
action here
break;
case 1:
action here
break;
}


all 'case x' must be followed by a colon :
all 'break' must be followed by a semicolon ;

Also, you can omit cases you won't be needing. If you don't want to take any action when the variable is 0, you can simply omit case 0 from the switch, and start with case 1 instead.

Re: Handling Multiple Actors (using clones)

PostPosted: Thu Feb 05, 2009 7:20 pm
by Fuzzy
Beautiful post. I'm giving you a point. I hope everyone that reads this does too.

Re: Handling Multiple Actors (using clones)

PostPosted: Mon Feb 09, 2009 2:28 pm
by Kalladdolf
I encourage newbies to read this very carefully (as well as pros who missed this chapter somehow). Awesome post, DST.

Re: Handling Multiple Actors (using clones)

PostPosted: Tue Feb 10, 2009 4:42 am
by Fuzzy
Also note that you dont have to have the break for each case. in that case it will assess the next case in line.

Re: Handling Multiple Actors (using clones)

PostPosted: Tue Feb 10, 2009 5:22 am
by DST
What fuzzy is saying is if you have a var of 1 and there's no break after 1, it will continue and perform case 2.

This could be useful as a cumulative event;

The following two codes will perform exactly the same.

Code: Select all
switch(hp){
case 0:
DestroyActor(etc.etc);
break;
case 1:
b-=100;          //<----- no break here
case 2:
g-=100;
break;
}


Code: Select all
switch(hp){
case 0:
DestroyActor(etc.etc);
break;
case 1:
b-=100;
g-=100;
break;
case 2:
g-=100;
break;
}


Either way, case 1 will reduce both b and g;
while case 2 will reduce only g;

Re: Handling Multiple Actors (using clones)

PostPosted: Tue Feb 10, 2009 5:29 am
by Fuzzy
Yes that is what I mean, thanks. also, since you can put a variable in the case to compare to the switch, you can do some neat stuff.
Code: Select all
switch(c) {
case y:
 b = 127;
case q:
 g = 255;
 break;
}


Which is an interesting way to do comparisons. You can do a strange sort of hybrid if/loop. note that it never goes back to the first case though.

You could also change the value of c, making a loop.

Re: Handling Multiple Actors (using clones)

PostPosted: Mon May 31, 2010 2:29 am
by sillydraco
Aha nevermind! i figured it out x3

i tried using the code, but it didnt seem to work :( im trying to have a block (like in mario) you hit it and it destroys it self, and it also has Destroy Actor>Create Actor (Powerup). the Powerup has CreateActor>Script Editor:

Code: Select all
type=rand(7);

switch(type)
   
{

    case 0:
    ChangeAnimation("Event Actor", "berry", FORWARD);
    break;

    case 1:
    ChangeAnimation("Event Actor", "bolt", FORWARD);
    break;

    case 2:
    ChangeAnimation("Event Actor", "coin", FORWARD);
    break;

    case 3:
    ChangeAnimation("Event Actor", "feather", FORWARD);
    break;

    case 4:
    ChangeAnimation("Event Actor", "Full", FORWARD);
    break;

    case 5:
    ChangeAnimation("Event Actor", "Health", FORWARD);
    break;

    case 6:
    ChangeAnimation("Event Actor", "Mana", FORWARD);
    break;
}



Powerup has 7 animations, just little icons. but whenever i try to finalize the script it gives me errors (see attatchment)

:<

Re: Handling Multiple Actors (using clones)

PostPosted: Mon May 31, 2010 4:13 am
by DST
You have to declare variables before you use them. To use type as a single (one use only) variable, start the script with:

int type=rand(7);

This declares it as an integer, and reserves the memory for it. Creating it in this way will make it disappear after the CreateActor script finishes.

To use it as a lasting variable, use the 'variables' tab at the bottom of the script window, and create a new variable with these settings:

Integer
Actor Variable

Now that variable will stay with the actor until it is destroyed, and there will be one type variable reserved for each actor that wants to use it.

If you use global instead of actor variable, then there will be only one type variable in the game, shared by all.

Examples of Actor Variables:
health
type
damage

Examples of global variables:
lives
score
level

Re: Handling Multiple Actors (using clones)

PostPosted: Mon May 31, 2010 7:43 pm
by sillydraco
yes, i noticed my mistake shortly after i posted here x3 heh heh, silly me ^^

Re: Handling Multiple Actors (using clones)

PostPosted: Sat May 31, 2014 6:22 pm
by Zivouhr
Thanks for the info on using the same clone actors for multiple tasks. I just started applying this idea prior to reading this thread, and it does save time.

Re: Handling Multiple Actors (using clones)

PostPosted: Sun Jun 01, 2014 9:03 pm
by Zivouhr
Bump Thread:

I gave this a try and got the first result, but then the other items didn't do what I wanted them to. I could use some help if possible.

Items: 3 treasure clones, all look the same using the same animation, just clones of the first in different locations.
Goal: When player collision meets treasure.0, treasure.1 becomes visible, then when you find that treasure.1, treasure.2 becomes visible somewhere else.

The first part worked, so when the player contacts treasure.0, treasure.1 then became visible. But after contacting treasure.1, treasure.2 stays invisible/transparent. Testing it, I want the treasures to be contacted in the exact order, so one leads to the appearance of the next one, each at a time.

After setting up the first part:
treasure.0 / draw actor / script editor: (also tried it separately at a time using create actor, but same result)
Code: Select all
type=rand(4);    //had to declare "type" as variable to get code to accept.
switch(type){

case 0:
"treasure.0";   //Wondering if I can just say which clone I'm using instead of an animation?
break;
case 1:
"treasure.1";    //Is this code correct?
break;
case 2:
"treasure.2";
break;
}




I used in the treasure.0 > collision with player: (all but treasure.0 have been originally set to full transparency/invisible).

Code: Select all
switch(collide.cloneindex){
case 0:  //just wondering where I went wrong with this code here?
ChangeTransparency("treasure.1"), 0.000); //this makes invisible treasure.1 visible after contacting treasure.0.
break;

case 1:
ChangeTransparency("treasure.2"), 0.000); //this makes invisible treasure.2 visible after contacting treasure.1.

case 2:
ChangeTransparency("treasure.3"), 0.000); //this makes invisible treasure.3 visible after contacting treasure.2.
}


And for the variable, I added the word "type" (without quotes) into the Integer Global code, and then tried it with Integer Actor code too, but can't get this to work right beyond the player contacting the first treasure and making treasure.1 visible. Treasure.2 never appears when contacting treasure.1 for some reason. But when I test it and make treasure.2 slightly visible just to see what happens if contacted by player, after going in order from treasure.0, treasure.2 makes treasure.1 reappear, looping back to that one (again as a test to see what happened).

Thanks for any help you can offer.

Re: Handling Multiple Actors (using clones)

PostPosted: Mon Jun 02, 2014 12:42 pm
by lcl
Hi again, Zivouhr! Image

I'm now going to try to explain what is wrong with your code, how you should fix it, and what you should do to make your game perform the desired actions more efficiently. I urge you to read the full post before beginning to modify your code based on my corrections of your code, since I first tell what is wrong with the code and how you could fix it, but after that I tell you about an alternative way of achieving what you want to do, and I strongly recommend using that one instead. Image

This code doesn't do anything:
Code: Select all
type=rand(4);

switch(type)
{
    case 0:
        "treasure.0";
    break;

    case 1:
        "treasure.1";
    break;

    case 2:
        "treasure.2";
    break;
}

Or, well, it does set a random value varying from 0 to 3 to type and then the compiler goes through the switch case and it type is equal to 0, 1 or 2, it interprets the texts but doesn't do anything with them. What is this part supposed to do? I don't see any meaning with this since you don't actually need to do anything in any actor's draw actor code to achieve what you want to do. Also, you should know that you can't add any code just for a single clone. You said that this code is in treasure.0's draw actor code, but it's actually in every treasure actor's draw actor code. The way to make some code happen only in certain clones is by using an if check to see what clone is interpreting the code, or to use a switch case for the same result as using an if statement.

Also, here you are using collide.cloneindex, when you'd want to only use cloneindex:
Code: Select all
switch(collide.cloneindex) //You shouldn't use collide.cloneindex here
{
case 0:  //just wondering where I went wrong with this code here?
ChangeTransparency("treasure.1"), 0.000); //this makes invisible treasure.1 visible after contacting treasure.0.
break;

case 1:
ChangeTransparency("treasure.2"), 0.000); //this makes invisible treasure.2 visible after contacting treasure.1.

case 2:
ChangeTransparency("treasure.3"), 0.000); //this makes invisible treasure.3 visible after contacting treasure.2.
}

I see that you're confusing this collision event with the thing I talked to you about earlier. The thing with "collide" is that it's meant for reading the variables of the actor the current actor is colliding with. So, for example, in your previous problem with the saving of the food actors, you had the code in the player's collision event with the food actors. And you wanted to know the cloneindex of the food actor the player collided with, so you had to use collide.cloneindex.

But now, in this case, the situation is reversed, you don't now have the code in the event when the player actor collides with the treasure actor, but instead where the treasure actor collides with the player actor. Of course, this is the same thing when you look at it in the game, but it differs in the way the code gets interpreted, and in this case, "collide" refers to player actor, not the treasure actor.

So now, because you're always using player's cloneindex, the code will always make treasure.1 reappear, since there's only 1 player actor and thus it's cloneindex is 0. Just remove the "collide." part from before of the "cloneindex" in the switch statement, and you should be good to go. :)






BUT. There is a lot simpler way to achieve what you want to do. Yes, this setup you have would do what you want, but think of it, you'll have to write 3 more lines of code for every new treasure you add to your game! Think if you end up to a point where you have 100 treasure actors in there, way too much code for something as simple as this. There is a very nice trick to achieving what you want to do, but first I'll point out another issue with this concept.

You currently have the code in the treasure actor's collision event with player. What this means in practice, is that every single frame of the game, each of the treasure actors runs a collision detection event to see if they collide with player. And that can cause slowdown on your game, and it's generally a bad habit to add any events to clones when you can have some single actor handle it all for the clones. So, instead of using treasure -> collision with player, use player -> collision with treasure. Only one actor having to check for collisions now. :)
(This would of course mean, that you now then again have to use collide.cloneindex in the collision event, to get the cloneindex of the treasure the player collides with, instead of using only cloneindex, because that would give you the 0 cloneindex of the player actor's)

Now, about that neat trick for avoiding the need to write three new lines of code for every new treasure you add to your game.
This is very simple because you want to have the treasures activate each other in the simple order based on their cloneindex. So what you want to do is this:

Player -> Collision with treasure -> script editor:
Code: Select all
char temp[256];
//The above line of code creates a temporary variable to be only used in this event. This variable is an array of characters, also called a string. This string is 256 characters long. The name temp is an abbreviation for temporary, you can call it whatever you want.

sprintf(temp, "treasure.%i", collide.cloneindex + 1);
//The above line of code prints the clonename (=actor name.cloneindex) of the next clone to the temporary string called temp. For example, if the treasure that collides with player in this event has the cloneindex of 2, the string printed to temp will be this: "treasure.3". That's because we use the "%i" to tell sprintf to add an integer value to that place in the string, and then we tell sprintf that this integer value will be equal to the collide actor's (the treasure the player collides with) cloneindex plus 1, which then is 2 + 1 = 3.

VisibilityState(temp, ENABLE);
//The above line of code sets the visibility state of the actor who's clonename is stored in the temp, to ENABLE, and that meas that the actor will become visible.

And that there, is all. This code will do what you want no matter how many clones of the treasure actor there is. :)

But now you might think what this VisibilityState command is? Well, I explained that in my latest answer to your previous question, and basically, it's just a better way of making actors invisible / visible. For more information on the command, see this page and search (F3 or CTRL + F) for the word VisibilityState.

Of course, for using VisibilityState instead of changing the transparency of the actors, you'll need to make them invisible via the use of VisibilityState in the first place. For doing this, just add a code like this to the Create Actor event of the treasure actor:
Code: Select all
if (cloneindex != 0) //This means "if cloneindex is not equal to 0". That's because we want the treasure number 0 to be visible upon startup, right? =)
{
    VisibilityState("Event Actor", DISABLE); //This makes the current clone have it's visibility state set to DISABLE, and because this code gets interpreted for every clone, it sets all clones (except clone 0) to be invisible
}


I hope this wasn't too messy of an explanation, I tried my best to cover all things as well as I could. If there's still some trouble, don't hesitate to ask more. :)




Oh, one more thing..
Zivouhr wrote:And for the variable, I added the word "type" (without quotes) into the Integer Global code, and then tried it with Integer Actor code too

Just so that you know, the variables created via the Variables window, are either:

- Global variables = This means that there's just that one variable with that name and it's accessible by every actor at any point in the game.
- Actor variables = This means that every actor in the game has it's own unique case of this variable, every actor has it's own copy of this variable, just like every actor has it's own value for it's x and y coordinates, for example. These are also accessible by any actor in the game, but you'll have to define which actor's variable you want to access, except if the code you're using for accessing the variable is in an event of the actor who's variable you want to access.

An example of actor variables:

Let's say we've created an actor variable called "myVar", and it's an integer variable.
Now, let's say we have an actor called "myActor" and we want to set it's "myVar" to 5.
What we can do, is to, for example, add this to "myActor"'s Create Actor event:
Code: Select all
myVar = 5;

Note that we can simply write myVar, because we are accessing the variable from an event of the actor itself, and Game Editor will then use the current actor's variable.

But if we wanted to set "myActor"'s "myVar" to 5 when, for example we click another actor with the left mouse button, we would add this code to that actor's mouse button down -> left -> script editor:
Code: Select all
myActor.myVar = 5;


I think that's all I wanted to say :D

Re: Handling Multiple Actors (using clones)

PostPosted: Tue Jun 03, 2014 2:25 am
by Zivouhr
Hi LCL. 8)
I read through your post regarding handling multiple actors and clones, and it looks like a very detailed, well thought out explanation that I will apply carefully and see what I can do with it this week. Thanks also for the suggestion to make the process easier, and for describing how the player should be the one doing all of the collision with events rather than the items or enemies in the game waiting to collide with the player. That is something I wasn't aware of till now regarding slow down, but thankfully that is how I was able to do most of my collisions aside from a number of the newer ones, thanks to some demos including Bee-Ant's Mario demo, where I saw how many collision events Mario was handling, and assumed that is the way to go.

Once again, awesome effort on your part explaining all of this in such great detail to help myself and others learning C and Game Editor! :D Keep up the awesome work. And thanks also to everyone on this forum who contributes their knowledge as well. All valuable information is appreciated! 8)

Re: Handling Multiple Actors (using clones)

PostPosted: Wed Jun 04, 2014 1:08 am
by Zivouhr
Hi LCL,

I gave the simpler scripts a try; very easy to code in since they're so short, and all scripts accepted for immediate action in the script editors for the appropriate actors (player, treasure).
The only thing is, when my player walked up to the first treasure, with the other treasures hidden as hoped, after colliding with the treasure, the treasure remained in place, and didn't disappear or allow other treasures to appear.

Should I add a visibility code after the player's collision code that you wrote? Just wondering, but it's still early so I will tinker with the code a little more if I can to get it working in the intended way.

In the meantime, I ran activation events that got the desired effect, but your coding would be much faster and more efficient if I can get it working as hoped. Thanks again!

Re: Handling Multiple Actors (using clones)

PostPosted: Wed Jun 04, 2014 1:30 am
by lcl
Hi.

Zivouhr wrote:The only thing is, when my player walked up to the first treasure, with the other treasures hidden as hoped, after colliding with the treasure, the treasure remained in place, and didn't disappear or allow other treasures to appear.

Well, yes, I forgot to mention, that you should also disable the current treasure actor's VisibilityState. But the current code does allow the other treasures to appear for me, are you sure you checked that, or did you just assume that because the current treasure doesn't vanish, it doesn't make the other ones appear either? :)

Zivouhr wrote:Should I add a visibility code after the player's collision code that you wrote?

If you meant disabling the treasure actor's VisibilityState, as I mentioned above, yes you should.