xxxxxxxxxx
565
/*
Concept:
I am making a game inspired by The Hobbits and the tap the circle game example. Basically, you are a hero who wants to protect this town from the dragon. You have a powerful crossbow and numerous giant arrow. All you need to do is to shoot down the dragon before it destroys everything.
Development Plan:
1. Dragon move from side to side (DONE!)
2. Dragon rises and drops to spit fire (SORT OF DONE!)
3. When the dragon spits fire, set a building on fire (NEED ANIMATION OF FIRE)
4. A red line indicating where the arrow will be launched (DONE)
5. The red line follows the players' mouse (DONE,changed to move with left/right arrow)
6. Press spacebar to shoot arrow (DONE)
7. When the arrow shoot the dragon, make the arrow disappear and make the dragon lose HP (DONE)
8. The dragon bleed when hit (Use class & object)
9. Game over when all 5 buildings are on fire (DONE)
10. Win when the dragon is defeated (DONE)
11. NPC chat when you miss/hit the dragon & when the dragon burn stuff (Optional)
Image:
Dragon: Final Fantasy Dimensions (https://www.spriters-resource.com/fullview/148749/)
Town Buildings and Props: https://www.pinterest.se/pin/658651514223112836/
Town Background made with Tileset from https://cardinalzebra.itch.io/grass-road-tiles
Fire asset from
https://brullov.itch.io/fire-animation
Sound:
Dragon Wing: https: //freesound.org/people/EminYILDIRIM/sounds/571563/
Arrow Load & Shoot: https://freesound.org/people/brendan89/sounds/321553/
Fire: https://freesound.org/people/Robinhood76/sounds/564041/
Dragon Hit: https://jdwasabi.itch.io/8-bit-16-bit-sound-effects-pack
Dragon Fall: https://freesound.org/people/Breviceps/sounds/457531/
BGM: https://www.fesliyanstudios.com/royalty-free-music/download/8-bit-adventure/2282
*/
//Variables
var mainSwitch = 0; // Game start when true
var dragonX; //X position of dragon
var dragonY = 100; // Y position
var dragonSpeed = 5; //Speed of dragon
var dragonDestroy; //Time interval for dragon destruction
var dragonTimer = 0; //If this timer = dragonDestroy, dragon will destroy a part of town. When all 5 parts of town is destroyed, game over.
var dragonHP = 15;
var dragonStay = 50;
var aniCountF = 0; //DragonAnimationStuff
var aniCountS = 2;
var aniCountFire = 0;
var dragonState = 0; // 0: fly, 1: rise to top, 2: drop to ground, 3: stand & fire; 4: rise from ground to top; 5: drop to reset
var groundY = 150;
var buildingDestroyed = -1; //Number of buildings destroyed by dragon
var recharge = 120; //Time for arrow to be recharged
var rechargeTim = 0;
var fire = false; //Dragon breathe fire
var riseBack = false; //Dragon rise from ground to sky
var fireA1 = 20; //Red flash effect
var arrowX;
var arrowY;
var arrowFlying = false;
var dragonBleed = false;
var arrowSp = 6;
var bowmanX;
var musicPlaying = false;
//Dragon Sprite
//Flying dragon
var dragonSF1;
var dragonSF2;
var dragonSF3;
//Standing dragon
var dragonSS1;
var dragonSS2;
var dragonSS3;
//Town
var town;
//Fire
var fStart1;
var fStart2;
var fStart3;
var fStart4;
var fLoop1;
var fLoop2;
var fLoop3;
var fLoop4;
var fLoop5;
var fLoop6;
var fLoop7;
var fLoop8;
//SFX
var hitFX;
var fireFX;
var wingFX;
var loadFX;
var shootFX;
// var textFX; Unused
var fallFX;
//Music
var bgm;
//Font
var dogicaReg;
var dogicaBold;
//DragonAnimationArray
var dragonSpF = [dragonSF1, dragonSF2, dragonSF3];
var dragonSpS = [dragonSS1, dragonSS2, dragonSS3];
//FireAnimationArray
var fireAni;
//FirePositionArray
var fire1_1 = [19, 190, 0];
var fire1_2 = [13, 300, 0];
var fire1_3 = [40, 178, 0];
var fire2_1 = [91, 205, 0];
var fire2_2 = [174, 237, 0];
var fire2_3 = [196, 302, 0];
var fire3_1 = [285, 246, 0];
var fire3_2 = [341, 264, 0];
var fire3_3 = [248, 303, 0];
var fire4_1 = [404, 252, 0];
var fire4_2 = [477, 191, 0];
var fire4_3 = [393, 185, 0];
var fire5_1 = [520, 101, 0];
var fire5_2 = [589, 219, 0];
var fire5_3 = [532, 150, 0];
var firePos = [
fire1_1,
fire1_2,
fire1_3,
fire2_1,
fire2_2,
fire2_3,
fire3_1,
fire3_2,
fire3_3,
fire4_1,
fire4_2,
fire4_3,
fire5_1,
fire5_2,
fire5_3,
]; //[xposition, yposition,state(0 is no fire, 1 is start fire, 2 is loop fire),animationCounter]
//Blood Range Array
var bloodRandom = [
[0, 0],
[0, 0],
[0, 0],
[0, 0],
[0, 0],
[0, 0],
[0, 0],
[0, 0],
];
//Object
//Blood Effect when Hit
var blood = {
size: 10,
speed: 5,
bleed() {
noStroke();
fill(255, 0, 0);
this.yPos += this.speed;
for (i = 0; i <= 7; i++) {
ellipse(
this.xPos + bloodRandom[i][0],
this.yPos + bloodRandom[i][1],
this.size
);
}
},
};
function preload() {
//LoadSprite
dragonSF1 = loadImage("fly1.png");
dragonSF2 = loadImage("fly2.png");
dragonSF3 = loadImage("fly3.png");
dragonSS1 = loadImage("stand1.png");
dragonSS2 = loadImage("stand2.png");
dragonSS3 = loadImage("stand3.png");
town = loadImage("town.png");
fStart1 = loadImage("burning_start_1_01.png");
fStart2 = loadImage("burning_start_1_02.png");
fStart3 = loadImage("burning_start_1_03.png");
fStart4 = loadImage("burning_start_1_04.png");
fLoop1 = loadImage("burning_loop_1_01.png");
fLoop2 = loadImage("burning_loop_1_02.png");
fLoop3 = loadImage("burning_loop_1_03.png");
fLoop4 = loadImage("burning_loop_1_04.png");
fLoop5 = loadImage("burning_loop_1_05.png");
fLoop6 = loadImage("burning_loop_1_06.png");
fLoop7 = loadImage("burning_loop_1_07.png");
fLoop8 = loadImage("burning_loop_1_08.png");
//DefineArray
dragonSpF = [dragonSF1, dragonSF2, dragonSF3];
dragonSpS = [dragonSS1, dragonSS2, dragonSS3];
fireAni = [
fStart1,
fStart2,
fStart3,
fStart4,
fLoop1,
fLoop2,
fLoop3,
fLoop4,
fLoop5,
fLoop6,
fLoop7,
fLoop8,
];
//LoadFont
dogicaReg = loadFont("dogicapixel.otf");
dogicaBold = loadFont("dogicapixelbold.otf");
//font from https://fontlibrary.org/en/font/dogica
//LoadSound
hitFX = loadSound("hit.wav"); //used
fireFX = loadSound("fireball.wav");//used
wingFX = loadSound("dragon flap.wav"); //used
loadFX = loadSound("load.wav"); //used
shootFX = loadSound("shoot.wav"); //used
// textFX = loadSound("text.wav"); // for optional function
fallFX = loadSound("fall.wav"); //used
bgm = loadSound("bgm.ogg");//music for the main part of game
}
function setup() {
createCanvas(640, 360);
noCursor();
blood.yPos = 100;
//Pixel
noSmooth();
dragonReset(500, 1000);
// noCursor();
bowmanX = width / 2;
}
function draw() {
if (mainSwitch == 2)
{
if (musicPlaying == false)
{
bgm.play();
musicPlaying = true;
}
background(220);
imageMode(CENTER);
image(town, width / 2, height / 2);
buildingBurn();
// console.log(dragonY);
if (dragonHP > 0 || buildingDestroyed < 4) {
dragonFly(dragonSpeed, 6);
bowman();
back2Sky();
if (dragonBleed == true) {
blood.bleed();
} else if (dragonBleed == true && blood.yPos >= height + 10) {
dragonBleed = false;
}
// console.log(dragonX)
//If arrow is shot draw an arrow
if (arrowFlying == true) {
arrowFly(arrowSp);
}
//bowman moves when press leftarrow / rightarrow
if (keyIsDown(37) && bowmanX >= 0) {
bowmanX -= 2;
}
if (keyIsDown(39) && bowmanX <= width) {
bowmanX += 2;
}
rechargeTim--;
}
if (dragonHP <= 0) {
win();
} else if (buildingDestroyed >= 4) {
lose();
}
} else if (mainSwitch == 0) {
background(0);
noStroke();
fill(200, 200, 200, 200);
textFont(dogicaBold);
textAlign(CENTER, CENTER);
fill(255);
textSize(24);
text("Press Any Button to Proceed", width / 2, height / 2);
textSize(12);
text("Proceed to instructions", width / 2, height / 2 + 30);
} else if (mainSwitch == 1) {
background(0);
textSize(12);
text(
"A dragon is approaching your town.\nIt will burn the whole town to ashes with its breath.\nLuckily, there is a giant crossbow in the town.\nAnd you know how to use it.\n\nUse Left & Right Arrow Key to move the crossbow.\n Press Spacebar or Up Arrow Key to fire.\nGood Luck!",
width / 2,
height / 2
);
}
}
function keyPressed() {
if (rechargeTim <= 0 && mainSwitch == 2) {
if (keyCode == 32 || keyCode == 38) {
shoot();
shootFX.play();
}
}
if (mainSwitch !== 2) {
mainSwitch++;
}
}
function dragonFly(speed, dropSpeed) {
imageMode(CENTER);
if (dragonHP > 0)
{
//Dragon drop from sky
if (dragonState == 2) {
dragonY += 20;
spriteAni(dragonSpF, 0, 1.5, dragonX, dragonY);
if (dragonY >= groundY) {
dragonState = 3;
}
}
//Dragon stand on ground
else if (dragonState == 3) {
dragonDestroyTown();
}
//Dragon rise to sky
else if (dragonY <= -50 && dragonState == 1) {
dragonState = 2;
dragonX = width / 2;
spriteAni(dragonSpF, aniCountF, 1, dragonX, dragonY);
}
//Flying dragon
else if (dragonState == 0 || dragonState == 1) {
spriteAni(dragonSpF, aniCountF, 1, dragonX, dragonY);
//When timer = destroy, fly up
if (dragonTimer < dragonDestroy) {
//Dragon Move from Side 2 Side
dragonX += speed;
if (dragonX >= width - 80 || dragonX <= 80) {
dragonSpeed = -speed;
}
} else {
dragonY -= 6;
dragonState = 1;
}
}
//Dragon Animation
// console.log(aniCount)
if (frameCount % 20 == 0 && dragonState != 3) {
if (aniCountF >= 2) {
aniCountF = 0;
wingFX.play(0, 1, 0.1);
} else {
aniCountF++;
}
}
//Add 1 to dragon timer
dragonTimer++;
// console.log(dragonDestroy)
// console.log(dragonTimer);
}
}
function dragonReset(minD, maxD) {
dragonDestroy = int(random(minD, maxD));
//https://p5js.org/reference/#/p5/int
dragonX = width / 2;
dragonY = 100;
dragonTimer = 0;
dragonStay = 50;
aniCountF = 0;
aniCountS = 2;
aniCountFire = 0;
dragonState = 0;
fire = false;
riseBack = false;
fireA1 = 20;
}
//Calls when the dragon reaches the ground
function dragonDestroyTown() {
spriteAni(dragonSpS, aniCountS, 1.5, dragonX, groundY);
//Wing closes and stop animation
if (frameCount % 20 == 0) {
if (aniCountS == 2) {
fallFX.play();
}
if (aniCountS >= 1) {
aniCountS--;
} else {
aniCountS = 0;
fire = true;
}
}
//Screen turn red to represent flame
if (fire == true) {
fireA1--;
if (fireA1 == 10) {
fireFX.play();
}
if (fireA1 > 0) {
rectMode(CENTER);
noStroke();
fill(255, 0, 0, 100);
rect(width / 2, height / 2, width, height);
} else if (fireA1 == 0) {
fire = false;
if (buildingDestroyed < 4) {
buildingDestroyed++;
}
dragonState++;
riseBack = true;
}
}
// console.log("D"+dragonX+","+dragonY);
// console.log("A"+arrowX+","+arrowY);
}
function spriteAni(sprArray, arrayCount, multiplier, x, y) {
image(
sprArray[arrayCount],
x,
y,
sprArray[arrayCount].width * multiplier,
sprArray[arrayCount].height * multiplier
);
}
function bowman() {
//Aiming line
rectMode(CENTER);
strokeWeight(3);
if (rechargeTim <= 0) {
stroke(255, 0, 0);
} else {
stroke(200);
}
line(bowmanX, height, bowmanX, height / 1.5);
}
function shoot() {
//define starting point of arrow
arrowX = bowmanX;
arrowY = height;
arrowFlying = true;
rechargeTim = recharge;
loadFX.play();
}
function arrowFly(sp) {
arrowY -= sp;
fill(0);
noStroke();
if (
arrowX <= dragonX + 80 &&
arrowX >= dragonX - 80 &&
arrowY <= dragonY + sp + 1 &&
arrowY >= dragonY - sp - 1 &&
arrowFlying == true
) {
// console.log("Shoot!");
dragonHP--;
blood.xPos = dragonX;
blood.yPos = dragonY;
for (i = 0; i <= 7; i++) {
bloodRandom[i][0] = random(-50, 50);
bloodRandom[i][1] = random(-50, 50);
}
dragonBleed = true;
hitFX.play();
arrowFlying = false;
} else {
rect(arrowX, arrowY, 3, 10);
}
}
function burn(f, x, y) {
spriteAni(fireAni, f, 2, x, y);
}
function buildingBurn() {
for (i = 0; i <= buildingDestroyed; i++) {
for (j = 0; j <= 2; j++) {
burn(firePos[i * 3 + j][2], firePos[i * 3 + j][0], firePos[i * 3 + j][1]);
if (frameCount % 10 == 0) {
if (firePos[i * 3][2] < 11) {
firePos[i * 3 + j][2]++;
} else {
firePos[i * 3 + j][2] = 4;
}
}
}
}
}
function back2Sky() {
//dragon rise to top
if (dragonY >= -50 && dragonState == 4) {
dragonY -= 12;
} else if (dragonY <= -50 && dragonState == 4) {
dragonState++;
}
//dragon drop to flying
if (dragonState == 5 && dragonY <= 100) {
dragonY += 6;
} else if (dragonY >= 100 && dragonState == 5) {
dragonReset(500, 1000);
}
// console.log(dragonY)
if (dragonState == 4) {
spriteAni(dragonSpS, aniCountS, 1.5, dragonX, dragonY);
} else if (dragonState == 5) {
spriteAni(dragonSpF, aniCountF, 1, dragonX, dragonY);
}
}
function win() {
noStroke();
fill(200, 200, 200, 200);
rect(width / 2, height / 2, width, height);
textFont(dogicaBold);
textAlign(CENTER, CENTER);
fill(255);
textSize(40);
text("Congratulations!", width / 2, height / 2);
textSize(12);
text("You have saved the town from the dragon!", width / 2, height / 2 + 30);
}
function lose() {
noStroke();
fill(200, 200, 200, 200);
rect(width / 2, height / 2, width, height);
textFont(dogicaBold);
textAlign(CENTER, CENTER);
fill(255);
textSize(40);
text("Burnt!", width / 2, height / 2);
textSize(12);
text("The town is burnt by the dragon!", width / 2, height / 2 + 30);
}
//The following are unused or work-in-progress functions
// function chat()
// {
// }