Repository navigation
PlatformerComponent
This component provides a jump ability to the player (and hopefully other entities down the line) that the component is attached to. It has double jump and super jump capabilities that can be opted into by the Setter functions or through the constructor. This paves the way for powerups later on which may include a double or super jump.
To jump, it takes in a Vector2 from the listener and determines if the entity is grounded unless the double jump ability is turned on and there's double jumps left, if neither is true then the player won't jump. The base jump scaler (and super jump scaler if the super jump ability was turned on) is applied. The jumping field is then turned on.
public boolean isGrounded() {
Body body = physicsComponent.getBody();
return (body.getLinearVelocity().y == 0);
}
Keep in mind that the top portion is the code for the wall jump (which will be explained later) and the bottom section is the general calculator for the jump
//Wall jump takes priority over a normal jump (given the player is not grounded),
//you cannot normal jump and wall jump at the same time. Wall jump doesn't
//replenish double jumps
this.jumpDirection.y = direction.y;
//Wall jump code
if((Objects.equals(canWallJump(), "RIGHT")||Objects.equals(canWallJump(), "LEFT"))&&!isGrounded()){
...
}//Normal jump code
else if (isGrounded() || (doubleJumpPowerup && doubleJumpRemaining > 0)) {
this.jumpDirection.y *= baseJumpScaler;
if (!isGrounded()) doubleJumpRemaining--;
if (superJumpPowerup) this.jumpDirection.y *= superJumpScaler;
jumping = true;
}
if (doubleJumpPowerup && isGrounded()) {
doubleJumpRemaining = maxDoubleJump;
}
}
The jump has a scaler (MAX_SPEED) applied to it which is passed to the function by the entity. The mass of the object is applied to the jump and the jump is then applied to the entity as a linear impulse.
public void updateJump(Vector2 MAX_SPEED) {
if (jumping) {
Body body = physicsComponent.getBody();
Vector2 desiredVelocity = jumpDirection.cpy().scl(MAX_SPEED);
Vector2 jumpImpulse = desiredVelocity.scl(body.getMass());
body.applyLinearImpulse(jumpImpulse, body.getWorldCenter(), true);
jumpDirection.y = 0;
jumping = false;
}
}
The wall jump works by checking if the player is near a wall by using a raycast to the left and right from the player's position. The distance between the player and the raycast hit point is calculated and set to left/right. If the raycast.point hits something and the distance is within the distanceThreshold then the wall jump is counted. The String is then sent to the jump(Vector2 direction) where it's processed
// Will return LEFT if can wall jump from the left, return RIGHT if can wall
// jump from the right. Will return NONE if can not wall jump
public String canWallJump() {
RaycastHit leftHit = new RaycastHit();
RaycastHit rightHit = new RaycastHit();
// as well as the right part of the wall, so we give a boost to the distanceThreshold
float distanceThreshold = 5f; // The wall jump applies if the collider is X units away
Vector2 from = entity.getPosition();
from.y+=5;
Vector2 fromRight = from;
fromRight.x+=8;//Moving "fromRight" to the right since entity.getPosition()
//returns the Entity's position form the bottom left of the character
Vector2 fromLeft = from;//It's already on the left
Vector2 vectorToRight = new Vector2(fromRight.x + (distanceThreshold), fromRight.y);
Vector2 vectorToLeft = new Vector2(fromLeft.x-distanceThreshold, fromLeft.y);
float left = 100000;
float right = 100000;
physics.raycast(fromLeft, vectorToLeft, PhysicsLayer.OBSTACLE, leftHit);
if (leftHit.point != null) {
left = Math.abs(from.x - leftHit.point.x);
}
physics.raycast(fromRight, vectorToRight, PhysicsLayer.OBSTACLE, rightHit);
if (rightHit.point != null) {
right = Math.abs(from.x - rightHit.point.x);
}
if(left<right) {
if (left <= distanceThreshold && leftHit.point != null) {
return "LEFT";
}
} else {
if (right <= distanceThreshold && rightHit.point != null) {
return "RIGHT";
}
}
return "NONE"; // If neither then return NONE
}
The jumpDirection is then sent to the updateSpeed() function
jump(Vector2 direction) application code:
private void jump(Vector2 direction) {
// Wall jump takes priority over a normal jump (given the player is not grounded),
// you cannot normal jump and wall jump at the same time. Wall jump doesn't
// replenish double jumps
this.jumpDirection.y = direction.y;
// Wall jump code
if ((Objects.equals(canWallJump(), "RIGHT") || Objects.equals(canWallJump(), "LEFT"))
&& !isGrounded()) {
if (Objects.equals(canWallJump(), "RIGHT")) {
this.jumpDirection.x = -1;
} else if (Objects.equals(canWallJump(), "LEFT")) {
this.jumpDirection.x = 1;
}
this.jumpDirection.x *= direction.y;
// Making sure that we are jumping off the wall with equal x and y forces
this.jumpDirection.scl(baseJumpScaler);
if (superJumpPowerup) this.jumpDirection.scl(superJumpScaler);
jumping = true;
}//Normal jump code
...
}