Prologue
Since the start of the class, I have been really struggling with practicing Processing consistently – I would usually start my homeworks 1-2 days in advance and not practice much outside of class hours. But this week is very special: I started working on the weekly assignment 4 days in advance and have even taken some time to practice geomerative* and come up with the midterm idea! 🥳 So here I am, typing this post on a Saturday afternoon (edit: publishing on Sunday though). Enjoy!
Introduction
Fascinated by last week’s spritesheet example, I could not resist using this idea for my assignment. General idea was to make a small game with a moving character catching objects – diamonds in this case. After browsing the web, I have downloaded this pixelated Mario (?) image and cropped it in Photoshop as it wasn’t a PNG.
Process
Milestone 0: learning how to use the spritesheet. I have re-visited the class example and have carefully studied it to understand what is going on behind the code. And especially this – confusing at first – part:
// loops through each step and returns to image 0 after reaching image 3 if(frameCount%speed==0){ step = (step+1)%col; }
Milestone 1: placing the diamond and building a collision detection function. It took me a good day (coding on and off) to figure out what is going on wrong with my collision detection function. Oh, I have repeated the same mistake as I did when building the OOP assignment! 😅 Good thing now I finally know how to detect collision between two rectangular objects:
// Mario right corner > diamond left AND Mario left corner < diamond right if ((posX + person.width/16) > diamondX && posX < (diamondX + diamond.width/4) && (posY+person.height/16) > diamondY && posY < (diamondY + diamond.height/4)){
Milestone 2: collision detection debugging – spritesheet’s width and height. OK, the function was built, BUT it didn’t work out the way I wanted it to. I took all of the creative debugging ways I had in mind and just started printing out line by line what the function is doing…After a few coordinate manipulations, it FINALLY hit me that I am uploading my spritesheet in the original size and then I manually resize the image without providing the new size coordinates to my collision function. So, after fixing the sizes I thought that the problem was fixed…Not quite!
Milestone 3: The spritesheet’s dimensions aren’t perfect! 🤦♀️😅 After fixing the sizes in Processing I actually went to the original image to see what might be wrong – and there it was: there were a lot of blank spaces between spritesheet’s movements that counted towards the current image’s width and height. Yay, now I finally understand what is happening in my program!
Milestone 4: Beautifying the program. After the main logic of the program was done, I decided to add some functions, such as counting and displaying the score, checking for win, and checking borders for Mario’s movement around the screen.
Epilogue
I actually never thought that building small games can be this fun and … actually simple? Definitely am proud for working consistently on this throughout the week and can also see some room for improvement (see milestone 3 and demo – there is a moment when Mario catches a diamond despite being a few pixels away from it xD)
Result
Code:
PImage diamond; PImage person; PImage[][] movement; PImage background; PFont font; int direction = 1; int step, score = 0; int posX, posY; int diamondX, diamondY; int speed = 5; int row = 4; int col = 4; int currentWidth, currentHeight; String textScore = "Score: "; void setup(){ // output window size (600, 600); // define font font = createFont("VT323-Regular", 40); textFont(font); // get images diamond = loadImage("diamond.png"); person = loadImage("person.png"); background = loadImage("background.png"); // place each direction in 2-dimensional array movement = new PImage[row][col]; // divide each step according to each step's dimenstions currentWidth = person.width/row; currentHeight = person.height/col; // place each step into the right location for(int posY = 0; posY < 4; posY++){ for(int posX = 0; posX < 4; posX++){ movement[posY][posX] = person.get(posX*currentWidth, posY*currentHeight, currentWidth, currentHeight); } } // always start with these coordinates posX = 0; posY = height-person.width/8+50; // dimanod location diamondX = (int)random(width-diamond.width-100); diamondY = (int)random(height-diamond.height-100); } void draw(){ background(255); image(background, 0, 0, width, height); // place the character onto the board image(movement[direction][step], posX, posY, width/4, height/4); // move the character movePerson(); checkBorder(); // place the diamond image(diamond, diamondX, diamondY, diamond.width/4, diamond.height/4); // check for collision detectDiamond(); // display score: displayScore(); // check for win checkWin(); } // move the character void movePerson(){ // activate if key is pressed if(keyPressed){ // move DOWN if(keyCode == DOWN){ // select the corresponding row direction = 0; // animate the steps to go DOWN in the y-dir (increase) posY+=speed; } // move UP if(keyCode == UP){ // select the corresponding row direction = 1; // animate the steps to go UP in the y-dir (decrease) posY-=speed; } // move LEFT if(keyCode == LEFT){ // select the corresponding row direction = 2; // animate the steps to go LEFT in the x-dir (decrease) posX-=speed; } // move RIGHT if(keyCode == RIGHT){ // select the corresponding row direction = 3; // animate the steps to go RIGHT in the x-dir (increase) posX+=speed; } // loops through each step and returns to image 0 after reaching image 3 if(frameCount%speed==0){ step = (step+1)%col; } } } // needs some bug fixing void checkBorder() { // return from the left if (posX >= width) { posX = -currentWidth; } // return from the right if (posX+currentWidth < 0) { posX = width; } // return from the bottom if (posY+currentHeight < 0) { posY = height; } // return from the top if (posY > height) { posY = -currentHeight; } } // check for the image collision (diamond collection) void detectDiamond(){ // Mario right corner > diamond left AND Mario left corner < diamond right if ((posX + person.width/16) > diamondX && posX < (diamondX + diamond.width/4) && (posY+person.height/16) > diamondY && posY < (diamondY + diamond.height/4)){ // increment the score score++; // replace diamond diamondX = (int)random(width-diamond.width-100); diamondY = (int)random(height-diamond.height-100); } } // display the score void displayScore(){ push(); fill(0); text("Score: " + score, width-180, 40); pop(); } void checkWin(){ if (score == 5) { background(103, 212, 239); push(); textAlign(CENTER); fill(random(255), random(255), random(255)); textSize(100); text("You WON!", width/2, height/2); pop(); } }
Great job Amina! You can tell you put in extra time and it paid off.