Page 1 of 1

Advanced platformer - the proper method

PostPosted: Tue Dec 24, 2013 10:54 pm
by Hares
Hi

I am new to game-editor.
First of all, thanks to the people that made the software. And thanks to all the contributors to this forum.

For my first game I am trying to make a platform game. So for moving the player around I started out using the simple method. But there was a moonwalking bug I couldn't get rid off.
So I turned to the help section on the website and found the advanced platformer tutorial: http://game-editor.com/Advanced_Platformers

In the tutorial the principle is explained well. But the code that goes along with it has a lot of bugs.
To get the code to work for me I tweaked it.

To check whether the player is jumping or not I find it easier to use the "canjump" variable, than the "vdir".

The animations were always repeating the first two frames, so I added a variable "prevanim" (Actor, String). Then I use this to check if the "anim" string has changed since the previous frame.

The whole animation bit in the tutorial I found confusing, and I didn't get it to work. Instead I just use an animation for walking, and single frame animations for standing, jumping and ducking. This way all the animations can keep the option FORWARD, no need to change to STOPPED or NO_CHANGE.

Here is the code:
player -> create actor
Code: Select all
speed=4; //player speed
hdir=0; //horizontal dir 0 = facing right
vdir=1; //0=duck 1=stand 2=jump
jump=-20; //players jump ability (in negative numbers)
canjump=1; //can jump already
run=1;
strcpy(facing, "right");
strcpy(jumping, "standing");


player -> draw actor
Code: Select all
char * key = GetKeyState();  // This allows you to use keys as variables
float tspeed=0;              //tspeed is temporaryspeed.
char anim[32];               //our animation string


//reset variables

run=1;                      //reset run(until pressed)

if(vdir==0)
    {
    vdir=1;                 //ducking (vdir0) defaults to standing each frame (untill pressed again)
    }

tspeed=0;                   //reset tspeed to 0


//get keys and set the variables

if (key[KEY_DOWN]==1 && key[KEY_SPACE]!=1) //pressing down, and not pressing jump at same time
{
    strcpy(jumping, "ducking");     //for our animation
 
    if (canjump==1)                 //if we are not jumping
    {
        tspeed=0;                   //cannot move while ducking
    }

    vdir=0;                         //duck
}

if (key[KEY_SPACE]==1 && vdir!=2 && canjump==1)
{
    if (vdir!=2)                    //if we are not jumping already
    {
        vdir=2;
        yvelocity=jump*canjump;     //jump (if we have canjump)
        canjump=0;                  //prevents moonwalking
    }
    strcpy(jumping, "jumping");    //for our animation
}

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
    }
    if (vdir>0)
    {
        tspeed=-speed;            //if not ducking, we have normal speed (left is -)
    }
    strcpy(facing, "left");       //our direction for animation
    if (vdir==1 && canjump==1)    //or walking animation
    {
        strcpy(jumping, "walking");
    }
    if (vdir==1 && canjump==0)    //or jumping animation
    {
        strcpy(jumping, "jumping");
    }
}

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

if (key[KEY_RCTRL]==1 || key[KEY_RMETA]==1)   //run button = right CTRL or right command button
{
    run=2;
    tspeed*=run;                 //make us go faster
    if (canjump!=0)              //if not jumping
    {
        strcpy(jumping, "running"); //set running animation
    }
}

if (vdir==1 && tspeed==0)        //if standing, and not moving horizontal
{
        strcpy(jumping, "standing");
}

//set animation string


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


//set animation

if (strcmp(anim, prevanim)!=0)
{
ChangeAnimation("player", anim, FORWARD);
}


//now apply all movement to the player
if (health>0)                         //if health is zero or less, the player doesn't move
{
    x+=tspeed;                        //move the player if right/left was pressed
    yvelocity+=1;                     //gravity
}


//and set our prevdir for the next frame
prevdir=hdir;


//set our prevanim for the next frame
strcpy(prevanim, anim);


For the collisions I have to use 3 different collision events:

To prevent the player from falling through the ground & to reactive the canjump.
player -> collision top side of land -> repeat yes:
Code: Select all
PhysicalResponse(MOVE_EVENT_ACTOR_ONLY, USE_CALCULATED_MASS, 1.0, 1.0, 0.0, 0.0);


if (canjump!=1)
{
    canjump=1;       //we can now jump again
}

if (vdir==2)    //if we were jumping
{
    vdir=1;     //we are now staning/running (or ducking)
}



To prevent the player from going through walls (left & right)
player -> collision any side of land -> repeat yes:
new variable: "player_yvel" (Actor, Integer)
Code: Select all
player_yvel=yvelocity;
PhysicalResponse(MOVE_EVENT_ACTOR_ONLY, USE_CALCULATED_MASS, 1, 1, 0, 0);
yvelocity=player_yvel;


To prevent player from flying throught the bottom of land
player -> collision bottom side of land -> repeat no:
Code: Select all
yvelocity=1;


As it says in the original tutorial, all you need to add is the player animations with the names:
playerstandingright
playerstandingleft
playerwalkingright
playerwalkingleft
playerduckingright
playerduckingleft
playerjumpingright
playerjumpingleft
playerrunningright
playerrunningleft

Re: Advanced platformer - the proper method

PostPosted: Wed Jan 08, 2014 10:03 pm
by Hares
The key to make the player run is the right shift key.

But on a windows computer, if you hold the right shift for 8 seconds there is the accessibility option "filter keys" that gets activated.
This filter makes the keyboard ignore brief or repeated keystrokes. Not cool when you're playing a game ... :?

Turns out that the left shift key also has an accessibility shortcut. If you tap it 5 times "sticky keys" switches on.

Then I am thinking to change the run button to the right ctrl key.

But my question is this: does the KEY_RCTRL KeyState also look for the "command" button on mac?

Re: Advanced platformer - the proper method

PostPosted: Sun Jan 12, 2014 11:55 am
by skydereign
Hares wrote:But my question is this: does the KEY_RCTRL KeyState also look for the "command" button on mac?

The right command key on a mac is bound to KEY_RMETA.

Re: Advanced platformer - the proper method

PostPosted: Sun Jan 12, 2014 7:08 pm
by Hares
Thanks skydereign

I changed the code in the original post for the running. Now it takes both the right contral and the right command button.
Also added an animation for the running.

Code: Select all
if (key[KEY_RCTRL]==1 || key[KEY_RMETA]==1)   //run button = right CTRL or right command button
{
    run=2;
    tspeed*=run;                 //make us go faster
    if (canjump!=0)              //if not jumping
    {
        strcpy(jumping, "running"); //set running animation
    }
}

Re: Advanced platformer - the proper method

PostPosted: Thu Feb 06, 2014 8:57 pm
by Hammerit
Hares wrote:To prevent the player from falling through the ground & to reactive the canjump.
player -> collision top side of land -> repeat yes:
Code: Select all
PhysicalResponse(MOVE_EVENT_ACTOR_ONLY, USE_CALCULATED_MASS, 1.0, 1.0, 0.0, 0.0);


if (canjump!=1)
{
    canjump=1;       //we can now jump again
}

if (vdir==2)    //if we were jumping
{
    vdir=1;     //we are now staning/running (or ducking)
}



To prevent hero to move on the ledge of block use this code.(suicide walking)
Just save actor X coordinate before collision with top side of land, because PhysicalResponse will reposition you character after collision.
Code: Select all
double tempXcoordinate = x; // saves x coordinate of player
PhysicalResponse(MOVE_EVENT_ACTOR_ONLY, USE_CALCULATED_MASS, 1.0, 1.0, 0.0, 0.0);
x = tempXcoordinate;

if (canjump!=1)
{
    canjump=1;       //we can now jump again
}

if (vdir==2)    //if we were jumping
{
    vdir=1;     //we are now staning/running (or ducking)
}