The curses have random x and y positions and they move at random speeds. Once they collide with Yuji (the character) they disappear and the player loses a life. (You start with 5 lives, and you can also lose a life when you allow the ghosts to go offscreen). The curses also disappear when you shoot them. This class has two functions: display and move. Display shows the image if the boolean (disp) is true, and move makes the ghosts move in the x direction and come back on the left side of the screen if they leave the screen on the right.
This is the bullets class: (I have 2 in my code but they are essentially the same so I’ll only copy one onto here):
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class Bullet {
float posx, posy;
float speed;
float a; //acceleration
float r;
boolean disp = true;
color col;
Bullet(float _posx, float _posy, float _speed, float _a, color _col){
posx = _posx;
posy = _posy;
col = _col;
speed = _speed;
a = _a;
r =50;
}
voiddisplay(){
fill(col);
if(disp){
circle(posx, posy, r);
}
}
voidmove(){
posx -= speed;
speed += a;
}
float distance(float x, float y){
returndist(posx, posy, x, y);
}
boolean done(){
// removing bullets once they leave the screen
if(posx <0-r){
returntrue;
}else{
returnfalse;
}
}
}
class Bullet {
float posx, posy;
float speed;
float a; //acceleration
float r;
boolean disp = true;
color col;
Bullet(float _posx, float _posy, float _speed, float _a, color _col) {
posx = _posx;
posy = _posy;
col = _col;
speed = _speed;
a = _a;
r =50;
}
void display() {
fill(col);
if (disp) {
circle(posx, posy, r);
}
}
void move() {
posx -= speed;
speed += a;
}
float distance(float x, float y) {
return dist(posx, posy, x, y);
}
boolean done() {
// removing bullets once they leave the screen
if (posx < 0-r) {
return true;
} else {
return false;
}
}
}
class Bullet {
float posx, posy;
float speed;
float a; //acceleration
float r;
boolean disp = true;
color col;
Bullet(float _posx, float _posy, float _speed, float _a, color _col) {
posx = _posx;
posy = _posy;
col = _col;
speed = _speed;
a = _a;
r =50;
}
void display() {
fill(col);
if (disp) {
circle(posx, posy, r);
}
}
void move() {
posx -= speed;
speed += a;
}
float distance(float x, float y) {
return dist(posx, posy, x, y);
}
boolean done() {
// removing bullets once they leave the screen
if (posx < 0-r) {
return true;
} else {
return false;
}
}
}
The bullets have the same functions as the curses class, with the addition of a color argument in the constructor (since there are two types of bullets in the game , one for the fingers and the other for the curses).
There is a distance variable which measures the distance of each bullet, since the bullets are in an array list.
The boolean ‘done’ removes the bullets once they’re offscreen to save memory!
The ‘Sukuna’Class refers to the fingers, here it is:
It only has a display function, which is exactly the same as the other classes display functions, since the finger doesn’t move on screen once it appears.
As for the main code, I’ll go through it bit by bit:
Here is my beginning code, which is mostly filled with initializing variables:
void setup () {
fullScreen();
battlebg = loadImage("battlebg.png");
battlebg.resize(displayWidth, displayHeight);
translate((displayWidth-1425)/2, (displayHeight-780)/2 +100);
yujix = width-100;
yujiidle = loadImage("yujiidle.png");
yujishoot= loadImage("yujishoot.png");
logo = loadImage("logo.png");
leftghost = loadImage("leftghost.png");
finger = loadImage("finger.png");
win = loadImage("win.jpg");
lose = loadImage("losepic.png");
bullets = new ArrayList<Bullet>();
sbullets = new ArrayList<SBullet>();
minim = new Minim(this);
powerup =minim.loadFile("powerup.wav");
theme = minim.loadFile("jjkop.wav");
theme.loop();
gameover = minim.loadFile("gameover.wav");
life = minim.loadFile("life.wav");
woosh = minim.loadFile("swoosh.wav");
winsound = minim.loadFile("winsound.wav");
gamefont = createFont("/Users/fatimaaljneibi/Library/Fonts/Anime Inept.otf", 32);
imageMode(CENTER);
textAlign(CENTER);
//ghosts:
curses = new Curse[8] ;
for (int i = 0; i<curses.length; i++) {
curses[i]= new Curse(0, random(200, height-200), random(2, 8), random(-5, 5) );
}
sukuna = new Sukuna[1] ;
for (int i = 0; i<sukuna.length; i++) {
sukuna[i]= new Sukuna(random(300, width-300), random(200, height-200));
sukuna[i].disp = false;
}
//serial setup stuff :
printArray(Serial.list());
String portname=Serial.list()[17];
println(portname);
myPort = new Serial(this, portname, 9600);
myPort.clear();
myPort.bufferUntil('\n');
}
void setup () {
fullScreen();
battlebg = loadImage("battlebg.png");
battlebg.resize(displayWidth, displayHeight);
translate((displayWidth-1425)/2, (displayHeight-780)/2 +100);
yujix = width-100;
yujiidle = loadImage("yujiidle.png");
yujishoot= loadImage("yujishoot.png");
logo = loadImage("logo.png");
leftghost = loadImage("leftghost.png");
finger = loadImage("finger.png");
win = loadImage("win.jpg");
lose = loadImage("losepic.png");
bullets = new ArrayList<Bullet>();
sbullets = new ArrayList<SBullet>();
minim = new Minim(this);
powerup =minim.loadFile("powerup.wav");
theme = minim.loadFile("jjkop.wav");
theme.loop();
gameover = minim.loadFile("gameover.wav");
life = minim.loadFile("life.wav");
woosh = minim.loadFile("swoosh.wav");
winsound = minim.loadFile("winsound.wav");
gamefont = createFont("/Users/fatimaaljneibi/Library/Fonts/Anime Inept.otf", 32);
imageMode(CENTER);
textAlign(CENTER);
//ghosts:
curses = new Curse[8] ;
for (int i = 0; i<curses.length; i++) {
curses[i]= new Curse(0, random(200, height-200), random(2, 8), random(-5, 5) );
}
sukuna = new Sukuna[1] ;
for (int i = 0; i<sukuna.length; i++) {
sukuna[i]= new Sukuna(random(300, width-300), random(200, height-200));
sukuna[i].disp = false;
}
//serial setup stuff :
printArray(Serial.list());
String portname=Serial.list()[17];
println(portname);
myPort = new Serial(this, portname, 9600);
myPort.clear();
myPort.bufferUntil('\n');
}
I set the game to be in fullscreen, loaded all my images and fonts, and called my classes ( there are 8 ghosts, 1 finger, and array lists for the bullets). I ended up using Minim instead of the processing sound library, because I found it easier to use for my sounds to play once.
My void draw code has all 4 of my game screens, here’s the code for the starting screen:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// starting screen:
if(gamemode == 1){
if(!theme.isPlaying()){
theme.rewind();
theme.loop();
}
background(#728DC6);
textFont(gamefont, 150);
image(logo, width/2, height/2-270, 400, 200);
fill(#1D194D);
text("CURSE BREAKERS!", width/2, height/2-100);
////title ^^ instructions below
textFont(gamefont, 40);
text("-press the red button to start-", width/2, height/2);
//personal note: might turn the controller instructions into an image
text("help yuji kill the curses and collect sukuna's fingers!", width/2, height/2+60);
text("use the slider to move yuji, the yellow button to attack", width/2, height/2+100);
text("and the blue button to collect the fingers!", width/2, height/2+140);
text("collect 5 fingers within the time limit to win!", width/2, height/2+190);
}//start screen end
// starting screen:
if (gamemode == 1) {
if (!theme.isPlaying()) {
theme.rewind();
theme.loop();
}
background(#728DC6);
textFont(gamefont, 150);
image(logo, width/2, height/2-270, 400, 200);
fill(#1D194D);
text("CURSE BREAKERS!", width/2, height/2-100);
////title ^^ instructions below
textFont(gamefont, 40);
text("-press the red button to start-", width/2, height/2);
//personal note: might turn the controller instructions into an image
text("help yuji kill the curses and collect sukuna's fingers!", width/2, height/2+60);
text("use the slider to move yuji, the yellow button to attack", width/2, height/2+100);
text("and the blue button to collect the fingers!", width/2, height/2+140);
text("collect 5 fingers within the time limit to win!", width/2, height/2+190);
} //start screen end
// starting screen:
if (gamemode == 1) {
if (!theme.isPlaying()) {
theme.rewind();
theme.loop();
}
background(#728DC6);
textFont(gamefont, 150);
image(logo, width/2, height/2-270, 400, 200);
fill(#1D194D);
text("CURSE BREAKERS!", width/2, height/2-100);
////title ^^ instructions below
textFont(gamefont, 40);
text("-press the red button to start-", width/2, height/2);
//personal note: might turn the controller instructions into an image
text("help yuji kill the curses and collect sukuna's fingers!", width/2, height/2+60);
text("use the slider to move yuji, the yellow button to attack", width/2, height/2+100);
text("and the blue button to collect the fingers!", width/2, height/2+140);
text("collect 5 fingers within the time limit to win!", width/2, height/2+190);
} //start screen end
It’s mostly just instructional text and starting the theme song loop. Here’s a screenshot of what it looks like in the game!
Here’s the main game code:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
//game screen:
if(gamemode == 2){
background(battlebg);
if(!theme.isPlaying()){
theme.loop();
}
image(yuji, yujix, analog, 140, 200);
// respawn curses:
if(timerActivated==true){
if(millis()>respawntimer ){
timerActivated = false;
for(int i=0; i<curses.length; i++){
if(curses[i].disp == false){
curses[i].curx = random(-100, -10) ;
curses[i].cury = random(200, height-200);
curses[i].disp=true;
}
}
}
}
if(timerActivated == false && gamemode == 2){
respawntimer = millis()+3000; // the curses reappear on screen
//game screen:
if (gamemode == 2) {
background(battlebg);
if (!theme.isPlaying()) {
theme.loop();
}
image(yuji, yujix, analog, 140, 200);
// respawn curses:
if (timerActivated==true) {
if (millis()>respawntimer ) {
timerActivated = false;
for (int i=0; i<curses.length; i++) {
if (curses[i].disp == false) {
curses[i].curx = random(-100, -10) ;
curses[i].cury = random(200, height-200);
curses[i].disp=true;
}
}
}
}
if (timerActivated == false && gamemode == 2) {
respawntimer = millis()+3000; // the curses reappear on screen
timerActivated = true;
}
//collision detection:
for (int i=0; i<curses.length; i++) {
float d1 = dist(yujix, analog, curses[i].curx, curses[i].cury);
if ( d1 <= ghostR + yujiR && curses[i].disp==true) {
lives-= 1;
life.rewind();
life.play();
curses[i].disp=false; //subtracts a life from yuji when he gets in contact with a ghost and makes it disappear on contact
}
for (int j = bullets.size()-1; j >= 0; j--) {
float d2 = bullets.get(j).distance(curses[i].curx, curses[i].cury);
if ( d2 <= ghostR + bulletR && curses[i].disp==true) {
curses[i].disp=false;
bullets.get(j).disp=false;
bullets.remove(j);
score += 10;
woosh.rewind();
woosh.play();
}
}
}
//shooting the fingers:
for (int i=0; i<sukuna.length; i++) {
for (int j = sbullets.size()-1; j >= 0; j--) {
float d2 = sbullets.get(j).distance(sukuna[i].posx, sukuna[i].posy);
if ( d2 <= fingerR + bulletR && sukuna[i].disp==true) {
sukuna[i].disp=false;
sbullets.get(j).disp=false;
sbullets.remove(j);
fingercount += 1;
powerup.rewind();
powerup.play();
}
}
}
//scoreboard + timer:
pushStyle();
textAlign(LEFT);
textFont(gamefont, 30);
fill(255);
text(" Fingers collected: " + fingercount, 0, 30);
text(" Score: " + score, 0, 60);
text(" Lives left: " + lives, 0, 90);
countdown = 60 -int((millis()-starttime)/1000);
text(" Time left: " + countdown, 0, 120);
popStyle();
// calling class functions for the curses + bullets:
for (int i=0; i<curses.length; i++) {
curses[i]. display();
curses[i]. move();
}
for (int i = bullets.size()-1; i >= 0; i--) {
Bullet bullet = bullets.get(i);
bullet.display();
bullet.move();
if (bullet.done()) {
bullets.remove(i);
// removes the bullets from the arraylist once they leave the screen to save memory
}
}
for (int i = sbullets.size()-1; i >= 0; i--) {
SBullet sbullet = sbullets.get(i);
sbullet.display();
sbullet.move();
if (sbullet.done()) {
sbullets.remove(i);
// removes the bullets from the arraylist once they leave the screen to save memory
}
}
//win condition:
if (countdown<=0 && fingercount <5) {
gamemode = 4;
theme.pause();
winsound.rewind();
for (int i = sbullets.size()-1; i >= 0; i--) {
sbullets.remove(i);
}
for (int i = bullets.size()-1; i >= 0; i--) {
bullets.remove(i);
}
//lose condition 2: (if time runs out)
} else if (countdown>=0 && fingercount == 5) {
gamemode =3;
theme.pause();
for (int i = sbullets.size()-1; i >= 0; i--) {
sbullets.remove(i);
}
for (int i = bullets.size()-1; i >= 0; i--) {
bullets.remove(i);
}
}
//finger mechanics:
for (int i=0; i<sukuna.length; i++) {
sukuna[i].display();
}
for (int i=0; i<sukuna.length; i++) {
if (score % 100 ==0 && score >0) {
fingertimer =3000+millis();
sukuna[i].disp = true;
}
if (millis() > fingertimer) {
sukuna[i].disp = false;
fingertimer =0;
}
}
// if the curses leave the screen without being shot, you lose 1 life
for (int i=0; i<curses.length; i++) {
if (curses[i].curx > width && curses[i].disp == true) {
lives -= 1;
life.rewind();
life.play();
curses[i].disp = false;
}
}
// you lose if your lives are at 0
if (lives <= 0) {
gameover.rewind();
gamemode = 4;
}
} // game screen end
//game screen:
if (gamemode == 2) {
background(battlebg);
if (!theme.isPlaying()) {
theme.loop();
}
image(yuji, yujix, analog, 140, 200);
// respawn curses:
if (timerActivated==true) {
if (millis()>respawntimer ) {
timerActivated = false;
for (int i=0; i<curses.length; i++) {
if (curses[i].disp == false) {
curses[i].curx = random(-100, -10) ;
curses[i].cury = random(200, height-200);
curses[i].disp=true;
}
}
}
}
if (timerActivated == false && gamemode == 2) {
respawntimer = millis()+3000; // the curses reappear on screen
timerActivated = true;
}
//collision detection:
for (int i=0; i<curses.length; i++) {
float d1 = dist(yujix, analog, curses[i].curx, curses[i].cury);
if ( d1 <= ghostR + yujiR && curses[i].disp==true) {
lives-= 1;
life.rewind();
life.play();
curses[i].disp=false; //subtracts a life from yuji when he gets in contact with a ghost and makes it disappear on contact
}
for (int j = bullets.size()-1; j >= 0; j--) {
float d2 = bullets.get(j).distance(curses[i].curx, curses[i].cury);
if ( d2 <= ghostR + bulletR && curses[i].disp==true) {
curses[i].disp=false;
bullets.get(j).disp=false;
bullets.remove(j);
score += 10;
woosh.rewind();
woosh.play();
}
}
}
//shooting the fingers:
for (int i=0; i<sukuna.length; i++) {
for (int j = sbullets.size()-1; j >= 0; j--) {
float d2 = sbullets.get(j).distance(sukuna[i].posx, sukuna[i].posy);
if ( d2 <= fingerR + bulletR && sukuna[i].disp==true) {
sukuna[i].disp=false;
sbullets.get(j).disp=false;
sbullets.remove(j);
fingercount += 1;
powerup.rewind();
powerup.play();
}
}
}
//scoreboard + timer:
pushStyle();
textAlign(LEFT);
textFont(gamefont, 30);
fill(255);
text(" Fingers collected: " + fingercount, 0, 30);
text(" Score: " + score, 0, 60);
text(" Lives left: " + lives, 0, 90);
countdown = 60 -int((millis()-starttime)/1000);
text(" Time left: " + countdown, 0, 120);
popStyle();
// calling class functions for the curses + bullets:
for (int i=0; i<curses.length; i++) {
curses[i]. display();
curses[i]. move();
}
for (int i = bullets.size()-1; i >= 0; i--) {
Bullet bullet = bullets.get(i);
bullet.display();
bullet.move();
if (bullet.done()) {
bullets.remove(i);
// removes the bullets from the arraylist once they leave the screen to save memory
}
}
for (int i = sbullets.size()-1; i >= 0; i--) {
SBullet sbullet = sbullets.get(i);
sbullet.display();
sbullet.move();
if (sbullet.done()) {
sbullets.remove(i);
// removes the bullets from the arraylist once they leave the screen to save memory
}
}
//win condition:
if (countdown<=0 && fingercount <5) {
gamemode = 4;
theme.pause();
winsound.rewind();
for (int i = sbullets.size()-1; i >= 0; i--) {
sbullets.remove(i);
}
for (int i = bullets.size()-1; i >= 0; i--) {
bullets.remove(i);
}
//lose condition 2: (if time runs out)
} else if (countdown>=0 && fingercount == 5) {
gamemode =3;
theme.pause();
for (int i = sbullets.size()-1; i >= 0; i--) {
sbullets.remove(i);
}
for (int i = bullets.size()-1; i >= 0; i--) {
bullets.remove(i);
}
}
//finger mechanics:
for (int i=0; i<sukuna.length; i++) {
sukuna[i].display();
}
for (int i=0; i<sukuna.length; i++) {
if (score % 100 ==0 && score >0) {
fingertimer =3000+millis();
sukuna[i].disp = true;
}
if (millis() > fingertimer) {
sukuna[i].disp = false;
fingertimer =0;
}
}
// if the curses leave the screen without being shot, you lose 1 life
for (int i=0; i<curses.length; i++) {
if (curses[i].curx > width && curses[i].disp == true) {
lives -= 1;
life.rewind();
life.play();
curses[i].disp = false;
}
}
// you lose if your lives are at 0
if (lives <= 0) {
gameover.rewind();
gamemode = 4;
}
} // game screen end
There’s quite a lot going on here. The character is drawn here, with his Y position being the slider (analog input). We’ll go over the serial communication in a bit!
I made a respawn timer for the curses, basically the logic here is that if the curses disp = false ( i.e. they’re not visible on screen) and the current time > respawn timer, the curses will respawn at a new random height on screen, with the width being offscreen on the left, so they move forward to the right.
After that, there’s the code for collision detection. The logic here is that if the distance between the two objects is less than the sum of their radii (which are variables that I set at the very beginning of my code) then something happens! The code for what that ‘something’ is differs depending on what two objects they are. There’s collision detection for the bullets and the curses, and for the curses and yuji, and for the bullets and the fingers.
Then, there’s code for the scoreboard and the timer. You can see the scoreboard in the top left of this screenshot: It has a finger counter(increases whenever you shoot a finger), a lives counter(starts at 5, decreases by one if Yuji gets hit by a ghost, or lets one get away), a score(based on the ghosts that you hit) and a timer! The timer is 60 seconds from the start of the game.
Following this code is the code to call class functions for the curses and bullets.
After this comes the code for win conditions. You can only win after collecting 5 of Sukuna’s fingers. A finger appears after you hit a score that’s divisible by 100, and it disappears after a few seconds if you don’t collect it in time! Once you win, you go to the winning screen!
To lose the game, you either lose all of your lives or you don’t collect 5 fingers by the time the timer ends! Once you lose, you are taken to the losing screen ><.
Then, we have the code for the finger mechanics! It’s pretty simple, I called the display function for the finger, and the disp boolean is initially false. It becomes true once you hit a score divisible by zero, and disappears shortly after.
The code following that is to decrease the lives variable by 1 every time a ghost leaves the screen.
Heres the winning and losing screen’s code, accompanied by screenshots of both in-game:
text("-press the red button to try again!-", width/2, height-50);
image(lose, width/2, 300, 700, 400);
}//losing screen end
}//draw bracket
// winning & losing screens:
//win screen, score/time , sound effect:
if (gamemode == 3) {
theme.pause();
winsound.play();
background(#1D194D);
textFont(gamefont, 100);
fill(#728DC6);
text("YOU WIN!", width/2, height-250);
//title ^^ info below
textFont(gamefont, 50);
text("score:"+score, width/2, height-200);
text("time left:"+countdown, width/2, height-150);
text("fingers collected:"+ fingercount, width/2, height-100);
textFont(gamefont, 40);
text("-press the red button to try again!-", width/2, height-50);
image(win, width/2, 250, 700, 400);
}//win screen end
if (gamemode == 4) {
//losing screen, click to try again, sound effect
theme.pause();
gameover.play();
background(#1D194D);
textFont(gamefont, 100);
fill(#728DC6);
text("YOU LOSE:(", width/2, height-200);
//title ^^ info below
textFont(gamefont, 50);
text("score:"+score, width/2, height-150);
text("fingers collected:"+ fingercount, width/2, height-100);
textFont(gamefont, 40);
text("-press the red button to try again!-", width/2, height-50);
image(lose, width/2, 300, 700, 400);
}//losing screen end
}//draw bracket
// winning & losing screens:
//win screen, score/time , sound effect:
if (gamemode == 3) {
theme.pause();
winsound.play();
background(#1D194D);
textFont(gamefont, 100);
fill(#728DC6);
text("YOU WIN!", width/2, height-250);
//title ^^ info below
textFont(gamefont, 50);
text("score:"+score, width/2, height-200);
text("time left:"+countdown, width/2, height-150);
text("fingers collected:"+ fingercount, width/2, height-100);
textFont(gamefont, 40);
text("-press the red button to try again!-", width/2, height-50);
image(win, width/2, 250, 700, 400);
}//win screen end
if (gamemode == 4) {
//losing screen, click to try again, sound effect
theme.pause();
gameover.play();
background(#1D194D);
textFont(gamefont, 100);
fill(#728DC6);
text("YOU LOSE:(", width/2, height-200);
//title ^^ info below
textFont(gamefont, 50);
text("score:"+score, width/2, height-150);
text("fingers collected:"+ fingercount, width/2, height-100);
textFont(gamefont, 40);
text("-press the red button to try again!-", width/2, height-50);
image(lose, width/2, 300, 700, 400);
}//losing screen end
}//draw bracket
Also, I’ve added various sound effects to the game, I’ll list them here:
A ‘whoosh’ sound when you shoot the curses
A powerup sound effect when you collect a finger
The theme song (which plays only during the start screen and the game screen)
A victory sound plays in the win screen
A game over sound plays on the lose screen
void serialEvent(Serial myPort) {
String s=myPort.readStringUntil('\n');
s=trim(s);
//int values = parseInt(s);
//boolean shoottest = false;
if (s!=null) {
//println(s);
int values[]=int(split(s, ','));
// note: values: 0 = slider, 1= yellow, 2= blue, 3= red
//slider:
analog =map(values[0], 0, 1023, 100, height-70);
yuji = yujiidle;
//attacking (yellow) button:
if (values[2] == 1 && gamemode == 2) {
// not working:
yuji = yujishoot;
color Ccircle = color(#98F7FF, 150);
noStroke();
if (millis() - prevbullettime > 400) {
bullets.add(new Bullet(width-150, analog+20, speed, acc, Ccircle));
prevbullettime= millis();
}
}
// start button:
if (values[3] == 1 && gamemode == 1) {
starttime=millis();
fingercount = 0;
score = 0;
gamemode = 2;
//replay : (red button)
} else if (values[3] == 1 && gamemode == 3 || values[3] == 1 && gamemode ==4) {
fingercount = 0;
lives = 5;
gamemode =1;
delay(1000); // so you dont skip to the start screen too quickly after pressing the button
for (int i=0; i<curses.length; i++) {
curses[i].curx = random(-100, -10);
}
} //fingers (blue)
if (values[1] == 1 && gamemode == 2) {
yuji = yujishoot;
color Scircle = color(#FF8B8B, 150);
noStroke();
if (millis() - prevbullettime > 400) {
sbullets.add(new SBullet(width-150, analog+20, speed, acc, Scircle ));
prevbullettime= millis();
}
}
}
myPort.write(int(0)+"\n");
}
void serialEvent(Serial myPort) {
String s=myPort.readStringUntil('\n');
s=trim(s);
//int values = parseInt(s);
//boolean shoottest = false;
if (s!=null) {
//println(s);
int values[]=int(split(s, ','));
// note: values: 0 = slider, 1= yellow, 2= blue, 3= red
//slider:
analog =map(values[0], 0, 1023, 100, height-70);
yuji = yujiidle;
//attacking (yellow) button:
if (values[2] == 1 && gamemode == 2) {
// not working:
yuji = yujishoot;
color Ccircle = color(#98F7FF, 150);
noStroke();
if (millis() - prevbullettime > 400) {
bullets.add(new Bullet(width-150, analog+20, speed, acc, Ccircle));
prevbullettime= millis();
}
}
// start button:
if (values[3] == 1 && gamemode == 1) {
starttime=millis();
fingercount = 0;
score = 0;
gamemode = 2;
//replay : (red button)
} else if (values[3] == 1 && gamemode == 3 || values[3] == 1 && gamemode ==4) {
fingercount = 0;
lives = 5;
gamemode =1;
delay(1000); // so you dont skip to the start screen too quickly after pressing the button
for (int i=0; i<curses.length; i++) {
curses[i].curx = random(-100, -10);
}
} //fingers (blue)
if (values[1] == 1 && gamemode == 2) {
yuji = yujishoot;
color Scircle = color(#FF8B8B, 150);
noStroke();
if (millis() - prevbullettime > 400) {
sbullets.add(new SBullet(width-150, analog+20, speed, acc, Scircle ));
prevbullettime= millis();
}
}
}
myPort.write(int(0)+"\n");
}
Arduino:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
int bluepin = 5;
int yellowpin = 3;
int redpin = 6;
int sliderpin = A5;
voidsetup(){
pinMode(bluepin , INPUT);
pinMode(yellowpin , INPUT);
pinMode(redpin , INPUT);
pinMode(sliderpin , INPUT);
Serial.begin(9600);
Serial.println("0,0,0,0");
}
voidloop(){
int bluebutton = digitalRead(bluepin);
int yellowbutton = digitalRead(yellowpin);
int redbutton = digitalRead(redpin);
int slider = analogRead(sliderpin);
//checking if everything is connected properly:
//comment this out to run processing
// Serial.print(bluebutton);
// Serial.print(yellowbutton);
// Serial.print(redbutton);
// Serial.println(slider);
while(Serial.available()){
int fromP = Serial.parseInt();
if(Serial.read() == '\n'){
Serial.print(slider);
Serial.print(",");
Serial.print(yellowbutton);
Serial.print(",");
Serial.print(bluebutton);
Serial.print(",");
Serial.println(redbutton);
}
}
}
int bluepin = 5;
int yellowpin = 3;
int redpin = 6;
int sliderpin = A5;
void setup() {
pinMode(bluepin , INPUT);
pinMode(yellowpin , INPUT);
pinMode(redpin , INPUT);
pinMode(sliderpin , INPUT);
Serial.begin(9600);
Serial.println("0,0,0,0");
}
void loop() {
int bluebutton = digitalRead(bluepin);
int yellowbutton = digitalRead(yellowpin);
int redbutton = digitalRead(redpin);
int slider = analogRead(sliderpin);
//checking if everything is connected properly:
//comment this out to run processing
// Serial.print(bluebutton);
// Serial.print(yellowbutton);
// Serial.print(redbutton);
// Serial.println(slider);
while (Serial.available()) {
int fromP = Serial.parseInt();
if (Serial.read() == '\n') {
Serial.print(slider);
Serial.print(",");
Serial.print(yellowbutton);
Serial.print(",");
Serial.print(bluebutton);
Serial.print(",");
Serial.println(redbutton);
}
}
}
int bluepin = 5;
int yellowpin = 3;
int redpin = 6;
int sliderpin = A5;
void setup() {
pinMode(bluepin , INPUT);
pinMode(yellowpin , INPUT);
pinMode(redpin , INPUT);
pinMode(sliderpin , INPUT);
Serial.begin(9600);
Serial.println("0,0,0,0");
}
void loop() {
int bluebutton = digitalRead(bluepin);
int yellowbutton = digitalRead(yellowpin);
int redbutton = digitalRead(redpin);
int slider = analogRead(sliderpin);
//checking if everything is connected properly:
//comment this out to run processing
// Serial.print(bluebutton);
// Serial.print(yellowbutton);
// Serial.print(redbutton);
// Serial.println(slider);
while (Serial.available()) {
int fromP = Serial.parseInt();
if (Serial.read() == '\n') {
Serial.print(slider);
Serial.print(",");
Serial.print(yellowbutton);
Serial.print(",");
Serial.print(bluebutton);
Serial.print(",");
Serial.println(redbutton);
}
}
}
I have 4 parts connected to my circuit: 3 buttons and a slider. I built a controller box out of foam to safely conceal my circuit while also making it easy for players to use! Here is my process making that:
It looked like this at first, but I spray painted it black afterwards and added a 3rd button! (the red one, to start playing the game. initially, you would use either the blue or yellow to start playing the game and switch between screens, but that wasn’t giving me great results, so I decided to add a third button)
the button in this image was tiny because I couldn’t find one that looks like my other two, thankfully I asked on discord and got one!! (thank you bhavicka!!)
Here’s the final product!
Aaaaaand that’s it! TA-DA!! I’m very proud of what I’ve learned and achieved in this course, I had lots of fun!! Thank you
As you might have seen in my previous posts, I am working on making a Jujutsu Kaisen- inspired video game for my final project! The object of the game is to shoot curses (ghosts) and collect Sukuna’s fingers. Collect 5 fingers without losing lives to win! (You lose lives by colliding with the ghosts).
Progress so far:
I’ve completely finished the Arduino code, and the processing code is almost done. The controller is functional, but it’s not stable yet, I’m planning on soldering the controller wires very soon! The user testing demo shows what it currently looks like.. The only thing left in the processing code is making the ghosts disappear when they’re shot, and making the fingers appear in intervals after you hit certain scores.
The first thing I worked on in processing was making the character move with the slider and preparing the code for the different game screens. After that, I worked on the serial communication code for the buttons, and made sure everything was communicating smoothly between processing and Arduino.
Here’s the Arduino code:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
int bluepin = 5;
int yellowpin = 3;
int sliderpin = A1;
voidsetup(){
pinMode(bluepin , INPUT);
pinMode(yellowpin , INPUT);
pinMode(sliderpin , INPUT);
Serial.begin(9600);
Serial.println("0,0,0");
}
voidloop(){
int bluebutton = digitalRead(bluepin);
int yellowbutton = digitalRead(yellowpin);
int slider = analogRead(sliderpin);
while(Serial.available()){
int fromP = Serial.parseInt();
if(Serial.read() == '\n'){
Serial.print(slider);
Serial.print(",");
Serial.print(yellowbutton);
Serial.print(",");
Serial.println(bluebutton);
}
}
}
int bluepin = 5;
int yellowpin = 3;
int sliderpin = A1;
void setup() {
pinMode(bluepin , INPUT);
pinMode(yellowpin , INPUT);
pinMode(sliderpin , INPUT);
Serial.begin(9600);
Serial.println("0,0,0");
}
void loop() {
int bluebutton = digitalRead(bluepin);
int yellowbutton = digitalRead(yellowpin);
int slider = analogRead(sliderpin);
while (Serial.available()) {
int fromP = Serial.parseInt();
if (Serial.read() == '\n') {
Serial.print(slider);
Serial.print(",");
Serial.print(yellowbutton);
Serial.print(",");
Serial.println(bluebutton);
}
}
}
int bluepin = 5;
int yellowpin = 3;
int sliderpin = A1;
void setup() {
pinMode(bluepin , INPUT);
pinMode(yellowpin , INPUT);
pinMode(sliderpin , INPUT);
Serial.begin(9600);
Serial.println("0,0,0");
}
void loop() {
int bluebutton = digitalRead(bluepin);
int yellowbutton = digitalRead(yellowpin);
int slider = analogRead(sliderpin);
while (Serial.available()) {
int fromP = Serial.parseInt();
if (Serial.read() == '\n') {
Serial.print(slider);
Serial.print(",");
Serial.print(yellowbutton);
Serial.print(",");
Serial.println(bluebutton);
}
}
}
After that, I made an Arraylist for the “bullets” that the character shoots and modified the code to shoot the bullets (circles) at fixed intervals.
As for the avatar, instead of using a sprite sheet since I only have 2 images to switch between, I decided to make an if statement to switch between the two images when the attack button is pressed. These are the two images Im using for the sprite:
idle and attack sprites
I made these using https://www.avatarsinpixels.com and added more details to the avatar with procreate to make it look more like the actual character from the anime.
Also, the curses disappear on contact with either a bullet or Yuji, the former adds points to the score while the latter subtracts 1 life from Yuji.
As for the game, it currently looks like this:
Main Screen:(there are no instructions for the slider so ill add that in soon)
game screen: (first pic is idle Yuji and the second is him while shooting)
As you might remember from Wednesday, my final project idea is a Jujutsu Kaisen themed video game! As I mentioned in my previous post, the main character in the anime, Yuji, swallows a cursed finger and is now a vessel to a cursed spirit, Sukuna. Now, he has to collect all 20 of Sukuna’s fingers so he can exorcise the curse and save the world, I guess..
As of season 1, Yuji has eaten 4/20 fingers. So, in my game, the player is going to collect the remaining 16 fingers in a set time. I was thinking of adding an HP bar, but I think something like this would be more doable:
The mechanics are quite simple, I plan on making a button for attacks towards curses, a joystick to move across the screen, and a button for collecting fingers. Every time an enemy is close to the sprite for more than 5 seconds without being defeated, the player will lose a heart. Lose 5 hearts to lose!
I’ve already started planning out the code on processing, but I haven’t actually started writing any code yet, I just typed out the general structure of my code and wrote down comments of my plan throughout. I wrote down a few variable names and image names that I will use later on while coding, including a gamemode variable, which I used in my midterm project. I will use this variable to switch between pages in my game!
Im thinking of making the final layout of my project something like this:
maybe I can build a cardboard box around my laptop?
Materials
I will need 2 buttons, a solderable breadboard , a joystick or a slider(depending on if the avatar will move across one axis or both axes, I still haven’t decided), and spare wires . I might need a cardboard box as well.
So far, I think the materials I mentioned are all I’ll need, but we’ll find out soon if I need anything else…
Hardest Parts
I think serial communication might be a bit challenging for me to figure out, and making the Arduino components respond correctly with Processing.
Also, I think I might need to make my own sprite sheet for Yuji, as I couldn’t find a sprite sheet for his character online.
Other than that, I’ll have to figure out how to code the hearts system as well as the timer system, and how to make a finger appear after defeating a set number of curses.
As for the number of curses to beat per finger and the duration of the timer, I think I’ll decide on that after user testing.
I was thinking of making a game that was themed around an anime called Jujutsu Kaisen. In the anime, the main character swallows a cursed finger and is now a vessel to a cursed spirit, Sukuna. So for my game, I was thinking of making the player fight cursed spirits (with a controller) and collect one of Sukuna’s fingers after defeating a set amount of enemies. I might add a timer, and people can see how many fingers they can collect with the given time, OR it can be a challenge, like collect 5 fingers in the given time or you lose! Something like that.
PROCESSING
The processing code will be the game interface itself, and there will probably be code similar to collision detection whenever you are near a finger, so you press a button on the controller to collect it. Maybe I can add an HP bar and it keeps decreasing when enemies are near the sprite, so it’s taking damage. If it gets to 0, game over. But if I add an HP bar, maybe I don’t need the sprite to move around the screen, maybe similar to Space Invaders? I’m still not 100% sure how this will work..
ARDUINO
I’m planning on making a controller that is connected to Arduino, with buttons for fighting enemies and collecting fingers and maybe a joystick for moving. The buttons will work like an on/off switch , but I’m still not sure about how the joystick will work yet. Everything on the controller will send info to Processing so that the game can respond on screen.
This week’s assignment was to use 2 or more LEDs, one analog and one digital. My project for this assignment is a light-up mini dollhouse, I just used a dollhouse I borrowed from my sister and connected all my wires and LEDs to it!
First, I connected everything on the breadboard and made my code to make sure everything works properly. Once everything worked, I started removing the LEDs and the photoresistor (which is my analog component) one by one and attach them to my dollhouse. To attach them, I mainly used alligator clips, copper tape and washi tape.
The photoresistor makes the LED brighter as the sensor picks up dimmer light, in other words, as your finger gets closer to the sensor, the LED gets brighter. The other two LEDs are controlled by the button, and I connected them in parallel so that they can both be bright. Once I connected the LEDs and the photoresistor to the dollhouse and the button to the breadboard, it worked out! yay!
This week, our assignment was to make an unusual switch that works without using our hands. For my project, I decided to make 2 switches that will turn on when the copper strip attached on the ground and the strip attached to your shoe touch (these are connected to the circuit via long wires). When they touch, the LED lights on either side will light up! So if you use your left foot, the yellow LED on the left will light up. If you use your right, the blue one on the right will light up.
I tried to make my circuit as neat as possible, so I organized my wires by color. Red ones are for power, black for GND, green for the left side, blue for the right. As for the longer wires, the ones connected to the strip on the ground are yellow, and the ones connected to your shoe are white.
Here’s the code:
Basically, if the switch is on, the led will light up. If its not on (the strip in the floor and the shoe aren’t touching) the LED will turn off.
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
//R = right side, L= left side.
const int ledpinR = 2;
const int ledpinL = 3;
const int switchpinR = 4;
const int switchpinL = 5;
bool switchreadR;
bool switchreadL;
voidsetup(){
// put your setup code here, to run once:
pinMode(ledpinR, OUTPUT);
pinMode(ledpinL, OUTPUT);
pinMode(switchpinR, INPUT);
pinMode(switchpinL, INPUT);
}
voidloop(){
// right LED code:
switchreadR = digitalRead(switchpinR);
if(switchreadR == true){
digitalWrite(ledpinR , HIGH );
}else{
digitalWrite(ledpinR , LOW);
}
// left LED code:
switchreadL = digitalRead(switchpinL);
if(switchreadL == true){
digitalWrite(ledpinL , HIGH );
}else{
digitalWrite(ledpinL , LOW);
}
}
//R = right side, L= left side.
const int ledpinR = 2;
const int ledpinL = 3;
const int switchpinR = 4;
const int switchpinL = 5;
bool switchreadR;
bool switchreadL;
void setup() {
// put your setup code here, to run once:
pinMode(ledpinR, OUTPUT);
pinMode(ledpinL, OUTPUT);
pinMode(switchpinR, INPUT);
pinMode(switchpinL, INPUT);
}
void loop() {
// right LED code:
switchreadR = digitalRead(switchpinR);
if (switchreadR == true) {
digitalWrite(ledpinR , HIGH );
} else {
digitalWrite(ledpinR , LOW);
}
// left LED code:
switchreadL = digitalRead(switchpinL);
if (switchreadL == true) {
digitalWrite(ledpinL , HIGH );
} else {
digitalWrite(ledpinL , LOW);
}
}
//R = right side, L= left side.
const int ledpinR = 2;
const int ledpinL = 3;
const int switchpinR = 4;
const int switchpinL = 5;
bool switchreadR;
bool switchreadL;
void setup() {
// put your setup code here, to run once:
pinMode(ledpinR, OUTPUT);
pinMode(ledpinL, OUTPUT);
pinMode(switchpinR, INPUT);
pinMode(switchpinL, INPUT);
}
void loop() {
// right LED code:
switchreadR = digitalRead(switchpinR);
if (switchreadR == true) {
digitalWrite(ledpinR , HIGH );
} else {
digitalWrite(ledpinR , LOW);
}
// left LED code:
switchreadL = digitalRead(switchpinL);
if (switchreadL == true) {
digitalWrite(ledpinL , HIGH );
} else {
digitalWrite(ledpinL , LOW);
}
}
For our midterm project, we were tasked with making a game!
The game I made is called Pixel Run! It’s a fun little game and I’m very proud of it!!
Concept
Basically, When you start the game (after you view the instructions) you will see your sprite in the center of the screen, which you can move with the arrow keys. There will be static stars at random places all around the screen and frantic bananas that move with random speeds across the screen. Your score is displayed at the top right corner of the screen.
Collect the stars!! They’re worth 20 points, but you must avoid the bananas! When your points are > 0 , they will take 10 points off your current score.
Goal of the game
To win, you must score 500 points! When you hit 500 or more points, you are taken to the end screen. You can press the space key to play again!
Different Screens
To make the different screens, I used an int variable called game mode.
I started by adding all my variables at the top of my code, then I loaded all my data like images, fonts and sounds.
I made 2 classes: one for bananas, one for stars. I made arrays for both classes and used a for loop in setup for each. I made it so that when you start the game, there are 20 stars and 10 bananas on screen. This is also where I made the nested array for my sprite sheet. I set imageMode and textAlign to center. I downloaded some theme music and made it loop while you play the game (The music keeps playing in all the game screens)
Here’s my setup code:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
PImage linksprite, bg, star, banana, start; // all of the images
PImage[][] sprites;
PFont mario, score;
int direction = 1;
int step = 0;
int x, y;
int r1, r2;
int speed = 4;
int gamemode = 0; // for the diff screens
int pts = 0; // points in game
import processing.sound.*;
SoundFile file;
String audioName = "music.wav";
float timer=0;
boolean timerActivated = false;
Banana[] bananas;
Star[] stars;
// arrays for both objects
voidsetup(){
size(1000, 700);
//loading the images and fonts here :
bg = loadImage("bg.png");
star = loadImage("star.png");
banana = loadImage("banana.png");
start = loadImage("start.png");
mario = createFont("/Users/fatimaaljneibi/Library/Fonts/Mario-Kart-DS.ttf", 32);
sprites = new PImage[4][10]; // 12 images across, 4 down, in the spritesheet
int w = linksprite.width/10;
int h = linksprite.height/4;
for(int y=0; y <4; y++){
for(int x=0; x<10; x++){
sprites[y][x] = linksprite.get(x*w, y*h, w, h);
}
}
x = width/2;
y = height/2;
imageMode(CENTER);
textAlign(CENTER);
}
PImage linksprite, bg, star, banana, start; // all of the images
PImage[][] sprites;
PFont mario, score;
int direction = 1;
int step = 0;
int x, y;
int r1, r2;
int speed = 4;
int gamemode = 0; // for the diff screens
int pts = 0; // points in game
import processing.sound.*;
SoundFile file;
String audioName = "music.wav";
float timer=0;
boolean timerActivated = false;
Banana[] bananas;
Star[] stars;
// arrays for both objects
void setup() {
size (1000, 700);
//loading the images and fonts here :
bg = loadImage("bg.png");
star = loadImage("star.png");
banana = loadImage("banana.png");
start = loadImage("start.png");
mario = createFont("/Users/fatimaaljneibi/Library/Fonts/Mario-Kart-DS.ttf", 32);
score = createFont("Courier New", 25);
linksprite = loadImage("linksprite.png");
//theme music loop:
file = new SoundFile(this, "music.wav");
file.loop();
stars = new Star[20] ;
for (int i=0; i<stars.length; i++) {
stars[i]= new Star(random(width), random(height));
}
bananas = new Banana[10] ;
for (int i=0; i<bananas.length; i++) {
bananas[i]= new Banana(random(width), random(height), random(-5, 5), random(-5, 5));
}
sprites = new PImage[4][10]; // 12 images across, 4 down, in the spritesheet
int w = linksprite.width/10;
int h = linksprite.height/4;
for (int y=0; y < 4; y++) {
for (int x=0; x< 10; x++) {
sprites[y][x] = linksprite.get(x*w, y*h, w, h);
}
}
x = width/2;
y = height/2;
imageMode(CENTER);
textAlign(CENTER);
}
PImage linksprite, bg, star, banana, start; // all of the images
PImage[][] sprites;
PFont mario, score;
int direction = 1;
int step = 0;
int x, y;
int r1, r2;
int speed = 4;
int gamemode = 0; // for the diff screens
int pts = 0; // points in game
import processing.sound.*;
SoundFile file;
String audioName = "music.wav";
float timer=0;
boolean timerActivated = false;
Banana[] bananas;
Star[] stars;
// arrays for both objects
void setup() {
size (1000, 700);
//loading the images and fonts here :
bg = loadImage("bg.png");
star = loadImage("star.png");
banana = loadImage("banana.png");
start = loadImage("start.png");
mario = createFont("/Users/fatimaaljneibi/Library/Fonts/Mario-Kart-DS.ttf", 32);
score = createFont("Courier New", 25);
linksprite = loadImage("linksprite.png");
//theme music loop:
file = new SoundFile(this, "music.wav");
file.loop();
stars = new Star[20] ;
for (int i=0; i<stars.length; i++) {
stars[i]= new Star(random(width), random(height));
}
bananas = new Banana[10] ;
for (int i=0; i<bananas.length; i++) {
bananas[i]= new Banana(random(width), random(height), random(-5, 5), random(-5, 5));
}
sprites = new PImage[4][10]; // 12 images across, 4 down, in the spritesheet
int w = linksprite.width/10;
int h = linksprite.height/4;
for (int y=0; y < 4; y++) {
for (int x=0; x< 10; x++) {
sprites[y][x] = linksprite.get(x*w, y*h, w, h);
}
}
x = width/2;
y = height/2;
imageMode(CENTER);
textAlign(CENTER);
}
When game mode = 0, (it starts at zero when you run the game) you can see the start screen, which looks like this:
Here’s the code for the first page: (it was inside void draw)
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
if(gamemode == 0){// starting screen
background(start);
fill(#5F9AEA);
textFont(mario, 100);
text("PIXEL RUN!", width/2, height/2-25);
// instructions
textFont(mario, 40);
text("-press the space key to start-", width/2, height-300);
textFont(mario, 25);
fill(#3F7CC9);
text("use arrow keys to move", width/2, height-200);
text("collect the stars but avoid the bananas!!", width/2, height-150);
text("score 500 points to win!", width/2, height-100);
if(keyPressed){
if(key == ' '){
gamemode = 1;
pts = 0;
}
}
if (gamemode == 0) { // starting screen
background(start);
fill(#5F9AEA);
textFont(mario, 100);
text("PIXEL RUN!", width/2, height/2-25);
// instructions
textFont(mario, 40);
text("-press the space key to start-", width/2, height-300);
textFont(mario, 25);
fill(#3F7CC9);
text("use arrow keys to move", width/2, height-200);
text("collect the stars but avoid the bananas!!", width/2, height-150);
text("score 500 points to win!", width/2, height-100);
if (keyPressed) {
if (key == ' ' ) {
gamemode = 1;
pts = 0;
}
}
if (gamemode == 0) { // starting screen
background(start);
fill(#5F9AEA);
textFont(mario, 100);
text("PIXEL RUN!", width/2, height/2-25);
// instructions
textFont(mario, 40);
text("-press the space key to start-", width/2, height-300);
textFont(mario, 25);
fill(#3F7CC9);
text("use arrow keys to move", width/2, height-200);
text("collect the stars but avoid the bananas!!", width/2, height-150);
text("score 500 points to win!", width/2, height-100);
if (keyPressed) {
if (key == ' ' ) {
gamemode = 1;
pts = 0;
}
}
I made the background on Picsart, then I downloaded a Mario Kart font and added it to my data folder. I used createFont() to use this font in my game, I used the font for the title & instructions, as well as in the win screen. When you press the space key, game mode = 1 and the next screen loads! (the actual game screen!!)
It looks like this:
Here’s the code for this page!
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
elseif(gamemode == 1){// actual game code goes here
background(bg);
// makes the disappeared objects reappear every 5 seconds:
if(timerActivated==true){
if(millis()>timer ){
println("timer done!");
timerActivated = false;
for(int i=0; i<15; i++){
if(stars[i].disp == false){
stars[i].starx = random(width);
stars[i].stary = random(height);
}
stars[i]. disp=true;
}
for(int i=0; i<8; i++){
bananas[i]. disp=true;
}
}
}
if(timerActivated == false&& gamemode == 1){
println("timer triggered");
timer = millis()+5000; // more objects appear on screen every 5 seconds
timerActivated = true;
}
// displays the initial stars & bananas, calls the functions from their classes
for(int i=0; i<20; i++){
stars[i]. display();
}
for(int i=0; i<10; i++){
bananas[i]. display();
bananas[i]. move();
}
//look at sprite sheet to determine which direction is which
if(keyPressed){
if(keyCode == DOWN){
direction = 0;
y+=speed;
}
if(keyCode == LEFT){
direction = 1;
x-=speed;
}
if(keyCode == RIGHT){
direction = 3;
x+=speed;
}
if(keyCode == UP){
direction = 2;
y-=speed;
}
if(key == 'b'|| key == 'B'){
gamemode = 0;
}
if(keyCode == DOWN || keyCode == UP || keyCode == LEFT || keyCode == RIGHT){
if(frameCount%speed==0){//the spritesheet images will loop only if the arrow keys are pressed
step = (step+1) % 10;
}
}
}
image(sprites[direction][step], x, y); // the sprite
// points system:
for(int i=0; i<10; i++){
float d2 = dist(x, y, bananas[i].banx, bananas[i].bany);
if( d2 <= 50&& bananas[i].disp==true){
if(pts >=10)
pts-= 10;
// takes 10 points off for every banana collided w the sprite
bananas[i].disp=false; //banana disappears
}
}
for(int i=0; i<20; i++){
float d1 = dist(x, y, stars[i].starx, stars[i].stary);
if( d1 <= 50&& stars[i].disp==true){
pts+= 20;
stars[i].disp=false; //adds 20 pts per star and makes it disappear on contact w sprite
text("press 'b' to go back to start!", 2, height-8);
popStyle();
if(pts >= 500){
gamemode = 3; //game ends when the player hits 500 pts
}
}// game code ends here
else if (gamemode == 1) { // actual game code goes here
background(bg);
// makes the disappeared objects reappear every 5 seconds:
if (timerActivated==true) {
if (millis()>timer ) {
println("timer done!");
timerActivated = false;
for (int i=0; i<15; i++) {
if (stars[i].disp == false) {
stars[i].starx = random(width);
stars[i].stary = random(height);
}
stars[i]. disp=true;
}
for (int i=0; i<8; i++) {
bananas[i]. disp=true;
}
}
}
if (timerActivated == false && gamemode == 1) {
println("timer triggered");
timer = millis()+5000; // more objects appear on screen every 5 seconds
timerActivated = true;
}
// displays the initial stars & bananas, calls the functions from their classes
for (int i=0; i<20; i++) {
stars[i]. display();
}
for (int i=0; i<10; i++) {
bananas[i]. display();
bananas[i]. move();
}
//look at sprite sheet to determine which direction is which
if (keyPressed) {
if (keyCode == DOWN) {
direction = 0;
y+=speed;
}
if (keyCode == LEFT) {
direction = 1;
x-=speed;
}
if (keyCode == RIGHT) {
direction = 3;
x+=speed;
}
if (keyCode == UP) {
direction = 2;
y-=speed;
}
if (key == 'b' || key == 'B' ) {
gamemode = 0;
}
if (keyCode == DOWN || keyCode == UP || keyCode == LEFT || keyCode == RIGHT) {
if (frameCount%speed==0) { //the spritesheet images will loop only if the arrow keys are pressed
step = (step+1) % 10;
}
}
}
image(sprites[direction][step], x, y); // the sprite
// points system:
for (int i=0; i<10; i++) {
float d2 = dist(x, y, bananas[i].banx, bananas[i].bany);
if ( d2 <= 50 && bananas[i].disp==true) {
if (pts >=10)
pts-= 10;
// takes 10 points off for every banana collided w the sprite
bananas[i].disp=false; //banana disappears
}
}
for (int i=0; i<20; i++) {
float d1 = dist(x, y, stars[i].starx, stars[i].stary);
if ( d1 <= 50 && stars[i].disp==true) {
pts+= 20;
stars[i].disp=false; //adds 20 pts per star and makes it disappear on contact w sprite
}
}
if (y>height) {
y=0;
}
if (y<0) {
y=height;
}
if (x>width) {
x=0;
}
if (x<0) {
x=width;
} // this is to keep the sprite always on screen
//the score board:
textFont(score);
pushStyle();
fill(255, 200);
noStroke();
rectMode(CENTER);
rect(width-80, 22, textWidth("Score:" + pts)+10, 30);
popStyle();
fill(0);
text("Score:" + pts, width-80, 30);
pushStyle();
fill(255, 180);
noStroke();
rect(2, height-20, 270, 15 );
textAlign(LEFT);
textFont(score, 15);
fill(0);
text("press 'b' to go back to start!", 2, height-8);
popStyle();
if (pts >= 500) {
gamemode = 3; //game ends when the player hits 500 pts
}
} // game code ends here
else if (gamemode == 1) { // actual game code goes here
background(bg);
// makes the disappeared objects reappear every 5 seconds:
if (timerActivated==true) {
if (millis()>timer ) {
println("timer done!");
timerActivated = false;
for (int i=0; i<15; i++) {
if (stars[i].disp == false) {
stars[i].starx = random(width);
stars[i].stary = random(height);
}
stars[i]. disp=true;
}
for (int i=0; i<8; i++) {
bananas[i]. disp=true;
}
}
}
if (timerActivated == false && gamemode == 1) {
println("timer triggered");
timer = millis()+5000; // more objects appear on screen every 5 seconds
timerActivated = true;
}
// displays the initial stars & bananas, calls the functions from their classes
for (int i=0; i<20; i++) {
stars[i]. display();
}
for (int i=0; i<10; i++) {
bananas[i]. display();
bananas[i]. move();
}
//look at sprite sheet to determine which direction is which
if (keyPressed) {
if (keyCode == DOWN) {
direction = 0;
y+=speed;
}
if (keyCode == LEFT) {
direction = 1;
x-=speed;
}
if (keyCode == RIGHT) {
direction = 3;
x+=speed;
}
if (keyCode == UP) {
direction = 2;
y-=speed;
}
if (key == 'b' || key == 'B' ) {
gamemode = 0;
}
if (keyCode == DOWN || keyCode == UP || keyCode == LEFT || keyCode == RIGHT) {
if (frameCount%speed==0) { //the spritesheet images will loop only if the arrow keys are pressed
step = (step+1) % 10;
}
}
}
image(sprites[direction][step], x, y); // the sprite
// points system:
for (int i=0; i<10; i++) {
float d2 = dist(x, y, bananas[i].banx, bananas[i].bany);
if ( d2 <= 50 && bananas[i].disp==true) {
if (pts >=10)
pts-= 10;
// takes 10 points off for every banana collided w the sprite
bananas[i].disp=false; //banana disappears
}
}
for (int i=0; i<20; i++) {
float d1 = dist(x, y, stars[i].starx, stars[i].stary);
if ( d1 <= 50 && stars[i].disp==true) {
pts+= 20;
stars[i].disp=false; //adds 20 pts per star and makes it disappear on contact w sprite
}
}
if (y>height) {
y=0;
}
if (y<0) {
y=height;
}
if (x>width) {
x=0;
}
if (x<0) {
x=width;
} // this is to keep the sprite always on screen
//the score board:
textFont(score);
pushStyle();
fill(255, 200);
noStroke();
rectMode(CENTER);
rect(width-80, 22, textWidth("Score:" + pts)+10, 30);
popStyle();
fill(0);
text("Score:" + pts, width-80, 30);
pushStyle();
fill(255, 180);
noStroke();
rect(2, height-20, 270, 15 );
textAlign(LEFT);
textFont(score, 15);
fill(0);
text("press 'b' to go back to start!", 2, height-8);
popStyle();
if (pts >= 500) {
gamemode = 3; //game ends when the player hits 500 pts
}
} // game code ends here
There’s a lot to unpack here:
When gamemode = 1, the background changes, the sprite appears at the center of the screen, the stars appear at random spots(they do not move) the bananas also appear at random spots, but they move with a random speed ranging from -5 to 5. This is because I added an extra argument for the bananas, which is spx and spy (speed x and speed y).
The sprite moves in directions 0-3, corresponding to the row on the sprite sheet image. The sprite is always on screen because of this code:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
if(y>height){
y=0;
}
if(y<0){
y=height;
}
if(x>width){
x=0;
}
if(x<0){
x=width;
}// this is to keep the sprite always on screen
if (y>height) {
y=0;
}
if (y<0) {
y=height;
}
if (x>width) {
x=0;
}
if (x<0) {
x=width;
} // this is to keep the sprite always on screen
if (y>height) {
y=0;
}
if (y<0) {
y=height;
}
if (x>width) {
x=0;
}
if (x<0) {
x=width;
} // this is to keep the sprite always on screen
I used a similar code in the bananas class, so that the bananas always appear on screen as well.
The bananas and the stars classes have a display() function, which displays them at random spots on screen. The banana also has a move() function.
When the sprite collides with a star or a banana, it disappears and the pts variable adds or subtracts points depending on whether it is a star or a banana. These images disappear because of a boolean disp in their classes which makes them disappear on contact with the sprite.
The way collision detection works here is it checks to see if the image is displayed (the boolean disp I mentioned earlier) and if it is && the distance between the sprite’s x and y positions and the image’s x and y positions is less than 50 pixels, the image(star or banana) will disappear.
I also made a timer which will make the disappeared objects ( if their disp boolean =false and the 5 seconds have passed, the star or banana will reappear at a different spot. I made it so that 8 bananas and 15 stars can reappear every 5 seconds. This happens continuously.
Here’s the code for the timer:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// makes the disappeared objects reappear every 5 seconds:
if(timerActivated==true){
if(millis()>timer ){
println("timer done!");
timerActivated = false;
for(int i=0; i<15; i++){
if(stars[i].disp == false){
stars[i].starx = random(width);
stars[i].stary = random(height);
}
stars[i]. disp=true;
}
for(int i=0; i<8; i++){
bananas[i]. disp=true;
}
}
}
if(timerActivated == false&& gamemode == 1){
println("timer triggered");
timer = millis()+5000; // more objects appear on screen every 5 seconds
timerActivated = true;
// makes the disappeared objects reappear every 5 seconds:
if (timerActivated==true) {
if (millis()>timer ) {
println("timer done!");
timerActivated = false;
for (int i=0; i<15; i++) {
if (stars[i].disp == false) {
stars[i].starx = random(width);
stars[i].stary = random(height);
}
stars[i]. disp=true;
}
for (int i=0; i<8; i++) {
bananas[i]. disp=true;
}
}
}
if (timerActivated == false && gamemode == 1) {
println("timer triggered");
timer = millis()+5000; // more objects appear on screen every 5 seconds
timerActivated = true;
// makes the disappeared objects reappear every 5 seconds:
if (timerActivated==true) {
if (millis()>timer ) {
println("timer done!");
timerActivated = false;
for (int i=0; i<15; i++) {
if (stars[i].disp == false) {
stars[i].starx = random(width);
stars[i].stary = random(height);
}
stars[i]. disp=true;
}
for (int i=0; i<8; i++) {
bananas[i]. disp=true;
}
}
}
if (timerActivated == false && gamemode == 1) {
println("timer triggered");
timer = millis()+5000; // more objects appear on screen every 5 seconds
timerActivated = true;
I also added a rectangle underneath the score counter & the bottom right text, it is not fully opaque so that you can see if there are any objects in that area of the screen. I used push & pop style here to make the rectMode= center for the score one.
When you hit 500 points or more, gamemode= 3 and the win screen is displayed. It looks like this :
As you can see from the image, clicking the space bar will reset the game.
For our midterm project, we were tasked with making a game on Processing, so I started by making a sketch of the layout for my game, and I wrote down a simple explanation about the game.
Idea:
Basically, the player will move a sprite around the screen with the arrow keys and collects the green circles, each worth 1 point. Alternatively, the player must avoid the pink ones. If you collide with a pink circle, you will lose 1 point. Get 10 points to win the game!
Here is my sketch of the layout-
Process: So, my current plan is to make booleans so that I can switch between the different pages. And I think I’ll have to make 2 classes: one for the pink circles and one for the green. As for the point counter, I still haven’t figured out how to implement that.
Progress: And so far, my sprite is moving with the arrow keys on screen, and I haven’t had time to start making separate pages, I will work on it over the weekend.
Sprite Code:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
PImage linksprite , bg ;// all of the images
PImage[][] sprites;
int direction = 1;
int step = 0;
int x;
int y;
int speed = 3;
int mode;
boolean start; // for the start screen
boolean play; // game screen
int pts; // points in game
voidsetup(){
size(1000,700);
//bg = loadImage("bg");
// start = true;
//if (start == false){
linksprite = loadImage("linksprite.png");
sprites = new PImage[4][10]; // 12 images across, 4 down, in the spritesheet
int w = linksprite.width/10;
int h = linksprite.height/4;
for(int y=0; y <4; y++){
for(int x=0; x<10; x++){
sprites[y][x] = linksprite.get(x*w, y*h, w, h);
}
}
//}
x = width/2;
y = height/2;
imageMode(CENTER);
}
voiddraw(){
background(255);
//if (start == true){
//background(bg);
//}
//look at sprite sheet to determine which direction is which
if(keyPressed){
//if (keyCode == ){
//}
if(keyCode == DOWN){
direction = 0;
y+=speed;
}
if(keyCode == LEFT){
direction = 1;
x-=speed;
}
if(keyCode == RIGHT){
direction = 3;
x+=speed;
}
if(keyCode == UP){
direction = 2;
y-=speed;
}
if(frameCount%speed==0){//the % is a modulo - its an easy way to make a loop
step = (step+1) % 10;
}
}
image(sprites[direction][step], x, y);
}
PImage linksprite , bg ; // all of the images
PImage[][] sprites;
int direction = 1;
int step = 0;
int x;
int y;
int speed = 3;
int mode;
boolean start; // for the start screen
boolean play; // game screen
int pts; // points in game
void setup() {
size (1000,700);
//bg = loadImage("bg");
// start = true;
//if (start == false){
linksprite = loadImage("linksprite.png");
sprites = new PImage[4][10]; // 12 images across, 4 down, in the spritesheet
int w = linksprite.width/10;
int h = linksprite.height/4;
for (int y=0; y < 4; y++) {
for (int x=0; x< 10; x++) {
sprites[y][x] = linksprite.get(x*w, y*h, w, h);
}
}
//}
x = width/2;
y = height/2;
imageMode(CENTER);
}
void draw() {
background(255);
//if (start == true){
//background(bg);
//}
//look at sprite sheet to determine which direction is which
if (keyPressed) {
//if (keyCode == ){
//}
if (keyCode == DOWN) {
direction = 0;
y+=speed;
}
if (keyCode == LEFT) {
direction = 1;
x-=speed;
}
if (keyCode == RIGHT) {
direction = 3;
x+=speed;
}
if (keyCode == UP) {
direction = 2;
y-=speed;
}
if (frameCount%speed==0) { //the % is a modulo - its an easy way to make a loop
step = (step+1) % 10;
}
}
image(sprites[direction][step], x, y);
}
PImage linksprite , bg ; // all of the images
PImage[][] sprites;
int direction = 1;
int step = 0;
int x;
int y;
int speed = 3;
int mode;
boolean start; // for the start screen
boolean play; // game screen
int pts; // points in game
void setup() {
size (1000,700);
//bg = loadImage("bg");
// start = true;
//if (start == false){
linksprite = loadImage("linksprite.png");
sprites = new PImage[4][10]; // 12 images across, 4 down, in the spritesheet
int w = linksprite.width/10;
int h = linksprite.height/4;
for (int y=0; y < 4; y++) {
for (int x=0; x< 10; x++) {
sprites[y][x] = linksprite.get(x*w, y*h, w, h);
}
}
//}
x = width/2;
y = height/2;
imageMode(CENTER);
}
void draw() {
background(255);
//if (start == true){
//background(bg);
//}
//look at sprite sheet to determine which direction is which
if (keyPressed) {
//if (keyCode == ){
//}
if (keyCode == DOWN) {
direction = 0;
y+=speed;
}
if (keyCode == LEFT) {
direction = 1;
x-=speed;
}
if (keyCode == RIGHT) {
direction = 3;
x+=speed;
}
if (keyCode == UP) {
direction = 2;
y-=speed;
}
if (frameCount%speed==0) { //the % is a modulo - its an easy way to make a loop
step = (step+1) % 10;
}
}
image(sprites[direction][step], x, y);
}
This week’s assignment was to either make a data visualization or generative text art. I decided to make a data visualization that involves text.
I went to Google Trends and found the most popular searches relating to anime, so I downloaded the csv file and added it to my sketch folder. I deleted the blank rows for my own convenience.
I made a for loop to display the searches in random places with random colors. It looked like this:
As you can see, the texts overlap and they continue on the right side outside of the sketch.
I wasn’t sure how to fix this from happening, so I just ended up adding transparency to the fill and it looks like this now: (I’d like to add that the positions are random so it changes every time you run it)