How do I share my javascript game with my friends - javascript

I am practicing making games with HTML canvas and JavaScript. I am making a flappy bird clone, and it is almost done. One of my friends wanted to see it but I couldn't figure out how they could play it. I sent them the folder with all the files in it, but it looked like the only problem was that when he tried to play it, he couldn't load the images. How would I go about letting people play the games I make. Was I on the right track, just sending them the folder?
const canvas = document.getElementById("canvas");
const c = canvas.getContext("2d");
const backgroundImage = document.getElementById("image")
const flappyBirdImage = document.getElementById("flappy-bird-image");
const topPipe1Image = document.getElementById("top-pipe-image");
const bottomPipe1Image = document.getElementById("bottom-pipe-image");
const gainAPointSound = document.getElementById("gain-a-point-sound");
const startButtonImage = document.getElementById("start-button-image")
let pause = true;
let scoreSet = 0;
let controlsKeyDown = {up: false, right: false, down: false, left: false};
let dx = 2;
let dy = 2;
let score = 0;
let seconds = 0;
if(pause === false) {
let secondsInterval = setInterval(() => {
seconds ++;
console.log(seconds)
}, 1000)
}
canvas.width = innerWidth;
canvas.height = innerHeight;
class Bird {
constructor(x, y, width, height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
draw() {
c.beginPath();
c.fillStyle = 'blue';
c.strokeStyle = 'lightBlue';
c.drawImage(flappyBirdImage, this.x, this.y, this.width, this.height)
c.fill()
c.stroke();
c.closePath();
}
}
class Pipe {
constructor(x, y, height, width) {
this.x = x;
this.y = y;
this.height = height;
this.width = width;
}
draw() {
c.beginPath();
c.drawImage(bottomPipe1Image, this.x, this.y, this.width, this.height)
c.fill();
}
drawtop() {
c.beginPath();
c.drawImage(topPipe1Image, this.x, this.y, this.width, this.height);
c.closePath()
}
}
class Button {
constructor(x,y,height,width) {
this.x = x;
this.y = y;
this.height = height;
this.width = width;
}
draw() {
c.beginPath();
c.drawImage(startButtonImage, this.x, this.y, this.height, this.width);
c.closePath();
}
}
// Game Objects
const topPipe1 = new Pipe(canvas.width - 300, 0, 300, 200)
const bottomPipe1 = new Pipe(canvas.width - 300, canvas.height - 300, 300, 200)
const topPipe2 = new Pipe(canvas.width + 300, 0, 300, 200);
const bottomPipe2 = new Pipe(canvas.width + 300, canvas.height - 300, 300, 200);
const myBird = new Bird(200, 200, 60, 60)
const startButton = new Button(canvas.width/2 - 300, canvas.height/2 - 75, 400, 150)
console.log(startButton)
// Game Mechanics
function birdControlsKeyDown(Event) {
if(Event.key === 'ArrowUp') {
controlsKeyDown.up = true;
}
if(Event.key === 'ArrowRight') {
controlsKeyDown.right = true;
}
if(Event.key === 'ArrowLeft') {
controlsKeyDown.left = true;
}
if(Event.key === "ArrowDown") {
controlsKeyDown.down = true;
}
}
function birdControlsKeyUp(Event) {
if(Event.key === 'ArrowUp') {
controlsKeyDown.up = false;
}
if(Event.key === 'ArrowRight') {
controlsKeyDown.right = false;
}
if(Event.key === 'ArrowLeft') {
controlsKeyDown.left = false;
}
if(Event.key === 'ArrowDown') {
controlsKeyDown.down = false;
}
}
//Bird With Edge Collision Detection
function birdCollisionDetection() {
// Bird Hits Bottom Of Screen
if(myBird.y + myBird.height >= canvas.height){
myBird.y = canvas.height - 100;
alert("You Lost")
document.location.reload()
}
// Bird Hits Top Of Screen
if(myBird.y <= 0) {
myBird.y += dy;
}
// Bird Hits Left Of Screen
if(myBird.x<= 0) {
myBird.x += dx;
}
// Bird Hits Right Of Screen
if(myBird.x + myBird.height >= canvas.width) {
myBird.x -= dx;
}
// Bird With Pipe Collision Detection
}
function birdWithPipeCollisionDetection(a,b) {
if(a.x + a.width >= b.x && a.x <= b.x + b.width && a.y <= b.y + b.height && a.y + a.height >= b.y){
console.log('test');
document.location.reload()
alert("You Lost")
}
}
function writeScore() {
c.font = '30px Georgia'
c.fillStyle = 'black';
c.fillText(`Score: ${score}`, 30, 30)
}
function writeTime() {
c.font = '30px Georgia';
c.fillStyle = 'black';
c.fillText(`Seconds: ${seconds}`, canvas.width/2 - 100, 30)
}
function writeStats() {
writeScore()
writeTime()
}
function resetPipePositions() {
if(topPipe1.x + topPipe1.width/2 < 0) {
topPipe1.x = canvas.width
topPipe1.height = Math.floor(Math.random() * 200 + 300);
scoreSet++;
}
if(bottomPipe1.x + bottomPipe1.width/2 < 0) {
bottomPipe1.x = canvas.width
bottomPipe1.height = canvas.height - topPipe1.height
}
if(bottomPipe2.x + bottomPipe2.width/2 < 0) {
bottomPipe2.x = canvas.width
bottomPipe2.height = canvas.height - topPipe2.height
}
if(topPipe2.x + topPipe2.width/2 < 0) {
topPipe2.x = canvas.width
topPipe2.height = canvas.height - bottomPipe2.height
}
}
function resetBirdPosition() {
if(myBird.x < 200) {
myBird. x += dx;
}
}
function updateScore() {
if(myBird.x + myBird.width >= bottomPipe1.x && myBird.x <= bottomPipe1.x + bottomPipe1.width && myBird.y + myBird.height <= bottomPipe1.y && myBird.y >= topPipe1.y + topPipe1.height) {
score = (scoreSet + 1)
}
}
function ifPause() {
addEventListener('keypress', (Event) => {
if(Event.key === 'Enter') {
console.log(pause)
pause = false;
} else if(Event.key === ' ') {
console.log(pause)
pause = true
}
console.log(pause)
})
}
function resizeScreen() {
canvas.height = window.innerHeight;
canvas.width = window.innerWidth;
}
function startButtonOnClick() {
pause = false;
}
// Game Loop
function draw() {
c.drawImage(backgroundImage, 0,0,canvas.width,canvas.height);
myBird.draw();
topPipe1.drawtop();
bottomPipe1.draw();
topPipe2.drawtop();
bottomPipe2.draw()
startButton.draw()
resetPipePositions();
resetBirdPosition();
updateScore();
ifPause()
writeStats();
// Check If Paused
if(pause === false) {
// Bird Controls
addEventListener('keydown', birdControlsKeyDown)
addEventListener('keyup', birdControlsKeyUp)
if(controlsKeyDown.up) {
setInterval(myBird.y -= dy, 10);
} else {
myBird.y += dy;
}
topPipe1.x -= dx;
bottomPipe1.x -= dx;
topPipe2.x -= dx;
bottomPipe2.x -= dx;
birdCollisionDetection();
birdWithPipeCollisionDetection(myBird, topPipe1);
birdWithPipeCollisionDetection(myBird, bottomPipe1);
birdWithPipeCollisionDetection(myBird, bottomPipe2);
birdWithPipeCollisionDetection(myBird, topPipe2);
}
requestAnimationFrame(draw)
}
draw()
html {
margin: 0;
padding: 0;
}
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
canvas {
overflow: hidden;
}
image {
background: transparent;
}
#start-button {
z-index: 100
}
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="icon" type="image/png" href="./Flappy Bird Pictures and Animations/Flappy Bird Icon.png" type="icon" height="100px" width="75px">
<script src="Flappy Bird.js" defer></script>
<link rel="stylesheet" href="Flappy Bird.css">
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Flappy Bird</title>
</head>
<body>
<canvas id="canvas"></canvas>
<img src="./Flappy Bird Pictures and Animations/background image.png" id="image">
<img src="./Flappy Bird Pictures and Animations/The Flappy Bird.png" id="flappy-bird-image">
<img src="./Flappy Bird Pictures and Animations/Bottom Pipe.png" id="bottom-pipe-image">
<img src="./Flappy Bird Pictures and Animations/Top Pipe.png" id="top-pipe-image">
<audio src="D:/Coding/2d Games/Flappy Bird/Audio" id="gain-a-point-sound"></audio>
<img src="./Flappy Bird Pictures and Animations/Start Button_files/Start-button-sprite.png" id="start-button-image">
</body>
</html>

Well, the simplest solution is to put the game online :). Services like Netlify allow you to do this in no time and for free. To get started, you can literally drag and drop the files to Netlify. Netlify creates a public link* of the form somename.netlify.app for you which you can then share with your friends.
When uploading your files make sure that there is no absolute path since this will not work on other machines let alone the internet. In your source code, "D:/Coding/2d Games/Flappy Bird/Audio" is an example of an absolute path. You need to use relative paths instead. As for your images, you need to make sure that your project folder has a directory "/Flappy Bird Pictures and Animations" and that this gets uploaded to Netlify (or other services) as well.
*You can also edit the link in case it is not taken already.

Related

How to make balls falling down from the top of the canvas in JavaScript

const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
const width = canvas.width;
const height = canvas.height;
class Position {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
class Player {
constructor() {
this.position = new Position(250, 460)
this.radius = 20;
this.speed = 5;
this.color = "teal";
this.lives = 1;
// Belongs to the handleKeyUp and handleKeyDown functions
this.right = false;
this.left = false;
}
}
let player = new Player();
// Creating a class to handle the enemy balls
class Enemy {
constructor() {
this.position = { x: Math.random() * width, y: 5 };
this.radius = 20;
this.velocity = { x: 0, y: (Math.random() * 8 + 4) }
this.color = "red";
}
move() {
this.position.x += this.velocity.x / 5;
this.position.y += this.velocity.y / 4;
}
draw() {
context.beginPath();
context.arc(this.position.x, this.position.y, this.radius, 0, Math.PI * 2);
context.fillStyle = this.color;
context.fill();
}
}
let enemy = new Enemy();
function isCircleOutside(entity) {
return (entity.position.x < - entity.radius ||
entity.position.x > width + entity.radius ||
entity.position.y < - entity.radius ||
entity.position.y > height + entity.radius);
}
//Creating our main player
function drawCircle(entity) {
context.beginPath();
context.arc(entity.position.x, entity.position.y, entity.radius, 0, Math.PI * 2);
context.fillStyle = entity.color;
context.fill();
}
//Handles the A and D keyboard buttons
function handleKeyDown(event) {
if (event.key === "a") {
player.left = true;
}
else if (event.key === "d") {
player.right = true;
}
}
function handleKeyUp(event) {
if (event.key === "a") {
player.left = false;
}
else if (event.key === "d") {
player.right = false;
}
}
//Makes sure that the player ball does not go outside the canvas
function handlePlayerMovement(player) {
if (player.right && player.position.x < canvas.width - player.radius)
player.position.x += player.speed;
if (player.left && player.position.x > player.radius)
player.position.x -= player.speed;
}
function circleCollision(circle1, circle2) {
let dx = circle1.position.x - circle2.position.x;
let dy = circle1.position.y - circle2.position.y;
let distance = Math.sqrt((dx * dx) + (dy * dy));
return distance < circle1.radius + circle2.radius;
}
window.addEventListener("keypress", handleKeyDown);
window.addEventListener("keyup", handleKeyUp);
let enemyArr = [];
let frameCount = 120;
function tick() {
context.clearRect(0, 0, canvas.width, canvas.height);
drawCircle(player);
handlePlayerMovement(player);
frameCount++;
if (frameCount >= 120) {
frameCount = 0;
enemyArr.push(new Enemy(enemy.position.x, enemy.position.y, enemy.velocity, enemy.radius, enemy.color));
}
for (let i = 0; i < enemyArr.length; i++) {
let enemy = enemyArr[i];
enemy.move();
enemy.draw();
if (isCircleOutside(enemy)) {
enemyArr.splice(i, 1);
continue;
}
if (circleCollision(enemy, player)) {
enemyArr.splice(i, 1);
player.lives -= 1;
if (player.lives <= 0) {
alert("GAME OVER");
document.location.reload();
clearInterval(interval);
return;
}
continue;
}
}
requestAnimationFrame(tick);
}
tick();
<!DOCTYPE html>
<html lang="en">
<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">
<title>Document</title>
<!-- <link rel="stylesheet" href="style.css"> -->
</head>
<body>
<canvas id="canvas" width="500" height="500" style="border: 1px solid rgb(0, 0, 0)"></canvas>
<script src="volcano.js"></script>
</body>
</html>
This my second version of the game. With the help I got here, I was able to finish the game the way I wanted to be. Maybe there are some bugs in it that I cannot see. The game is pretty simple, the player can only move the main ball to the left and right at the bottom of the canvas. After a few seconds random balls will start to fall down from the top and the player has to avoid touching the enemy balls. Otherwise the game is over with an alert window saying "Game Over" and you can simply restart the game.
(This is the first part of my question)
I'm trying to create a game where the player has to dodge the balls coming down from the top of the canvas. I have been able to make the player move to the right and left but now I'm stuck in the part where I have to create the falling balls. I know that I have to create an empty array where I store all the falling balls but how do I create a function to generate the positions? I would appreciate any suggestions or ideas to get me going, thank you!
const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
const width = canvas.width;
const height = canvas.height;
class Position {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
class Player {
constructor() {
this.position = new Position(250, 460)
this.radius = 20;
this.speed = 5;
this.color = "teal";
// Belongs to the handleKeyUp and handleKeyDown functions
this.right = false;
this.left = false;
}
}
let player = new Player();
// Creating a class to handle the enemy balls (stuck!)
class Enemy {
constructor(position, velocity) {
this.position = position;
this.radius = 10;
this.velocity = velocity;
this.color = "red";
}
}
//Creating our main player
function drawCircle(entity) {
context.beginPath();
context.arc(entity.position.x, entity.position.y, entity.radius, 0, Math.PI * 2);
context.fillStyle = entity.color;
context.fill();
}
//Handles the A and D keyboard buttons
function handleKeyDown(event) {
if (event.key === "a") {
player.left = true;
}
else if (event.key === "d") {
player.right = true;
}
}
function handleKeyUp(event) {
if (event.key === "a") {
player.left = false;
}
else if (event.key === "d") {
player.right = false;
}
}
window.addEventListener("keypress", handleKeyDown);
window.addEventListener("keyup", handleKeyUp);
//Makes sure that the player ball does not go outside the canvas
function handlePlayerMovement(player) {
if (player.right && player.position.x < canvas.width - player.radius)
player.position.x += player.speed;
if (player.left && player.position.x > player.radius)
player.position.x -= player.speed;
}
function tick() {
context.clearRect(0, 0, canvas.width, canvas.height);
drawCircle(player);
handlePlayerMovement(player);
requestAnimationFrame(tick);
}
tick();
<!DOCTYPE html>
<html lang="en">
<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">
<title>Document</title>
<!-- <link rel="stylesheet" href="style.css"> -->
</head>
<body>
<canvas id="canvas" width="500" height="500" style="border: 1px solid rgb(0, 0, 0)"></canvas>
<script src="volcano.js"></script>
</body>
</html>
Every now and then create an Enemy with a random position (x,y) and velocity. push it to array of enemies. update this array and draw it every loop. when an Enemy position (due to speed and time) is off screen, remove it from enemies array.
Update: I threw in a collision detection and some more natural improvements. You should be recognizing your code.
const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
const width = canvas.width = canvas.clientWidth;
const height = canvas.height = canvas.clientHeight
class Position {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
class Player {
constructor() {
this.radius = 20;
this.position = new Position(width / 2, height - this.radius)
this.speed = 5;
this.color = "teal";
// Belongs to the handleKeyUp and handleKeyDown functions
this.right = false;
this.left = false;
this.up = false;
this.down = false;
}
}
// Creating a class to handle the enemy balls (stuck!)
class Enemy {
constructor(position, velocity) {
this.position = position;
this.radius = 10;
this.velocity = velocity;
this.color = "red";
}
}
function generateEnemy() {
let enemy = new Enemy(new Position(Math.random() * width, 0 - 10), 0.01 + Math.random() / 5)
enemies.push(enemy);
}
// Creating our main player
function drawCircle(entity) {
context.beginPath();
context.arc(entity.position.x, entity.position.y, entity.radius, 0, Math.PI * 2);
context.fillStyle = entity.color;
context.fill();
}
// Handles the A and D keyboard buttons
function handleKeyDown(event) {
if (event.key === "a" || event.key === 'ArrowLeft') {
player.left = true;
event.preventDefault()
}
if (event.key === "d" || event.key === 'ArrowRight') {
player.right = true;
event.preventDefault()
}
if (event.key === "w" || event.key === 'ArrowUp') {
player.up = true;
event.preventDefault()
}
if (event.key === "s" || event.key === 'ArrowDown') {
player.down = true;
event.preventDefault()
}
}
function handleKeyUp(event) {
if (event.key === "a" || event.key === 'ArrowLeft') {
player.left = false;
event.preventDefault()
}
if (event.key === "d" || event.key === 'ArrowRight') {
player.right = false;
event.preventDefault()
}
if (event.key === "w" || event.key === 'ArrowUp') {
player.up = false;
event.preventDefault()
}
if (event.key === "s" || event.key === 'ArrowDown') {
player.down = false;
event.preventDefault()
}
}
// Makes sure that the player ball does not go outside the canvas
function handlePlayerMovement(player) {
if (player.right) {
player.position.x += player.speed;
}
if (player.left) {
player.position.x -= player.speed;
}
player.position.x = Math.min(width - player.radius, player.position.x)
player.position.x = Math.max(player.radius, player.position.x)
if (player.up) {
player.position.y -= player.speed;
}
if (player.down) {
player.position.y += player.speed;
}
player.position.y = Math.min(height - player.radius, player.position.y)
player.position.y = Math.max(player.radius, player.position.y)
}
function update(dt) {
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i]
enemy.position.y += enemy.velocity * dt;
if (enemy.position.y >= height + enemy.radius) {
enemies.splice(i, 1)
}
}
handlePlayerMovement(player);
}
function draw() {
context.clearRect(0, 0, width, height);
drawCircle(player);
enemies.forEach(drawCircle)
}
function is_colliding(player, enemy) {
var dx = player.position.x - enemy.position.x
var dy = player.position.y - enemy.position.y
var safe = player.radius + enemy.radius
if (dx * dx + dy * dy < safe * safe) {
return true;
}
}
function detect_collisions() {
var boom = false
enemies.forEach(function(enemy) {
if (is_colliding(player, enemy)) {
boom = true;
}
})
if (boom) {
player.color = 'gray'
} else {
player.color = 'teal'
}
}
function timestamp() {
return new Date().getTime();
}
function tick() {
var now = timestamp();
var dt = Math.min(now - last, 250);
update(dt);
detect_collisions()
if (Math.random() < 0.05) {
generateEnemy()
}
draw();
last = now;
requestAnimationFrame(tick);
}
var last = timestamp()
var now;
let enemies = [];
window.addEventListener("keydown", handleKeyDown);
window.addEventListener("keyup", handleKeyUp);
let player = new Player();
tick();
body {
margin: 0;
padding: 0;
overflow: hidden;
}
#canvas {
box-sizing: border-box;
}
<canvas id="canvas" style="border: 1px solid rgb(0, 0, 0); height: 100vh; width: 100%"></canvas>

JS/HTML/CSS animation game -- only select animations freeze

I'm following a tutorial on using vanilla JS/HTML/CSS to create a 2D animation game. I'm currently stuck, however, because some of my "spiders" become stuck in their path, and won't moveā€”and some of them do so out of the screen such that their webs are visible and won't disappear. I went back to the tutorial's code and tried to find any differences in the code, but couldn't find any. I've been playing around with the vertical values, as well as the part where I deal with animation frames, but couldn't fix the bug.
Could someone please help me figure out what I'm doing wrong?
document.addEventListener('DOMContentLoaded', function() {
const canvas = document.getElementById('canvas1');
const ctx = canvas.getContext('2d');
canvas.width = 500;
canvas.height = 800;
class Game {
constructor(ctx, width, height) {
this.ctx = ctx;
this.width = width;
this.height = height;
this.enemies = [];
this.enemyInterval = 400;
this.enemyTimer = 0;
this.enemyTypes = ["worm", "ghost", "spider"];
}
update(deltaTime) {
this.enemies = this.enemies.filter(object => !object.markedForDeletion);
if (this.enemyTimer > this.enemyInterval) {
this.#addNewEnemy();
this.enemyTimer = 0;
} else {
this.enemyTimer += deltaTime;
}
this.enemies.forEach(object => object.update(deltaTime));
}
draw() {
this.enemies.forEach(object => object.draw(this.ctx));
}
#addNewEnemy() {
const randomEnemy = this.enemyTypes[Math.floor(Math.random() * this.enemyTypes.length)];
if (randomEnemy === "worm") this.enemies.push(new Worm(this));
else if (randomEnemy === "ghost") this.enemies.push(new Ghost(this));
else if (randomEnemy === "spider") this.enemies.push(new Spider(this));
// this.enemies.sort(function(a, b) {
// return a.y - b.y;
// });
}
}
class Enemy {
constructor(game) {
this.game = game;
this.markedForDeletion = false;
this.frameX = 0;
this.maxFrame = 5;
this.frameInterval = 100;
this.frameTimer = 0;
}
update(deltaTime) {
this.x -= this.vx * deltaTime;
if (this.x < 0 - this.width) this.markedForDeletion = true;
if (this.frameTimer > this.frameInterval) {
if (this.frameX < this.maxFrame) this.frameX++;
else this.frameX = 0;
this.frameTimer = 0;
} else {
this.frameTimer += deltaTime;
}
}
draw(ctx) {
ctx.drawImage(this.image, this.frameX * this.spriteWidth, 0, this.spriteWidth, this.spriteHeight, this.x, this.y, this.width, this.height);
}
}
class Spider extends Enemy{
constructor() {
super(game);
this.spriteWidth = 310;
this.spriteHeight = 175;
this.width = this.spriteWidth/2;
this.height = this.spriteHeight/2;
this.x = Math.random() * this.game.width;
this.y = 0 - this.height;
this.image = spider;
this.vx = 0;
this.vy = Math.random() * 0.1 + 0.1;
this.maxLength = Math.random() * this.game.height * 0.7;
}
update(deltaTime) {
super.update(deltaTime);
if (this.y < 0 - this.height * 1.5) this.markedForDeletion = true;
this.y += this.vy * deltaTime;
if (this.y > this.maxLength) this.vy *= -1;
}
draw(ctx) {
ctx.beginPath();
ctx.moveTo(this.x + this.width/2, 0);
ctx.lineTo(this.x + this.width/2, this.y + 10);
ctx.stroke();
super.draw(ctx);
}
}
const game = new Game(ctx, canvas.width, canvas.height);
let lastTime = 1;
function animate(timeStamp) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
const deltaTime = timeStamp - lastTime;
lastTime = timeStamp;
game.update(deltaTime);
game.draw();
requestAnimationFrame(animate);
}
animate(0);
})
#canvas1 {
border: 3px solid black;
width: 500px;
height: 800px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
img {
display: none;
}
<!DOCTYPE html>
<html lang="en">
<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">
<title>Enemy Variety</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<canvas id="canvas1"></canvas>
<img src="images/enemy_worm.png" id="worm">
<img src="images/enemy_ghost.png" id="ghost">
<img src="images/enemy_spider.png" id="spider">
<script src="script.js"></script>
</body>
</html>
Apologies for the current snippet not working. I assume it's because I can't find a way to upload the image with the code, but I'm attaching it here for reference: https://www.frankslaboratory.co.uk/downloads/enemy_spider.png (Warning: this image is only to be used for educational purposes)
In the draw() method inside the Spider class, you must call super.draw() before running other code:
draw(ctx) {
super.draw(ctx);
ctx.beginPath();
ctx.moveTo(this.x + this.width/2, 0);
ctx.lineTo(this.x + this.width/2, this.y + 10);
ctx.stroke();
}

Player glitches through left side of horizontal moving block

EDIT: I rewrote a minimal reproducible example in p5.js, so you can see what's happening here:
let keyInput = []
let player
let block
function setup() {
createCanvas(600, 600)
player = new Player(0, height/2)
block = new Block(200, height-100, 100, 1000)
}
function draw() {
background(220);
player.draw()
block.draw()
player.moveX()
block.checkCollisionsX()
player.moveY()
block.checkCollisionsY()
}
function keyPressed() {
keyInput[keyCode] = true;
}
function keyReleased() {
keyInput[keyCode] = false;
}
function rectCollide(x1, y1, w1, h1, x2, y2, w2, h2) {
return x1 + w1 > x2 && x1 < x2 + w2 && y1 + h1 > y2 && y1 < y2 + h2;
}
//BLOCK CONSTRUCTOR
class Block {
constructor(x, y, w, h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.movingSpeed = 3;
this.start = 200
this.stop = 400
}
draw() {
fill(255)
rect(this.x, this.y, this.w, this.h)
this.x += this.movingSpeed;
if (this.x > this.stop) {
this.movingSpeed = -this.movingSpeed;
}
if (this.x < this.start) {
this.movingSpeed = abs(this.movingSpeed);
}
}
checkCollisionsX() {
if (rectCollide(player.pos.x, player.pos.y, player.width, player.height, this.x, this.y, this.w, this.h)) {
if (player.vel.x < 0) { // If the player moved left and collided with the right side of block
player.pos.x = this.x + this.w;
} else { // If the player moved right and collided with the left side of block
player.pos.x = this.x - player.width;
}
player.vel.x = 0;
}
}
checkCollisionsY() {
if (rectCollide(player.pos.x, player.pos.y, player.width, player.height, this.x, this.y, this.w, this.h)) {
if (player.vel.y < 0) {
player.pos.y = this.y + this.h;
player.vel.y *= -yRebound; // Not -1 because collisions are not perfectly elastic
} else {
//player.pos.x += movingSpeed; //Keep player on platform while platform is moving
player.jumps = player.numJumps;
player.pos.y = this.y - player.height;
player.vel.y = 0;
player.acc.y = 0;
}
}
}
}
//PLAYER CONSTRUCTOR
class Player {
constructor(x, y) {
this.width = 50
this.height = 100
// all 3 chars for pretty code
this.pos = new p5.Vector(x, y);
this.vel = new p5.Vector(0, 0);
this.acc = new p5.Vector(0, 0);
this.accSpeed = 0.05;
this.gravity = 0.5;
this.maxVel = 10;
this.jumpForce = 15;
this.friction = 0.15;
this.numJumps = 1;
this.jumps = this.numJumps;
this.isGrounded = false;
this.canMove = true;
this.dir = "DOWN"
}
draw() {
fill(255, 0, 0)
rect(this.pos.x, this.pos.y, this.width, this.height)
}
moveX() {
//MOVE X
if (keyInput[LEFT_ARROW] && this.vel.x > -this.maxVel && this.canMove) {
this.acc.x = -this.accSpeed;
} else if (keyInput[RIGHT_ARROW] && this.vel.x < this.maxVel && this.canMove) {
this.acc.x = this.accSpeed;
} else if (abs(this.vel.x) > 0.2) {
this.acc.x = (this.vel.x < 0) ? this.friction : -this.friction;
} else {
this.vel.x = 0;
this.acc.x = 0;
}
this.vel.x += this.acc.x; // vel += acc
this.pos.x += this.vel.x; // pos += vel
}
moveY() {
//MOVE Y
if (keyInput[UP_ARROW] && this.jumps > 0 && this.canMove) {
this.jumps--;
this.vel.y = -this.jumpForce;
}
this.acc.y += this.gravity;
this.vel.y += this.acc.y;
this.pos.y += this.vel.y;
this.acc.y = 0; // Reset acceleration
if (this.pos.y >= height - this.height) {
this.pos.y = height-this.height
this.jumps = this.numJumps;
}
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/addons/p5.sound.min.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="utf-8" />
</head>
<body>
<main>
</main>
</body>
</html>
I'm making a 2D platformer game, and all block collisions work correctly except for the left side of a horizontally moving block. Here's what the block looks like (ignore the lag):
Here's the code that makes up the moving block:
if (type.equals("moving-horizontal-2x1")) {
image(img2x1, pos.x, pos.y, 200, 100);
pos.x += movingSpeed;
if (pos.x > stop) {
movingSpeed = -movingSpeed;
}
if (pos.x < start) {
movingSpeed = abs(movingSpeed);
}
}
When the player collides with the block, it works for all sides except the left side on the X axis, as shown by the image below.
This video shows what happens when the player collides with the moving block: https://www.youtube.com/watch?v=ewVSYd5h4rg
As you can see, the player gets moved to the other side of the block. I don't know why this is happening, since the collision detection/resolution code is the same as the other static blocks. Why does only one side work?
Here is my collision detection code for the X axis:
if (rectCollide(player.pos.x, player.pos.y, player.width, player.height, pos.x, pos.y, width, height)) {
if (player.vel.x < 0) { // If the player moved left and collided with the right side of block
player.pos.x = pos.x + width;
} else { // If the player moved right and collided with the left side of block (this is the broken side)
player.pos.x = pos.x - player.width;
}
player.vel.x = 0;
}
I've tried fixing this issue by incrementing the player's x pos when it collides with the left side, by doing something like player.pos.x += movingSpeed, but this still doesn't work.
I believe the bug has something to do with how I draw the moving block, since the collision detection/resolution code works perfectly fine with all other static blocks.
Thanks for any help!
The problem occurs when you are slowly moving away from the block, but the block is faster than you. The player's direction of movement therefore says nothing about whether he is to the left or to the right of the obstacle. Don't check the player's velocity, check the player's position relative to the obstacles position:
Replace
if (player.vel.x < 0)
with
if (player.pos.x > this.x)

solid obstacle in an JavaScript game

I am very new to coding. I am trying to make a game using java in notepad++. I cant seem to get it so that when the red square (player) hits the purple (TopEdge) the red square will not stop completely but also wont travel through the purple. Like a wall. Right now when the red square hits the purple, you cant move it anymore. I have tried almost everything i could find on the internet. Here is my code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta charset="utf-8">
<style>
canvas {
border:4px solid #000000;
background-color: #1FB026;
}
</style>
</head>
<body onload="startGame()">
<script>
var player;
var TopEdge;
function startGame() {
player = new component(30, 30, "red", 10, 120);
TopEdge = new component(10000, 300, "purple", 0, -200);
myGameArea.start();
}
var myGameArea = {
canvas : document.createElement("canvas"),
start : function() {
this.canvas.width = 1150;
this.canvas.height = 500;
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas,
document.body.childNodes[0]);
this.interval = setInterval(updateGameArea, 10);
window.addEventListener('keydown', function (e) {
myGameArea.keys = (myGameArea.keys || []);
myGameArea.keys[e.keyCode] = (e.type == "keydown");
})
window.addEventListener('keyup', function (e) {
myGameArea.keys[e.keyCode] = (e.type == "keydown");
})
},
clear : function(){
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
},
stop : function(){
clearInterval(this.interval);
}
}
function component(width, height, color, x, y) {
this.width = width;
this.height = height;
this.speedX = 0;
this.speedY = 0;
this.x = x;
this.y = y;
this.update = function() {
ctx = myGameArea.context;
ctx.fillStyle = color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
this.newPos = function() {
this.X += this.speedX;
this.Y += this.speedY;
let playerX = this.X + this.speedX;
let playerY = this.Y + this.speedY;
if (playerX >= 0 && this.width + playerX <= this.gamearea.canvas.width)
{
this.X = playerX;
}
if (playerY >= 0 && this.height + playerY <= this.gamearea.canvas.height)
{
this.Y = playerY;
}
}
this.crashWith = function(otherobj) {
var myleft = this.x;
var myright = this.x + (this.width);
var mytop = this.y;
var mybottom = this.y + (this.height);
var otherleft = otherobj.x;
var otherright = otherobj.x + (otherobj.width);
var othertop = otherobj.y;
var otherbottom = otherobj.y + (otherobj.height);
var crash = true;
if ((mybottom < othertop) ||
(mytop > otherbottom) ||
(myright < otherleft) ||
(myleft > otherright)) {
crash = false;
}
return crash;
}
}
function stopY() {
player.speedY = 0;
}
function updateGameArea() {
if (player.crashWith(TopEdge)) {
} else {
myGameArea.clear();
TopEdge.update();
player.x += player.speedX;
player.y += player.speedY;
player.update();
}
TopEdge.update();
player.speedX = 0;
player.speedY = 0;
if (myGameArea.keys && myGameArea.keys[65]) {player.speedX = -2.5; }
if (myGameArea.keys && myGameArea.keys[68]) {player.speedX = 2.5; }
if (myGameArea.keys && myGameArea.keys[87]) {player.speedY = -2.5; }
if (myGameArea.keys && myGameArea.keys[83]) {player.speedY = 2.5; }
player.newPos();
player.update();
}
</script>
</body>
</html>
The problem starts with your updateGameArea() function.
If your the player crashes with the TopEdge then you do nothing. Your creating a problem with your else-part over there. It will never reach the else like this, so nothing while change, so next time it still won't move and again it will not reach the else.....
How about removing the else part. Just check for everything all the time, but don't allow it to move up when it reached the TopEdge.
This should help.
function updateGameArea() {
// I'd prefer these calls at the end of the function block
// but right now your program would start kinda buggy then
myGameArea.clear();
player.newPos();
player.update();
TopEdge.update();
// In default state (nothing pressed) player shouldn't move up or down
player.speedX = 0;
player.speedY = 0;
// If the player does press a key set correct speed/direction
if (myGameArea.keys[65]) {player.speedX = -2.5; }
if (myGameArea.keys[68]) {player.speedX = 2.5; }
if (myGameArea.keys[87]) {player.speedY = -2.5; }
if (myGameArea.keys[83]) {player.speedY = 2.5; }
// Check if player reached the top
// If it did, then it shouldn't be able to climb any higher.
// So even if the player presses the up-button,
// the vertical speed should still not be aloud to change.
if (player.crashWith(TopEdge) && myGameArea.keys[87]) {
player.speedY = 0;
}
// Move the position of the player
player.x += player.speedX; //
player.y += player.speedY;
}

Why does the page start to lag when drawing many elements on the canvas?

I'm creating a game, and I need to draw) some elements at the top of the <canvas>, but the more elements appear, the more lag the page itself. I found this example where a lot of circles appear, but everything works fine - JSFiddle. Can someone tell me how to optimize my case?
"use strict";
/*Determing canvas*/
window.onload = () => {
const canvas = document.getElementById("canvas"),
ctx = canvas.getContext('2d'),
endTitle = document.getElementById('gameover');
let spawnRate = 300,
lastspawn = -1;
class Wall {
/*Getting values*/
constructor(x, y, width, height, speed) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.speed = speed;
}
/*Draw rectangle*/
draw() {
ctx.beginPath();
ctx.fillStyle = "#000000";
ctx.fillRect(this.x, this.y, this.width, this.height)
}
}
/*Making walls*/
let walls = [];
/*Spawn walls endlessly*/
function spawnWalls() {
const wall_x = Math.floor(Math.random() * (canvas.width - 20)) + 10
const wall_y = 0
for (let i = 0; i < 200; i++) {
walls.push(new Wall(wall_x, wall_y, 10, 10, 10))
}
}
/*Update game*/
function refresh() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
let time = Date.now()
if (time > (lastspawn + spawnRate)) {
lastspawn = time;
spawnWalls();
spawnRate -= 10;
}
walls.forEach(wall => wall.draw())
for (let j of walls) {
j.y += j.speed;
j.draw();
};
};
let interval = setInterval(refresh, 50);
Walls is too big.
It looks like you're never removing old walls, so they are continuing to be drawn well after they have been removed from the canvas. In your Refresh function, check if the wall has passed the canvas size and if so, remove that from the walls array.
EDIT:
I've added your 'remove' code from the comment.
Another easy win is to stop using new Date() because of who knows what, probably time zones and localization, dates are very expensive to instantiate. However modern browsers offer a performance API, and that can tell you the time since page load, which seems to have a substantial improvement on your existing performance.
"use strict";
/*Determing canvas*/
window.onload = () => {
const canvas = document.getElementById("canvas"),
ctx = canvas.getContext('2d'),
endTitle = document.getElementById('gameover');
let spawnRate = 300,
lastspawn = -1;
endTitle.style.display = "none";
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
/*Classes*/
class Player {
/*Get player info*/
constructor(x, y, width, height, speed) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.speed = speed;
}
/*Draw player*/
draw() {
ctx.beginPath();
ctx.fillStyle = "#000000";
ctx.fillRect(this.x, this.y, this.width, this.height);
}
/*Move player*/
move() {
}
};
class Wall {
/*Getting values*/
constructor(x, y, width, height, speed) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.speed = speed;
}
/*Draw rectangle*/
draw() {
ctx.beginPath();
ctx.fillStyle = "#000000";
ctx.fillRect(this.x, this.y, this.width, this.height)
}
}
/*Defining players*/
let player_01 = new Player(20, 70, 20, 20, 10);
let player_02 = new Player(50, 500, 20, 20, 10);
let players = [];
players.push(player_01);
/*Making walls*/
let walls = [];
/*Spawn Walls for infinity*/
function spawnWalls() {
const wall_x = Math.floor(Math.random() * (canvas.width - 20)) + 10
const wall_y = 0
for (let i = 0; i < 200; i++) {
walls.push(new Wall(wall_x, wall_y, 10, 10, 10))
}
}
/*Update game*/
function refresh() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
let time = performance.now()
if (time > (lastspawn + spawnRate)) {
lastspawn = time;
spawnWalls();
spawnRate -= 10;
}
walls.forEach(wall => wall.draw())
outOfWindow()
for (let i of players) {
i.draw();
};
for (let j of walls) {
if (j.y > canvas.height) {
walls.shift(j)
}
j.y += j.speed;
j.draw();
if (player_01.height + player_01.y > j.y && j.height + j.y > player_01.y && player_01.width + player_01.x > j.x && j.width + j.x > player_01.x) {
clearInterval(interval);
endTitle.style.display = "flex";
};
};
};
let interval = setInterval(refresh, 50);
/*Move players on keypress*/
for (let i of players) {
window.addEventListener("keydown", (event) => {
let key = event.key.toLowerCase();
if (key == "w") i.y -= i.speed;
else if (key == "s") i.y += i.speed;
else if (key == "a") i.x -= i.speed;
else if (key == "d") i.x += i.speed;
})
}
/*Check if player out of the window*/
function outOfWindow() {
for (let i of players) {
if (i.x < 0) i.x = 0;
else if (i.x + i.width > canvas.width) i.x = canvas.width - i.width;
else if (i.y < 0) i.y = 0;
else if (i.y + i.height > canvas.height) i.y = canvas.height - i.height;
}
}
}
#gameover {
position: absolute;
width: 100%;
height: 100%;
justify-content: center;
align-items: center;
flex-direction: column;
background-color: rgba(0, 0, 0, .5);
}
<div id="gameover">
<h2>The Game Is Over</h2>
<button onclick="restart()">Try again!</button>
</div>
<canvas id="canvas"></canvas>

Categories

Resources