/*
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();
}