Fisica Platformer
In the first part of this tutorial we went over the platformer genre, how apparent it is in the gaming industry, and we began making the very basics of our own in Processing using the Fisica library. By the end of the tutorial we had our player able to move and jump around on a surface. In this tutorial we’ll be adding an entity that will roam around randomly and give our player the ability to shoot it.
Final note before the tutorial, all code in this tutorial will be added into the final code from part 1 of this tutorial series.
Firstly, we’ll need to add two ArrayList objects to store the enemies along with the bullets shot by the player. The reasoning for using an ArrayList is that the size/length of these lists will vary. The snippet of code down below will demonstrate how to declare and instantiate the two ArrayList objects.
ArrayList enemies = new ArrayList();
ArrayList bullets = new ArrayList();
void setup() {
...
}
Now that we have the means of storing our enemies and bullets, we’ll add our enemies. We’ll start by adding a “addEnemy” function with two parameters, the desired x & y position of our enemy (both are floats.) The function will create an FBox named enemy and set its position to the ones given in the arguments. We will then set the color of the enemy to bright red using “setFill” and reducing the friction to ensure the enemies move smoothly using “setFriction”. After our enemies are made with the given details we will add them to the enemies ArrayList and then add it to the FWorld. The resulting code is below.
void addEnemy(float x, float y) {
FBox enemy = new FBox(30, 30); //Adds enemy as FBox
enemy.setRotatable(false);
enemy.setPosition(x, y); //Sets position to given x or y
enemy.setFriction(0);
enemy.setFill(255, 0, 0); //Sets enemy to red
enemies.add(enemy); //Adds enemy to world & array
world.add(enemies.get(enemies.size()-1)); //^ (Uses "enemies.size() - 1" to add most recent enemy)
}
We’ll make the movement of our enemies considerably random by creating a “moveEnemies” function which will just loop through the enemies ArrayList and using addForce we’ll add a random force making them move left or right.
void moveEnemies() {
//Randomly moves enemies
for (int i=0; i<enemies.size(); i++) {
enemies.get(i).addForce(random(-250, 250), 0);
}
}
Now that we have the basics down for our enemies it’s a lot more useful if we actually used the code we just wrote. We’ll add “addEnemy(random(width), height / 8);” to our setup function along with the other “world.add” lines. This will add an enemy near the top of the screen in a random x-position that will fall down to the platform with our player. Next, we’ll simply add “moveEnemies” above “world.step()” in our draw function. Now our program should have one red square enemy which roams around with our player.
To finish off this part of the tutorial we’ll be implementing bullets, collision between bullets & enemies, and tweaking the “platformCheck” function.
To add the bullets we’ll create a “addBullet(float x, float y)” function. Then we’ll add Processing’s built-in “mousePressed” function which will call our “addBullet” function with the mouse x & y as the arguments.
void mousePressed() {
addBullet(mouseX, mouseY); //Adds bullet upon mouse being pressed
}
void addBullet (float x, float y) {
}
Now the obvious issue with “addBullet” is that it’s empty. Firstly, we’ll make two float variables named “heightDiff” and “widthDiff” which will equal the distance between the mouse’s x & y positions and the player’s. We’ll then create an FBox named “bullet” and give it a radius of 5. Then will use Fisica’s “setBullet(true)” as it gives fast-moving objects more accurate calculations. Then we’ll add an if-else statement that checks which side of the player the mouse is on two make the bullet come out of that side of the player. Then we’ll set the bullets x & y velocities to the width & height difference variables multiplied by 15 to give the bullets a fast speed in the direction of the mouse. Lastly, just like the addEnemy function we’ll add the bullet to the bullets ArrayList and the world. The code should appear as down below.
void addBullet (float x, float y) {
float heightDiff = mouseY - player.getY(); //Calculates difference between mouse position and player's
float widthDiff = mouseX - player.getX(); //^
FBox bullet = new FBox(5, 5); //Creates bullet with radius of 5
bullet.setBullet(true); //Setting an FBox as a bullet is ideal for fast moving objects, more accurate calculations
//Makes bullet appear on left or right side of player depending on mouseX
if (mouseX < player.getX()) {
bullet.setPosition(player.getX() - 20, player.getY());
} else {
bullet.setPosition(player.getX() + 20, player.getY());
}
bullet.setVelocity(widthDiff * 15, heightDiff * 15); //Sets velocity bases on mouse position
bullets.add(bullet); //Adds bullet to array
world.add(bullets.get(bullets.size()-1)); //adds bullet to world
}
Now that we've added our enemies and bullets we'll add a function named "bulletCheck()" which will loop through our bullets, check if they're touching anything with "getTouching()" and if so, loop through our enemies and then use "getTouching()" and if it returns true, remove the bullet & enemy from the world and their arrays.
void bulletCheck() {
//Loops through all bullets
for (int i=0;i 0) {
//Loops through enemies
for (int j=0; j
We'll then call this function in our draw function so it runs every frame. The last thing we'll be doing in this part of the tutorial is changing the way platformCheck() works to base if off of the players y-velocity rather then whether or not they're touching the platform. This will allow the function to work if you were to add other platforms or obstacles. This is a fairly simple change which can be seen below.
void platformCheck() {
//Keeps track of if the player touching platform for ease of access
if (player.getVelocityY() < 0.001 && player.getVelocityY() > -0.001) {
onGround = true;
} else {
onGround = false;
}
}
We should now have a platformer with a player able to move around and shoot, with enemies who roam around randomly. Now with the basics over, you should challenge yourself to add more to it. Some ideas could be adding more enemies and make them chase the player, add a score for killing enemies and make them respawn or make the player have health so the game could end. The complete code can be found down below.
//Declares Fisica variables
FWorld world;
FBox platform;
FBox player;
ArrayList enemies = new ArrayList();
ArrayList bullets = new ArrayList();
boolean left, right, onGround;
void setup() {
size(480, 360); //Creates canvas
Fisica.init(this); //Initiates Fisica library
world = new FWorld(); //Instantiates world as FWorld()
world.setEdges(); //Sets edges of the screen to physical border
player = new FBox(30, 30);
player.setPosition(width / 2, height / 8);
platform = new FBox(width, 30);
platform.setPosition(width / 2, height * 0.8);
platform.setStatic(true); //Sets "platform" to static (won't be affected by forces such as gravity
addEnemy(random(width), height / 8);
//Adds content to world.
world.add(player);
world.add(platform);
}
void draw() {
background(30); //Sets background to grey, clears previous content
fill(255);
text("A & D to move left & right", 10, 15);
text("Space to jump", 10, 30);
platformCheck(); //Detects whether or not player is touching platform.
bulletCheck();
world.step(); //Moves "world" forward by 1/60th of a second
world.draw(); //Draws all content contained in "world"
if (left) {
player.setVelocity(-100, player.getVelocityY()); //Moves player left
}
if (right) {
player.setVelocity(100, player.getVelocityY()); //Moves player right
}
}
void platformCheck() {
//Keeps track of if the player touching platform for ease of access
if (player.getVelocityY() < 0.001 && player.getVelocityY() > -0.001) {
onGround = true;
} else {
onGround = false;
}
}
void keyPressed() {
//Keeps track if player is moving left or right
if (key == 'a' || key == 'A') {
left = true;
}
if (key == 'd' || key == 'D') {
right = true;
}
if (key == ' ' && onGround) {
player.addForce(0, - (player.getMass() * 10000)); //Makes player jump
}
}
void keyReleased() {
//Keeps track if player is going left & right, if not it slows down player quickly
if (key == 'a' || key == 'A') {
left = false;
player.setVelocity(player.getVelocityX() * 0.5, player.getVelocityY()); //Reduces player's velocity by half
}
if (key == 'd' || key == 'D') {
right = false;
player.setVelocity(player.getVelocityX() * 0.5, player.getVelocityY()); //Reduces player's velocity by half
}
}
void addEnemy(float x, float y) {
FBox enemy = new FBox(30, 30); //Adds enemy as FBox
enemy.setRotatable(false);
enemy.setPosition(x, y); //Sets position to given x or y
enemy.setFriction(0);
enemy.setFill(255, 0, 0); //Sets enemy to red
enemies.add(enemy); //Adds enemy to world & array
world.add(enemies.get(enemies.size()-1)); //^ (Uses "enemies.size() - 1" to add most recent enemy)
}
void moveEnemies() {
//Randomly moves enemies
for (int i=0; i 0) {
//Loops through enemies
for (int j=0; j