//Allison Mui
//15-104 Section A
//amui1@andrew.cmu.edu
//Final Project
//variables for image
var monty = [];
var flyingMonty;
var swimmingMonty;
var evilOcty;
var bubble;
var bubbleX = [];
var bubbleY = [];
var punchMonty = [];
var monster;
var monstFall = [];
var homeMonty;
//variables for mouse movement
var targetX;
var targetY;
//variables for different states
var begin = true;
var home = false;
var world1 = false;
var world2 = false;
var world3 = false;
var over = false;
//variables for begin state
var playX;
var playY;
//variables for fire world1
var fires = [];
var fireCounter = 0;
var waterArray = [];
//variables for sea world
var octyY = 10;
var octySpeed = 4;
var inkSpeed;
var inkX = 280;
var inks = [];
var inkCounter = 0;
//variables for fight world
var fightmontyX = 130;
var fightmontyY = 350;
var fighttargetX = 130;
var fighttargetY = 350;
var monstX = 300;
var monstY = 280;
var monstSpeed = 5;
var level = 1;
//loads images
function preload() {
//image for home monty
homeMonty = loadImage("https://i.imgur.com/LudAnMM.png");
//images for walking monty
var montyfile = [];
montyfile[0] = "https://i.imgur.com/jF4qiIL.png";
montyfile[1] = "https://i.imgur.com/Q2Y2NMk.png";
montyfile[2] = "https://i.imgur.com/Bhzuxet.png";
montyfile[3] = "https://i.imgur.com/NXGRLMb.png";
//loads monty
for (var i = 0; i < 4; i++) {
monty[i] = loadImage(montyfile[i]);
}
//image for fire world
flyingMonty = loadImage("https://i.imgur.com/uogV1b7.png");
//images for sea world
bubble = loadImage("https://i.imgur.com/ZzkbRgi.png")
swimmingMonty = loadImage("https://i.imgur.com/FwBvECT.png");
evilOcty = loadImage("https://i.imgur.com/gYrnKp2.png");
//images for fight world
kickmonty = loadImage("https://i.imgur.com/ZpfaJlx.png")
punchMonty[0] = loadImage("https://i.imgur.com/jF4qiIL.png");
punchMonty[1] = loadImage("https://i.imgur.com/Q2Y2NMk.png");
punchMonty[2] = loadImage("https://i.imgur.com/wCvUx2R.png");
punchMonty[3] = loadImage("https://i.imgur.com/NXGRLMb.png");
monster = loadImage("https://i.imgur.com/E0lKepM.png")
monstFall[0] = loadImage("https://i.imgur.com/E0lKepM.png")
monstFall[1] = loadImage("https://i.imgur.com/FX8hPMk.png");
}
function setup() {
createCanvas(480,450);
imageMode(CENTER);
frameRate(4);
// Initialize the character and target positions
characterX = width/2;
characterY = height/2;
targetX = characterX;
targetY = characterY;
//fire world1
dif = 0;
for (var i = 0; i < 6; i++) {
fires[i] = makeFire(width/4 + dif);
dif += random(50,80);
}
//randomizing location for bubbles for sea world
for (b = 0; b < 15; b++) {
bubbleX.push(random(width));
bubbleY.push(random(height));
}
//load bubble picture
bubble.loadPixels();
//loads home monty picture
homeMonty.loadPixels();
}
function draw(){
if (begin == true) {
drawBegin();
}
if (home == true) {
drawHome();
}
//calculates distance from monty to the world 1 icon
var distWorld1 = dist(characterX,characterY,width/4,height/4);
//if close enough, change the booleans to show a new screen
if (distWorld1 < 10) {
home = false;
world1 = true;
drawworld1();
}
//calulate distance from monty to world 2 icon
var distWorld2 = dist(characterX,characterY,width/2+width/4,height/4);
//if close enough, change booleans and show new screen
if (distWorld2 < 10) {
home = false;
world2 = true;
drawworld2();
}
//calculates distance from monty to world 3 icon
var distWorld3 = dist(characterX,characterY,width/2,height/2+width/4+20);
//if close enough, change booleans and show new screen
if (distWorld3 < 10) {
home = false;
world3 = true;
drawworld3();
}
//if too many points were lost (parameters in specific world), change screen
if (over == true) {
gameOver();
}
}
function drawBegin() {
background(0);
image(homeMonty,width/2,height/2-20);
textSize(24);
fill(255);
text("Lonnie's World",160,80);
textSize(16);
text("Lonnie travels from fire to sea, avoiding danger",80,110);
textSize(20);
text("Press play to begin", 160,350);
var dPlay = dist(playX,playY,160,350);
print(dPlay);
if (dPlay < 80) {
begin = false;
home = true;
}
}
function drawHome() {
textSize(14);
background(0);
frameRate(4);
//world 1
strokeWeight(0);
fill(229,115,115);
ellipse(width/4,height/4,50,50);
fill(240,171,171);
ellipse(width/4,height/4,35,35);
fill(255);
text("Flames of Fury", width/4-40,height/4-35);
//world 2
fill(109,181,255);
ellipse(width/2+width/4,height/4,50,50);
fill(167,211,255);
ellipse(width/2+width/4,height/4,35,35);
fill(255);
text("Waves of Fear", width/2+width/4-35,height/4-35);
//fight world
fill(255,253,41);
ellipse(width/2,height/2+width/4+20,50,50);
fill(255,254,127);
ellipse(width/2,height/2+width/4+20,35,35);
fill(255);
text("Fight Club",width/2-25,height/2+width/4-15);
//move monty according to where user clicks
var dx = targetX - characterX;
var dy = targetY - characterY;
//cycles through all image files to walk
image(monty[frameCount%4], characterX, characterY);
characterX = characterX + dx/10;
characterY = characterY + dy/10;
}
function mousePressed() {
//sets new target for play button
playX = mouseX;
playY = mouseY;
//set boundaries for user's mouse
targetX = mouseX;
targetY = mouseY;
targetX = constrain(mouseX,0,width-50);
targetY = constrain(mouseY,0,height-50);
//sets new target for the fight world
fighttargetX = mouseX;
fighttargetY = mouseY;
}
function drawworld1() {
background(0);
frameRate(12);
//sets the monster's position
var flyingmontyX = mouseX;
var flyingmontyY = mouseY;
//constrains the monsters position to not move past the middle and canvase
var flyingmontyY = constrain(flyingmontyY,40,height-90);
var flyingmontyX = constrain(flyingmontyX,45,height/2);
//displays image
image(flyingMonty,flyingmontyX,flyingmontyY);
strokeWeight(0);
//displays fire
showFire();
//instructions
noFill();
stroke(255);
strokeWeight(1);
rect(0,height-50,width,50);
strokeWeight(0);
fill(255);
text("Avoid the fire or you'll get burned!", 10,height-28);
text("Points: " + fireCounter, width-70,height-30);
//if mouse over "go home" returns to the home screen
text("Go Home", width-70, height-10);
var distHome = dist(mouseX,mouseY,width-70,height-10);
if (distHome < 15) {
home = true;
}
//ends game if points too low
if (fireCounter < -100) {
over = true;
}
}
function drawworld2() {
frameRate(15);
background(175,246,249);
//draw bubbles
for (bub = 0; bub < 15; bub++) {
image(bubble,bubbleX[bub],bubbleY[bub]);
}
//changes speed by a random amount(speedif) as time goes on
if (frameCount % 60 == 0) {
speeddif = random(1,3);
octySpeed = octySpeed + speeddif;
}
//make new ink blots at different times
if (frameCount % 60 == 0) {
inks.push(makeInk(inkX,octyY));
}
//displays ink
showInk();
//monty moves with mouse
swimX = mouseX;
swimY = mouseY;
//sets boundaries so monty doesn't go off the page
var swimY = constrain(swimY,30,height-90);
var swimX = constrain(swimX,0,width/4);
//display monty
image(swimmingMonty,swimX,swimY);
//displays the octopus monster
image(evilOcty,width-120,octyY);
//moves octy
octyY += octySpeed;
//sets actions so octy doesn't move off the page
if (octyY > height-90) {
octySpeed = -octySpeed;
}
if (octyY < 10) {
octySpeed = -octySpeed;
}
//instructions
rectMode(CORNER);
fill(40,40,57);
stroke(255);
strokeWeight(1);
rect(0,height-50,width,50);
strokeWeight(0);
fill(255);
text("The evil octopus is squirting ink!", 10,height-28);
text("Avoid the head of the ink!", 10, height-10);
text("Points: " + inkCounter, width-70,height-30);
text("Go Home", width-70, height-10);
//calculates where mouse is, if over home button, draw home state
var distHome = dist(mouseX,mouseY,width-65,height-10);
if (distHome < 15) {
home = true;
}
//only go through this only if inks array is populated
//add points if monster successfully avoids the ink
if (inks.length > 0) {
//if monster hits the ink, deduct 5 points
if ((swimX > inks[0].x-100 & swimX < inks[0].x+100) &&
(swimY > inks[0].y-5 && swimY < inks[0].y+30)) {
inkCounter -= 1;
}
//remove ink blots after it moves off the page
if (inks[0].x < 0) {
inkCounter += 1;
inks.shift(1);
}
}
//end game if too many points lost
if (inkCounter < -100) {
over = true;
}
}
function drawworld3() {
background(47,100,145);
//draw boxing design
drawBoxingRing();
//calculates distance between monster fighting and monty
var dFight = dist(fightmontyX,fightmontyY,monstX,monstY);
//if monty runs into monster, then game is over
if (dFight < 90) {
over = true;
}
//fight monster
//punches monster if monty is close enough
if(dFight < 98 & keyIsDown(80)) {
//if monster is punched, monster "falls down"
//cycles through image array
image(monstFall[frameCount%2],monstX,monstY);
}
//if monster is not punched, move monster from right to left
else {
image(monster,monstX,monstY);
monstX -= monstSpeed;
//sets boundary for the monster
if (monstX < 150) {
monstSpeed = -monstSpeed;
}
if (monstX > 300) {
monstSpeed = -monstSpeed;
}
}
//image of the fighting monty
//calculates distance for movement of monty
var dx = fighttargetX - fightmontyX;
var dy = fighttargetY - fightmontyY;
//constrains the boundary of monty
fightmontyX = constrain(fightmontyX,30,300);
fightmontyY = constrain(fightmontyY,height-150,height-80);
//moves monty
fightmontyX = fightmontyX + dx/10;
fightmontyY = fightmontyY + dy/10;
//if user doesn't call monty to move, monty is still
if (fightmontyX == fighttargetX & fightmontyY == fighttargetY) {
image(monty[0], fightmontyX, fightmontyY);
}
//if monty is punching, restrict image so punch monty will match
if (keyIsDown(80) & (frameCount%4 == 0 || (frameCount%4 == 2))) {
image(punchMonty[2],fightmontyX,fightmontyY);
}
//if user calls monty to move, monty moves and cycles through all image files
if (fightmontyX != fighttargetX || fightmontyY != fighttargetY) {
image(monty[frameCount%4],fightmontyX,fightmontyY);
}
//instructions
fill(35,75,109);
stroke(255);
strokeWeight(1);
rect(0,height-50,width,50);
strokeWeight(0);
fill(255);
textSize(13);
text("Battle the hungry bear!", 10,height-28);
text("Click to move and hold 'p' to punch!", 10, height-10);
text("Level: " + level, width-70,height-30);
text("Go Home", width-70, height-10);
//calculates distance from user's mouse to the go home button
var distHome = dist(mouseX,mouseY,width-65,height-10);
//if user's mouse is on the go home button, draw home state
if (distHome < 15) {
home = true;
}
//increases level after some time passed
if (frameCount%2000 == 0) {
level += 1;
}
}
function drawBoxingRing() {
//background design to make look like boxing setting
strokeWeight(0);
fill(35,79,109);
rect(0,height-120,width,100);
stroke(35,79,109);
strokeWeight(15);
line(10,height-50,width/4-20,130);
line(250,height-50,width/2+80,130);
line(250,height-50,width/4+30,130);
line(480,height-50,380,130);
strokeWeight(0);
fill(35,75,109);
rect(0,0,width,130);
//lights
stroke(255);
strokeWeight(5);
line(150,145,160,145);
line(155,140,155,150);
line(300,170,310,170);
line(305,165,305,175);
//banner
fill(189,57,51);
strokeWeight(5);
rect(width-180,30,140,40);
strokeWeight(0);
fill(255);
textSize(15);
text("Fight! Train! Win!",width-165,55);
//boxing ring
fill(255);
strokeWeight(0);
triangle(20,height-50,100,height-160,100,height-50);
rect(100,height-160,280,150);
triangle(380,height-50,380,height-160,460,height-50);
fill(189,57,51);
triangle(30,height-50,100,height-150,100,height-50);
rect(100,height-150,280,150);
triangle(380,height-50,380,height-150,450,height-50);
//boxing horizontal lines - "strings around the ring"
stroke(255);
strokeWeight(3);
//left
line(30,height-140,125,height-248);
line(30,height-120,125,height-230);
line(30,height-100,125,height-210);
//mid
line(125,height-230,360,height-230);
line(125,height-210,360,height-210);
line(125,height-190,360,height-190);
//right
line(360,height-248,450,height-140);
line(360,height-230,450,height-120);
line(360,height-210,450,height-100);
//boxing columns
fill(142,43,38);
strokeWeight(0);
rect(20,height-200,40,200,5);
rect(100,height-250,40,100,5);
rect(340,height-250,40,100,5);
rect(height-30,height-200,40,200,5);
}
function gameOver() {
background(0);
textSize(50);
text("Game Over",15,height/2);
textSize(14);
text("Please refresh to start over :)",20,height/2+50);
}
function showInk() {
//moves and draws inks in the ink array
for (var i = 0; i < inks.length; i++) {
inks[i].draw();
inks[i].move();
}
}
function moveInk() {
this.x -= this.speed;
}
function drawInk() {
//draw ink
strokeWeight(0);
fill(40,40,57);
rectMode(CENTER);
rect(this.x,this.y,200,20,10);
rect(this.x,this.y+25,180,20,10);
}
function makeInk(x,y) {
m = {x:x,
y:y,
speed: random(5,8),
draw: drawInk,
move: moveInk}
return m;
}
function showFire() {
//go through fire Array
for (var fiyah = 0; fiyah < fires.length; fiyah++) {
//alternate fire design
//if even number, show fire coming from the bottom of the canvas
if (fiyah % 2 == 0) {
fires[fiyah].drawup();
fires[fiyah].move();
}
//if odd number, show fire coming from the top
if (fiyah % 2 != 0) {
fires[fiyah].drawdown();
fires[fiyah].move();
}
}
}
function moveFire() {
//sets the monster's position
var flyingmontyX = mouseX;
var flyingmontyY = mouseY;
//constrains the monsters position to not move past the middle and canvase
var flyingmontyY = constrain(flyingmontyY,40,height-90);
var flyingmontyX = constrain(flyingmontyX,45,height/2);
//moves fire
this.x -= this.speed;
//if fire moves off page, points go up
if (this.x < 0-30) {
this.x = width;
fireCounter += 1;
}
//calculates distance from monty to fire
if (flyingmontyY < height/2) {
var dFire = dist(flyingmontyX,flyingmontyY,this.x,this.h);
}
if (flyingmontyY > height/2) {
var dFire = dist(flyingmontyX,flyingmontyY,this.x,height-this.h);
}
//if monty too close to fire, deduct points
if (dFire < 20) {
fireCounter -= 5;
}
}
//if fire is coming from the floor
function drawupFire(){
//draws redish flame
fill(216,82,42);
triangle(this.x-20,height-50,this.x-5-random(1,10),height-50-(this.h+60)-random(1,50),
this.x+50+random(1,10),height-50);
triangle(this.x,height-50,this.x+10+random(-1,5),height-50-(this.h+60)-random(1,60),
this.x+50+random(1,10),height-50);
triangle(this.x,height-50,this.x+20+random(1,10),height-50-(this.h+60)-random(1,50),
this.x+55+random(1,10),height-50);
//draws orange flame
fill(221,144,44);
triangle(this.x-15,height-50,this.x-5-random(1,10),height-50-(this.h+40)-random(1,40),
this.x+40+random(1,10),height-50);
triangle(this.x,height-50,this.x+10+random(-1,5),height-50-(this.h+40)-random(1,50),
this.x+40+random(1,10),height-50);
triangle(this.x,height-50,this.x+20+random(1,10),height-50-(this.h+40)-random(1,40),
this.x+45+random(1,10),height-50);
//draws dark yellow flame
fill(233,219,47);
triangle(this.x-10,height-50,this.x-5-random(1,10),height-50-(this.h+20)-random(1,30),
this.x+30+random(1,10),height-50);
triangle(this.x,height-50,this.x+10+random(-1,5),height-50-(this.h+20)-random(1,40),
this.x+30+random(1,10),height-50);
triangle(this.x,height-50,this.x+20+random(1,10),height-50-(this.h+20)-random(1,30),
this.x+35+random(1,10),height-50);
//draws light yellow frame
fill(255,250,163);
triangle(this.x-5,height-50,this.x-5-random(1,10),height-50-this.h-random(1,20),
this.x+20+random(1,10),height-50);
triangle(this.x,height-50,this.x+10+random(-1,5),height-50-this.h-random(1,30),
this.x+20+random(1,10),height-50);
triangle(this.x,height-50,this.x+20+random(1,10),height-50-this.h-random(1,20),
this.x+25+random(1,10),height-50);
}
//if fire coming from ceiling
function drawdownFire(){
//draws redish flame
fill(216,82,42);
triangle(this.x-20,0,this.x-5-random(1,10),0+(this.h+60)-random(1,50),
this.x+50+random(1,10),0);
triangle(this.x,0,this.x+10+random(-1,5),0+(this.h+60)-random(1,60),
this.x+50+random(1,10),0);
triangle(this.x,0,this.x+20+random(1,10),0+(this.h+60)-random(1,50),
this.x+55+random(1,10),0);
//draws orange flame
fill(221,144,44);
triangle(this.x-15,0,this.x-5-random(1,10),0+(this.h+40)-random(1,40),
this.x+40+random(1,10),0);
triangle(this.x,0,this.x+10+random(-1,5),0+(this.h+40)-random(1,50),
this.x+40+random(1,10),0);
triangle(this.x,0,this.x+20+random(1,10),0+(this.h+40)-random(1,40),
this.x+45+random(1,10),0);
//draws dark yellow flame
fill(233,219,47);
triangle(this.x-10,0,this.x-5-random(1,10),0+(this.h+20)-random(1,30),
this.x+30+random(1,10),0);
triangle(this.x,0,this.x+10+random(-1,5),0+(this.h+20)-random(1,40),
this.x+30+random(1,10),0);
triangle(this.x,0,this.x+20+random(1,10),0+(this.h+20)-random(1,30),
this.x+35+random(1,10),0);
//draws light yellow frame
fill(255,250,163);
triangle(this.x-5,0,this.x-5-random(1,10),0+this.h-random(1,20),
this.x+20+random(1,10),0);
triangle(this.x,0,this.x+10+random(-1,5),0+this.h-random(1,30),
this.x+20+random(1,10),0);
triangle(this.x,0,this.x+20+random(1,10),0+this.h-random(1,20),
this.x+25+random(1,10),0);
}
function makeFire(x){
f = {x:x,
h: random(20,130),
speed: random(1,8),
drawup: drawupFire,
drawdown: drawdownFire,
move: moveFire}
return f;
}
Features
- Click to move or “hit” buttons such as play or go home
- In different worlds, character moves along with the user’s mouse movements to avoid obstacles.
- In the fight world, user can click p for added interaction.
Reflection
I enjoyed this project a lot because it was so challenging, but fun and rewarding. I really felt like I put what I learned in this class to test. Trying to incorporate something I learned from each week, I saw the vast power creative computing has. The most enjoyable part was seeing how far this project has come: from storyboard to now. The most challenging part was trying to fix, adjust, and adapt my game when a programming difficulty came up (which was often). In addition, I had a lot of fun creating the visuals in this project and then adding motion to them. All in all, I am happy with my project’s final outcome.
Caption: Above is my first storyboard of my game. As you can see, my idea has changed quite a bit from beginning to end. However, my main concept of moving a character through different worlds or states remained the same.
Caption: Above are the 3 worlds my character travels through.