Difference between revisions of "PRJ-Motion:MechanicsAndFlow"

From Digibase Knowledge Base
Jump to: navigation, search
 
(9 intermediate revisions by the same user not shown)
Line 2: Line 2:
 
This is a poorly written up page on the mechanics and flow of Motion. This is written for later use when C is in a better position to properly exercise his theories. All of this applies to the player objects in the game.  
 
This is a poorly written up page on the mechanics and flow of Motion. This is written for later use when C is in a better position to properly exercise his theories. All of this applies to the player objects in the game.  
  
This does not address VIP things like the player state or frame rate.
+
This does not address VIP things like the player state or frame rate. Slopes are not considered in these code snippets.
  
==Various Variables==
+
The idea with Motion is to have Super Mario World style gameplay, as close a 1:1 experience as we can get it, with the addition of wall jump and slide kick mechanics.
*'''bool''' run
 
*'''bool''' lockJump
 
*'''bool''' inAir
 
*'''bool''' wallJumpAble
 
  
*'''float''' walkVel = 2.0
+
<pre>
*'''float''' runVel = 2.75
+
bool run
*'''float''' jumpVel = 4.5
+
bool lockJump
*'''float''' runJumpVel = 5.1
+
bool inAir
 +
bool wallJumpAble
  
*'''float''' gravity = 0.20
+
float walkVel = 2.0
 +
float runVel = 2.75
 +
float jumpVel = 4.5
 +
float runJumpVel = 5.1
 +
 
 +
float gravity = 0.20
 +
</pre>
 +
 
 +
Also note that the CPlayer::think() snippets presented here are not the whole thing. The entire thing would actually be quite lengthy, so it is cut down to save space.
  
 
==Collision==
 
==Collision==
Line 24: Line 29:
 
==Walking and Running==
 
==Walking and Running==
 
Self explanatory, for the most part. A global variable determines the player's movement speed for when they press the left and right buttons.  
 
Self explanatory, for the most part. A global variable determines the player's movement speed for when they press the left and right buttons.  
 +
 +
<pre>
 +
void CPlayer::think(){
 +
velx=0; //don't move left / right by default
 +
 +
if(keystates[SDLK_RIGHT]){
 +
velx = walkVel; //move right
 +
faceright = true; //player graphic is facing right
 +
}
 +
if(keystates[SDLK_LEFT]){
 +
velx = -walkVel; //move left
 +
faceright = false;
 +
}
 +
}
 +
</pre>
  
 
Running, however, can actually be implemented two ways:
 
Running, however, can actually be implemented two ways:
Line 36: Line 56:
 
===Hold Button Run===
 
===Hold Button Run===
 
"Hold Button" Run is seen in most 2d platformers, like Donkey Kong Country and Super Mario Brothers. Of the two, it is easier to implement because it simply adds a check for a button being pressed before deciding which movement speed variable to apply to the movement calculation.  
 
"Hold Button" Run is seen in most 2d platformers, like Donkey Kong Country and Super Mario Brothers. Of the two, it is easier to implement because it simply adds a check for a button being pressed before deciding which movement speed variable to apply to the movement calculation.  
 +
 +
<pre>
 +
void CPlayer::think(){
 +
velx=0; //don't move left / right by default
 +
 +
if(keystates[SDLK_x]){
 +
if(keystates[SDLK_RIGHT]){
 +
velx = runVel; //move right
 +
faceright = true; //player graphic is facing right
 +
}
 +
if(keystates[SDLK_LEFT]){
 +
velx = -runVel; //move left
 +
faceright = false;
 +
}
 +
}
 +
else{
 +
if(keystates[SDLK_RIGHT]){
 +
velx = walkVel; //move right
 +
faceright = true; //player graphic is facing right
 +
}
 +
if(keystates[SDLK_LEFT]){
 +
velx = -walkVel; //move left
 +
faceright = false;
 +
}
 +
}
 +
}
 +
</pre>
 +
 +
This is actually slightly inefficient, since it's more lines. However, if most of your mechanics' physics are more contingent on a run button being or not being held down, then you may be better off in the long run doing this.
 +
 +
[C, double check with an actual programmer on that.]
 +
 +
<pre>
 +
void CPlayer::think(){
 +
velx=0; //don't move left / right by default
 +
 +
if(keystates[SDLK_RIGHT]){
 +
                if(keystates[SDLK_x])
 +
                    velx = runVel;            //run right
 +
                else
 +
    velx = walkVel; //walk right
 +
faceright = true; //player graphic is facing right
 +
}
 +
if(keystates[SDLK_LEFT]){
 +
                if(keystates[SDLK_x])
 +
                    velx = -runVel;            //run left
 +
                else
 +
    velx = -walkVel; //walk left
 +
faceright = false; //player graphic is facing right
 +
    }
 +
}
 +
</pre>
  
 
A bool for running is not necessary, but recommended anyway for later mechanics checking movement speed.  
 
A bool for running is not necessary, but recommended anyway for later mechanics checking movement speed.  
 +
 +
==Acceleration==
 +
To create acceleration, instead of having a base movement velocity, you have a smaller velocity that that gets incremented into the movement speed by a check. Movement speed is checked against a defined max speed. If movement speed is less than the max speed, the movement speed is incremented. Otherwise, the calculation stops incrementing and defaults the movement speed to max speed.
  
 
==Jumping==
 
==Jumping==
 
In the case of having a run mechanic, a second global variable for jump velocity should be set. So you have jumpVel and then runJumpVel.
 
In the case of having a run mechanic, a second global variable for jump velocity should be set. So you have jumpVel and then runJumpVel.
  
Button is pressed and jumpVel is applied to player object as long as button is held down, allowing for variable jump height- short hops and high jumps. With a run mechanic, there is an if/else or switch check to check whether or not run bool is set true. When run bool is set true, you'd instead apply the runJumpVel.
+
Button is pressed and jumpVel is applied to player object.  
  
Once the player has jumped, a inAir bool is set true, and lockJump is set true. If lockJump is not set, the player gets infinite jumps in the air.  
+
<pre>
 +
void CPlayer::think(){
 +
if(keystates[SDLK_RSHIFT] && !lockjump){ //if the player isn't jumping already
 +
vely = -VELJUMP; //jump!
 +
lockjump = true; //player is not allowed to jump anymore
 +
}
 +
}
 +
</pre>
 +
 
 +
With a run mechanic, there is an if/else or switch check to check whether or not run bool is set true. When run bool is set true, you'd instead apply the runJumpVel.
 +
 
 +
<pre>
 +
void CPlayer::think(){
 +
if(keystates[SDLK_z] && !lockjump){ //if the player isn't jumping already
 +
if(running)
 +
vely = -runJump; //jump!!!
 +
else
 +
vely = -nrmJump; //jump
 +
lockjump = true; //player is not allowed to jump anymore
 +
}
 +
}
 +
</pre>
 +
 
 +
Once the player has jumped, a jumping bool is set true, and lockJump is set true. If lockJump is not set, the player gets infinite jumps in the air.  
 +
 
 +
===Variable Jump Height===
 +
We need the jumping bool for variable jump height. Variable jump height is when you can slightly control the height of your jump by holding the button down until the apex of the jump. If you release the jump button before the apex, the jump is cut short to a hop.
 +
 
 +
<pre>
 +
void CPlayer::think(){
 +
        if(keystates[SDLK_z] && !lockjump){ //if the player isn't jumping already
 +
if(running)
 +
vely = -runJump; //jump!!!
 +
else
 +
vely = -nrmJump; //jump
 +
lockjump = true; //player is not allowed to jump anymore...
 +
        jumping = true;                        //...because the player is jumping now!
 +
        }
 +
 
 +
if(!keystates[SDLK_z] && jumping){ //when the player has released the jump button during his jump.
 +
vely += jumpFraction;
 +
jumping = false;                      //The player stopped jumping.
 +
}
 +
}
 +
</pre>
  
 
==Wall Jumps==
 
==Wall Jumps==
Line 57: Line 176:
  
 
To make the wall jump seem a bit more realistic, do a check on the player's vertical velocity. If the player's vertical velocity is still increasing, the player's wall jump has more velocity away and up from the wall from the wall than if they were sliding down it.
 
To make the wall jump seem a bit more realistic, do a check on the player's vertical velocity. If the player's vertical velocity is still increasing, the player's wall jump has more velocity away and up from the wall from the wall than if they were sliding down it.
 +
 +
==Slide Kick==
 +
It'd look roughly like this. Lock walking would probably be a separate function called to disable the player's controls for a timeframe so player inputs do not interrupt the slide. Should the player be able to jump out of the slide, though?
 +
 +
<pre>
 +
void CPlayer::think(){
 +
if(!keystates[SDLK_x]) { //Can't already be pressing the x button.
 +
if(keystates[SDLK_DOWN] && keystates[SDLK_x] && !lockslide && !jumping){ //the player is pressing down, X, isn't jumping, and isn't sliding.
 +
lockslide = true;
 +
<change hitbox sizes from standing to sliding sizes, which means from Tall and Skinny to Short and Fat>
 +
if(faceright)
 +
velx += slideVel; //Takes players current velocity and adds sliding velocity to it. Slides right.
 +
else
 +
velx += -slideVel; //Takes players current velocity and adds sliding velocity to it. Slides left.
 +
<lock walking for half a second>
 +
velx = 0;
 +
lockslide = false;
 +
<unlock walking >
 +
}
 +
}
 +
}
 +
</pre>

Latest revision as of 16:13, 26 June 2014

Motion: Mechanics and Flow

This is a poorly written up page on the mechanics and flow of Motion. This is written for later use when C is in a better position to properly exercise his theories. All of this applies to the player objects in the game.

This does not address VIP things like the player state or frame rate. Slopes are not considered in these code snippets.

The idea with Motion is to have Super Mario World style gameplay, as close a 1:1 experience as we can get it, with the addition of wall jump and slide kick mechanics.

bool run
bool lockJump
bool inAir
bool wallJumpAble

float walkVel = 2.0
float runVel = 2.75
float jumpVel = 4.5
float runJumpVel = 5.1

float gravity = 0.20

Also note that the CPlayer::think() snippets presented here are not the whole thing. The entire thing would actually be quite lengthy, so it is cut down to save space.

Collision

Collision in Motion is detected on a tile by tile basis. The game flow checks the tiles, not the pixels, that the player's hitbox has collided with. Typical collision with a tile from the sides- that is, the tiles left and right sides- reduces player's horizontal velocity to zero so that the player doesn't go through the tile on either side.

Similarly, the tile's collision is checked from the top and bottoms and sets the player's vertical velocity to zero so that gravity doesn't push them through the ground, or so that the player doesn't jump up through the ceiling. When the bottom of the player's hitbox is touching the top of a tile, the player is not considered in air. So, inAir bool would be set false.

Walking and Running

Self explanatory, for the most part. A global variable determines the player's movement speed for when they press the left and right buttons.

void CPlayer::think(){
	velx=0;	//don't move left / right by default

	if(keystates[SDLK_RIGHT]){
		velx = walkVel;		//move right
 		faceright = true;		//player graphic is facing right
	}
	if(keystates[SDLK_LEFT]){
		velx = -walkVel;		//move left
		faceright = false;
 	}
}

Running, however, can actually be implemented two ways:

Double Tap Run

"Double Tap" Run is the sort of run mechanic seen in the Kirby series or in Super Smash Brothers. Basically, you double tap a direction to run.

A bool for running is set up. When the bool for running is set false, the player moves with their globally defined walking speed variable. When true, the player moves with the defined running speed variable.

A timer is set up during the initial movement button press. If the button is pressed again during that timer and held, a bool for running is set true, then the player moves with the run velocity instead of the walk velocity. The running bool remains true as long as the button is pressed and held.

Hold Button Run

"Hold Button" Run is seen in most 2d platformers, like Donkey Kong Country and Super Mario Brothers. Of the two, it is easier to implement because it simply adds a check for a button being pressed before deciding which movement speed variable to apply to the movement calculation.

void CPlayer::think(){
	velx=0;	//don't move left / right by default

	if(keystates[SDLK_x]){
		if(keystates[SDLK_RIGHT]){
			velx = runVel;		//move right
 			faceright = true;		//player graphic is facing right
		}
		if(keystates[SDLK_LEFT]){
			velx = -runVel;		//move left
			faceright = false;
 		}
 	}
	else{
		if(keystates[SDLK_RIGHT]){
			velx = walkVel;		//move right
 			faceright = true;		//player graphic is facing right
		}
		if(keystates[SDLK_LEFT]){
			velx = -walkVel;		//move left
			faceright = false;
 		}
	}
}

This is actually slightly inefficient, since it's more lines. However, if most of your mechanics' physics are more contingent on a run button being or not being held down, then you may be better off in the long run doing this.

[C, double check with an actual programmer on that.]

void CPlayer::think(){
	velx=0;	//don't move left / right by default

	if(keystates[SDLK_RIGHT]){
                if(keystates[SDLK_x])
                     velx = runVel;             //run right
                else
		     velx = walkVel;		//walk right
 		faceright = true;		//player graphic is facing right
	}
	if(keystates[SDLK_LEFT]){
                if(keystates[SDLK_x])
                     velx = -runVel;            //run left
                else
		     velx = -walkVel;		//walk left
 		faceright = false;		//player graphic is facing right 	
     }
}

A bool for running is not necessary, but recommended anyway for later mechanics checking movement speed.

Acceleration

To create acceleration, instead of having a base movement velocity, you have a smaller velocity that that gets incremented into the movement speed by a check. Movement speed is checked against a defined max speed. If movement speed is less than the max speed, the movement speed is incremented. Otherwise, the calculation stops incrementing and defaults the movement speed to max speed.

Jumping

In the case of having a run mechanic, a second global variable for jump velocity should be set. So you have jumpVel and then runJumpVel.

Button is pressed and jumpVel is applied to player object.

void CPlayer::think(){
	if(keystates[SDLK_RSHIFT] && !lockjump){	//if the player isn't jumping already
		vely = -VELJUMP;		//jump!
		lockjump = true;		//player is not allowed to jump anymore
	}
}

With a run mechanic, there is an if/else or switch check to check whether or not run bool is set true. When run bool is set true, you'd instead apply the runJumpVel.

void CPlayer::think(){
	if(keystates[SDLK_z] && !lockjump){ //if the player isn't jumping already
		if(running)
			vely = -runJump;		//jump!!!
		else	
			vely = -nrmJump;		//jump
		lockjump = true;			//player is not allowed to jump anymore
	}
}

Once the player has jumped, a jumping bool is set true, and lockJump is set true. If lockJump is not set, the player gets infinite jumps in the air.

Variable Jump Height

We need the jumping bool for variable jump height. Variable jump height is when you can slightly control the height of your jump by holding the button down until the apex of the jump. If you release the jump button before the apex, the jump is cut short to a hop.

void CPlayer::think(){
        if(keystates[SDLK_z] && !lockjump){ //if the player isn't jumping already
		if(running)
			vely = -runJump;		//jump!!!
		else	
			vely = -nrmJump;		//jump
		lockjump = true;			//player is not allowed to jump anymore...
	        jumping = true;                         //...because the player is jumping now!
        }

	if(!keystates[SDLK_z] && jumping){ //when the player has released the jump button during his jump.
		vely += jumpFraction;
		jumping = false;                       //The player stopped jumping.
	}
}

Wall Jumps

The player's inAir bool is true and lockJump is true. The player has also collided with a wall and a timer is set. A bool, wallJumpAble is set true and checked with inAir.

If both are true, then the player gets a Wall Jump with the velocity they had hit the wall with, but only during the timer.

Wall Stick/Slide

To make this appear more fluid (because the wall catching sprite is wider on either side than the usual sprite) apply a second hitbox when the player has reached appropriate velocity. Instead of checking the player's collision against the wall, it checks the slight extension of the box.

When this hitbox touches the wall, the player's horizontal velocity is set zero, but their vertical velocity doesn't change, meaning they will slide up and down the wall on that extended hitbox. During this time, wallJumpAble is set true, and lockJump is false, meaning the player can jump again off the wall.

To make the wall jump seem a bit more realistic, do a check on the player's vertical velocity. If the player's vertical velocity is still increasing, the player's wall jump has more velocity away and up from the wall from the wall than if they were sliding down it.

Slide Kick

It'd look roughly like this. Lock walking would probably be a separate function called to disable the player's controls for a timeframe so player inputs do not interrupt the slide. Should the player be able to jump out of the slide, though?

void CPlayer::think(){
	if(!keystates[SDLK_x]) { //Can't already be pressing the x button.
		if(keystates[SDLK_DOWN] && keystates[SDLK_x] && !lockslide && !jumping){ //the player is pressing down, X, isn't jumping, and isn't sliding.
			lockslide = true;	
			<change hitbox sizes from standing to sliding sizes, which means from Tall and Skinny to Short and Fat>	
			if(faceright)
				velx += slideVel;	//Takes players current velocity and adds sliding velocity to it. Slides right.
			else
				velx += -slideVel;	//Takes players current velocity and adds sliding velocity to it. Slides left.
			<lock walking for half a second>
			velx = 0;
			lockslide = false;
		<unlock walking >
		}	
	}
}