There is a problem with my previous character positions in canvas - javascript

I'm working to a JS game where I have a player named Ronin and the game is something like a 2d platformer. I worked on canvas to make him and I made him move x pixels to left/ right at keys A/D onkeydown. The problem is that I can't erase his 'copies' (previous positions of the character that now should dissapear). I would not want to use ctx.clearRect(), so please give me another solution.
Thanks in advance!
WalkLeft1------WalkLeft2------WalkRight1------WalkRight2
/* Walk Left/Right 1/2 in the description no matter with the'broken' state file, it's because it can't draw a file that he does not know :) */
/* ------------------------------------------ */
/* files in my directory:
index.html
style.css
script.js
Costumes >
WalkLeft >
WalkLeft1.jpg
WalkLeft2.jpg
WalkRight >
WalkRight1.jpg
WalkRight2.jpg
*/
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
Scene = function () {
this.x = 0;
this.y = 0;
this.w = canvas.width;
this.h = canvas.height;
this.style = {
fillStyle: "white",
strokeStyle: "red",
lineWidth: 5,
}
this.draw = function () {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = this.style.fillStyle;
ctx.strokeStyle = this.style.strokeStyle;
ctx.lineWidth = this.style.lineWidth;
ctx.fillRect(this.x, this.y, this.w, this.h);
}
}
Character = function () {
this.width = 77;
this.height = 92;
this.x = 10;
this.vx = 20;
this.padding = 10;
this.y = canvas.height - this.height - 10;
this.img0 = document.getElementById("img0");
this.img1 = document.getElementById("img1");
this.img2 = document.getElementById("img2");
this.img3 = document.getElementById("img3");
this.counter = {
walkLeft: 0,
walkRight: 0,
};
this.draw = {
walkLeft: () => {
if (this.counter.walkLeft == 0) {
ctx.drawImage(this.img0, this.x, this.y, this.width, this.height);
this.counter.walkLeft = 1;
} else if (this.counter.walkLeft == 1) {
ctx.drawImage(this.img1, this.x, this.y, this.width, this.height);
this.counter.walkLeft = 0;
}
},
walkRight: () => {
if (this.counter.walkRight == 0) {
ctx.drawImage(this.img2, this.x, this.y, this.width, this.height);
this.counter.walkRight = 1;
} else if (this.counter.walkRight == 1) {
ctx.drawImage(this.img3, this.x, this.y, this.width, this.height);
this.counter.walkRight = 0;
}
}
};
}
const scene = new Scene();
scene.draw();
var player = new Character();
var initInterval = setInterval(
function () {
player.draw.walkRight();
}, 400
);
var currentInterval = undefined;
document.addEventListener("keydown", function (e) {
if (e.key == "a" || e.key == "ArrowLeft") {
if (initInterval) {
clearInterval(initInterval);
initInterval = undefined;
}
if (currentInterval) {
clearInterval(currentInterval);
currentInterval = undefined;
}
setTimeout( // for first 300ms delay onchange
function () {
player.draw.walkLeft();
}, 1);
if(player.x - player.vx > player.padding) {
player.x -= player.vx;
} else {
player.x = player.padding;
}
currentInterval = setInterval(
function () {
player.draw.walkLeft();
}, 300);
}
if (e.key == "d" || e.key == "ArrowRight") {
if (initInterval) {
clearInterval(initInterval);
initInterval = undefined;
}
if (currentInterval) {
clearInterval(currentInterval);
currentInterval = undefined;
}
setTimeout( // for first 300ms delay onchange
function () {
player.draw.walkRight();
}, 1);
if(player.x + player.vx < canvas.width - player.padding) {
player.x += player.vx;
} else {
player.x = canvas.width - player.padding;
}
currentInterval = setInterval(
function () {
player.draw.walkRight();
}, 300);
}
});
body {
overflow: hidden;
margin: 0;
padding: 0;
}
<html>
<head>
<title></title>
</head>
<link rel="stylesheet" href="style.css">
<body>
<canvas id="canvas"></canvas>
<div id="images">
<img id="img0" width="77px" height="92px" src="Costumes\WalkLeft\WalkLeft1.jpg" />
<img id="img1" width="77px" height="92px" src="Costumes\WalkLeft\WalkLeft2.jpg" />
<img id="img2" width="77px" height="92px" src="Costumes\WalkRight\WalkRight1.jpg" />
<img id="img3" width="77px" height="92px" src="Costumes\WalkRight\WalkRight2.jpg" />
</div>
<script src="script.js"></script>
</body>
</html>

Work in layers. You put your background layer images in one canvas, your character and enemies in another, then copy the contents of each layer starting from the back, in order, onto a 'buffer' canvas. once that's done, you copy the result onto the visible on-screen canvas. Throw away the buffer (or clear it) at the end of each loop.
If a layer doesn't change, just keep it; if it does, create a new canvas for each frame (or clear the canvas you used). You can create as many layers as you like this way (or as many as you've got memory).

Related

Flickering images with Javascript

I am trying to make a game in Javascript with Repl.it, but every few seconds the player's images flickers. I cannot figure out why this is happening? I am loading some images onto a canvas and it only started flickering once I added in the animate() function and started changing the image. Can someone please explain this? (go to this website to see the flicker and play the game too: https://advanced-chrome-dino-game.isaacroot.repl.co/) My code:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var ground_size = 75;
var up = false;
var game_over = false;
const start_speed = 8;
var score = 0;
function randBetween(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
class Player {
constructor(x_pos) {
this.color = "black";
this.image = "dino_1.png"
this.img = new Image();
this.width = 120;
this.height = 120;
this.x = x_pos;
this.y = c.height - ground_size - this.height;
this.speed = 0;
this.jump_power = 22.5;
this._gravity = 1;
this.an_time = 7;
this.an_count = 0;
}
ground_height() {
return c.height - ground_size - this.height;
}
on_ground() {
if (this.y == this.ground_height()) {
return true;
} else {
return false;
}
}
jump() {
if (this.on_ground()) {
this.speed = this.jump_power;
this.image = "dino_jump.png";
}
}
gravity() {
this.speed -= this._gravity;
}
animate() {
if (this.an_count <= 0) {
if (this.image == "dino_1.png") {
this.image = "dino_2.png";
} else {
if (this.image == "dino_2.png") {
this.image = "dino_1.png"
}
}
this.an_count = this.an_time;
} else {
this.an_count -= 1;
}
}
react() {
this.y -= this.speed
if (this.y > this.ground_height()) {
this.y = this.ground_height();
this.speed = 0;
}
if (this.on_ground() && this.image == "dino_jump.png") {
this.image = "dino_1.png"
}
}
rect() {
return [this.x, this.y, this.width, this.height]
}
}
class Obstacle {
constructor(x_pos, speed) {
this.color = "red";
this.img = new Image();
this.img.src = "cactus_big.png";
this.width = 52 * 1.5;
this.height = 75 * 1.5;
this.x = x_pos;
this.y = c.height - ground_size - this.height;
this.speed = speed;
}
ground_height() {
return c.height - ground_size - this.height;
}
on_ground() {
if (this.y == this.ground_height()) {
return true;
} else {
return false;
}
}
react() {
if (this.x <= 0 - this.width) {
this.x = randBetween(c.width, c.width + 500);
}
this.x -= this.speed;
}
rect() {
return [this.x, this.y, this.width, this.height]
}
}
player = new Player(75);
obstacle1 = new Obstacle(c.width, start_speed);
function inRect(rect1, rect2) {
var rect1_left = rect1[0];
var rect1_right = rect1[0] + rect1[2];
var rect1_top = rect1[1];
var rect1_bottom = rect1[1] + rect1[3];
var rect2_left = rect2[0];
var rect2_right = rect2[0] + rect2[2];
var rect2_top = rect2[1];
var rect2_bottom = rect2[1] + rect2[3];
var horizontal = false;
var vertical = false;
if (rect1_right > rect2_left && rect2_right > rect1_left) {
horizontal = true;
}
if (rect1_bottom > rect2_top && rect2_bottom > rect1_top) {
vertical = true;
}
return (vertical && horizontal);
}
function draw() {
ctx.beginPath();
ctx.fillStyle = "white";
ctx.fillRect(0, 0, c.width, c.height);
ctx.fillStyle = "#4b4b4b";
ctx.fillRect(0, c.height - ground_size, c.width, c.height);
ctx.fillStyle = player.color;
// ctx.fillRect(player.x, player.y, player.width, player.height);
player.img.src = player.image;
ctx.drawImage(player.img, player.x, player.y, player.width, player.height)
ctx.fillStyle = obstacle1.color;
// ctx.fillRect(obstacle1.x, obstacle1.y, obstacle1.width, obstacle1.height);
ctx.drawImage(obstacle1.img, obstacle1.x, obstacle1.y, obstacle1.width, obstacle1.height)
ctx.fillStyle = "black";
ctx.font = "30px Arial";
ctx.fillText("Score: " + Math.round(score / 25).toString(), 20, 50);
if (game_over) {
ctx.font = "80px Arial";
}
ctx.stroke();
}
document.addEventListener('keydown', (event) => {
if (event.key == 'ArrowUp' || event.key == 'Spacebar') {
up = true;
} else if (event.key == 'ArrowDown') {
//pass
}
});
document.addEventListener('keyup', (eventt) => {
if (eventt.key == 'ArrowUp') {
up = false;
} else if (event.key == 'ArrowDown') {
//pass
}
});
function update_speed() {
obstacle1.speed += 0.001;
}
function run() {
if (up == true) {
player.jump()
}
player.gravity();
player.react();
player.animate();
obstacle1.react();
if (inRect(player.rect(), obstacle1.rect())) {
game_over = true
}
score += obstacle1.speed
draw();
update_speed();
if (game_over == false) {
requestAnimationFrame(run);
}
}
run();
I checked the code and I realized you were loading images each time into the player.img variable.
function createImage(path){
let image = new Image();
image.src = path;
return image;
}
var images = {
dino:[
createImage("dino_1.png"),
createImage("dino_2.png"),
createImage("dino_jump.png")
],
cactus:createImage("cactus_big.png")
}
If you use my code here, you need to change the code to use those images instead. Because now, each time you draw, you are loading an image. Like this, all images are stored and I tried it, no more flickering.
Well, all you have to do is have the images get preloaded so your index.html should look like:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Block Runner</title>
<link href="style.css" rel="stylesheet" type="text/css" />
<link rel="preload" href="cactus_big.png" as="image">
<link rel="preload" href="dino_1.png" as="image">
<link rel="preload" href="dino_2.png" as="image">
<link rel="preload" href="dino_jump.png" as="image">
<link rel="preload" href="ground.png" as="image">
</head>
<body>
<canvas id="myCanvas" width="900" height="600" style="border:0px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
<script src="script.js"></script>
</body>
</html>
That should make it so that it doesn't flicker.

Game not iterating, not sure why

I'm trying to make a browser game with pure javascript. I was using codesandbox.io for writing it at first, but the I decided I was done for the day and needed to check if it works in a browser. Lo and behold, it does not. I genuinely have no idea why it's not working.
All the code is supposed to do, is make a square jump. which it does do, however right when you let go of the up key, the page hangs, it won't even refresh. Doesn't crash the browser though. Anyways, here's my code.
class player {
constructor(gameW, gameH) {
this.gameH = gameH;
this.width = 50;
this.heigth = 50;
this.maxUpV = 5;
this.currV = 0;
this.gravConst = 50;
this.position = {
x: 50,
y: 150
};
}
jumpUp() {
this.currV = -this.maxUpV;
}
fall(falling) {
while (this.position.y < 150) {
this.currV = this.maxUpV;
}
return (falling = false);
}
draw(ctx) {
ctx.fillStyle = "#F00";
ctx.fillRect(this.position.x, this.position.y, this.width, this.heigth);
}
update(deltaTime) {
if (!deltaTime) {
return;
}
this.position.y += this.currV;
if (this.position.y + this.heigth > 200) {
this.position.y = 150;
}
}
}
class input {
constructor(Player) {
this.falling = false;
document.addEventListener("keydown", event => {
if (event.keyCode === 38) {
if (!Player.fall(this.falling)) {
Player.jumpUp();
}
}
});
document.addEventListener("keyup", event => {
if (event.keyCode === 38) {
this.falling = true;
Player.fall(this.falling);
}
});
}
}
const GAME_WIDTH = 800;
const GAME_HEIGHT = 300;
var canvas = document.getElementById("gameScreen");
var ctx = canvas.getContext("2d");
var Player = new player(GAME_WIDTH, GAME_HEIGHT);
ctx.clearRect(0, 0, 800, 300);
ctx.fillRect(0, 200, 800, 200);
ctx.fillRect(400, 100, 50, 1);
Player.draw(ctx);
new input(Player);
var lastTime = 0;
function gameLoop(timeStamp) {
var deltaTime = timeStamp - lastTime;
lastTime = timeStamp;
ctx.clearRect(0, 0, 800, 200);
Player.update(deltaTime);
Player.draw(ctx);
requestAnimationFrame(gameLoop);
}
gameLoop();
Oh and also, when I was writing it in codesandbox.io, the classes were separate files that I imported into the main .js file. That gave me an error in the browser, so I just put everything in one file. I tried both Vivaldi and Firefox, to no avail.
I originally misread the question. Your code is locking up in your fall function. Once you hit the max height you were getting stuck in a loop waiting for the fall but never returning control to anywhere that could generate a fall. I'm having some difficulty understanding your max height validation.
The fall function will always return false.
fall(falling) {
while (this.position.y < 150) {
this.currV = this.maxUpV;
}
return (falling = false);
}
The return value of an assignment is the value assigned, so in this case your return value will always be false
I also had to modify the logic for the end button press
if (!Player.fall(this.falling)) {
Player.jumpUp();
}
The conditional was basically always returning true and could be simplified.
I hope this helps!
class player {
constructor(gameW, gameH) {
this.gameH = gameH;
this.width = 50;
this.height = 50;
this.maxUpV = 5;
this.currV = 0;
this.gravConst = 50;
this.position = {
x: 50,
y: 150
};
}
jumpUp() {
this.currV = -this.maxUpV;
}
fall(falling) {
if (this.position.y <150) {
this.currV = this.maxUpV;
return true
}
return false;
}
draw(ctx) {
ctx.fillStyle = "#F00";
ctx.fillRect(this.position.x, this.position.y, this.width, this.height);
}
update(deltaTime) {
if (!deltaTime) {
return;
}
this.position.y += this.currV;
if (this.position.y + this.height > 200) {
this.position.y = 150;
}
}
}
class input {
constructor(Player) {
this.falling = false;
document.addEventListener("keydown", event => {
if (event.keyCode === 38) {
if (!this.falling) {
Player.jumpUp();
}
}
});
document.addEventListener("keyup", event => {
if (event.keyCode === 38) {
this.falling = true;
this.falling = Player.fall();
}
});
}
}
const GAME_WIDTH = 800;
const GAME_HEIGHT = 300;
var canvas = document.getElementById("gameScreen");
var ctx = canvas.getContext("2d");
var Player = new player(GAME_WIDTH, GAME_HEIGHT);
ctx.clearRect(0, 0, 800, 300);
ctx.fillRect(0, 200, 800, 200);
ctx.fillRect(400, 100, 50, 1);
Player.draw(ctx);
new input(Player);
var lastTime = 0;
function gameLoop(timeStamp) {
var deltaTime = timeStamp - lastTime;
lastTime = timeStamp;
ctx.clearRect(0, 0, 800, 200);
Player.update(deltaTime);
Player.draw(ctx);
requestAnimationFrame(gameLoop);
}
gameLoop();
<canvas id="gameScreen" width=400 height=400></canvas>

Alert when the car hits the track in canvas

var car;
var front;
var back;
var img = new Image();
img.src = 'https://cdn4.iconfinder.com/data/icons/transportation-2-4/60/transportation-2-flat-036-racing-car-top-512.png';
function startGame() {
car = new move(12, 20, "red", 600, 300);
pg.start();
}
var pg = {
canvas: document.createElement("canvas"),
start: function() {
this.canvas.width = 1200;
this.canvas.height = 600;
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
this.frameNo = 0;
this.interval = setInterval(updateframe, 20);
window.addEventListener('keydown', function(e) {
e.preventDefault();
pg.keys = (pg.keys || []);
pg.keys[e.keyCode] = (e.type == "keydown");
})
window.addEventListener('keyup', function(e) {
pg.keys[e.keyCode] = (e.type == "keydown");
})
},
stop: function() {
clearInterval(this.interval);
},
clear: function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
}
function move(width, height, color, x, y, type) {
this.type = type;
this.width = width;
this.height = height;
this.speed = 0;
this.angle = 0;
this.moveAngle = 0;
this.x = x;
this.y = y;
this.update = function() {
ctx = pg.context;
ctx.save();
ctx.translate(this.x, this.y);
ctx.rotate(this.angle);
ctx.drawImage(img, this.width / -2, this.height / -2,20,40);
ctx.beginPath();
ctx.moveTo(this.width / -2, this.height / -2);
ctx.lineTo(this.width / -2, 30);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(this.width / -2, 30);
ctx.lineTo(13, (this.height / -2)+40);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(14, (this.height / -2)+40);
ctx.lineTo(14, this.height / -2);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(14, this.height / -2);
ctx.lineTo(this.width / -2, this.height / -2);
ctx.stroke();
ctx.restore();
ctx.beginPath();
ctx.moveTo(300, 150);
ctx.lineTo(600, 800);
ctx.stroke();
}
this.newPos = function() {
this.angle += this.moveAngle * Math.PI / 180;
this.x += this.speed * Math.sin(this.angle);
this.y -= this.speed * Math.cos(this.angle);
}
}
function updateframe() {
pg.clear();
car.moveAngle = 0;
car.speed = 0;
if (pg.keys && pg.keys[37]) {
if (pg.keys && pg.keys[40]) {
car.moveAngle = 5;
}
if (pg.keys && pg.keys[38]) {
car.moveAngle = -5;
}
}
if (pg.keys && pg.keys[39]) {
if (pg.keys && pg.keys[40]) {
car.moveAngle = -5;
}
if (pg.keys && pg.keys[38]) {
car.moveAngle = 5;
}
}
if (pg.keys && pg.keys[38]) {
car.speed = 5;
}
if (pg.keys && pg.keys[40]) {
car.speed = -5;
}
car.newPos();
car.update();
}
startGame();
canvas {
border: 1px solid #d3d3d3;
background-color: #f1f1f1;
}
There is a car and a line, now i want to make an alert whenever the car get touched by the the line.
I know how to do this logically. like if i convert the car image in four lines (border) then use line intersection formula to get if there is a intersection but i am new to this canvas drawing and i cant figure how to get the border line equation of car.
update: i have made lines of border around the car, now i just need help with getting if these lines intersects with each other...
code is updated plz check it now...
one more thing, at this point there is only one line and i am going to add more lines in it... so i need a function to call it more often and get if the lines are intersecting with car border...
Note : use arrow keys to move car in snippet

Error message when using drawimage() on a pushed canvas object, not helped by preloading()

When trying to draw an image on an obstacle in an html canvas game I get this error message: Uncaught InvalidStateError: Failed to execute 'drawimage' on 'CanvasRenderingContext2D': The HTMLImageElement provided is in the 'broken' state.
The obstacle is invisible but the game still stops if the player collides with where it should be. The other stationary obstacles' images in the game are visible. What do I do?
I tried uploading the images in my html as a preload() function but it still doesn't work. Other articles about similar situations do not cover this same context and do not help me who is quite new to programming.
Here is the code:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link rel="stylesheet" type="text/css" href="stylesheet.css"> <link/>
<script>
function preloader()
{
// counter
var i = 0;
// create object
imageObj = new Image();
// set image list
images = new Array();
images[0]="player.jpg"
images[1]="player2.jpg"
images[2]="obstacle.jpg"
images[3]="obstacle2.jpg"
images[3]="obstacle3.jpg"
// start preloading
for(i=0; i<=3; i++)
{
imageObj.src=images[i];
}
}
</script>
</head>
<body onload="startGame(), preloader()">
<h2> My Lost Game </h2>
<p>Press the 'up', 'down', 'left' and 'right' keys on your keyboard to move. Avoid the obstacles and reach the goal.</p><br>
<p></p>
<script>
var myObstacle = [];
function startGame() {
myGameArea.start();
myGameGoal = new component(75, 95, "player2.jpg", 710, 215, "image");
myGamePiece = new component(75, 95, "player.jpg", 10, 215, "image");
myObstacle2 = new component (110, 150, "obstacle2.jpg", 350, 0, "image");
myObstacle3 = new component (110, 150, "obstacle3.jpg", 530, 350, "image");
}
var myGameArea = {
canvas : document.createElement("canvas"),
start : function() {
this.canvas.width = 800;
this.canvas.height = 500;
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[4]);
this.frameNo = 0;
this.interval = setInterval(updateGameArea, 20);
window.addEventListener('keydown', function (e) {
myGameArea.keys = (myGameArea.keys || []);
myGameArea.keys[e.keyCode] = true;
})
window.addEventListener('keyup', function (e) {
myGameArea.keys[e.keyCode] = false;
})
},
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, type) {
this.type = type;
if (type == "image") {
this.image = new Image();
this.image.src = color;
}
this.width = width;
this.height = height;
this.x = x;
this.y = y;
this.update = function() {
ctx = myGameArea.context;
if (type == "image") {
ctx.drawImage(this.image,
this.x,
this.y,
this.width, this.height);
} else {
ctx.fillStyle = color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
}
this.newPos = function() {
this.x += this.speedX;
this.y += this.speedY;
}
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 updateGameArea() {
var x, y;
for (i = 0; i < myObstacle.length; i += 1) {
if (myGamePiece.crashWith(myObstacle[i])) {
myGameArea.stop();
return;
}
}
myGameArea.clear();
myGameArea.frameNo += 1;
if (myGameArea.frameNo == 1 || everyinterval(150)) {
x = 200;
y = 300;
myObstacle.push(new component(110, 150, "obstacle1.jpg", x, y, "image"));
}
for (i = 0; i < myObstacle.length; i += 1) {
myObstacle[i].y += -1;
myObstacle[i].update();
}
myGameArea.clear();
myGamePiece.speedX = 0;
myGamePiece.speedY = 0;
if (myGameArea.keys && myGameArea.keys[37]) {myGamePiece.speedX = -3; }
if (myGameArea.keys && myGameArea.keys[39]) {myGamePiece.speedX = 3; }
if (myGameArea.keys && myGameArea.keys[38]) {myGamePiece.speedY = -3; }
if (myGameArea.keys && myGameArea.keys[40]) {myGamePiece.speedY = 3; }
myObstacle2.update();
myObstacle3.update();
myGameGoal.update();
myGamePiece.newPos();
myGamePiece.update();
}
function everyinterval(n) {
if ((myGameArea.frameNo / n) % 1 == 0) {return true;}
return false;
}
</script>
</body>
</html>
You need to create a separate image object for each image
The code below loads images from an array of image URLs and returns an array of images in the same order as the URL names
var loading = 0; // number of images still loading
function preloader(imageURLs){
// function creates and loads an image
function createImage(url){
loading += 1; // count up when loading images
const image = new Image;
image.src = url;
image.onload = () => loading -= 1; // count down when loaded
return image;
}
const images = imageURLs.map(createImage);
return images;
}
const imageList = preloader(["player.jpg", "player2.jpg", "obstacle3.jpg"]);
// at this point loading greater than zero
When loading is 0 you know all images have loaded
Thus in your render loop
function mainLoop(){
if(loading === 0){ // all images have loaded
ctx.drawImage(imageList[0],0,0); // draw first image
ctx.drawImage(imageList[1],0,0); // draw second image
ctx.drawImage(imageList[2],0,0); // draw third image
}
requestAnimationFrame(mainLoop);
}
requestAnimationFrame(mainLoop);
Or you can have it call a function when all loaded
var loading = 0; // number of images still loading
function preloader(imageURLs, callback){
// function creates and loads an image
function createImage(url, callback){
loading += 1; // count up when loading images
const image = new Image;
image.src = url;
image.onload = () => {
loading -= 1; // count down when loaded
if(loading === 0){ // all done
callback(); // call callback
}
}
return image;
}
const images = imageURLs.map(createImage);
return images;
}
function start(){ // function to start main loop when images have loaded
requestAnimationFrame(mainLoop);
}
// second argument is the callback function that is called when all images have loaded
const imageList = preloader(["player.jpg", "player2.jpg", "obstacle3.jpg"], start);
function mainLoop(){
ctx.drawImage(imageList[0],0,0); // draw first image
ctx.drawImage(imageList[1],0,0); // draw second image
ctx.drawImage(imageList[2],0,0); // draw third image
requestAnimationFrame(mainLoop);
}

Trouble Displaying Canvas in Basic HTML Canvas Game

I am trying to create a basic HTML game using the Canvas element, but I am having trouble with it. Unfortunately, I don't know where the error is in my code, so I have posted the entirety of the document I'm working on below.
My problem: The canvas is not displaying when I run the HTML document.
This code's based off of (as in it pretty much is) the Movement tutorial from w3schools for using the Canvas, available at https://www.w3schools.com/graphics/tryit.asp?filename=trygame_movement_keyboard, but when chaing variable names I must've broken something, because after looking at this for hours I can't figure out what I'm missing.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<style>
canvas {
border:1px solid #d3d3d3;
background-color: #f1f1f1;
}
</style>
</head>
<body onload = "initial()">
<script>
var playerOne;
function initial() {
playerOne = new canvasObject(30, 30, "red", 225, 225);
gameArea.start();
}
var gameArea = {
canvas : document.createElement("canvas");
start : function() {
this.canvas.width = 480;
this.canvas.height = 270;
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
this.frameNo = 0;
this.interval = setInterval(updateGameArea, 20);
window.addEventListener('keydown', function (e) {
e.preventDefault();
gameArea.keys = (gameArea.keys || []);
gameArea.keys[e.keyCode] = (e.type == "keydown");
})
window.addEventListener('keyup', function (e) {
gameArea.keys[e.keyCode] = (e.type == "keydown");
})
},
stop : function() {
clearInterval(this.interval);
},
clear : function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
}
function canvasObject(width, height, color, x, y, type)
{
this.type = type;
this.width = width;
this.height = height;
this.speed = 0;
this.angle = 0;
this.moveAngle = 0;
this.x = x;
this.y = y;
this.update = function() {
ctx = gameArea.context;
ctx.save();
ctx.translate(this.x, this.y);
ctx.rotate(this.angle);
ctx.fillStyle = color;
ctx.fillRect(this.width / -2, this.height / -2, this.width, this.height);
ctx.restore();
}
this.newPos = function() {
this.angle += this.moveAngle * Math.PI / 180;
this.x += this.speed * Math.sin(this.angle);
this.y -= this.speed * Math.cos(this.angle);
}
}
function updateGameArea() {
gameArea.clear();
playerOne.moveAngle = 0;
playerOne.speed = 0;
if (gameArea.keys && gameArea.keys[37]) {
playerOne.moveAngle = -1;
}
if (gameArea.keys && gameArea.keys[39]) {
playerOne.moveAngle = 1;
}
if (gameArea.keys && gameArea.keys[38]) {
playerOne.speed= 1;
}
if (gameArea.keys && gameArea.keys[40]) {
playerOne.speed= -1;
}
playerOne.newPos();
playerOne.update();
}
</script>
</body>
</html>
gameArea is an object. Object properties are separated with ,, not ;. Hence, there is a syntax error after the definition of canvas.
var playerOne;
function initial() {
playerOne = new canvasObject(30, 30, "red", 225, 225);
gameArea.start();
}
var gameArea = {
canvas : document.createElement("canvas"),
start : function() {
this.canvas.width = 480;
this.canvas.height = 270;
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
this.frameNo = 0;
this.interval = setInterval(updateGameArea, 20);
window.addEventListener('keydown', function (e) {
e.preventDefault();
gameArea.keys = (gameArea.keys || []);
gameArea.keys[e.keyCode] = (e.type == "keydown");
})
window.addEventListener('keyup', function (e) {
gameArea.keys[e.keyCode] = (e.type == "keydown");
})
},
stop : function() {
clearInterval(this.interval);
},
clear : function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
}
function canvasObject(width, height, color, x, y, type)
{
this.type = type;
this.width = width;
this.height = height;
this.speed = 0;
this.angle = 0;
this.moveAngle = 0;
this.x = x;
this.y = y;
this.update = function() {
ctx = gameArea.context;
ctx.save();
ctx.translate(this.x, this.y);
ctx.rotate(this.angle);
ctx.fillStyle = color;
ctx.fillRect(this.width / -2, this.height / -2, this.width, this.height);
ctx.restore();
}
this.newPos = function() {
this.angle += this.moveAngle * Math.PI / 180;
this.x += this.speed * Math.sin(this.angle);
this.y -= this.speed * Math.cos(this.angle);
}
}
function updateGameArea() {
gameArea.clear();
playerOne.moveAngle = 0;
playerOne.speed = 0;
if (gameArea.keys && gameArea.keys[37]) {
playerOne.moveAngle = -1;
}
if (gameArea.keys && gameArea.keys[39]) {
playerOne.moveAngle = 1;
}
if (gameArea.keys && gameArea.keys[38]) {
playerOne.speed= 1;
}
if (gameArea.keys && gameArea.keys[40]) {
playerOne.speed= -1;
}
playerOne.newPos();
playerOne.update();
}
canvas {
border:1px solid #d3d3d3;
background-color: #f1f1f1;
}
<body onload = "initial()">
You have a syntax error:
var gameArea = {
canvas : document.createElement("canvas");
...
}
You've used ; instead of ,

Categories