Issue
I am currently creating a fighting game, and I have two sprites (the player is blue and the enemy is red). I currently have a working timer. However, after the time is up, the sprites can still attack each other and the text in the middle will change constantly (it will make more sense if you run the snippet).
Question: How can I make it so that my sprites cannot attack each other after the timer is finished?
Side question: How can I also stop my sprites from moving after the timer runs out? I feel like if the first on gets answered, I can do this question
Note: I am not using any libraries or frameworks, I am using native JavaScript, CSS, and HTML.
Note: Using "enter" or "space", make when of the sprites get down to no health. Then with the other sprite, smack that original one a bunch more. Eventually, the text will switch from "Player 1/2 wins!" to "Player 2/1 wins!", even though the health is already gone.
const canvas = document.querySelector('#canvas');
const ctx = canvas.getContext("2d");
const winnerDisplay = document.querySelector('#winner-display');
canvas.width = 1024;
canvas.height = 576;
function logMessage(msg) {
document.querySelector('#myMessage').textContent += msg + '. ';
}
ctx.fillRect(0, 0, canvas.width, canvas.height);
const gravity = 0.7;
class Sprite {
constructor({position, velocity, color, offset}) {
this.position = position;
this.velocity = velocity;
this.height = 150;
this.width = 50;
this.lastKey;
this.attackBox = {
position: {
x: this.position.x,
y: this.position.y
},
offset,
width: 100,
height: 50,
color: 'green'
}
this.color = color;
this.isAttacking;
this.health = 100;
}
draw() {
ctx.fillStyle = this.color;
ctx.fillRect(this.position.x, this.position.y, this.width, this.height);
//Attack box
if (this.isAttacking) {
ctx.fillStyle = this.attackBox.color;
ctx.fillRect(
this.attackBox.position.x,
this.attackBox.position.y,
this.attackBox.width,
this.attackBox.height
)
}
}
update() {
this.draw();
this.attackBox.position.x = this.position.x - this.attackBox.offset.x;
this.attackBox.position.y = this.position.y;
this.position.x = Math.max(0, Math.min(canvas.width - this.width, this.position.x + this.velocity.x));
this.position.y = Math.max(0, Math.min(canvas.height, this.position.y + this.velocity.y));
if (this.position.y + this.height + this.velocity.y >= canvas.height) {
this.velocity.y = 0;
} else {
this.velocity.y += gravity;
}
}
attack() {
this.isAttacking = true;
setTimeout(() => {
this.isAttacking = false
}, 50)
}
}
const Player = new Sprite({
position: {
x: 0,
y: 0
},
velocity: {
x: 0,
y: 0
},
offset: {
x: 0,
y: 0
},
color: 'blue'
})
const Enemy = new Sprite({
position: {
x: canvas.width,
y: 100
},
velocity: {
x: 0,
y: 0
},
offset: {
x: 50,
y: 0
},
color: 'red'
})
const keys = {
w: {
pressed: false
},
a: {
pressed: false
},
d: {
pressed: false
},
ArrowUp: {
pressed: false
},
ArrowLeft: {
pressed: false
},
ArrowRight: {
pressed: false
}
}
function rectangularCollision({rectangle1, rectangle2}) {
return (
rectangle1.attackBox.position.x + rectangle1.attackBox.width >= rectangle2.position.x &&
rectangle1.attackBox.position.x <= rectangle2.position.x + rectangle2.width &&
rectangle1.attackBox.position.y + rectangle1.attackBox.height >= rectangle2.position.y &&
rectangle1.attackBox.position.y <= rectangle2.position.y + rectangle2.height &&
rectangle1.isAttacking
)
}
function determineWinner({ Player, Enemy, timerId }) {
clearTimeout(timerId);
winnerDisplay.style.display = 'flex';
if (Player.health == Enemy.health) {
winnerDisplay.innerHTML = 'Tie!';
}
if (Player.health > Enemy.health) {
winnerDisplay.innerHTML = 'Player 1 wins!';
}
if (Player.health < Enemy.health) {
winnerDisplay.innerHTML = 'Player 2 wins!';
}
}
//Timer and end game
//Feel free to change these starting values as you need
const startingMinutes = 1;
const startingSeconds = 30;
let time = startingMinutes * 60 + startingSeconds;
let timerId;
function decreaseTimer() {
const timeLeft = document.querySelector('#time-left');
if (time > 0) {
timerId = setTimeout(decreaseTimer, 1000);
const minutes = Math.floor(time / 60);
let seconds = time % 60;
seconds = seconds < 10 ? '0' + seconds : seconds;
timeLeft.innerHTML = `0${minutes}:${seconds}`;
time--;
}
if (time == 0) {
timeLeft.innerHTML = `00:00`;
determineWinner({ Player, Enemy, timerId });
Player.position.x = 0;
Enemy.position.x = canvas.width;
}
}
decreaseTimer();
function animate() {
window.requestAnimationFrame(animate);
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, canvas.width, canvas.height);
Player.update();
Enemy.update();
//Player movement
Player.velocity.x = 0;
if (keys.a.pressed == true && Player.lastKey == "a") {
Player.velocity.x = -5;
} else if (keys.d.pressed == true && Player.lastKey == "d") {
Player.velocity.x = 5;
}
//Enemy movement
Enemy.velocity.x = 0;
if (keys.ArrowLeft.pressed == true && Enemy.lastKey == "ArrowLeft") {
Enemy.velocity.x = -5;
} else if (keys.ArrowRight.pressed == true && Enemy.lastKey == "ArrowRight") {
Enemy.velocity.x = 5;
}
//Detect for the player hitting the enemy
if (rectangularCollision({rectangle1: Player, rectangle2: Enemy})) {
Player.isAttacking = false;
Enemy.health -= 20;
document.querySelector('#enemy-health').style.width = Enemy.health + '%';
}
//Detect for the enemy hitting the player
if (rectangularCollision({rectangle1: Enemy, rectangle2: Player})) {
Enemy.isAttacking = false;
Player.health -= 20;
document.querySelector('#player-health').style.width = Player.health + '%';
}
//End game based on health
if (Enemy.health <= 0 || Player.health <= 0) {
determineWinner({ Player, Enemy, timerId });
}
}
animate();
window.addEventListener('keydown', (event) => {
switch (event.key) {
//Player movement
case 'w':
Player.velocity.y = -20;
break;
case 'a':
keys.a.pressed = true;
Player.lastKey = "a";
break
case 'd':
keys.d.pressed = true;
Player.lastKey = "d";
break;
case ' ':
Player.attack();
break;
}
//Enemy movement
switch (event.key) {
case 'ArrowUp':
Enemy.velocity.y = -20;
break;
case 'ArrowRight':
keys.ArrowRight.pressed = true;
Enemy.lastKey = 'ArrowRight'
break
case 'ArrowLeft':
keys.ArrowLeft.pressed = true;
Enemy.lastKey = 'ArrowLeft'
break;
case 'Enter':
Enemy.attack();
break;
}
})
window.addEventListener('keyup', (event) => {
//Player keys
switch (event.key) {
case 'w':
keys.w.pressed = false;
break;
case 'a':
keys.a.pressed = false;
break
case 'd':
keys.d.pressed = false;
break;
}
//Enemy keys
switch (event.key) {
case 'ArrowUp':
keys.ArrowUp.pressed = false;
break;
case 'ArrowLeft':
keys.ArrowLeft.pressed = false;
break
case 'ArrowRight':
keys.ArrowRight.pressed = false;
break;
}
})
* {
box-sizing: border-box;
}
#mother-div {
position: relative;
display: inline-block;
}
#small-container {
position: absolute;
display: flex;
width: 100%;
align-items: center;
padding: 20px;
}
.healthDiv {
position: relative;
height: 30px;
width: 100%;
}
.backgroundHealth {
background-color: red;
height: 30px;
width: 100%
}
#player-health {
position: absolute;
background-color: lime;
top: 0;
right: 0;
bottom: 0;
width: 100%
}
#enemy-health {
position: absolute;
background-color: yellow;
top: 0;
right: 0;
bottom: 0;
left: 0
}
#playerHealthDiv {
display: flex;
justify-content: flex-end;
}
#timer {
background-color: red;
width: 100px;
height: 100px;
flex-shrink: 0;
border: solid white 2px;
display: flex;
align-items: center;
justify-content: center;
}
#winner-display {
position: absolute;
color: white;
align-items: center;
justify-content: center;
top: 0;
right: 0;
bottom: 0;
left: 0;
display: none;
}
#myConsole {
background-color: black;
color: white;
min-height: 100px;
}
<!DOCTYPE html>
<html lang="en">
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE-edge">
<meta name="viewport", content="width=device-width, initial-scale=1.0">
<meta name="author" content="Christian Davis">
<link rel="stylesheet" href="styles.css">
<title>Fighting Game</title>
</head>
<body>
<!--Red container div-->
<div id="mother-div">
<!--Smaller red container div-->
<div id="small-container">
<!--Player Health-->
<div class="healthDiv" id="playerHealthDiv">
<div class="backgroundHealth"></div>
<div id="player-health"></div>
</div>
<!--Timer-->
<div id="timer">
<span id="time-left">02:00</span>
</div>
<!--Enemy Health-->
<div class="healthDiv">
<div class="backgroundHealth"></div>
<div id="enemy-health"></div>
</div>
</div>
<!--Winner display-->
<div id="winner-display"></div>
<canvas id="canvas"></canvas>
</div>
<p id="myConsole">> <span id="myMessage"></span></p>
<script src="app.js"></script>
</body>
</html>
Solution
Track overall game state
Use a variable to track the state of the game and help orchestrate the entire user experience.
How you track state(s) is up to you. It could be a single boolean variable (true/false) or an ENUM (e.g. 'loading', 'intro', 'paused', 'active', 'over', etc). In any case, you'd make something to hold the state of the game.
Going deeper, you'd probably also hold states for game rounds (e.g. current round, or number of rounds, etc), what the current character is (in the case where game characters can be swapped), whether a player has a boost mode enabled, etc.
In any case, during the game, you set-or-get state(s) during certain events:
- Timer start
- Timer end
- Winner determined
- Key press
- Game paused
- etc...
To illustrate, here I make a global var "gameIsActive":
var gameIsActive = true
Then, at certain events, we set state, for example, when the timer finishes:
gameIsActive = false
Then, at certain events, we get state and do logic accordingly, for example, movement only occurs when gameIsActive
is true
:
window.addEventListener('keyup', (event) => {
if (gameIsActive) {
// do stuff...
Here it is applied to your mini-game:
https://codepen.io/MarsAndBack/pen/OJqLRWK?editors=1111
const canvas = document.querySelector('#canvas');
const ctx = canvas.getContext("2d");
const winnerDisplay = document.querySelector('#winner-display');
// NEW
var gameIsActive = true;
canvas.width = 1024;
canvas.height = 576;
function logMessage(msg) {
document.querySelector('#myMessage').textContent += msg + '. ';
}
ctx.fillRect(0, 0, canvas.width, canvas.height);
const gravity = 0.7;
class Sprite {
constructor({position, velocity, color, offset}) {
this.position = position;
this.velocity = velocity;
this.height = 150;
this.width = 50;
this.lastKey;
this.attackBox = {
position: {
x: this.position.x,
y: this.position.y
},
offset,
width: 100,
height: 50,
color: 'green'
}
this.color = color;
this.isAttacking;
this.health = 100;
}
draw() {
ctx.fillStyle = this.color;
ctx.fillRect(this.position.x, this.position.y, this.width, this.height);
//Attack box
if (this.isAttacking) {
ctx.fillStyle = this.attackBox.color;
ctx.fillRect(
this.attackBox.position.x,
this.attackBox.position.y,
this.attackBox.width,
this.attackBox.height
)
}
}
update() {
this.draw();
this.attackBox.position.x = this.position.x - this.attackBox.offset.x;
this.attackBox.position.y = this.position.y;
this.position.x = Math.max(0, Math.min(canvas.width - this.width, this.position.x + this.velocity.x));
this.position.y = Math.max(0, Math.min(canvas.height, this.position.y + this.velocity.y));
if (this.position.y + this.height + this.velocity.y >= canvas.height) {
this.velocity.y = 0;
} else {
this.velocity.y += gravity;
}
}
attack() {
this.isAttacking = true;
setTimeout(() => {
this.isAttacking = false
}, 50)
}
}
const Player = new Sprite({
position: {
x: 0,
y: 0
},
velocity: {
x: 0,
y: 0
},
offset: {
x: 0,
y: 0
},
color: 'blue'
})
const Enemy = new Sprite({
position: {
x: canvas.width,
y: 100
},
velocity: {
x: 0,
y: 0
},
offset: {
x: 50,
y: 0
},
color: 'red'
})
const keys = {
w: {
pressed: false
},
a: {
pressed: false
},
d: {
pressed: false
},
ArrowUp: {
pressed: false
},
ArrowLeft: {
pressed: false
},
ArrowRight: {
pressed: false
}
}
function rectangularCollision({rectangle1, rectangle2}) {
return (
rectangle1.attackBox.position.x + rectangle1.attackBox.width >= rectangle2.position.x &&
rectangle1.attackBox.position.x <= rectangle2.position.x + rectangle2.width &&
rectangle1.attackBox.position.y + rectangle1.attackBox.height >= rectangle2.position.y &&
rectangle1.attackBox.position.y <= rectangle2.position.y + rectangle2.height &&
rectangle1.isAttacking
)
}
function determineWinner({ Player, Enemy, timerId }) {
clearTimeout(timerId);
winnerDisplay.style.display = 'flex';
if (Player.health == Enemy.health) {
winnerDisplay.innerHTML = 'Tie!';
}
if (Player.health > Enemy.health) {
winnerDisplay.innerHTML = 'Player 1 wins!';
}
if (Player.health < Enemy.health) {
winnerDisplay.innerHTML = 'Player 2 wins!';
}
}
//Timer and end game
//Feel free to change these starting values as you need
const startingMinutes = 1;
const startingSeconds = 30;
let time = startingMinutes * 60 + startingSeconds;
let timerId;
function decreaseTimer() {
const timeLeft = document.querySelector('#time-left');
if (time > 0) {
timerId = setTimeout(decreaseTimer, 1000);
const minutes = Math.floor(time / 60);
let seconds = time % 60;
seconds = seconds < 10 ? '0' + seconds : seconds;
timeLeft.innerHTML = `0${minutes}:${seconds}`;
time--;
}
if (time == 0) {
timeLeft.innerHTML = `00:00`;
// NEW
gameIsActive = false;
determineWinner({ Player, Enemy, timerId });
Player.position.x = 0;
Enemy.position.x = canvas.width;
}
}
decreaseTimer();
function animate() {
window.requestAnimationFrame(animate);
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, canvas.width, canvas.height);
Player.update();
Enemy.update();
//Player movement
Player.velocity.x = 0;
if (keys.a.pressed == true && Player.lastKey == "a") {
Player.velocity.x = -5;
} else if (keys.d.pressed == true && Player.lastKey == "d") {
Player.velocity.x = 5;
}
//Enemy movement
Enemy.velocity.x = 0;
if (keys.ArrowLeft.pressed == true && Enemy.lastKey == "ArrowLeft") {
Enemy.velocity.x = -5;
} else if (keys.ArrowRight.pressed == true && Enemy.lastKey == "ArrowRight") {
Enemy.velocity.x = 5;
}
//Detect for the player hitting the enemy
if (rectangularCollision({rectangle1: Player, rectangle2: Enemy})) {
Player.isAttacking = false;
Enemy.health -= 20;
document.querySelector('#enemy-health').style.width = Enemy.health + '%';
}
//Detect for the enemy hitting the player
if (rectangularCollision({rectangle1: Enemy, rectangle2: Player})) {
Enemy.isAttacking = false;
Player.health -= 20;
document.querySelector('#player-health').style.width = Player.health + '%';
}
//End game based on health
if (Enemy.health <= 0 || Player.health <= 0) {
// NEW
gameIsActive = false;
determineWinner({ Player, Enemy, timerId });
}
}
animate();
window.addEventListener('keydown', (event) => {
// NEW
if (gameIsActive) {
switch (event.key) {
//Player movement
case 'w':
Player.velocity.y = -20;
break;
case 'a':
keys.a.pressed = true;
Player.lastKey = "a";
break
case 'd':
keys.d.pressed = true;
Player.lastKey = "d";
break;
case ' ':
Player.attack();
break;
}
//Enemy movement
switch (event.key) {
case 'ArrowUp':
Enemy.velocity.y = -20;
break;
case 'ArrowRight':
keys.ArrowRight.pressed = true;
Enemy.lastKey = 'ArrowRight'
break
case 'ArrowLeft':
keys.ArrowLeft.pressed = true;
Enemy.lastKey = 'ArrowLeft'
break;
case 'Enter':
Enemy.attack();
break;
}
}
})
window.addEventListener('keyup', (event) => {
// NEW
if (gameIsActive) {
//Player keys
switch (event.key) {
case 'w':
keys.w.pressed = false;
break;
case 'a':
keys.a.pressed = false;
break
case 'd':
keys.d.pressed = false;
break;
}
//Enemy keys
switch (event.key) {
case 'ArrowUp':
keys.ArrowUp.pressed = false;
break;
case 'ArrowLeft':
keys.ArrowLeft.pressed = false;
break
case 'ArrowRight':
keys.ArrowRight.pressed = false;
break;
}
}
})
* {
box-sizing: border-box;
}
#mother-div {
position: relative;
display: inline-block;
}
#small-container {
position: absolute;
display: flex;
width: 100%;
align-items: center;
padding: 20px;
}
.healthDiv {
position: relative;
height: 30px;
width: 100%;
}
.backgroundHealth {
background-color: red;
height: 30px;
width: 100%
}
#player-health {
position: absolute;
background-color: lime;
top: 0;
right: 0;
bottom: 0;
width: 100%
}
#enemy-health {
position: absolute;
background-color: yellow;
top: 0;
right: 0;
bottom: 0;
left: 0
}
#playerHealthDiv {
display: flex;
justify-content: flex-end;
}
#timer {
background-color: red;
width: 100px;
height: 100px;
flex-shrink: 0;
border: solid white 2px;
display: flex;
align-items: center;
justify-content: center;
}
#winner-display {
position: absolute;
color: white;
align-items: center;
justify-content: center;
top: 0;
right: 0;
bottom: 0;
left: 0;
display: none;
}
#myConsole {
background-color: black;
color: white;
min-height: 100px;
}
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE-edge">
<meta name="viewport", content="width=device-width, initial-scale=1.0">
<meta name="author" content="Christian Davis">
<link rel="stylesheet" href="styles.css">
<title>Fighting Game</title>
</head>
<body>
<!--Red container div-->
<div id="mother-div">
<!--Smaller red container div-->
<div id="small-container">
<!--Player Health-->
<div class="healthDiv" id="playerHealthDiv">
<div class="backgroundHealth"></div>
<div id="player-health"></div>
</div>
<!--Timer-->
<div id="timer">
<span id="time-left">02:00</span>
</div>
<!--Enemy Health-->
<div class="healthDiv">
<div class="backgroundHealth"></div>
<div id="enemy-health"></div>
</div>
</div>
<!--Winner display-->
<div id="winner-display"></div>
<canvas id="canvas"></canvas>
</div>
<p id="myConsole">> <span id="myMessage"></span></p>
<script src="app.js"></script>
</body>
</html>
Answered By - Kalnode
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.