Advanced Platformers

From Game Editor

Jump to: navigation, search

NOTICE

Make sure you read the Basics of a platformer before going any further.

The Proper Method

Using this example, you can make your character follow the basic rules of SuperMarioBrothers games.

The first thing we need is a few variables to control our player. Create the following using the variables tab:

  • speed (actor, real) //the permanent speed of our player
  • hdir (actor, int) //our players horizontal keypress
  • vdir (actor, int) //vertical keypress
  • jump (actor, int) //the power of player jump
  • canjump (actor, int)//is player allowed to jump?
  • run (actor, real) //to indicate run key is pressed
  • facing (actor, string)
  • jumping (actor, string)
  • prevdir (actor, int) //our previous direction


To keep control of your player and it's animations in C the best method is to use strings. If you are not already familiar with it, a string can be substituted for arguments in a function. For example:

 char anim[32];  //creates a string called anim, 32 characters long 
 strcpy(anim, "playerwalking"); //sets the value of anim to playerwalking
 ChangeAnimation("player", anim, FORWARD); //note that you do not use "" on     
 // a string variable.

This will call changeanimation with a value of "playerwalking".

Now lets set our variables at the start of the game:

Player>CreateActor>ScriptEditor>

speed=4; //you can adjust this anytime, player speed
hdir=0;  //horizontal dir 0 = facing right
vdir=1;  //0=duck,  1=stand, 2=jump
jump=-12;  //player's jump ability (in negative numbers)
canjump=0; //cannot jump yet
run=1;    //

Now we've set the starting variables, we'll capture the keys and output the character action based on them.

Player>Draw Actor>

char * key = GetKeyState();  // This allows you to use keys as variables 
float tspeed=0;          //tspeed is temporaryspeed.
char anim[32];          //our animation string
run=1;                  //reset run (until pressed)
if(vdir==0){vdir=1;}   //ducking(vdir0) defaults to standing each 
//frame (until pressed again).

//get keys and set the variables------------------------------------>
if(key[KEY_DOWN]==1){
 if(vdir<2){ //if we are not jumping
vdir=0;                      //duck!
strcpy(jumping, "duck");    //for our animation
tspeed=0;                  //cannot move while ducking!
}
else if(vdir==2){ //if we are already in a jump
vdir=0;                    //duck!(While jumping!)
strcpy(jumping, "duck");    //for our animation
tspeed=speed;            //speed as normal!
               } }
if(key[KEY_SPACE]==1 && vdir!=2){ //if we are not jumping already
yvelocity=jump*canjump;           //jump! (if we have canjump!)
strcpy(jumping, "jump");    //for our animation
canjump=0;                        //prevents moonwalking
}


if(key[KEY_LEFT]==1){
hdir=1;                        //1=left, 0=right
if(vdir==0){ //ducking
 tspeed*=-1; //if jumpducking, tspeed already==speed, so just set the +-.
 //if we're normal ducking, tspeed is 0, so it will stay that way.
 }
else if(vdir>0){
tspeed=-speed;  //if not ducking, we have normal speed (left is-)
               }
 strcpy(anim, "LEFT");//our direction for animation
                     }


if(key[KEY_RIGHT]==1){
hdir=0;
if(vdir>0){      //for normal speed
 tspeed=speed;
 }
strcpy(facing, "right"); //our direction for animation
}


if(key[KEY_RSHIFT]==1){ //run button
run=2;
tspeed*=run;        //make us go faster!
} 


We now have all the variables we need to control the player! After this script runs in draw actor, we can look a the variables it output, and determine exactly what animation to depict for our player. We have 3 strings to assemble this animation from. anim - will store the entire animation name jumping - stores duck/jump/standing facing - stores left/right

So after this script, we're going to join them together, and process player movement.

Now we can use sprintf to join multiple strings and integers together. In this case, we only have strings.

 sprintf(anim, "%s%s%s", "player", jumping, facing);

We made a string that will result in words like: playerduckleft or playerjumpright. You will need to name your players animations to match this word scheme.

Now we use our new anim string on changeanimation.

Now the only issue to be found here is that unfortunately, we cannot use a string to control the final argument of changeanimation, that is FORWARD, STOPPED, NO_CHANGE. We will have to make a case switch for these.

However, it's quite simple really: Note that we haven't added our x and y movement to player yet; this is important. We must distinguish between standing and moving, because they will both use the walking animation, but when standing, it's stopped on the first frame. In addition, once we have started moving, we must use 'NO_CHANGE' to keep the animation cycling properly (we don't want to reset it each frame), but we also much start it at forward if it was stopped previously.

 if(vdir==1 && tspeed!=0){  //we only animate forward when walking running,
 //and a tspeed != 0 means we have pressed a key...
 if(xvelocity==0 || prevdir!=hdir){
 /*if we have a tspeed but our xvelocity is 0, then we WERE standing 
 but are now moving. If we have a tspeed and our hdir != prevdir, then
 the player has just changed direction. Either way, it's a new animation.
 */    
 ChangeAnimation("player", anim, FORWARD); 
 }
 else {  //if we haven't changed direction and are just moving forward
 ChangeAnimation("player", anim, NO_CHANGE);
 }
 }
 //
 else{  //if we are jumping, standing still, or jumping
 ChangeAnimation("player", anim, STOPPED);
 animpos=0;  //we will stay on frame 0 
 }
 
 //now apply all movement to the player.                   
 x+=tspeed;  //move the player if right/left was pressed
 yvelocity+=1; //gravity
 
 // and set our prevdir for the next frame
 prevdir=hdir;


Then on Player>Collision>TopSide>Block>RepeatYes>Script Editor>

PhysicalResponse(MOVE_EVENT_ACTOR_ONLY, USE_CALCULATED_MASS, 1,1,0,1);
canjump=1;      //we can now jump again!
if(vdir==2){ //if we were jumping
vdir=1;      //we are now standing/running (or ducking if you want)
}

And when player falls off a cliff, we need to turn off the canjump. Player>DrawActor>ScriptEditor (the same one we used above, not a new one):

if(yvelocity>2 && canjump==1){   //if player falls off a cliff and is 
//moving downward and has not jumped since leaving the cliff
canjump=0;       //player cannot jump now
vdir=2;        //falling is the same as jumping
}

Notice that you don't need any KeyDown or KeyUP events for this script to work!

The next step would be to create another variable to explain the user mode: normal, hurt, attack, invincible, and die, as a string. This would output a new string to add to our animation string.

Note that you can add infinite strings together using sprintf; The proper usage is

 sprintf(nameofstringtowriteto, "%s%s%s", string1, string2, string3);
 sprintf will always overwrite anything previously in the string. 

You can also add ints to the string using "%i" instead of %s.

If you do not wish to overwrite the string, but add more onto it, use strcat instead:

 strcat(nameofstringtoaddonto, nameofstringtoadd);

If you want to create different sets of player animations, i.e. big mario, raccoon mario, then simply add a new word to all of your animations, and insert that as another string into the sprintf. Only this one is a constant string, based on what powerup(s) the player has.

So playerjumpright would become playernormaljumpright, and player big would be playerbigjumpright;

Now we've got a complete interaction system going here already, which cannot be made from the simpler examples. Adding attacks to the simple methods and trying to synchronize them with jumping and running...is much harder than this method. In this method, it's just a matter of adding new words to the string, and setting the appropriate animation direction.