/* Designer: Mosang Liu Instructor: Nicolas Hesler Oct.3,2018 */ ////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////Controls/////////////////////////////////////////////////////////////////////////////////////////// ///////Press any key to start///////////////////////////////////////////////////////////////////////////// ///////Click mosue button to fire///////////////////////////////////////////////////////////////////////// ///////The charactor will following the cursor which is insteaded by an aim icon////////////////////////// ///////The farther the aim is, the charactor moves faster///////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////Game play////////////////////////////////////////////////////////////////////////////////////////// ///////Zombies will chase you and respawn after you kill them///////////////////////////////////////////// ///////Kill them or avoid them//////////////////////////////////////////////////////////////////////////// ///////Get score by kill zombie and survive longer//////////////////////////////////////////////////////// ///////Difficulty will increase based on servive time///////////////////////////////////////////////////// ///////There are 7 difficulties/////////////////////////////////////////////////////////////////////////// ///////No one can survive in difficulty 7///////////////////////////////////////////////////////////////// ///////Let's try your limit/////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////// //interface variables int waitTime; int serviveTime = 0; int serviveRank = 0; int score = 0; int highScore = 0; int difficulty; boolean gameStart = false; //player's variables float playerX = 200; float playerY = 200; float playerSpeed = 4; float playerMoveX = 0; float playerMoveY = 0; float distance = sqrt(sq(mouseX-playerX)+sq(mouseY-playerY)); float directionRadian = sqrt(1-sq(cos((mouseY-playerY)/distance))); //zombie's variables //zombie1 float zombie1X = -25; float zombie1Y = random(-25, 425); float zombie1MoveX = 0; float zombie1MoveY = 0; float zombie1Distance = sqrt(sq(playerX-zombie1X)+sq(playerY-zombie1Y)); float zombie1DirectionRadian = sqrt(1-sq(cos((playerY-zombie1Y)/zombie1Distance))); float zombie1Speed; //zombie2 float zombie2X = 425; float zombie2Y = random(-25, 425); float zombie2MoveX = 0; float zombie2MoveY = 0; float zombie2Distance = sqrt(sq(playerX-zombie2X)+sq(playerY-zombie2Y)); float zombie2DirectionRadian = sqrt(1-sq(cos((playerY-zombie2Y)/zombie2Distance))); float zombie2Speed; //shooting variables float fireX, fireY; float aimX, aimY; float bulletX, bulletY; float bulletSpeed = 30; void setup() { size(400, 400); frameRate(50); ellipseMode(CENTER); rectMode(CENTER); noCursor(); } void draw() { //draw// background(0); drawTexture(); drawAim(); drawPlayer(); drawZombie1(); drawZombie2(); scoreCard(); //update// playerAction(); zombie1Move(); zombie2Move(); collisionTest(); hitTest1(); hitTest2(); timeUpdate(); updateDifficulty(); //if game is not started, run game menu if (gameStart == false) { gameStartScreen(); } } //Press any key to start void gameStartScreen() { waitTime = millis(); textSize(30); fill(125, 255, 43); text("Use mouse to move", 60, 100); fill(55, 12, 232); text("Click to fire", 115, 150); fill(255); text("Press any key to start", 45, 300); if (keyPressed) { gameStart = true; } } //update servive time //servive time = millis() - wait time in manu interface void timeUpdate() { if (gameStart==true) { serviveTime = (millis() - waitTime)/1000; } } //score card include scores, high scores and difficulty void scoreCard() { fill(255); textSize (15); text ( "Servive time:" + serviveTime, 10, 16); text ( "Score:" + (score + serviveTime), 160, 16); text ( "Difficulty:" + difficulty, 300, 16); text ("Highscores: Suervive time " + serviveRank + " " + "Score" + highScore, 10, 386); } //increase zombie speed based on servive time void updateDifficulty() { if (serviveTime<=10) { zombie1Speed = 1200/zombie1Distance; zombie2Speed = 1200/zombie2Distance; difficulty = 1; } else if (serviveTime>10 && serviveTime<=20) { zombie1Speed = 1500/zombie1Distance; zombie2Speed = 1500/zombie2Distance; difficulty = 2; } else if (serviveTime>20 && serviveTime<=30) { zombie1Speed = 1800/zombie1Distance; zombie2Speed = 1800/zombie2Distance; difficulty = 3; } else if (serviveTime>30 && serviveTime<=60) { zombie1Speed = 2100/zombie1Distance; zombie2Speed = 2100/zombie2Distance; difficulty = 4; } else if (serviveTime>60 && serviveTime<=120) { zombie1Speed = 2400/zombie1Distance; zombie2Speed = 2400/zombie2Distance; difficulty = 5; } else if (serviveTime>120 && serviveTime<=180) { zombie1Speed = 2700/zombie1Distance; zombie2Speed = 2700/zombie2Distance; difficulty = 6; }else { zombie1Speed = 3200/zombie1Distance; zombie2Speed = 3200/zombie2Distance; difficulty = 7; } } //background texture //full fill screen with 20*20 rectangles filled by random() function. void drawTexture() { int size = 20; for (int x = 0; x < width/size+1; ++x) { for (int y = 0; y <height; ++y) { noStroke(); fill(random(80, 130), 8, 10); rect(x*size, y*size, size, size); } } } //Aim icon instead of cursor void drawAim() { noFill(); stroke(0); strokeWeight(2); ellipse(mouseX, mouseY, 25, 25); point(mouseX, mouseY); line(mouseX, mouseY-8, mouseX, mouseY-17); line(mouseX, mouseY+8, mouseX, mouseY+17); line(mouseX-8, mouseY, mouseX-17, mouseY); line(mouseX+8, mouseY, mouseX+17, mouseY); } //drawPlayer features and bullet //hand and gun will turn to the direction of the aim void drawPlayer() { //bullet stroke(150, 250, 0); strokeWeight(5); point(bulletX, bulletY); //gun stroke(0); line(playerX, playerY, playerX+(mouseX-playerX)*50/distance, playerY+(mouseY-playerY)*50/distance); //Body noStroke(); fill(248, 197, 116); ellipse(playerX, playerY, 25, 25); //hand stroke(0); strokeWeight(1); ellipse(playerX+(mouseX-playerX)*25/distance, playerY+(mouseY-playerY)*25/distance, 10, 10); //halmet fill(102, 62, 42); ellipse(playerX+(mouseX-playerX)*2/distance, playerY+(mouseY-playerY)*2/distance, 18, 18); fill(229, 206, 223); ellipse(playerX+(mouseX-playerX)*2/distance, playerY+(mouseY-playerY)*2/distance, 15, 15); } //record fire position coordinates and aim coordinates when mouse is pressed void mousePressed() { fireX=playerX+(mouseX-playerX)*50/distance; fireY=playerY+(mouseY-playerY)*50/distance; aimX=mouseX; aimY=mouseY; } //player actions //player move towards aim //assign bullet coordinates by fire position. void playerAction() { if (gameStart) { //move playerMoveX=(mouseX-playerX)/distance * playerSpeed; playerMoveY=(mouseY-playerY)/distance * playerSpeed; playerX+=playerMoveX; playerY+=playerMoveY; //mouse click to shoot if (mousePressed) { bulletX = fireX; bulletY = fireY; } /* shooting system debug notes At first the way I calculate bulletSpeed in Y derection by this function: float bulletDistance = sqrt(sq(aimX-fireX)+sq(aimY-fireY)); float bulletDirectionRadian = sqrt(1-sq(cos((aimY-fireY)/bulletDistance))); However, the problem is: by this way bulletY can not larger if (shoot==true){ than bulletX. It Caused player can't shootingin a huge area. if(fireX<aimX){ if(fireY>aimY){ so I changed to the mathematic method, which lead to another bug: bulletX += bulletSpeed*cos(bulletDirectionRadian); player can't shoot up and down. I speculated two reasons: bulletY -= bulletSpeed*sin(bulletDirectionRadian); }else{ 1. bulletSpeedX is a constant. So if aimY very close to fireY, bulletX += bulletSpeed*cos(bulletDirectionRadian); bulletSpeedY will become super large and beyong the limits of human bulletY += bulletSpeed*sin(bulletDirectionRadian); vison. } } 2. because float is not precise, so if two values are two close, they if(fireX>aimX){ are abbreviated into the same number. if(fireY>aimY){ bulletX -= bulletSpeed*cos(bulletDirectionRadian); I can't sovle this problem, but I find a nother way to make up. bulletY -= bulletSpeed*sin(bulletDirectionRadian); I defined a small area up and down. so if aimX is in this area, }else{ it shoot straight up or down. bulletX -= bulletSpeed*cos(bulletDirectionRadian); bulletY += bulletSpeed*sin(bulletDirectionRadian); } } } */ //bullet movement logic if (fireX<=aimX+25 && fireX>=aimX-25) { if (fireY>=aimY) { bulletY -= bulletSpeed; } if (fireY<aimY) { bulletY += bulletSpeed; } } if (fireX<aimX-25) { bulletX += bulletSpeed; bulletY += bulletSpeed*(aimY-fireY)/(aimX-fireX); } if (fireX>aimX+25) { bulletX -= bulletSpeed; bulletY -= bulletSpeed*(aimY-fireY)/(aimX-fireX); } } } //zombie functions //if game started, zombies are moving toward player //hands have 4 directions follow player's position //draw zombie1 void drawZombie1() { float z1Hand1X = cos(zombie1DirectionRadian-PI/6)*15; float z1Hand1Y = sin(zombie1DirectionRadian-PI/6)*15; float z1Hand2X = cos(zombie1DirectionRadian+PI/6)*15; float z1Hand2Y = sin(zombie1DirectionRadian+PI/6)*15; noStroke(); //zombie1 body fill(133, 119, 40); ellipse(zombie1X, zombie1Y, 25, 25); //zombie1 hands //hand1 stroke(0); fill(133, 119, 40); if (zombie1X > playerX) { if (zombie1Y > playerY) { ellipse(zombie1X-z1Hand1X, zombie1Y-z1Hand1Y, 10, 10 ); } if (zombie1Y < playerY) { ellipse(zombie1X-z1Hand1X, zombie1Y+z1Hand1Y, 10, 10 ); } } if (zombie1X < playerX) { if (zombie1Y > playerY) { ellipse(zombie1X+z1Hand1X, zombie1Y-z1Hand1Y, 10, 10 ); } if (zombie1Y < playerY) { ellipse(zombie1X+z1Hand1X, zombie1Y+z1Hand1Y, 10, 10 ); } } //hand2 if (zombie1X > playerX) { if (zombie1Y > playerY) { ellipse(zombie1X-z1Hand2X, zombie1Y- z1Hand2Y, 10, 10 ); } if (zombie1Y < playerY) { ellipse(zombie1X-z1Hand2X, zombie1Y+ z1Hand2Y, 10, 10 ); } } if (zombie1X < playerX) { if (zombie1Y > playerY) { ellipse(zombie1X+z1Hand2X, zombie1Y- z1Hand2Y, 10, 10 ); } if (zombie1Y < playerY) { ellipse(zombie1X+z1Hand2X, zombie1Y+ z1Hand2Y, 10, 10 ); } } } //zombie1 Movement logics void zombie1Move() { if (gameStart) { zombie1MoveX=(playerX-zombie1X)/distance * zombie1Speed; zombie1MoveY=(playerY-zombie1Y)/distance * zombie1Speed; zombie1X+=zombie1MoveX; zombie1Y+=zombie1MoveY; } } //draw zombie2 void drawZombie2() { float z2Hand1X = cos(zombie2DirectionRadian-PI/6)*15; float z2Hand1Y = sin(zombie2DirectionRadian-PI/6)*15; float z2Hand2X = cos(zombie2DirectionRadian+PI/6)*15; float z2Hand2Y = sin(zombie2DirectionRadian+PI/6)*15; noStroke(); //zombie2 body fill(133, 119, 40); ellipse(zombie2X, zombie2Y, 25, 25); //zombie2 hands //hand1 stroke(0); strokeWeight(1); fill(133, 119, 40); if (zombie2X > playerX) { if (zombie2Y > playerY) { ellipse(zombie2X-z2Hand1X, zombie2Y-z2Hand1Y, 10, 10 ); } if (zombie2Y < playerY) { ellipse(zombie2X-z2Hand1X, zombie2Y+z2Hand1Y, 10, 10 ); } } if (zombie2X < playerX) { if (zombie2Y > playerY) { ellipse(zombie2X+z2Hand1X, zombie2Y-z2Hand1Y, 10, 10 ); } if (zombie2Y < playerY) { ellipse(zombie2X+z2Hand1X, zombie2Y+z2Hand1Y, 10, 10 ); } } //hand2 if (zombie2X > playerX) { if (zombie2Y > playerY) { ellipse(zombie2X-z2Hand2X, zombie2Y- z2Hand2Y, 10, 10 ); } if (zombie2Y < playerY) { ellipse(zombie2X-z2Hand2X, zombie2Y+ z2Hand2Y, 10, 10 ); } } if (zombie2X < playerX) { if (zombie2Y > playerY) { ellipse(zombie2X+z2Hand2X, zombie2Y- z2Hand2Y, 10, 10 ); } if (zombie2Y < playerY) { ellipse(zombie2X+z2Hand2X, zombie2Y+ z2Hand2Y, 10, 10 ); } } } //zombie2 Movement logics void zombie2Move() { if (gameStart) { zombie2MoveX=(playerX-zombie2X)/distance * zombie2Speed; zombie2MoveY=(playerY-zombie2Y)/distance * zombie2Speed; zombie2X+=zombie2MoveX; zombie2Y+=zombie2MoveY; } } void collisionTest() { float zombie1Distance = sqrt(sq(playerX-zombie1X)+sq(playerY-zombie1Y)); float zombie2Distance = sqrt(sq(playerX-zombie2X)+sq(playerY-zombie2Y)); if (zombie1Distance < 35 || zombie2Distance < 35 ) { reset(); } } //hit tests void hitTest1() { float bulletDistance1 = sqrt(sq(zombie1X-bulletX)+sq(zombie1Y-bulletY)); if (bulletDistance1 <25 ) { killZombie1(); } } void hitTest2() { float bulletDistance2 = sqrt(sq(zombie2X-bulletX)+sq(zombie2Y-bulletY)); if ( bulletDistance2 <25) { killZombie2(); } } //reset zombies void killZombie1() { zombie1X = -25; zombie1Y = random(-25, 425); score+=1; resetBullet(); } void killZombie2() { zombie2X = 425; zombie2Y = random(-25, 425); score+=1; resetBullet(); } //reset bullet void resetBullet() { bulletX = playerX; bulletY = playerY; } //reset game and record highscores void reset() { gameStart = false; playerX = 200; playerY = 200; zombie1X = -25; zombie1Y = random(-25, 425); zombie2X = 425; zombie2Y = random(-25, 425); resetBullet(); zombie1Speed = 1200/zombie1Distance; zombie2Speed = 1200/zombie2Distance; if (highScore < score+serviveTime) { highScore = score+serviveTime; } score = 0; if (serviveRank < serviveTime) { serviveRank = serviveTime; } serviveTime = 0; resetBullet(); }