Table of contents
Player Class Overview
Player Resources Setup
The Player
class has a ton of instance variables that need to be setup upon creation, but they are all relatively straightforward.
First, let’s start with the “movement” based variables – the following define how the Player
character is able to move throughout a level. These are all float values, so decimal precision for movement is available.
- walkSpeed - how fast the player walks
- gravity - how fast the player falls when in air
- jumpHeight - how high the player jumps
- jumpDegrade - as the player is jumping upwards, less and less vertical velocity gets applied per cycle based on this value
- momentumYIncrease - how much extra the player falls in addition to gravity while in the air
- terminalVelocityY - the fastest speed the player can fall before the fall speed gets “capped” (stops being able to increase)
Generally, Player
subclasses will set those values as desired.
The Player
has several other important variables it uses to keep track of its current state:
- playerState - based on the
PlayerState
enum in theLevel
package, aPlayer
can be in a certain state which affects its game logic; currently, the supported states areSTANDING
,WALKING
,JUMPING
, andCROUCHING
- facingDirection - which direction the player is facing; can be either
LEFT
orRIGHT
- airGroundState - if the player is currently on the ground
GROUND
or in the airAIR
(yes I know this is a horrible variable name but I couldn’t think of anything better) - levelState - allows the player to keep track of the current level state so it can know if it has beaten a level or has died in a level; more details on
LevelState
can be found in thePlayLevelScreen
documentation here
Player Class Methods
The player’s update
cycle handles a ton of different cases based on the current PlayerState
, and the Player
class has split up most of that state logic into separate methods. For example, walking logic is in a separate method to jumping logic, etc. The handlePlayerState
method determines which game logic method to go to based on the playerState
instance variable:
protected void handlePlayerState() {
switch (playerState) {
case STANDING:
playerStanding();
break;
case WALKING:
playerWalking();
break;
case CROUCHING:
playerCrouching();
break;
case JUMPING:
playerJumping();
break;
}
}
Player Subclasses
Players to be used in game are defined by subclassing the Player
class. These are found in the Player
package. The cat player is defined by the Cat
class.
The subclass doesn’t have to do much, as the Player
class contains all of the standard player functionality. If a change is going to be specific to one player, then it can be added to a subclass, but any changes that would affect all players should be done in the base Player
class.
The Cat
subclass sets various movement related attributes to desired values and also defines the player’s animations. The Player
class expects certain animations be included in a player subclass by name, all of which are included in the Cat
subclass, although this can be easily changed and additional animations can be added freely. Currently, the Player
class expects the following animations. Most animations have a “left” and “right” counterpart, which are used based on the way the player is facing.
STAND_RIGHT
andSTAND_LEFT
– player standing stillWALK_RIGHT
andWALK_LEFT
– player walkingJUMP_RIGHT
andJUMP_LEFT
– player jumping (rising upwards)FALL_RIGHT
andFALL_LEFT
– player fallingCROUCH_RIGHT
andCROUCH_LEFT
– player crouchingDEATH_RIGHT
andDEATH_LEFT
– player dyingSWIM_STAND_RIGHT
andSWIM_STAND_LEFT
– player is standing still in water
Looking at the Cat
class’s constructor is a good reference point for making an additional player.
public Cat(float x, float y) {
super(new SpriteSheet(ImageLoader.load("Cat.png"), 24, 24), x, y, "STAND_RIGHT");
gravity = .5f;
terminalVelocityY = 6f;
jumpHeight = 14.5f;
jumpDegrade = .5f;
walkSpeed = 2.3f;
momentumYIncrease = .5f;
}
The image file for the cat player is Cat.png
.
Player Moving
When the player moves through the level, you may notice that most of the time the player is not actually moving around screen, and instead stays in the middle of the screen while the map’s camera moves to show more of the map. The only time the player actually moves is when the map’s camera reaches the end of the map and has no more map to show. You can see this behavior in the below gif. Notice how the player is kept in the middle of the screen a majority of the time while the camera continually shows different parts of the map.
While the player is in charge of the overall movement of the game, the map class’s adjustMovementX
and adjustMovementY
methods are called each frame which adjusts the player’s position and the camera’s position as needed. Usually, what happens is the player will move forward while at the center of the screen, and then the adjust methods will move the player back to the center of the screen and move the camera instead to show more of the map. This gives the appearance that the map is “scrolling”. And yes, nearly all games do this: 99% of the time your player character is not actually moving; instead the map’s camera is.
Player Update Cycle
Each update
cycle, the Player
class will do a few things:
- Apply gravity (downward force)
- Handle player state (more details on player state here)
- Move player by the amount it should be moved by based on the results of the handle player state step
- Handle player animation updates and see if a switch is needed
- Call super class’s update cycle in order to apply animation logic (
super.update();
)