For this extra credit project, I wanted to test my knowledge of the handshake between processing and arduino and so I came up with a space shooter game. It is a pretty basic game in which the space ship has to shoot the incoming meteoroids and if it shoots 10 of them the game is over.
Processing
The processing part is basically the interface of the game, which includes the start screen, the space ship, the asteroid and the whole shooting mechanism and also the end screen.
The game starts with the start screen in which the player clicks within a box to start playing.
The code basically spawns random sizes of asteroids, that fall at random speeds too. If the player is able to shoot 10 asteroids, the game is over and the player is prompted to either restart the game or click on game over to return to the start screen.
Processing Code:
import processing.serial.*; Serial myPort; ArrayList<Asteroid> asteroids = new ArrayList<Asteroid>(); //gives the list of asteroids Player player; //player object boolean shoot = false; // ensures that the player only shoots when commanded ArrayList<Player.Bullet> bullets = new ArrayList<Player.Bullet>(); //bullet list float timer = 0; float timerlength = 4000; boolean game_over = false; boolean start = false; int count = 0; int currentButtonState = 0; int prevButtonState = 0; float mover = width/2; void setup() { size(1280, 960); imageMode(CENTER); //asteroids.add(new Asteroid(random(width*0.25, width*0.75), 0, int(random(1, 3)))); //initialising the list of asteroids to spawn in between the roads of the game player = new Player(); printArray(Serial.list()); String portname=Serial.list()[6]; println(portname); myPort = new Serial(this,portname,9600); myPort.clear(); myPort.bufferUntil('\n'); } void draw() { PImage bg; bg = loadImage("space.jpeg"); bg.resize(int(width),int(height)); background(bg); //background is the top down view of a road if (start == false) { textAlign(BASELINE); rectMode(CENTER); fill(255); stroke(230,153,0); rect(width/2,height/2,700,500,10); rect(width/2, height/2,680,480,10); fill(0); textSize(50); text("Welcome", 480, 410); fill(255); rect(625,580,600,100,10); fill(0); text("Click to Play", 420, 610); if ((mouseX >= 325 && mouseX <= 925) && (mouseY >= 530 && mouseY <= 630) && (mousePressed == true)) { start = true; } } else{ if(game_over == false) { Player_Mechanics(); Asteroid_Mechanics(); Shoot(); Mover(); if( millis() > timer) { asteroids.add(new Asteroid(random(width*0.25, width*0.75), 0, int(random(1, 3)))); //initialising the list of asteroids to spawn timerlength = random(1000,5000); timer = millis() + timerlength; } } else{ textAlign(BASELINE); rectMode(CENTER); fill(255); stroke(230,153,0); rect(width/2,height/2,700,500,10); rect(width/2, height/2,680,480,10); fill(0); textSize(50); stroke(0); text("Game Over!", 420, 410); fill(255); rect(625,580,600,100,10); fill(0); text("Restart", 420, 610); if ((mouseX >= 325 && mouseX <= 925) && (mouseY >= 530 && mouseY <= 630) && (mousePressed == true)) { game_over = false; count = 0; } if ((mouseX >= 325 && mouseX <= 925) && (mouseY >= 330 && mouseY <= 430) && (mousePressed == true)) { start = false; } } } } void serialEvent(Serial myPort){ String s=myPort.readStringUntil('\n'); s=trim(s); if (s!=null){ println(s); int values[]=int(split(s,',')); if (values.length==3){ currentButtonState=(int)values[0]; prevButtonState=(int)values[1]; mover = map(values[2], 0, 1023, player.size/2, width-player.size/2); } } myPort.write("\n"); } void Player_Mechanics() { player.drawPlayer(); //draws the Player on Screen for(int i =0; i< bullets.size(); i++) { bullets.get(i).draw_Bullet(); bullets.get(i).shoot_Bullet(); //if bullets are present, draws them and shoots them if(bullets.get(i).bullet_posY_1 < 0 ) bullets.remove(i); //removes the bullet once they are out of frame } } void Asteroid_Mechanics() { for (int i = 0; i < asteroids.size(); i++) { asteroids.get(i).drawAsteroid(); asteroids.get(i).moveAsteroid(); //draws and moves asteroids on screen if(asteroids.get(i).posY > height + asteroids.get(i).size) asteroids.remove(i); //removes the asteroids once they are out of frame if( bullets.size() > 0 && asteroids.size() > 0 ) { for(int j=0; j<bullets.size(); j++) { if( bullets.size() > 0 && asteroids.size() > 0 ) { if(asteroids.get(i).vicinty_check(bullets.get(j).bullet_posX,bullets.get(j).bullet_posY_2)) { asteroids.remove(i); //destroys the asteroid and removes it once bullet touches it count++; } } } } } if (count == 10){ game_over = true; } } void keyPressed() { if (key == ' ') { asteroids.add(new Asteroid(random(width*0.25, width*0.75), 0, int(random(1, 3)))); //spawns an asteroid } if (key == 'a') { player.moveLeft(); //player goes left } if (key == 'd') { player.moveRight(); //player goes right } if (key == 'f') { bullets.add(player.new Bullet(0)); //shoots bullets } } void Shoot() { if (currentButtonState == 1 && prevButtonState == 0) { bullets.add(player.new Bullet(0)); println("cheeky"); } } void Mover() { player.posX = mover; }
class Asteroid { float posX; float posY; int speed = (int)random(2,6); int size; PImage asteroid; Asteroid(float x, float y, int s) { posX = x; posY = y; size = s*100; asteroid = loadImage("asteroid_brown.png"); imageMode(CENTER); } void drawAsteroid() { asteroid.resize(size, 0); image(asteroid, posX, posY); //resizes and draws the asteroid } void moveAsteroid() { posY += speed; //moves the asteroid } boolean vicinty_check(float x, float y) { if ((x < posX+size/2 && x > posX-size/2) && (y < posY+size/2 && y > posY-size/2)) //checks if anything exists in the vicintiy of the asteroid's body return true; else return false; } }
class Player { public float posX = width/2; public float posY = height-100; PImage player; int movement=20; int size =100; Player() { player = loadImage("Spaceship_tut.png"); imageMode(CENTER); } void drawPlayer() { player.resize(size, 0); pushMatrix(); translate(posX, posY); //rotate(radians(270)); image(player, 0, 0); popMatrix(); //resizes and rotates the image of the player on screen so that it is appropriate for the game } void moveLeft() { if (posX > size/2) posX -= movement; //player moves left } void moveRight() { if (posX < width-size/2) posX += movement; //player moves right } class Bullet { //nested bullet class in player class float bullet_posX = posX ; float bullet_posY_1 = posY - size/2; float bullet_size = size * 0.1; float bullet_posY_2 = posY - size/2 - bullet_size; int bullet_speed = 20; Bullet(float y) { bullet_posY_1 -= y; bullet_posY_2 -= y; //assigns intial position to bullet } void draw_Bullet() { stroke(102,255,102); strokeWeight(6); line(bullet_posX, bullet_posY_1, bullet_posX, bullet_posY_2); //draws a line for a bullet } void shoot_Bullet() { bullet_posY_1 -= bullet_speed; bullet_posY_2 -= bullet_speed; //moves bullet } } }
Arduino
The Arduino part involves the controls for the game in which the potentiometer is used to move the spaceship around and the push button is used to shoot the missiles from the spaceship.
Arduino Code:
int buttonPin = 2; int prevButtonState = LOW; void setup() { pinMode(buttonPin, INPUT); Serial.begin(9600); Serial.println("0,0"); } void loop() { while (Serial.available()) { if (Serial.read() == '\n') { int currentButtonState = digitalRead(buttonPin); delay(1); Serial.print(currentButtonState); Serial.print(','); Serial.print(prevButtonState); Serial.print(','); prevButtonState = currentButtonState; int mover = analogRead(A0); delay(1); Serial.println(mover); } } //Serial.println(sensor); }
Circuit:
Videos:
This is the video of me showing the way the game works:
This is a video of me actually playing the game:
Difficulties:
In certain instances, I felt that the button was not responding in the way I wanted it to but I believe that is primarily because I hadn’t plugged it well or the communication of information was slow.
Overall:
This project was actually really fun and it made me feel so cool to create my own joystick for my game. This has also motivated me quite a lot for my final project which I am really looking forward to!