Difference between revisions of "PRJ-Motion:MechanicsAndFlow"
(One intermediate revision 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. |
+ | |||
+ | 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. | ||
<pre> | <pre> | ||
Line 182: | Line 184: | ||
if(!keystates[SDLK_x]) { //Can't already be pressing the x button. | 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. | 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 > | <unlock walking > | ||
} | } | ||
Line 196: | Line 198: | ||
} | } | ||
</pre> | </pre> | ||
− | |||
− |
Latest revision as of 16:13, 26 June 2014
Contents
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 > } } }