Player p; Ghost g ; int LITELENGTH = 4; int frameTimer; int instructionsTimer; int endTime; boolean gameGoing; ArrayList stones = new ArrayList(); void keyPressed() { reset(); } void reset() { g = new Ghost(); p = new Player(); points = 0; endTime = millis() + 30 * 1000; gameGoing = true; instructionsTimer = 5000; } float PSPEED = 2.6; float targetx = 250, targety= 250; void setup() { size(500, 500); textAlign(CENTER); reset(); frameRate(50); for (int i = 0; i < 3; i++) { stones.add(new Stone(150 + i * 100, 250, 1.5)); } for (int i = 0; i < 4; i++) { stones.add(new Stone(130 + i * 80, 320, 1)); } for (int i = 0; i < 3; i++) { stones.add(new Stone(110 + i * 140, 400, 2)); } } void draw() { frameTimer++; drawBG(); for (Stone s : stones) { s.draw(); } p.move(); p.draw(); g.move(); g.draw(); /* noFill(); stroke(255, 0, 0); for (Stone s : stones) { rect(s.x, s.y, s.w, s.h); } rect(g.x, g.y, g.w, g.h); rect(p.x, p.y, p.w, p.h);*/ } void mouseMoved() { updateTarget(); } void mousePressed() { updateTarget(); } void mouseDragged() { updateTarget(); } void updateTarget() { targetx = mouseX - p.w/2; targety = constrain(mouseY - p.h/2, 175, 500); } color TOMB=color(170); color PINK = color(200, 100, 100); color SKIN = color(255, 128, 128); color DARKPINK = color(150, 75, 75); color YELLOW = color(255, 255, 0); int points = 0; int litTimer = 0; void drawBG() { //if (frameTimer % 25 == 0 ) { boolean gotIt = false; for (Stone s : stones) { if (s.overlaps(g)) { if (s.overlaps(p) && ! s.wasTouchingBoth) { litTimer = LITELENGTH; points++; s.light(); s.wasTouchingBoth = true; } } else { //stone not overlapping ghost s.wasTouchingBoth = false; } } if (litTimer > 0) { background(255); litTimer--; } else background(0, 0, 100); fill(255); text("G H O S T M A N N E R S", 250, 20); if (gameGoing) { if (instructionsTimer > 0) { text("tag the sherbert ghost when", 250, 40); text("he's over a tombstone!", 250, 60); instructionsTimer--; } } else { text("GAME OVER", 250, 40); text("reset to play again", 250, 60); } text("TIME LEFT", 450, 50); if (endTime - millis() < 0) text(0, 450, 70); else text(round((endTime - millis())/1000), 450, 70); if(! gameGoing) fill(random(128,255)); text("SCORE", 50, 50); text(points, 50, 70); noStroke(); fill(0, 100, 0); rect(0, 200, 500, 300); triangle(0, 200, 150, 175, 150, 200); triangle(500, 200, 350, 175, 350, 200); rect(150, 175, 200, 25); fill(TOMB); rect(50, 200, 175, 10); rect(275, 200, 175, 10); //main castle fill(DARKPINK); rect(200, 125, 100, 50); //basic towers rect(180, 100, 40, 75); rect(280, 100, 40, 75); //ramparts for (int i = 0; i < 7;i++) { rect(222+ i * 10, 120, 5, 5); } towerTop(168, 90); towerTop(268, 90); stroke(0); noFill(); strokeWeight(2); //doors arc(250, 175, 30, 50, PI, 2*PI); arc(250, 175, 36, 56, PI, 2*PI); line(250, 150, 250, 175); line(247, 166, 253, 166); noStroke(); fill(PINK); //tower hilite rect(180, 100, 20, 75); rect(300, 100, 20, 75); if (endTime - millis() < 0) { gameGoing = false; } } void towerTop(float x, float y) { rect(x, y, 65, 10); for (int i = 0; i < 7;i++) { rect(x+ i * 10, y-5, 5, 5); } } class Mover { float x, y, w, h; boolean overlaps(Mover m) { if (linearOverlap(x, w, m.x, m.w) && linearOverlap(y, h, m.y, m.h)) return true; return false; } boolean linearOverlap(float x1, float w1, float x2, float w2) { if (x1 + w1 < x2) return false; if (x1 > x2 + w2) return false; return true; } } color DRESSCOLOR = color(150, 250, 200); color BELTCOLOR = color(100, 200, 150); class Player extends Mover { boolean facingLeft; boolean moving = false; float footangle = random(2*PI); Player() { x=300; y=300; w = 40; h = 53; } void move() { moving = false; if (dist(x, y, targetx, targety) < 2) return; if (x > targetx) { x-= PSPEED; facingLeft = true; moving = true; } if (x < targetx) { x+= PSPEED; facingLeft = false; moving = true; } if (y < targety) { y+= PSPEED; moving = true; } if (y > targety) { y-= PSPEED; moving = true; } } void draw() { if (moving)footangle += .15; int dir = 1; if (facingLeft) dir = -1; //HITBOX // noFill(); // stroke(255,0,0); // rect(x,y,w,h); pushMatrix(); translate(x+w/2, y+h/2 +6); noStroke(); //feet fill(150); ellipse(sin(footangle) * 10, 20, 8, 8); ellipse(-sin(footangle) * 10, 20, 8, 8); fill(DRESSCOLOR); //skirt triangle(0, -10, -20, 20, 20, 20); //torso rect(-5, -20, 10, 40); //arm if (! facingLeft) rect(-2, -15, 15, 5); else rect(-12, -15, 15, 5); //hand fill(SKIN); ellipse(dir * 15, -12, 8, 8); //head ellipse(0, -25, 20, 20); //hair fill(YELLOW); float a = PI/2; if (! facingLeft) a = 0; arc(0, -25, 20, 20, a + PI*3/4, a + PI*7/4); ellipse(dir*-10, -25, 8, 8); ellipse(dir*-14, -20, 8, 8); ;//bow fill(BELTCOLOR); rect(-9, 0, 18, 5); ellipse(dir * -10, 0, 5, 5); popMatrix(); } } class GhostGoal { float sx, sy, ex, ey, x, y; int numsteps; int nowstep; GhostGoal(float px, float py, int psteps) { ex = px; ey = py; numsteps = psteps; } void reset(GhostGoal prev) { nowstep = 0; sx = prev.ex; sy = prev.ey; } void step() { nowstep++; x = lerp(sx, ex, (float)nowstep / (float)numsteps); y = lerp(sy, ey, (float)nowstep / (float)numsteps); } boolean isDone() { return nowstep >= numsteps; } } class Ghost extends Mover { int coloroff = 0; float a; color[] paint = new color[60]; GhostGoal[] goals = new GhostGoal[6]; int goalptr; color[] b = new color[6]; Ghost() { x = 250; y = 400; w = 40; h = 60; b[0] = color(200, 200, 255); b[1] = color(200, 255, 200); b[2] = color(200, 255, 255); b[3] = color(255, 200, 200); b[4] = color(255, 200, 255); b[5] = color(255, 255, 200); for (int i = 0; i < 60; i++) { paint[i] = b[floor(i/10)]; } goals[0] = new GhostGoal(400, 400, 30); goals[1] = new GhostGoal(55, 400, 60); goals[2] = new GhostGoal(102, 310, 15); goals[3] = new GhostGoal(357, 310, 45); goals[4] = new GhostGoal(336, 230, 15); goals[5] = new GhostGoal(122, 230, 30); GhostGoal start = goals[0]; x = start.ex; x = start.ey; goalptr = 1; goals[goalptr].reset(start); } void move() { a += .2; GhostGoal current = goals[goalptr]; if (gameGoing) { current.step(); x = current.x; y = current.y + 10 * sin(a); } else { x += 10 * sin(a); y -= 5; // y = current.y + 10 * sin(a); } if (current.isDone()) { goalptr++; goalptr = goalptr % 6; goals[goalptr].reset(current); } } void draw() { /* //drawing goals for(int i = 0; i < 6; i++){ fill(255); text(i,goals[i].ex,goals[i].ey); noFill(); stroke(255); rect(goals[i].ex,goals[i].ey,w,h); }*/ coloroff++; noFill(); strokeWeight(1); int j = 60; for (int i = 0; i < 60; i++) { j--; stroke(paint[(j+coloroff)%60]); if (i >= 0 && i <= 5) { //top midline(w - 5 + i, i); } else if (i >= 10 && i <= 20) { //eyes midlines(8, i); } else if (i >= 30 && i <= 33) { //mouth line(x, y+i, x+5, y+i); line(x+w, y+i, x+w-5, y+i); } else if (i> 55) { //bottom midlines(8, i); } else { line(x, y+i, x+w, y+i); } } // stroke(255,0,0); // rect(x,y,w,h); } void midline(float wa, int i) { float c = x+(w/2); line(c-wa/2, y+i, c+wa/2, y+i); } void midlines(float wa, int i) { float c1 = x+(w/4); float c2 = x+(w*3/4); line(x, y+i, c1-wa/2, y+i); line(c1+wa/2, y+i, c2-wa/2, y+i); line(c2+wa/2, y+i, x+w, y+i); } } class Stone extends Mover { int litTimer; boolean wasTouchingBoth; boolean rounded = false; Stone(float px, float py, float m) { w = map(py, 250, 500, 20, 50) * m; h = map(py, 250, 500, 40, 70); x = px - w / 2; y = py; if (random(1) < .8) rounded = true; } void draw() { noStroke(); fill(TOMB); if (this.overlaps(g)) { strokeWeight(4); stroke(g.b[floor(random(6))]); //random base color of ghost } if (wasTouchingBoth) { litTimer--; fill(g.b[floor(random(6))]); //rando base color of ghost } if (! rounded) { rect(x, y, w, h); } else { rect(x, y+h/4, w, h*3/4); arc(x+w/2, 1+y+h/4, w, h/2, PI, PI*2); noStroke(); rect(x, y+h/4, w, h*3/4); } // noFill(); stroke(255,0,0); // rect(x,y,w,h); } void light() { litTimer = 10; } }