/* Snake on a Plane (on a Mobile Phone on a Plane) : The Game! Coded by Matthias Shapiro and Jason Alderman All characters and luggage designed by Kate Compton Pixel font SILKSCREEN by Jason Kottke, kottke.org Title font NYAMOMOBILE by Vic Fieger, vicfieger.com SNAKES ON A PLANE is a movie that is coming out in August that will be purdy dang awesinine. No money is being made from this; it's just for fun. (Please don't sue us.) */ /******************************* * GLOBAL VARIABLES * *******************************/ int game; // stage of the game int downcount; PFont f; ScoreBoard scores; int globDirection; int snakeLength; String[] snakeParts = { "snakeBody.png", "snakeHeadLeft.png", "snakeHeadUp.png", "snakeHeadRight.png", "snakeHeadDown.png", "snakeTailLeft.png", "snakeTailUp.png", "snakeTailRight.png", "snakeTailDown.png"}; PImage[] snakeImages; SnakeBody[] snake; String[] foodNames = { "sj.png", "p1.png", "p2.png", "p3.png", "p4.png", "cat.png", "pilot1.png", "pilot2.png", "baby1.png", "baby2.png", "baby3.png", "fa1.png", "fa2.png", "l1.png", "l2.png"}; PImage[] foodImages; FoodList allFood; Food Sammy; String gameEndMsg; boolean yesSelected; PImage titles; boolean gamePause; // int for screenheight and width? /******************************* * SETUP * *******************************/ void setup() { size(176,220); framerate(6); game = 0; downcount = 0; titles = loadImage("titlescreen.png"); f = loadFont("silky.vlw"); textFont(f, 8); gameInit(); gamePause = true; } /******************************* * DRAW (LOOP) * *******************************/ void draw() { switch (game) { case 0: image(titles, 0,0); downcount++; if(downcount>40){ game = 1; downcount = 0; } break; case 1: gamePause = true; background(0); fill(100); rect(10,10, width-20, height-20); textAlign(CENTER); fill(255); text("Snakes On A Plane.", width/2, 20); //fill(255,255,0); //text("", width/2, 35); fill(255); //** Only mobile.processing has a textWrap function. Boo. // String[] lines = textWrap("This is the classic game SNAKE. Only...set on a plane.\nPress the arrow keys or 2,4,6,8 " + // "on your keypad to move.\nEat EVERYTHING you can, but watch out for walls, your tail, and, of course, "+ // "Samuel L. Jackson.\nPress any key to start.",155); String[] lines = {"This is the","classic game SNAKE.","Only...set on a plane.","Press the arrow keys","or 2,4,6,8 on your", "keypad to move.","Eat EVERYTHING you can, ","but watch out for walls, ","your tail, and, of course, ", "Samuel L. Jackson.","","\"I've about had it with","these snakes!\"","","","Press any key to start."}; for(int l=0; l100){ game = 2; globDirection = 1; downcount = 0; } break; case 2: background(102,153,204); //(102,204,255); ? drawBackground(); textAlign(LEFT); scores.drawMe(); //** allFood.drawFood(); //** //Insert Update Code here if (!gamePause) updateSnake(); //Insert drawCode Here drawSnake(snake); Sammy.drawMe(); break; case 3: fill(104); rect(30,(height/2)-50, width-60, 75); textAlign(CENTER); fill(255,0,0); textFont(f,12); text("GAME OVER.", width/2, height/2-38); textFont(f,8); fill(255); text(gameEndMsg, width/2, height/2-28); text("Play again?", width/2, height/2-18); drawButtons(" yes! ", " um...no. ", height/2-4); break; } } /******************************* * GAMEINIT * *******************************/ void gameInit(){ //game = 0; downcount = 0; snake = new SnakeBody[570]; scores = new ScoreBoard(0,height-10,0); snakeImages = loadSnakeParts(snakeParts); println("images Loaded"); int snakeStartX = 64; int snakeStartY = 175; globDirection = 1; snakeLength = 3; for(int i = 0; i < snakeLength; i++){ int[] snakeMult = giveSnakeMult(globDirection); if(i == 0){ snake[i] = new SnakeHead(snakeImages[1], snakeImages[2], snakeImages[3], snakeImages[4], snakeStartX, snakeStartY, globDirection); } else if(i == (snakeLength-1)) { snake[i] = new SnakeTail(snakeImages[5], snakeImages[6], snakeImages[7], snakeImages[8], (snakeStartX + (-i*snakeMult[0])), (snakeStartY + (-i*snakeMult[1])), globDirection); } else { snake[i] = new SnakeBody(snakeImages[0], (snakeStartX + (-i*snakeMult[0])), (snakeStartY + (-i*snakeMult[1])), globDirection); } } foodImages = new PImage[foodNames.length]; // initialize the foods for(int j = 0; j < foodNames.length; j++) { foodImages[j] = loadImage(foodNames[j]); } allFood = new FoodList(20); allFood.printSlotReport(); // Sammy is now instantiated when new FoodList() is called //** still need to deconflict his location with the snake's //** so that he doesn't appear RIGHT before the snake at levelUp(); gameEndMsg = ""; yesSelected = false; } /******************************* * DRAWBUTTONS * *******************************/ void drawButtons(String yt, String nt, int y){ int yesWidth = (int) textWidth(yt); int noWidth = (int) textWidth(nt); int totalWidth = 13+yesWidth+noWidth; if(yesSelected) fill(255,255,0); else fill(124); rect((width/2) -(totalWidth/2), y, yesWidth+4, 15); if(yesSelected) fill(0); else fill(255); text(yt, (width/2)-(totalWidth/2)+2+yesWidth/2, y+11); if(!yesSelected) fill(255,255,0); else fill(124); rect((width/2) -(totalWidth/2)+9+yesWidth, y, noWidth+4, 15); if(!yesSelected) fill(0); else fill(255); text(nt, (width/2)+totalWidth/2-(noWidth)/2-2, y+11); } /******************************* * DRAWBACKGROUND * *******************************/ void drawBackground(){ noStroke(); // draw clouds: 204,255,255 fill(204,255,255); // draw clouds here...blaaaaah // draw rectangle for floor of plane: 204,204,204 fill(204); rect(24,0,128,height-10); //draw wings fill(192); beginShape(); vertex(0,35); vertex(15,40); vertex(15,155); vertex(0,150); endShape(); beginShape(); vertex(176,35); vertex(161,40); vertex(161,155); vertex(176,150); endShape(); //draw walls fill(153); strokeWeight(1); stroke(102); rect(10,0,4,height-10); rect(161,0,4,height-10); noStroke(); fill(255); rect(14,0,10,height-10); rect(152,0,10,height-10); fill(102); beginShape(); vertex(14,0); vertex(23,7); vertex(152,7); vertex(161,0); endShape(); beginShape(); vertex(14,height-10); vertex(23,height-10-8); vertex(152,height-10-8); vertex(161,height-10); endShape(); fill(120,120,204); rect((width/2) - 15, 0, 30, 7); rect((width/2) - 15, height-18, 30, 8); // draw seats for(int k = 0; k<12; k++){ if(k != 6) { //emergency exit row for(int j = 0; j<8; j++){ if(j != 3 && j != 4) { // center aisle //x : (j*16)+24 , y : (k*16)+8 //draw seat bottom fill(120,120,204); rect((j*16)+24, (k*16)+8, 16,12); //draw seat backs fill(153,153,255); rect((j*16)+25, (k*16)+8, 14,4); } } } } fill(102,102,204); } /******************************* * LOADSNAKEPARTS * *******************************/ PImage[] loadSnakeParts(String[] loadList){ PImage[] returnImages = new PImage[loadList.length]; for(int i=0; i < loadList.length; i++){ returnImages[i] = loadImage(loadList[i]); println("Loaded Image: " + loadList[i]); } return returnImages; } /******************************* * DRAWSNAKE * *******************************/ void drawSnake(SnakeBody[] snakeArray){ int i = 0; while( i < snakeArray.length && snakeArray[i] != null) { snakeArray[i].drawMe(); i++; } } /******************************* * KEYPRESSED * *******************************/ void keyPressed() { if(game == 1) { game = 2; } else if (game == 2) { if(gamePause) gamePause=false; if(key == 'p') allFood.printSlotReport(); if((key == '8' || keyCode == UP) && (globDirection != 3)) { globDirection = 1; } else if((key == '4' || keyCode == LEFT) && (globDirection != 2)){ globDirection = 0; } else if((key == '6' || keyCode == RIGHT) && (globDirection != 0)){ globDirection = 2; } else if((key == '2' || keyCode == DOWN) && (globDirection != 1)){ globDirection = 3; } } else if (game == 3) { if((key == '4' || keyCode == LEFT) && !yesSelected) yesSelected = (!yesSelected); if((key == '6' || keyCode == RIGHT) && yesSelected) yesSelected = (!yesSelected); if(key == ' ' || keyCode == ENTER || key == '5'){ if (yesSelected) { game=1; gameInit(); } else { game=0; gameInit(); //** how do you tell it to QUIT??? } } } } /******************************* * GIVESNAKEMULT * *******************************/ int[] giveSnakeMult(int direct){ int[] output = { 0, 0 }; switch(direct){ case 0: output[0] = -8; break; case 1: output[1] = -8; break; case 2: output[0] = 8; break; case 3: output[1] = 8; break; } return output; } // when updating, check for collision (if collision, die) , then for food // (if food (and not SLJ), move food, add point, add body segment, // move (else die)) /******************************* * UPDATESNAKE * *******************************/ void updateSnake(){ boolean moveSnake; boolean addSection; int globDir = globDirection; int[] snakeMult = giveSnakeMult(globDir); int movementMultX = snakeMult[0]; int movementMultY = snakeMult[1]; int[] forCollision = snake[0].getData(); forCollision[0] = forCollision[0] + movementMultX; forCollision[1] = forCollision[1] + movementMultY; moveSnake = true; //if next move is outside bounds, stop the snake. if (forCollision[0] < 24 || forCollision[0] > 151 || forCollision[1] < 1 || forCollision[1] > 195) { moveSnake = false; // ...and DIE! (game=3;) game=3; gameEndMsg = "Yep, that was a wall."; } //if next move is into Sam Jackson, stop the snake. if (Sammy.containsPoint(forCollision[0],forCollision[1])) { moveSnake = false; // ...and DIE! (game=3;) game=3; gameEndMsg = "Jedi: 1. Snake: 0."; } //if next move is into self, stop snake. int[] tempSnakeData; int sn = 0; while(sn=0 && allFood.checkFood(enteringSlot)){ addSection = true; print("eating "+enteringSlot+"..."); allFood.eat( enteringSlot ); if (allFood.stuffed()) { println("resetting food"); allFood = new FoodList(48); scores.levelUp(); } } //** if(moveSnake){ //println("I should be moving"); if(addSection || ((keyPressed) && (key == 'x'))){ //println("snakeLength starts as "+snakeLength); // this code is faulty...it adds a gap in the middle, but doesn't add snake body permanently for(int i = (snakeLength - 1); i > -1; i--){ if(i > 1){ snake[(i+1)] = snake[i]; } else if(i == 1){ snake[(i+1)] = snake[i]; //** int[] setNewBody = snake[(i-1)].getData(); snake[i] = new SnakeBody(snakeImages[0], setNewBody[0], setNewBody[1], setNewBody[2]); } else if(i == 0){ int[] updateHead = snake[i].getData(); updateHead[0] = updateHead[0] + movementMultX; updateHead[1] = updateHead[1] + movementMultY; updateHead[2] = globDir; snake[i].setData(updateHead); } } snakeLength++; println("The snakeLength is now "+snakeLength); scores.addPoints(10); //probably should put this on the food side, so diff foods can be worth more? addSection = false; } else { //println("globDirection = " + globDir); for(int i = (snakeLength -1); i > -1; i--){ if(i == 0){ int[] updateHead = snake[i].getData(); updateHead[0] = updateHead[0] + movementMultX; updateHead[1] = updateHead[1] + movementMultY; updateHead[2] = globDir; snake[i].setData(updateHead); } else { int[] tempData = snake[(i-1)].getData(); snake[i].setData(tempData); if(i == (snakeLength - 1)){ int[] tempData2 = snake[(i-2)].getData(); int[] tempData1 = snake[(i-1)].getData(); tempData1[2] = tempData2[2]; snake[i].setData(tempData1); } } } } } } /******************************* * CALCSLOT * *******************************/ int calcSlot(int x, int y) { if(y<8 || y>199 || x<24 || x>151){ return -1; // out of bounds } else { return floor((y-8)/16)*8+floor((x-24)/16); } } /********************************** c l a s s e s **********************************/ class Food { int iconIndex; int h, w; int x, y; int id; boolean active; int slot; Food(int appearance, int s, int index){ this.iconIndex = appearance; this.h = 16; this.w = 16; this.id = index; this.setSlot(s); this.active = true; } void drawMe() { //println(this.active); //println("for slot "+this.slot+", x,y: "+this.x+","+this.y+", iconIndex "+this.iconIndex+", drawing."); image(foodImages[this.iconIndex], this.x, this.y); } void setCoords(int nx, int ny) { this.x = nx; this.y = ny; } /* void placeMe(int sx, int sy) { this.setCoords(sx, sy); this.active = true; } */ void beEaten() { this.active = false; } void setSlot(int s) { this.slot = s; this.y = ((int)floor(s/8))*16 + 8; // calculate out from slot this.x = (s % 8)*16 + 24; // calculate out from slot } boolean containsPoint(int px, int py){ return ((px >= this.x) && (px < (this.x + this.w)) && (py >= this.y) && (py < this.y + this.h)); } boolean notEaten() { return this.active; } } class FoodList { int listLength; int maxSize; int totalEaten; Food[] foodArray; int[] foodSlots; FoodList(int biggestSize){ this.totalEaten = 0; this.maxSize = biggestSize; // don't forget to take out the (int)s --mobile.processing: int random(){} this.listLength = (int)random((int)(this.maxSize/8),this.maxSize); //println("listLength = "+listLength); this.foodArray = new Food[listLength]; this.foodSlots = new int[96]; // should rather tie to biggestSize...? for(int k=0; k=0)); //if (foodSlots[tempSlot]>=0) println("recalculating..."); while(foodSlots[tempSlot]>=0){ tempSlot++; if(tempSlot>95) tempSlot = 0; } //println("yep, tempSlot is "+tempSlot); tempimg = floor(random(1,foodImages.length)); foodSlots[tempSlot] = i; this.foodArray[i] = new Food(tempimg,tempSlot,i); } // place Sammy tempSlot = (int)floor(random(95.999)); //println("tempslot for Sam Jackson = "+tempSlot+" and "+(foodSlots[tempSlot]>=0)); while(foodSlots[tempSlot]>=0){ tempSlot++; if(tempSlot>95) tempSlot = 0; } //println("yep, tempSlot is "+tempSlot); Sammy = new Food(0,tempSlot,187); } //** for debugging void printSlotReport(){ int totalCount = 0; print("There are food people in slots: "); for(int r=0; r<96; r++){ if(foodSlots[r]>=0){ print(""+r+", "); totalCount += 1; } } println(); println("...for a total of "+totalCount+" slots still full o' food."); } void drawFood(){ for(int i=0; i=0 && foodSlots[s] >= 0) foodFound = true; return foodFound; } boolean checkFood(int x, int y){ return checkFood(calcSlot(x,y)); } void eat(int g){ //println("eat g="+g+", foodSlots[g] is "+foodSlots[g]+" or id="+foodArray[foodSlots[g]].id); //println("foodSlots[g] is eaten: "+foodArray[foodSlots[g]].notEaten()); if(g>=0 && foodSlots[g]= this.listLength("+this.listLength+") :"+(this.totalEaten >= this.listLength)); return (this.totalEaten >= this.listLength); } } class SnakeBody { PImage body_img; int h, w; int x, y; int direction; //0 = left, 1 = up, 2 = right, 3 = down SnakeBody(PImage bod_icon, int bodPosX, int bodPosY, int dir){ x = bodPosX; y = bodPosY; body_img = bod_icon; direction = dir; } void drawMe(){ image(body_img, x, y); } int[] getData(){ int[] dataTransfer = { x, y, direction }; return dataTransfer; } void setData(int[] importData){ x = importData[0]; y = importData[1]; direction = importData[2]; } } class SnakeHead extends SnakeBody { PImage head_left, head_right, head_up, head_down; //0 = left, 1 = up, 2 = right, 3 = down SnakeHead(PImage hLeft, PImage hUp, PImage hRight, PImage hDown, int bodPosX, int bodPosY, int dir){ super(hLeft, bodPosX, bodPosY, dir); head_left = hLeft; head_up = hUp; head_down = hDown; head_right = hRight; } void drawMe(){ switch(direction) { case 0: image(head_left, x, y); break; case 1: image(head_up, x, y); break; case 2: image(head_right, x, y); break; case 3: image(head_down, x, y); break; } } int getDir(){ return direction; } void setDir(int newDir){ direction = newDir; } } class SnakeTail extends SnakeBody { PImage tail_left, tail_right, tail_up, tail_down; SnakeTail(PImage tLeft, PImage tUp, PImage tRight, PImage tDown, int bodPosX, int bodPosY, int dir){ super(tLeft, bodPosX, bodPosY, dir); tail_left = tLeft; tail_up = tUp; tail_down = tDown; tail_right = tRight; } void drawMe(){ switch(direction) { case 0: image(tail_left, x, y); break; case 1: image(tail_up, x, y); break; case 2: image(tail_right, x, y); break; case 3: image(tail_down, x, y); break; } } } class ScoreBoard { int x, y; int w, h; int score; int level; ScoreBoard(int sx, int sy, int sc){ this.x = sx; this.y = sy; this.w = width; this.h = 10; this.score = 0; this.level = 1; } void setScore(int newScore){ if (newScore>=0) this.score = newScore; } void levelUp(){ this.level += 1; } void addPoints(int points){ if (points>=0) this.score += points; } void drawMe(){ fill(0); noStroke(); rectMode(CORNER); rect( this.x, this.y, this.w, this.h); fill(255); text("level", this.x+3, this.y+this.h-2); fill(255,255,0); text(nf(this.level,0), this.x+3+textWidth("level "), this.y+this.h-2); fill(255); text("score", this.x+3+textWidth("level 00 "), this.y+this.h-2); fill(255,255,0); text(this.score, this.x+this.w-textWidth(nf(this.score,0)), this.y+this.h-2); } }