<head>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Lato&family=Poppins&family=Press+Start+2P&display=swap"
rel="stylesheet"
/>
<style>
* {
font-family: "Press Start 2P", cursive;
}
body {
background-color: #000000;
display: flex;
justify-content: center;
align-items: center;
}
h1 {
margin: 0;
}
button {
border: 0;
cursor: pointer;
font-size: 16px;
}
button:hover {
background-color: #e0e0e0;
}
</style>
</head>
<div style="display: inline-block; position: relative">
<div
id="overlappingDiv"
style="
background-color: black;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
opacity: 0;
pointer-events: none;
z-index: 10;
"
></div>
<canvas></canvas>
<div id="userInterface" style="display: none">
<!--- Health bar of Forest Spirit (opponent) -->
<div
style="
background-color: white;
width: 250px;
position: absolute;
top: 50px;
left: 50px;
border: 4px black solid;
padding: 12px;
border-radius: 4px;
"
>
<h1 style="font-size: 16px">Forest Spirit</h1>
<div style="position: relative">
<div
style="height: 5px; background-color: #ccc; margin-top: 10px"
></div>
<div
id="opponentHealthBar"
style="
height: 5px;
background-color: green;
position: absolute;
top: 0;
left: 0;
right: 0;
"
></div>
</div>
</div>
<!--- Health bar of Raccacoonie (hobemon) -->
<div
style="
background-color: white;
width: 250px;
position: absolute;
top: 330px;
right: 50px;
border: 4px black solid;
padding: 12px;
border-radius: 4px;
"
>
<h1 style="font-size: 16px">Raccacoonie</h1>
<div style="position: relative">
<div
style="height: 5px; background-color: #ccc; margin-top: 10px"
></div>
<div
id="hobemonHealthBar"
style="
height: 5px;
background-color: green;
position: absolute;
top: 0;
left: 0;
right: 0;
"
></div>
</div>
</div>
<div
style="
background-color: white;
height: 140px;
position: absolute;
bottom: 0;
left: 0;
right: 0;
border-top: 4px black solid;
display: flex;
"
>
<div
id="dialogueBox"
style="
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: white;
padding: 12px;
display: none;
cursor: pointer;
"
>
abcd
</div>
<div
id="attacksBox"
style="
width: 66.66%;
display: grid;
grid-template-columns: repeat(2, 1fr);
"
></div>
<div
style="
display: flex;
align-items: center;
justify-content: center;
width: 33.33%;
border-left: 4px black solid;
"
>
<h1 id="attackType" style="font-size: 16px">Attack Type</h1>
</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/howler/2.2.3/howler.min.js" integrity="sha512-6+YN/9o9BWrk6wSfGxQGpt3EUK6XeHi6yeHV+TYD2GR0Sj/cggRpXr1BrAQf0as6XslxomMUxXp2vIl+fv0QRA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/gsap.min.js"
integrity="sha512-H6cPm97FAsgIKmlBA4s774vqoN24V5gSQL4yBTDOY2su2DeXZVhQPxFK4P6GPdnZqM9fg1G3cMv5wD7e6cFLZQ=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
<script src="data/audio.js"></script>
<script src="data/battleZonesData.js"></script>
<script src="data/collisions.js"></script>
<script src="data/attacks.js"></script>
<script src="data/monsters.js"></script>
<script src="classes.js"></script>
<script src="index.js"></script>
<script src="data/battleScene.js"></script>
</div>
const canvas = document.querySelector("canvas");
const c = canvas.getContext("2d");
canvas.width = 1024;
canvas.height = 576;
const collisionsMap = [];
for (let i = 0; i < collisions.length; i += 70) {
collisionsMap.push(collisions.slice(i, 70 + i));
}
const battleZonesMap = [];
for (let i = 0; i < battleZonesData.length; i += 70) {
battleZonesMap.push(battleZonesData.slice(i, 70 + i));
}
const boundaries = [];
const offset = {
x: -600,
y: -425,
};
collisionsMap.forEach((row, i) => {
row.forEach((symbol, j) => {
if (symbol === 1025)
boundaries.push(
new Boundary({
position: {
x: j * Boundary.width + offset.x,
y: i * Boundary.height + offset.y,
},
})
);
});
});
const battleZones = [];
battleZonesMap.forEach((row, i) => {
row.forEach((symbol, j) => {
if (symbol === 1025)
battleZones.push(
new Boundary({
position: {
x: j * Boundary.width + offset.x,
y: i * Boundary.height + offset.y,
},
})
);
});
});
const image = new Image();
image.src = "./img/Oregon City.png";
const foregroundImage = new Image();
foregroundImage.src = "./img/foregroundObjects.png";
const playerDownImage = new Image();
playerDownImage.src = "./img/playerDown.png";
const playerUpImage = new Image();
playerUpImage.src = "./img/playerUp.png";
const playerLeftImage = new Image();
playerLeftImage.src = "./img/playerLeft.png";
const playerRightImage = new Image();
playerRightImage.src = "./img/playerRight.png";
const player = new Sprite({
position: {
x: canvas.width / 2 - 192 / 4 / 2,
y: canvas.height / 2 - 68 / 2,
},
image: playerDownImage,
frames: {
max: 4,
hold: 10,
},
sprites: {
up: playerUpImage,
left: playerLeftImage,
right: playerRightImage,
down: playerDownImage,
},
});
const background = new Sprite({
position: {
x: offset.x,
y: offset.y,
},
image: image,
});
const foreground = new Sprite({
position: {
x: offset.x,
y: offset.y,
},
image: foregroundImage,
});
const keys = {
w: {
pressed: false,
},
a: {
pressed: false,
},
s: {
pressed: false,
},
d: {
pressed: false,
},
ArrowUp: {
pressed: false,
},
ArrowLeft: {
pressed: false,
},
ArrowDown: {
pressed: false,
},
ArrowRight: {
pressed: false,
},
};
// Animate();
const movables = [background, boundaries, foreground, battleZones];
function rectangularCollision({ rectangle1, rectangle2 }) {
return (
rectangle1.position.x + rectangle1.width >= rectangle2.position.x &&
rectangle1.position.x <= rectangle2.position.x + rectangle2.width &&
rectangle1.position.y <= rectangle2.position.y + rectangle2.height &&
rectangle1.position.y + rectangle1.height >= rectangle2.position.y
);
}
const battle = {
initiated: false,
};
function animate() {
const animationId = window.requestAnimationFrame(animate);
background.draw();
boundaries.forEach((boundary) => {
boundary.draw();
});
battleZones.forEach((battleZones) => {
battleZones.draw();
});
player.draw();
foreground.draw();
let moving = true;
player.animate = false;
if (battle.initiated) return;
// Activate a Battle
if (
keys.w.pressed ||
keys.a.pressed ||
keys.s.pressed ||
keys.d.pressed ||
keys.ArrowUp.pressed ||
keys.ArrowLeft.pressed ||
keys.ArrowDown.pressed ||
keys.ArrowRight.pressed
) {
for (let i = 0; i < battleZones.length; i++) {
const battleZone = battleZones[i];
const overlappingArea =
(Math.min(
player.position.x + player.width,
battleZone.position.x + battleZone.width
) -
Math.max(player.position.x, battleZone.position.x)) *
(Math.min(
player.position.y + player.height,
battleZone.position.y + battleZone.height
) -
Math.max(player.position.y, battleZone.position.y));
if (
rectangularCollision({
rectangle1: player,
rectangle2: battleZone,
}) &&
overlappingArea > (player.width * player.height) / 2 &&
Math.random() < 0.01
) {
// Deactivate Current Animation Loop
window.cancelAnimationFrame(animationId);
audio.Map.stop();
audio.initBattle.play();
audio.battle.play();
battle.initiated = true;
gsap.to("#overlappingDiv", {
opacity: 1,
repeat: 3,
yoyo: true,
duration: 0.4,
onComplete() {
gsap.to("#overlappingDiv", {
opacity: 1,
duration: 0.4,
onComplete() {
// Activate a new animation loop
initBattle();
animateBattle();
gsap.to("#overlappingDiv", {
opacity: 0,
duration: 0.4,
});
},
});
},
});
break;
}
}
}
if (
(keys.w.pressed && lastKey === "w") ||
(keys.ArrowUp.pressed && lastKey === "ArrowUp")
) {
player.animate = true;
player.image = player.sprites.up;
for (let i = 0; i < boundaries.length; i++) {
const boundary = boundaries[i];
if (
rectangularCollision({
rectangle1: player,
rectangle2: {
boundary,
position: {
x: boundary.position.x,
y: boundary.position.y + 3,
},
},
})
) {
moving = false;
break;
}
}
if (moving)
movables.forEach((movable) => {
movable.position.y += 3;
});
} else if (
(keys.a.pressed && lastKey === "a") ||
(keys.ArrowLeft.pressed && lastKey === "ArrowLeft")
) {
player.animate = true;
player.image = player.sprites.left;
for (let i = 0; i < boundaries.length; i++) {
const boundary = boundaries[i];
if (
rectangularCollision({
rectangle1: player,
rectangle2: {
boundary,
position: {
x: boundary.position.x + 3,
y: boundary.position.y,
},
},
})
) {
moving = false;
break;
}
}
if (moving)
movables.forEach((movable) => {
movable.position.x += 3;
});
} else if (
(keys.s.pressed && lastKey === "s") ||
(keys.ArrowDown.pressed && lastKey === "ArrowDown")
) {
player.animate = true;
player.image = player.sprites.down;
for (let i = 0; i < boundaries.length; i++) {
const boundary = boundaries[i];
if (
rectangularCollision({
rectangle1: player,
rectangle2: {
boundary,
position: {
x: boundary.position.x,
y: boundary.position.y - 3,
},
},
})
) {
moving = false;
break;
}
}
if (moving)
movables.forEach((movable) => {
movable.position.y -= 3;
});
} else if (
(keys.d.pressed && lastKey === "d") ||
(keys.ArrowRight.pressed && lastKey === "ArrowRight")
) {
player.animate = true;
player.image = player.sprites.right;
for (let i = 0; i < boundaries.length; i++) {
const boundary = boundaries[i];
if (
rectangularCollision({
rectangle1: player,
rectangle2: {
boundary,
position: {
x: boundary.position.x - 3,
y: boundary.position.y,
},
},
})
) {
moving = false;
break;
}
}
if (moving)
movables.forEach((movable) => {
movable.position.x -= 3;
});
}
}
// Event Listener - Keydown
let lastKey = "";
window.addEventListener("keydown", (e) => {
switch (e.key) {
case "w": {
keys.w.pressed = true;
lastKey = "w";
break;
}
case "a": {
keys.a.pressed = true;
lastKey = "a";
break;
}
case "s": {
keys.s.pressed = true;
lastKey = "s";
break;
}
case "d": {
keys.d.pressed = true;
lastKey = "d";
break;
}
case "ArrowUp": {
keys.ArrowUp.pressed = true;
lastKey = "ArrowUp";
break;
}
case "ArrowLeft": {
keys.ArrowLeft.pressed = true;
lastKey = "ArrowLeft";
break;
}
case "ArrowDown": {
keys.ArrowDown.pressed = true;
lastKey = "ArrowDown";
break;
}
case "ArrowRight": {
keys.ArrowRight.pressed = true;
lastKey = "ArrowRight";
break;
}
}
});
// Event Listener - Keyup
window.addEventListener("keyup", (e) => {
switch (e.key) {
case "w": {
keys.w.pressed = false;
break;
}
case "a": {
keys.a.pressed = false;
break;
}
case "s": {
keys.s.pressed = false;
break;
}
case "d": {
keys.d.pressed = false;
break;
}
case "ArrowUp": {
keys.ArrowUp.pressed = false;
break;
}
case "ArrowLeft": {
keys.ArrowLeft.pressed = false;
break;
}
case "ArrowDown": {
keys.ArrowDown.pressed = false;
break;
}
case "ArrowRight": {
keys.ArrowRight.pressed = false;
break;
}
}
});
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.