In this tutorial we will make the game more challenging and fun by adding more cats at random positions and increasing the cat speed over time. You will learn how to organise and reuse your code by using tabs, lists and classes in Processing with Java.
This tutorial follows on from the last tutorial where we created a cat and mouse game.
This is what the final result looks like:
Step 1: Circle tab
In order to better organise our code, we are going to use tabs.
At the top of the code editor, there should be a downward arrow. If you click on it, you should be able to click on ‘New Tab’. Name the new tab ‘Circle’, and click ok.
Now you will be able to switch between your main tab which is named after your sketch, and the circle tab.
From the main tab, find the circle class, select all of it with your mouse, right click and press cut. Then go to the circle tab and paste it.
class Circle
{
...
}
Step 2: Player tab
To keeps things more generic, I will refer to the animal mouse as the player.
Next we are going to create a ‘Player’ class and use it to manage the game logic and the rendering of the player sprite.
Create a new tab called ‘Player’. Then create a class called ‘Player’ in the player tab.
class Player
{
}
First add an image variable to the player class.
PImage myImage;
Then add a circle variable to our player class.
Circle circle = new Circle();
Next add a SetPosition and SetRadius function inside the player class, we will use them to set the circle position and radius.
void SetPosition(float x, float y)
{
circle.SetPosition(x, y);
}
void SetRadius(float radius)
{
circle.SetRadius(radius);
}
Now add a ‘Update’ function inside the player class. This function will handle the player game logic. So it will set the position of the circle to the mouse position.
void Update()
{
SetPosition(mouseX, mouseY);
}
Next create a ‘Render’ function inside the player class. This function will render the player sprite and the optional debug circle.
void Render()
{
// Image
float x = mouseX - myImage.width / 2;
float y = mouseY - myImage.height / 2;
image(myImage, x, y);
// Debug circle
noStroke();
fill(255, 0, 0, 125);
circle(circle.x, circle.y, circle.radius*2);
}
We can now remove this at the top of the main tab:
PImage mouseImage;
Circle playerCircle = new Circle();
And add this instead:
Player player = new Player();
In the setup function, replace this:
mouseImage = loadImage("Mouse.png");
playerCircle.SetPosition(width / 2, height / 2);
playerCircle.SetRadius(32);
With this:
player.myImage = loadImage("Mouse.png");
player.SetPosition(width / 2, height / 2);
player.SetRadius(32);
Note how we are setting the player image to the mouse image.
We will fix the main tab GameLogic and Render functions later.
Step 3: Enemy tab
Like with the mouse and the player, I will refer to the cat as an enemy. If you don’t like this idea, then you can always replace the cat and mouse sprites with your own images 🙂
Next we are going to create a ‘Enemy’ class and use it to manage the game logic and the rendering of the enemy sprite.
Create a new tab called ‘Enemy’. Then create a class called ‘Enemy’ in the enemy tab. Like with the ‘Player’ class, we will use a PImage, Circle, SetPosition and SetRadius function.
class Enemy
{
PImage myImage;
Circle circle = new Circle();
void SetPosition(float x, float y)
{
circle.SetPosition(x, y);
}
void SetRadius(float radius)
{
circle.SetRadius(radius);
}
}
Next add the ‘Update’ function, which handles the game logic for the enemy. Notice how it is the same logic as before, except we use the class circle variable. This means we don’t need to prefix everything with ‘cat’. Since the circle is in the enemy class, we know the circle variable belongs to the enemy.
We also pass in an instance of the Player in the Update function as an argument. Later on we will pass in the player we created earlier to all the enemies.
void Update(Player player)
{
// Movement
float dx = player.circle.x - circle.x;
float dy = player.circle.y - circle.y;
float len = sqrt(dx*dx + dy*dy);
if(len > 0)
{
dx /= len;
dy /= len;
}
float speed = 2.0f;
circle.x += dx * speed;
circle.y += dy * speed;
}
We will add the Render function next. Which renders an image and the optional debug circle.
void Render()
{
// Image
float x = circle.x - myImage.width / 2;
float y = circle.y - myImage.height / 2;
image(myImage, x, y);
// Debug circle
noStroke();
fill(0, 0, 255, 125);
circle(circle.x, circle.y, circle.radius*2);
}
Step 4: Enemy list
We now have our enemy class, so next we will create a list of enemies. This will allow us to manage many enemies at once.
Go back to the main tab, and remove this:
Circle catCircle = new Circle();
Next we will create an ArrayList at the top of the program. An ArrayList allows us to store 0 to many objects. In this case we will store instances of the Enemy class we created.
ArrayList<Enemy> enemyList = new ArrayList<Enemy>();
You can remove this from the setup function now, since we will spawn the enemies in the next step inside of the GameLogic function.
catCircle.SetPosition(200, 100);
catCircle.SetRadius(32);
Step 5: Spawn enemies
The time has come to add more enemies to the game, and make the game more challenging!
First create two new variables at the top of the program.
int lastSpawnTime = 0;
final int MAX_ENEMIES = 100;
The lastSpawnTime represents the last time an enemy spawned. The MAX_ENEMIES integer is the maximum number of enemies which can spawn at once. The final keyword means the value is constant, and cannot be changed.
In the setup function, set the lastSpawnTime variable to the value of millis.
lastSpawnTime = millis();
Next create a new function called SpawnEnemies.
void SpawnEnemies()
{
if(enemyList.size() < MAX_ENEMIES && millis() - lastSpawnTime > 1000)
{
lastSpawnTime = millis();
Enemy e = new Enemy();
enemyList.add(e);
e.myImage = catImage;
e.SetRadius(32);
float radius = width / 2;
float x = width / 2;
float y = height / 2;
float angle = random(0, 360);
angle = radians(angle);
x += cos(angle) * radius;
y += sin(angle) * radius;
e.SetPosition(x, y);
}
}
This function only executes if the two conditions are true:
- The current number of enemies is less than max enemies.
- And it has been greater than a second since the last enemy spawned. We compare against 1000, since we are using milliseconds.
if(enemyList.size() < MAX_ENEMIES && millis() - lastSpawnTime > 1000)
We set the last spawn time to the current time, since we now want to compare against the next second in the future.
lastSpawnTime = millis();
Next we create a new enemy, add it to our enemy list, then set it’s image to use the cat image and finally set the radius.
Enemy e = new Enemy();
enemyList.add(e);
e.myImage = catImage;
e.SetRadius(32);
Now all we need to do is set the position of the enemy. First we will create a radius variable. We use half the width, so the enemy is always spawned outside the screen. Since width is the largest dimension.
float radius = width / 2;
Next we create an x and y position variables, and set them to the centre of the screen.
float x = width / 2;
float y = height / 2;
Pick a random angle in the 360 degree range.
float angle = random(0, 360);
Then convert to radians.
angle = radians(angle);
We plug the angle into the cosine and sine function. This gives us a value in the unit circle range of -1 to 1. We then multiply by our radius, and add the result to the x and y variables. This positions our new enemy outside the screen. Finally we just need to set the enemy position using the SetPosition function.
x += cos(angle) * radius;
y += sin(angle) * radius;
e.SetPosition(x, y);
Step 6: Enemy Speed
Lets make every enemy faster every time a new enemy spawns.
Create a new variable at the top of the program, which will represent the speed of all enemies.
float enemySpeed = 2.0f;
Go to the enemy tab and change this:
float speed = 2.0f;
circle.x += dx * speed;
circle.y += dy * speed;
To this:
circle.x += dx * enemySpeed;
circle.y += dy * enemySpeed;
Next go back to the main tab and find the SpawnEnemies function you created earlier. Add the enemySpeed variable in here:
void SpawnEnemies()
{
if(enemyList.size() < MAX_ENEMIES && millis() - lastSpawnTime > 1000)
{
lastSpawnTime = millis();
enemySpeed += 0.1f;
enemySpeed = min(enemySpeed, 5.0f);
This will increase the enemy speed by 0.1. Then make sure the max enemy speed doesn’t go beyond 5.
Step 7: Game Logic
Find the GameLogic function. Delete all the code inside of it. Then add SpawnEnemies to the top of the function.
SpawnEnemies();
Next call the player’s Update function.
player.Update();
Now we will update all the enemies. We can loop through all the enemies with this for loop. The e variable will get set to every enemy in the enemy list. We can use this variable to call each enemy’s Update function.
for(Enemy e : enemyList)
{
e.Update(player);
}
Finally we need to handle the collision between the player and enemies. Using another for loop, we loop through every enemy in the list.
We check if the current enemy’s circle overlaps the player circle. If it does, then:
- Reset the survival time.
- Empty the enemy list.
- Reset the enemy speed.
- And call break, to exit the for loop.
for(Enemy e : enemyList)
{
if(e.circle.Overlaps(player.circle))
{
startTime = millis();
enemyList.clear();
enemySpeed = 2.0f;
break;
}
}
Step 8: Render
Find the Render function. Delete all the code inside of it. Then clear the background.
background(190);
Next we will render all the enemies with the for loop.
for(Enemy e : enemyList)
{
e.Render();
}
Then we will render the player.
player.Render();
And finally draw the survival time as text again.
// Draw text
fill(255);
textSize(128);
textAlign(CENTER);
String currentTime = str((millis() - startTime) / 1000);
text(currentTime, width / 2, 120);
Conclusion
This tutorial has shown you how to use tabs, lists and classes in Processing. We created a circle, player and enemy tab. Then we created a player and enemy classes which handle there respective game logic and render themselves. We spawned many enemies randomly outside the screen, and increased the enemy speed over time to make the game more challenging and fun.
Thank you for reading this tutorial. Let me know in the comments section if you enjoyed it, or have any questions!

