On a Saturday night, NYUAD students tend to have more meal swipes than they need. Students face the dilemma of either stacking more food with their extra swipes or losing all the swipes the next day.
The idea then is to create a game where the player (student) would try to stack as much food as can be balanced on an unstable food tray.
To win and make the most of your meal swipes, just be patient and stack away. Oh, don’t forget we are working with time😄
Process
To build this game, I need
1. Start / Instructions page
2. Game window
3. Win / Lose / Restart Page
4. Sound Integration
Progress Work
Let’s get to work
I explored how I would be changing the game screens based on the stage of the game. I created functions to take care of each of the 3 main stages of the game: start, gameplay, and game over. I represented the different screens with 3 different colors.
I moved on to integrate a timer for the gameplay screen which when runs out and automatically changes the screen to indicate game over. That’s when I started facing difficulties.
I added some buttons and signal text to make the user’s life easier.
Demo
Challenges
Timer!
For some reason, I couldn’t figure it out for a long time, my timer was not working as expected, the gameplay screen didn’t change even if the timer was out. Oh, I get it now! I fell into the trap of not scoping my variables properly. I experimented with the location of my timer function and I finally got it to work when I globalized the variables accessed by the timer function.
Please stay we me, we are not done with the timer yet! I decided to print the timer values on the game screen and I was getting negative seconds. How? Yeah, I was confused as you are. Still haven’t figured why but it seems to work fine now.
// THE THREE SCREENS
// 0: Start Page (Instructions)
// 1: Game Window
// 2: Win / Lose Page ( GameOver)
int gameScreen = 0;
int score = 0;
int totalTime = 10; // 10 seconds
int savedTime = second();
int passedTime;
void setup() {
size(640, 640);
}
void draw() {
// Display the contents of the current screen
if (gameScreen == 0) {
startScreen();
} else if (gameScreen == 1) {
gameWindow();
timer();
} else if (gameScreen == 2) {
gameOverScreen();
}
}
// THE THREE SCREENS
void startScreen() {
background(#6f00ff);
textAlign(CENTER);
textSize(70);
text("It's Saturday Night", width/2, height/2-50);
textSize(20);
text("Stack Up as much food as you can while you have the time.", width/2, height/2);
text("Click on the Start button, The clock is ticking!", width/2, height/2 + 50);
textSize(20);
// start button
noFill();
rectMode(CENTER);
rect(width/2, height-100, 120, 30, 10);
text("Click to start", width/2, height-95);
}
void gameWindow() {
background(#a75502);
textSize(50);
text("Timer!", width/2, 95);
}
void gameOverScreen() {
background(#6f00ff);
textAlign(CENTER);
fill(236, 240, 241);
textSize(15);
text("Your Score", width/2, height/2 - 120);
textSize(130);
text(score, width/2, height/2);
// restart button
noFill();
rectMode(CENTER);
rect(width/2, height-100, 150, 30, 10);
textSize(20);
text("Click to Restart", width/2, height-95);
}
// SCREEN CHANGERS
void startGame() {
gameScreen=1;
}
void gameOver() {
gameScreen=2;
}
// RESTART
void restart() {
score = 0;
savedTime = second();
startGame();
}
// TIMER
void timer() {
passedTime = second() - savedTime;
textSize(100);
text(passedTime, width/2, height/2 + 30);
if (passedTime > totalTime) {
gameOver();
}
}
// BUTTON CONTROLS
void mousePressed() {
// toggle between instructions and restart when mouse is clicked
if (gameScreen==0) {
startGame();
}
if (gameScreen==2) {
restart();
}
}
Next Steps
It’s going to be more fun and challenging. I will be working mainly on the gameplay screen and polishing the start and end screen
1. Create the assets ( the food to be stacked) and the unstable tray block
2. Work on the game mechanics ( counting length of the food stack )
3. Add sound to make it lively
PS. Would appreciate any resources to achieve the above steps. I know it’s going to be existing!
Instead of making the character move inside the display window, I used an infinite side-scrolling in which the character is static whereas the background moves from the right to the left. To achieve that, I used two images placed next to each other that reappear on the right side once they get out of the display window.
Parallax effect
To give the game a realistic aspect, I added a Parallax effect in which the far-away clouds and mountains seem to move more slowly than the closer ones, by changing each layer’s (6 layers) position by a different amount (between 1 and 5).
// Parallax effect
void update(){
x6--; x6_2--;
x5-=2; x5_2-=2;
x4-=3; x4_2-=3;
x3-=3; x3_2-=3;
x2-=4; x2_2-=4;
x1-=5; x1_2-=5;
// Infinite scrolling
if (x6<=-width){x6=width;} if (x6_2<=-width){x6_2=width;}
if (x5<=-width){x5=width;} if (x5_2<=-width){x5_2=width;}
if (x4<=-width){x4=width;} if (x4_2<=-width){x4_2=width;}
if (x3<=-width){x3=width;} if (x3_2<=-width){x3_2=width;}
if (x2<=-width){x2=width;} if (x2_2<=-width){x2_2=width;}
if (x1<=-width){x1=width;} if (x1_2<=-width){x1_2=width;}
}
For the midterm, I wanted to work on a game that was in the board games genre of games, and thus, I decided to take a spin on Snakes and Ladders. Snakes and Ladders is a board game with a grid of numbers. It is a multi-player game and the target is to reach the 100th block from the 1st block. The movement of the tokens is decided by a die and if you happened to land on a square with a snake or a ladder – you’ll either move down a lot of squares or move up respectively.
Setting the elements of the game
On brainstorming how I could rethink this game, I ended up deciding on having the elements of cards in the game. In addition, I started off with a lot of variations for the pathway: from spirals to a boat path to circles – but I finalized on a grid-style format so that, the familiarity of the grid-style game plays into easing the player into learning how to play the game.
Instead of the elements of snakes and ladders, I put in cards on random squares on the grid – these squares are randomly picked at the beginning of every game – on landing on the square – the player would have to look at the corresponding card and do what the instructions say (related to moving on the squares). These cards are related to my home in Kerala and things that a person from Kerala, India would be familiar with. I wanted to make the cards accessible for anyone, without context to understand – so, there will be text included that will dictate the movement of the user token. Types of cards would include:
Move-ahead cards: Examples – Dosa, Grandma’s Food, Filter Coffee, etc.
Move-behind cards: Examples – Powercuts, Humungous mosquitoes, Coconut falling on your head, etc.
I tried making these cards using images I could find online but since the styles of art depicting all of these ideas were different, it looked out of place. So, I decided to draw the card art on my own for the game – to keep the aesthetics consistent.
Finally, since it is a multiplayer game – I decided to limit the number to two people to play the game. But if I have the time, I might consider improving the game by having the players input the number of players. For now, the user tokens are images from celebrated artforms in Kerala – Kathakali & Theyyam. Depending on whose turn it is, the corresponding token lights up and the other token is grayed out.
Implementation
I started off working on the grid. The grid is made by putting together a number of squares – so I made a class called Rect and a function called grid() which was responsible for making the objects of class Rect and numbering and displaying them. Having classes here helped a lot in adding additional functionality like putting in the number of the rectangle when displaying. For the later part of implementation too, this would greatly help in terms of randomly assigning squares in the grid and have them light a different color to represent the snake or ladder element.
//grid print
void grid(){
int xlen = (width)/size ;
int ylen = (height)/size;
rect = new Rect[(xlen-7)*(ylen)];
int i=0;
for (int y=0; y < ylen; y++) {
for (int x = 3; x <xlen-4; x++) {
PVector p = new PVector(x*size,y*size);
rect[i] = new Rect(p, size,i);
i++;
}
}
}
class Rect{
float size;
PVector position;
int num;
Rect(PVector p, float s, int n){
position = p;
size = s;
num=n;
}
void display(){
stroke(255);
fill(0);
rect(position.x,position.y,size,size);
fill(255);
text(num,position.x,position.y+size-5);
}
}
Then, I worked on implementing a die program on a separate processing sketch. I used this link as a reference to work on this. When you press within the die, it stops otherwise it keeps rolling.
void dice(){
fill(255);
text("Click on the dice to roll it, Player 1", diceX-diceSize,diceY-diceSize+20);
fill(#FFF3D6);
rectMode(CENTER);
rect(diceX, diceY, diceSize, diceSize, diceSize/5);
//dots
fill(50);
int side = int(random(1, 7));
if (side == 1 || side == 3 || side == 5)
ellipse(diceX, diceY, diceSize/5, diceSize/5);
if (side == 2 || side == 3 || side == 4 || side == 5 || side == 6) {
ellipse(diceX - diceSize/4, diceY - diceSize/4, diceSize/5, diceSize/5);
ellipse(diceX+ diceSize/4, diceY + diceSize/4, diceSize/5, diceSize/5);
}
if (side == 4 || side == 5 || side == 6) {
ellipse(diceX - diceSize/4,diceY + diceSize/4, diceSize/5, diceSize/5);
ellipse(diceX + diceSize/4, diceY- diceSize/4, diceSize/5, diceSize/5);
}
if (side == 6) {
ellipse(diceX, diceY- diceSize/4, diceSize/5, diceSize/5);
ellipse(diceX, diceY + diceSize/4, diceSize/5, diceSize/5);
}
rectMode(CORNER);
}
void mousePressed(){
if(mouseX>(diceX)-(diceSize/2) && mouseX<(diceX)+(diceSize/2) && mouseY>(diceY)-(diceSize/2) && mouseY<(diceY)+(diceSize/2 ))
toggleRun=!toggleRun;
}
I combined all of these together and finally, put in the user tokens on the side indicating whose turn it is.
PImage kathakali,kathakaliInactive;
PImage theyyam,theyyamInactive;
Rect rect[];
int size = 80;
int diceX = (100*width/8)+25;
int diceY =(60*height/8)+10;
int diceSize = 90;
boolean toggleRun=false;
void setup() {
fullScreen();
background(0);
theyyam = loadImage("theyyam.png");
theyyamInactive = loadImage("theyyamInactive.png");
theyyam.resize(220, 260);
theyyamInactive.resize(220, 260);
kathakali = loadImage("kathakali.png");
kathakaliInactive = loadImage("kathakaliInactive.png");
kathakali.resize(180,224);
kathakaliInactive.resize(180,224);
//how to play
//players choose whether they want theyyam or kathakali
image(theyyamInactive, 0, height/2-190);
image(kathakaliInactive, 15, height/2+20);
dice();
}
void draw() {
grid();
for (int j=0; j<rect.length; j++){
rect[j].display();
}
scale(0.4);
image(theyyam, width/2+80, height/2+140);
if(toggleRun){
for(int i=0;i<10;i++)
{
dice();
}
}
}
Next Steps:
Add in a beginning and final sketch for the game
Add an instructions page
Random function to assign cards to squares and change their colors
Make the movement function, so that the tokens move according to the die input and the cards, if applicable.
Celebration visuals when one of the players wins – My idea is to have the grid light up in all sorts of colors to generate excitement.
For my midterm project, I referred to OpenProcessing. This game is a combination of Tetris and SameGame. In this game, the player’s goal is to eliminate the highlighted cube. Every turn, a cube falls down and the player can move it left or right, just like in the Tetris, but only in the form of a cube. Also, random cubes will generate across the canvas to increase the difficulty and playability. The player should manage to make combos of cubes with the same color in order to eliminate them. It is set that the player can eliminate at most 5 cubes.
Challenges:
Considering the mechanisms of the game is the most challenging part so far. Since it is a new game (I’ve never seen it elsewhere), it takes me a lot of time to play it myself and adjust the game rules.
At first, I set the goal to be eliminating every cube, which is almost impossible because if you are left with only a few cubes, you have to be really lucky to get the color you want to make combos.
I also found it logically tricky to write the codes for combos. 👇
void checkSame() {
int nb = 0;//number of full lines
int mark_x = 0;
int mark_y = 0;
boolean same = false;
// check horizontal
for (int j = 0; j < h; j ++) {
for (int i = 0; i < w; i++) {
color c1 = cells[i][j];
if ((i+2 < w) && (!isFree(i, j))) {
if ((cells[i+1][j] == c1) &&
(cells[i+2][j] == c1)) {
int mark_num = 2;
mark_x = i;
mark_y = j;
if ((i+3 < w) && (cells[i+3][j] == c1)) {
mark_num = 3;
}
if ((i+4 < w) && (cells[i+4][j] == c1)) {
mark_num = 4;
}
nb = nb + mark_num - 1;
for (int k = mark_y; k > 0; k--) {
for (int m = mark_x; m <= mark_x + mark_num; m++) {
if ((j+2 < h) && (cells[m][j+1] == c1) &&
(cells[m][j+2] == c1)) {
cells[m][j+1] = 0;
cells[m][j+2] = 0;
}
checkGame();
cells[m][k] = cells[m][k-1];
cells[m][0] = 0;
continue;
}
}
}
}
if ((j+2 < h) && (!isFree(i, j))) {
if ((cells[i][j+1] == c1) &&
(cells[i][j+2] == c1)) {
same = true;
mark_x = i;
mark_y = j;
}
}
if (same) {
nb++;
for (int k = mark_y; k < mark_y + 3; k++) {
try{
cells[mark_x][k] = 0;
checkGame();
} catch(Exception e) {
}
}
for (int k = mark_y; k > 2; k--) {
cells[mark_x][k] = cells[mark_x][k-2];
}
}
}
}
deleteLines(nb);
}
Codes:
int w = 10;
int h = 10;
int q = 40;
int dt;
int currentTime;
Grid grid;
Piece piece;
Piece nextPiece;
Pieces pieces;
Score score;
int level = 1;
int nbLines = 0;
int txtSize = 20;
int textColor = 0;
int x1;
Boolean gameOver = false;
Boolean gameOn = false;
Boolean gamePause = false;
Boolean gameWin = false;
void setup()
{
size(600, 480, P2D);
textSize(30);
}
void initialize() {
nbLines = 0;
dt = 1000;
currentTime = millis();
score = new Score();
grid = new Grid();
pieces = new Pieces();
piece = new Piece(-1);
nextPiece = new Piece(-1);
grid.generate();
score = new Score();
level = 1;
x1 = int(random(0, w));
while (grid.isFree(x1,h-1)) {
x1 = int(random(0, w));
}
}
void draw()
{
background(#3D4E81);
if (grid != null) {
grid.drawGrid();
int now = millis();
if (gameOn) {
if (now - currentTime > dt) {
currentTime = now;
piece.oneStepDown();
}
}
piece.display(false);
score.display();
fill(#F2D7D7);
text("Goal: ", 40, 200);
stroke(#F8FC08);
strokeWeight(5);
fill(grid.cells[x1][h-1]);
rect(50, 220, q, q);
}
if (gameOver) {
noStroke();
background(0);
fill(255);
text("Game Over", width/2 - 80, height/2 - 80);
text("Press 'ENTER' to restart.", width/2 - 140, height/2 + 60);
text("Press 'ESC' to exit.", width/2 - 140, height/2 + 100);
}
if (!gameOn) {
noStroke();
fill(0, 60);
rect(30, 30, 540, 420, 10);
fill(255);
text("Press <-- or --> to move the cubes.", 40, 200);
text("If a chain of three same colors is formed, ", 40, 100);
text("they can be eliminated!", 40, 140);
text("Press 'P' to pause.", 40, 260);
fill(#F0A5A5);
text("Press 'ENTER' to start.", width/2-160, 360);
}
if (gameWin) {
noStroke();
background(#C9A4D8);
fill(255);
text("Congratulations! You win!", width/2 - 160, height/2 - 80);
text("Press 'ENTER' to restart.", width/2 - 140, height/2 + 60);
text("Press 'ESC' to exit.", width/2 - 140, height/2 + 100);
}
}
void goToNextPiece() {
piece = new Piece(nextPiece.kind);
nextPiece = new Piece(-1);
}
void goToNextLevel() {
score.addLevelPoints();
level = 1 + int(nbLines / 100);
dt *= .98;
}
void keyPressed() {
if (key == CODED && gameOn) {
switch(keyCode) {
case LEFT:
case RIGHT:
case DOWN:
case UP:
case SHIFT:
piece.inputKey(keyCode);
break;
}
} else if (keyCode == 80) {
if (gameOn) {
gamePause = !gamePause;
if (gamePause) {
fill(0, 60);
rect(width/2 - 200, height/2 - 50, 400, 100, 10);
fill(255);
text("Press 'P' to restart the game.", width/2 - 180, height/2);
noLoop();
} else if (!gamePause){
loop();
}
}
} else if (keyCode == ENTER) {
if (gameOver) {
gameOn = false;
gameOver = false;
loop();
}
if (!gameOn) {
initialize();
gameOver = false;
gameOn = true;
loop();
}
}
}
class Piece {
final color[] colors = {
//color(#047E83),
//color(#760483),
//color(#830424),
color(#DE5410),
color(#368E6D),
color(#D380C1),
color(#E3A7AC)
};
final int[][] pos;
int x = int(w/2);
int y = 0;
int kind;
int c;
int c0, c1, c2, c3, c4;
Piece(int k) {
if (k < 0) {
kind = int(random(0, 4));
} else {
kind = k;
}
c = colors[kind];
pos = pieces.pos[kind];
}
void display(Boolean still) {
stroke(250);
fill(c);
pushMatrix();
if (!still) {
translate(160, 40);
translate(x*q, y*q);
}
rect(pos[0][0] * q, pos[0][1] * q, 40, 40);
popMatrix();
}
// returns true if the piece can go one step down
void oneStepDown() {
y += 1;
if(!grid.pieceFits()){
piece.y -= 1;
grid.addPieceToGrid();
}
}
// try to go one step left
void oneStepLeft() {
x --;
}
// try to go one step right
void oneStepRight() {
x ++;
}
void goToBottom() {
grid.setToBottom();
}
void inputKey(int k) {
switch(k) {
case LEFT:
x --;
if(grid.pieceFits()){
}else {
x++;
}
break;
case RIGHT:
x ++;
if(grid.pieceFits()){
}else{
x--;
}
break;
case DOWN:
oneStepDown();
break;
case SHIFT:
goToBottom();
break;
}
}
}
class Pieces {
int[][][] pos = new int [4][1][2];
Pieces() {
pos[0][0][0] = -1;
pos[0][0][1] = 0;
pos[1][0][0] = -1;
pos[1][0][1] = 0;
pos[2][0][0] = -1;
pos[2][0][1] = 0;
pos[3][0][0] = -1;
pos[3][0][1] = 0;
//pos[4][0][0] = -1;
//pos[4][0][1] = 0;
//pos[5][0][0] = -1;
//pos[5][0][1] = 0;
//pos[6][0][0] = -1;
//pos[6][0][1] = 0;
}
}
class Grid {
int [][] cells = new int[w][h];
Grid() {
for (int i = 0; i < w; i ++) {
for (int j = 0; j < h; j ++) {
cells[i][j] = 0;
}
}
}
Boolean isFree(int x, int y) {
if (x > -1 && x < w && y > -1 && y < h) {
return cells[x][y] == 0;
} else if (y < 0) {
return true;
}
return false;
}
Boolean pieceFits() {
int x = piece.x;
int y = piece.y;
int[][] pos = piece.pos;
Boolean pieceOneStepDownOk = true;
int tmpx = pos[0][0]+x;
int tmpy = pos[0][1]+y;
if (tmpy >= h || !isFree(tmpx, tmpy)) {
pieceOneStepDownOk = false;
}
return pieceOneStepDownOk;
}
void addPieceToGrid() {
int x = piece.x;
int y = piece.y;
int[][] pos = piece.pos;
if(pos[0][1]+y >= 0){
cells[pos[0][0]+x][pos[0][1]+y] = piece.c;
}else{
gameOn = false;
gameOver = true;
return;
}
checkSame();
goToNextPiece();
random_gen(int(random(0, 2)));
checkSame();
drawGrid();
checkGame();
}
void checkSame() {
int nb = 0;//number of full lines
int mark_x = 0;
int mark_y = 0;
boolean same = false;
// check horizontal
for (int j = 0; j < h; j ++) {
for (int i = 0; i < w; i++) {
color c1 = cells[i][j];
if ((i+2 < w) && (!isFree(i, j))) {
if ((cells[i+1][j] == c1) &&
(cells[i+2][j] == c1)) {
int mark_num = 2;
mark_x = i;
mark_y = j;
if ((i+3 < w) && (cells[i+3][j] == c1)) {
mark_num = 3;
}
if ((i+4 < w) && (cells[i+4][j] == c1)) {
mark_num = 4;
}
nb = nb + mark_num - 1;
for (int k = mark_y; k > 0; k--) {
for (int m = mark_x; m <= mark_x + mark_num; m++) {
if ((j+2 < h) && (cells[m][j+1] == c1) &&
(cells[m][j+2] == c1)) {
cells[m][j+1] = 0;
cells[m][j+2] = 0;
}
checkGame();
cells[m][k] = cells[m][k-1];
cells[m][0] = 0;
continue;
}
}
}
}
if ((j+2 < h) && (!isFree(i, j))) {
if ((cells[i][j+1] == c1) &&
(cells[i][j+2] == c1)) {
same = true;
mark_x = i;
mark_y = j;
}
}
if (same) {
nb++;
for (int k = mark_y; k < mark_y + 3; k++) {
try{
cells[mark_x][k] = 0;
checkGame();
} catch(Exception e) {
}
}
for (int k = mark_y; k > 2; k--) {
cells[mark_x][k] = cells[mark_x][k-2];
}
}
}
}
deleteLines(nb);
}
Boolean checkWin() {
if (isFree(x1, h-1)) {
return true;
}
return false;
}
void deleteLines(int nb) {
nbLines += nb;
if (int(nbLines / 100) > level-1) {
goToNextLevel();
}
score.addLinePoints(nb);
}
void setToBottom() {
int j = 0;
for (j = 0; j < h; j ++) {
if (!pieceFits()) {
break;
} else {
piece.y++;
}
}
piece.y--;
delay(1500);
addPieceToGrid();
}
void drawGrid() {
stroke(150);
pushMatrix();
translate(160, 40);
line(-10, 0, -10, h*q);
strokeWeight(sin(10/4-200)*6);
stroke(0,0,10);
for (int i = 0; i < w; i ++) {
for (int j = 0; j < h; j ++) {
if (cells[i][j] != 0) {
fill(cells[i][j]);
rect(i*q, j*q, q, q);
}
}
}
pick(x1, h-1);
popMatrix();
}
void generate() {
color[] colors = {
//color(#047E83),
//color(#760483),
//color(#830424),
color(#DE5410),
color(#368E6D),
color(#D380C1),
color(#E3A7AC)
};
for (int i = 0; i < w; i ++) {
for (int j = h * 2/3 ; j < h ; j ++) { // h * 3/4
color c1 = colors[int(random(0, 4))];
fill(c1);
cells[i][j] = c1;
}
}
checkSame();
}
void random_gen(int num) {
color[] colors = {
//color(#047E83),
//color(#760483),
//color(#830424),
color(#DE5410),
color(#368E6D),
color(#D380C1),
color(#E3A7AC)
};
int i=1, j=1;
for (int k=0; k<=num; k++) {
while (isFree(i, j+1) || !isFree(i, j)){
i = int(random(1, w));
j = int(random(1, h-1));
}
color c1 = colors[int(random(0, 4))];
fill(c1);
cells[i][j] = c1;
}
checkSame();
}
void checkGame() {
for (int i=0; i<w; i++) {
if (!isFree(i, 0)) {
gameOver = true;
}
}
if (checkWin()) {
gameWin = true;
}
}
void pick(int x, int y) {
stroke(#F8FC08);
strokeWeight(5);
fill(cells[x][y]);
rect(x*q, y*q, q, q);
}
}
For the next week, I plan to insert images and music to make the game visually better, and changing the display for the game rules, game over and game clear.
I will also modify the calculations of the scores to be more reasonable.
The inspiration behind the game I want to create comes from how overprotective I tend to be with my GPA. Since I was a kid, I always would work to achieve the highest grades and an even the slightest deduction of grades would make me cry. However, after I came to university, that reality changed, and it’s been like a roller-coaster with all its ups and downs. The games resemble a university student who is running all over to catch the grades they want. Based on that, the gpa gets either incremented or decremented depending on the letter grade they catches. I have always been keen to understand how gpa calculation works, so I searched it up and decided to base my game on that. Also, gpa calculator still always saves my life. Finally, uni rush is a game logic in which a student character is moving different grades comes along the path. So, when the student catches the appearing grade, then GPA is getting calculated at the back end based on the overall grades taken.
GAME RULES:
To score a higher GPA score, the character must catch the better grades and skip the bad ones. The winner of the game will get a maximum GPA score of four. For the movement, the user must move the character in the right path either up or down, right, or left.
IMPLEMENTATION STRATEGY:
I will be using object-oriented approach to divide the coding patterns based on the game logic. Then, I will use an array data structure to store the grade letters in form of images. Afterwards, I will implement 3 different sound effects for each game screen. Eventually, I will have a win sound effect if GPA score was 4.0.
OBJECTS TO BE USED IN GAME:
Grade letters
The grade letter objects will be images of each grade letter on its own
Student Character
This can be any cartoon character with a bigger size as compared to grade letters and can move either left-right or up and down based on the key pressing
Game Background
This object will be a university campus image which is set as the background of the game
GPA Score Prompt
This object will be a simple text prompt and the value of the GPA score will be calculated at run time depending on the game logic.
STORY BOARD OF THE GAME
The game starts with a menu screen on which a prompt will display that shows which key to press to start the game and other instructions. On the main menu screen there is a button to move to the game rules screen. The game rule screen shows all keys for the movement of character for example up, down, left, and right. The start game button on the main menu screen will move to the game screen which is the main part of the game. Furthermore, on the top there will be a GPA score prompt. The character on the other hand will be either standing on one side, and the grades are coming towards him from the other side, or the character is moving while grades are appearing suddenly on a random basis. Background sound effects will be played on every screen.
PROGRESS :
CODE FOR NOW :
// import library for sound
import processing.sound.*;
// objects for bakcground, charcter, alphabets, and gpa calculation
PImage background;
PImage character;
PImage A;
PImage B;
PImage C;
PImage D;
PImage F;
int score;
// Position of the character in x and y coordinates
int posx=0;
int posy=300;
// background sound object
SoundFile backmusic;
// Set up function
void setup()
{
// setting screen size
size(1080, 720);
// every 30 milescond, a new screen is rendering
frameRate(30);
// initialzie background image object and setting background image as parameter
background = loadImage("back.png");
// initializing charcter image object
character = loadImage("character.png");
// initializing letter grade objects
A= loadImage("A.png");
B= loadImage("B.png");
C= loadImage("C.png");
D= loadImage("D.png");
F= loadImage("F.png");
// initiliaze sound object
backmusic = new SoundFile(this, "BackSound.mp3");
}
void keyPressed()
{
// if key is pressend by w , then move charcter up
if(key == 'w')
{
image(character,0,posy-1);
}
// if press a, charcter move to left side
if(key == 'a')
{
image(character,posx-1,0);
}
// if charcter press s, charcter move down
if(key == 's')
{
image(character,posx,posy);
}
// if press d, character, move right
if(key == 'd')
{
image(character,posx+1,posy);
}
}
void draw()
{
// playing the sound
backmusic.play();
// dispalying background image
image (background,0,0);
// displaying chacrter image and give its initial positions (x,y)
image(character,posx,posy);
// displaying letter grades, plus I give each letter grade their position (x,y)
image(A,width-120,300);
image(B,width-150,500);
image(C,width-180,200);
image(D,width-220,600);
image(F,width-140,150);
// displaying gpa score at the top
text("GPA Score: ",30,30);
I wanted to create something, fun and simple. I remember loving the where’s Waldo books when I was young, and there was this super Mario game where you have to find Mario. I decided to incorporate nyuad as a theme. The players have to find the thief on our campus before it’s too late!
These are the main points of the game:
The campus will be pitch black other than a flashlight the the player has.
use the flashlight to find the thief before the 45 second timer goes off, if you don’t it is game over and nyuad will be robbed !
the thief will change places every time a new game is started.
Progress until now:
First of all in order to create a unique background I loaded a nyuad backdrop image.
Then after a lot of research and a lot of help from the coding train(https://www.youtube.com/watch?v=j-ZLDEnhT3Q) I was able to create the flashlight effect and make the rest pitch black. By using image processing with pixels.
void draw() {
loadPixels();
nyu.loadPixels();
for (int x = 0; x < nyu.width; x++ ) {
for (int y = 0; y < nyu.height; y++ ) {
int loc = x + y*width;
float r = red (nyu.pixels[loc]);
float g = green(nyu.pixels[loc]);
float b = blue (nyu.pixels[loc]);
float distance = dist(mouseX,mouseY,x,y);
float adjustBrightness = map(distance, 0, 200, 2, 0);
pixels[loc]=color(r*adjustBrightness,g*adjustBrightness,b*adjustBrightness);
}
}
updatePixels();
image(sprites[direction][step], x, y);
}
This created this effect which I think is very cool:
Now I had to incorporate a sprite in order to add the thief. This is what I decided to go with
Challenges:
there are definitely a lot of questions that I need to ask in order to be able to move forward. The main one being, that when I added the sprite (thief) to the game he was visible above the darkness as is shown here:
I am not sure how to fix this.
Next steps:
add instructions to the beginning and a game over or congratulations indication at the end.
make the sprite appear in random locations every time a new game begins.
make the game stop (and congrats appears) when the mouse is clicked on the sprite.
add alarm sounds to when the thief is found.
Hopefully it goes well!
PImage nyu;
PImage spritesheet;
PImage[][] sprites;
int direction = 1;
int step = 0;
int x;
int y;
int speed = 3;
void setup() {
size(1200, 800);
spritesheet = loadImage("thief.png");
sprites = new PImage[4][3];
int w = spritesheet.width/3;
int h = spritesheet.height/4;
for (int y=0; y < 4; y++) {
for (int x=0; x< 3; x++) {
sprites[y][x] = spritesheet.get(x*w, y*h, w, h);
}
}
x = width/2;
y = height/2;
imageMode(CENTER);
nyu = loadImage( "nyu.png" );
}
void draw() {
loadPixels();
nyu.loadPixels();
for (int x = 0; x < nyu.width; x++ ) {
for (int y = 0; y < nyu.height; y++ ) {
int loc = x + y*width;
float r = red (nyu.pixels[loc]);
float g = green(nyu.pixels[loc]);
float b = blue (nyu.pixels[loc]);
float distance = dist(mouseX,mouseY,x,y);
float adjustBrightness = map(distance, 0, 200, 2, 0);
pixels[loc]=color(r*adjustBrightness,g*adjustBrightness,b*adjustBrightness);
}
}
updatePixels();
image(sprites[direction][step], x, y);
}
There is a Taiwanese myth about catching fallen stars to make a wish come true. I intend to create a game that consists of a traditional Taiwanese bamboo woven basket and white stars falling from the night sky.
RULES:
The way to win is to collect a set number of stars. The player would be faced with fallen meteoroids, plastic trash, and satellite remains. They have three lives in total and loses the game when all three lives are wasted. However, players can catch Taiwanese street food to restore lost lives.
OBJECTS:
Array to store these objects
Background: import an image of Taiwanese famous night sky
Sound:
Background music: summer night time in Taiwanese mountains
Fallen objects: all have their respective sounds
Object behavior:
Meteoroids: will look like a fallen star at first, but will enlarge and transform into a disastrous meteoroid
Plastic trash: if it hits the basket, the player would be paralyzed for 1-2 second
Satellite: falling with extremely fast speed
Food: will be moving from side to side
STORYBOARD:
MENU (START/RESTART)
RULES
STORYTIME
GAME
CODES (FOR NOW):
PImage sky;
void setup(){
size (512,1024);
//drag image into processing and it creates a file in the folder
sky = loadImage("pinxi sky lantern.jpeg");
noStroke();
}
void draw (){
image (sky,0,0);
}
I find that Google Trends is great for telling time when you search for seasonal or repetitive events. For example, searches for Mariah Carey’s “All I Want for Christmas” always increases around the start of the holiday season in the United States. I eventually chose to use Ramadan, as it occurs once per calendar year, but changes when in the calendar year it occurs.
Process:
I started by downloading the Google Trends spreadsheet and adding it to Processing. I first made a simple version of what I wanted the final graph to look like, simply by telling Processing to pull the dates and searches from the .csv file. This made a simple bar chart, at which point I started to mess with the scale I wanted. I had to map the values from the .csv chart into x and y coordinates. I did this simply by messing around with different values until I found a scale I liked.
Next I added a title and a date/searches counter to display the values from the .csv file. I thought that labelling each date and having a scale on the y-axis would be too difficult for the user to read. This calculator allowed the user to easily tell exactly when and how much “Ramadan” was being searched.
The final aspect that I wanted in my graph was to highlight the bar that was being selected. I wanted the color and thickness of the bar to change to make it very clear which was being selected. Rather than have the user click each bar, I wanted it to happen automatically based on where the users mouse was.
Final Work:
Below is a video displaying how the graph works.
Challenges:
I had a lot of trouble figuring out the highlighting. I made an integer mx for the x position of the mouse. I initially tried “if (mx == x)” with x being the x value of the bar, but that would only highlight a few bars when the mouse hovered over them, rather than each bar. In the end I used if(abs(mx>3)), which worked much better.
Code:
Table table;
PFont titleFont;
int mx = 30; // mouseX position
void setup() {
size(1280, 400);
titleFont = createFont("Courier New", 15);
table = loadTable("RamadanTimeline.csv", "header");
smooth(0);
}
void draw() {
background(235,236,237);
textFont(titleFont);
stroke(0);
fill(227,70,126);
textAlign(CENTER);
text("Interest in Ramadan by Week over past 5 years", width/2, 50);
fill(253,93,96);
text("Data via Google Trends", width/2, 70);
//take data from the .csv file
for (int row = 0; row < table.getRowCount(); row++) {
String dates = table.getString(row, 0);
float searches = table.getFloat(row, 1);
float x = map(row, 0, 216, 0, width);
float y = map(searches, 0, 100, 375, 60);
//draw the lines on the graph, and change the color of the selected line
line(x, y, x, 375);
if(abs(mx - x)<3){
strokeWeight(6);
stroke(252,192,109);
}else{
strokeWeight(2);
stroke(60,73,129);
}
//display the date and data for each selected line
if(abs(mx - x) < 3) {
fill(66,190,171);
text(dates, width-50, 50);
text(nfp(searches, 1, 3), width-50, 80);
}
}
}
void mouseMoved() {
mx = mouseX;
}
This data visualization was done in celebration of NYU Abu Dhabi’s 10th anniversary. What has been the interest in NYU Abu Dhabi overtime for the past ten years based on google searches?
Process
Using Google Trends, I got the data of searches for NYUAD from 2004 to the present grouped by months.
After loading the data, I went through each column mapping the rows to a wider range of values. For the second column, I mapped from 150 to 0 as opposed to the other way round to avoid drawing the lines upside-down.
After cleaning my data through the map function, I drew lines with a little circle on top. The little circle on top was drawn using ellipses with small diameters. I used smooth() to draw lines with anti-aliased edges.
To make things more interesting, I added a new line with red color that shows the date and increment in searches when the mouse pointer is moved. I achieved this using the nfp () function which formats a number to a string and shows ” + ” when positive and ” – ” when negative.
Final Work
DataViz
Video
Challenges
Cleaning the data was the biggest challenge. Did a lot of trial and error to find the right scale for mapping. I had trouble making the lines a bit bigger. I wanted to deepen the line representing the start of each year but it looked horrible. I wanted to add labels below the line graph but it appeared to be clustered.
Code
// Line plot of NYUAD search per month
color [] Pride = { #ffffff, #560BAD , #480CA8,#3A0CA3, #FF0000};
color [] palette = Pride;
Table table;
PFont titleFont;
int mx = 30; // mouseX position
void setup() {
size(640, 200);
// set fonts
titleFont = createFont("Georgia", 12);
// load Data
table = loadTable("NYUADTimeline.csv", "header");
// draw with smooth anti-aliased edges
smooth(2);
}
void draw() {
background(palette[0]);
textFont(titleFont);
stroke(palette[4]);
fill(palette[3]);
textAlign(CENTER);
text("Interest in NYUAD per month over 10 years", width/2, 20);
for (int row = 0; row < table.getRowCount(); row++) {
String dates = table.getString(row, 0);
float searches = table.getFloat(row, 1);
float x = map(row, 0, 216, 0, 600);
float y = map(searches, 0, 100, 150, 0);
// SLIDER
if((mx > 30) && (mx < 640)) {
line(mx, 30, mx, 150);
if(abs(mx - x) < 2) {
fill(palette[4]);
// show the dates and search count
text(dates, mx + 6, 40);
// format numbers into strings with 1 decimal to left and 3 to right
text(nfp(searches, 1, 3), mx + 6, 55);
}
}
// DRAW Lines and dots on top
// thickness of each line
strokeWeight(1);
stroke(palette[1]);
line(x, y, x, 150);
noStroke();
fill(palette[1]);
int d = 3;
ellipse(x, y, d, d);
}
}
void mouseMoved() {
mx = mouseX;
}