Laggy movement with canvas game - javascript

Hey guys not entirely sure what I'm doing wrong. I've played a few HTML5 games and they've seem to suffer from a different issue. The drawing lags behind the movement and it looks weird. This doesn't seem to be the case here.
In my game the drawing seems fine, but it lags like every second as he moves.(movement is arrow keys). It does it without arrow keys also, if I set him up to move automatically, so I don't think it's a key detection issue.
It's almost as if the garbage collector is running every second. I don't think I'm spewing out that many objects though.
I'm using Chrome 21 (MacOSX) and also Firefox 14.
http://tempdrew.dreamhosters.com/spine/
Here is the js fiddle with relevant code.
http://jsfiddle.net/ju3ag/
This is fine on chrome canary. I don't know if it's just because the javascript is so much faster in canary then standard chrome. It's terrible in latest Firefox. I'm not sure what I'm doing wrong. I'm updating movement based on time. If I take that out though it's still bad.
I'm just wondering if anything will stand out to anyone. Thanks for any help.
sg = Class.extend({
});
sg.entities = [];
sg.buttonStates = [];
sg.createEntity = function (entity) {
this.entities.push(entity);
};
window.requestAnimFrame = (function () {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function (callback, element) {
window.setTimeout(callback, 1000 / 60);
};
})();
(function defineUtil() {
sg.util = {};
sg.util.getRandomInt = function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
};
sg.util.getRandomNumber = function getRandomNumber(min, max) {
return Math.random() * (max - min) + min;
};
})();
/*************************/
(function createEntity() {
var Entity = Class.extend({
init: function (x, y) {
this.name = 'Entity';
this.health = 100;
this.pos = {
x: x,
y: y
};
this.vel = {
x: 0,
y: 0
};
this.accel = {
x: 0,
y: 0
}
console.log(this.name + ' created ' + x + ' ' + y);
},
update: function (elapsed) {
},
draw: function (ctx) {
}
});
sg.Entity = Entity;
})();
/************************/
// -- player.js
(function createPlayer() {
var Player = sg.Entity.extend({
x: 0,
y: 0,
moveLeft: false,
moveRight: false,
speed : 5,
init: function (x, y) {
this.x = x;
this.y = y;
this.name = 'Player';
},
draw: function (ctx) {
var x = this.x,
y = this.y;
ctx.beginPath();
ctx.rect(x, y, 40, 50);
ctx.fillStyle = 'white';
ctx.fill();
ctx.lineWidth = .5;
ctx.strokeStyle = 'rgba(0,0,0,.3)';
ctx.stroke();
ctx.fillStyle = 'rgba(0,0,0,.5)';
ctx.fillRect(x + 25, y + 15, 5, 5);
},
update: function (elapsed) {
var distance = (60 / 1000) * elapsed;
if (this.moveLeft) {
this.x += this.speed * distance;
} else if (this.moveRight) {
this.x -= this.speed * distance;
}
},
keyDown: function (e) {
if (e.keyCode === 39) {
this.moveLeft = true;
} else if (e.keyCode === 37) {
this.moveRight = true;
} else {
this.moveLeft = false;
this.moveRight = false;
}
},
keyUp: function (e) {
if (e.keyCode === 39) {
this.moveLeft = false;
} else if (e.keyCode === 37) {
this.moveRight = false;
}
}
});
sg.Player = Player;
})();
/**********************************/
(function createGame() {
var Game = Class.extend({
canvas: null,
context: null,
width: null,
height: null,
init: function (width, height) {
this.canvas = document.getElementById('canvas');
this.context = this.canvas.getContext('2d');
this.width = width || 800;
this.height = height || 600;
this.canvas.width = this.width;
this.canvas.height = this.height;
},
clear: function () {
this.context.clearRect(0, 0, this.width, this.height);
},
draw: function () {
this.clear();
for (var i = 0; i < sg.entities.length; i++) {
sg.entities[i].draw(this.context);
}
},
update: function (elapsed) {
for (var i = 0; i < sg.entities.length; i++) {
sg.entities[i].update(elapsed);
}
},
keyDown: function (e) {
for (var i = 0; i < sg.entities.length; i++) {
if (typeof sg.entities[i].keyDown === 'function') {
sg.entities[i].keyDown(e);
}
}
},
keyUp: function (e) {
for (var i = 0; i < sg.entities.length; i++) {
if (typeof sg.entities[i].keyUp === 'function') {
sg.entities[i].keyUp(e);
}
}
}
});
sg.Game = Game;
var game = sg.currentGame = new sg.Game(800, 600);
var player = new sg.Player(200, 459);
sg.createEntity(player);
function update(elapsed) {
game.update(elapsed);
}
var lastUpdate = Date.now();
function draw() {
var now = Date.now();
var elapsed = (now - lastUpdate);
lastUpdate = now;
game.draw();
update(elapsed);
requestAnimFrame(draw);
}
window.addEventListener('keydown', sg.currentGame.keyDown, false);
window.addEventListener('keyup', sg.currentGame.keyUp, false);
draw();
})();

The keydown/keyup events are waiting a little bit of time between one and another press.
Here is how I solved on my case (not sure if that's exactly your problem); adding a setInterval that every 20ms checks if there are key downs (more than one for diagonal movements).
var keys = {};
$(document).bind('keyup', function(e){
delete keys[e.which];
});
$(document).bind('keydown', function(e){
keys[e.which] = true;
});
setInterval(keyEvent, 20);
function keyEvent(){
for(var idKeyPressed in keys){
switch(idKeyPressed){
case "87": // "W" key; Move to the top
// Do something
break;
}
}
}
Hope that helps :)

Related

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>

Video Game Score Issues

Currently I am creating a Javascript game. I have successfully created all the game pieces and how my game's basic functions should work. However, I am having 2 issues that I can't seem to solve, and I've looked for a few weeks now trying to figure out how to do it. I can't figure out how to get the game to result in a gameover if my player gets pushed of falls off screen. Also, I am unsure on how I can get the score to continously increase for as long as the player is still "alive". If anyone can either demonstrate how to do these things or point me in the direction of a tutorial or article on how to do it it would be very helpful.
(function() {
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
window.requestAnimationFrame = requestAnimationFrame;
})();
const seeded = (() => {
var seed = 1;
return {
max: 2576436549074795,
reseed(s) {
seed = s
},
random() {
return seed = ((8765432352450986 * seed) + 8507698654323524) % this.max
},
}
})();
const randSeed = (seed) => seeded.reseed(seed);
const randSI = (min, max = min + (min = 0)) => (seeded.random() % (max - min)) + min;
const randS = (min, max = min + (min = 0)) => (seeded.random() / seeded.max) * (max - min) + min;
randSeed(100); // seed the random generators
function Player(color, keymap, x) {
this.x = (typeof x === 'undefined') ? 1 : x;
this.y = 7;
this.width = 15;
this.height = 15;
this.speed = 10;
this.velX = 0;
this.velY = 0;
this.jumping = false;
this.keymap = {}
for (let key in keymap) {
switch (keymap[key]) {
case 'jump':
this.keymap[key] = this.jump
break;
case 'left':
this.keymap[key] = this.moveLeft
break;
case 'right':
this.keymap[key] = this.moveRight
break;
}
}
this.color = color;
} // Player()
Player.prototype.jump = function() {
if (!this.jumping) {
this.jumping = true;
this.velY = -this.speed * 1.5;
}
}
Player.prototype.moveRight = function() {
if (this.velX < this.speed) {
this.velX++;
}
}
Player.prototype.moveLeft = function() {
if (this.velX > -this.speed) {
this.velX--;
}
}
// Globals
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
width = 700,
height = 600,
keys = [],
friction = .9,
gravity = .9;
canvas.width = width;
canvas.height = height;
// Set up players
var players = [];
players.push(new Player('purple', {
32: 'jump',
37: 'left',
38: 'jump',
39: 'right'
}))
/*players.push(new Player('yellow', {
56: 'jump',
52: 'left',
54: 'right'
}, width-25))*/
players.push(new Player('blue', {
87: 'jump',
65: 'left',
68: 'right'
}, (width-25)/2))
function update() {
ctx.clearRect(0, 0, width, height);
addPlatformsToBottom(); // will add platforms if needed
drawPlatforms();
players.forEach(player => {
// check player-specific keys
for (let i in player.keymap) {
if (keys[i] && typeof player.keymap[i] === 'function')
player.keymap[i].bind(player)();
}
player.velX *= friction;
player.velY += gravity;
player.x += player.velX;
player.y += player.velY;
if (player.x >= width - player.width) {
player.x = width - player.width;
} else if (player.x <= 0) {
player.x = 0;
}
if (player.y >= height - player.height) {
player.y = height - player.height;
player.jumping = false;
player.velY = 0;
}
testPlayerForPlatforms(player);
ctx.fillStyle = player.color;
ctx.fillRect(player.x, player.y, player.width, player.height);
}) // player.forEach
requestAnimationFrame(update);
}
document.body.addEventListener("keydown", function(e) {
// console.log(e.keyCode);
keys[e.keyCode] = true;
});
document.body.addEventListener("keyup", function(e) {
keys[e.keyCode] = false;
});
window.addEventListener("load", function() {
update();
});
function testPlayerForPlatforms(player) {
player.hitPlatform = false; // reset platform hit flag
for (var i = 0; i < platforms.length; i++) {
var p = platforms[i];
if (p.active) {
testPlayer(player, p);
if (player.hitPlatform) {
break; // stop search as player has hit a platform
}
}
}
}
function drawPlatforms() { // draws all platforms and move up
platformInfo.lastPlatformY += platformInfo.speed;
for (var i = 0; i < platforms.length; i++) {
var p = platforms[i];
if (p.active) {
p.yPos += platformInfo.speed;
if (p.yPos + p.height < 0) { // platform above top
p.active = false; // turn it off
} else {
p.draw();
}
}
}
}
function addPlatformsToBottom() {
while (platformInfo.lastPlatformY < ctx.canvas.height) {
generateLevel();
}
}
// some constants and vars to control random generation of platforms
const platformInfo = {
speed: -2.5,
height: 8, // platform height
minLength: 100, // in pixels
maxLength: 300,
vertSpacing: 100, // distance between platforms
minHorSpacing: 50, // should be larger than player
maxHorSpacing: 80,
lastPlatformY: 100, // y position of last platform created
maxHoleCount: 3,
color: "#FFF",
}
// array object holds platforms
const platforms = [];
// a platform template object that will be used to create platforms from
const platform = {
left: 0,
right: 0,
yPos: 0,
height: 0, // thickness
active: false, // true if platform in use
color: "#F84",
draw() { // function to draw the platform
ctx.fillStyle = this.color;
ctx.fillRect(this.left, this.yPos, this.right - this.left, this.height);
},
init(left, right, yPos) { // function to initialize
// alias to save typing.
const pI = platformInfo
this.yPos = yPos;
this.left = left;
this.right = right;
this.height = pI.height;
this.color = pI.color;
this.active = true;
},
}
// function adds platforms to array. If no inactive platforms a
// new one is created
function addPlatform() {
var platform;
for (var i = 0; i < platforms.length; i++) {
if (!platforms[i].active) { // is the platform inactive
platform = platforms[i];
break; // stop searching
}
}
if (!platform) { // if no inactive platform then create a new one
platform = createPlatform();
platforms.push(platform);
}
return platform;
}
// a function to create a platform object
function createPlatform(customProps = {}) { // custom props can be used to modify the
// platform in future. For now it just defaults to empty
return Object.assign({}, platform, customProps);
}
// creates a set of platforms for a single level
function generateLevel() {
var numHoles = randSI(1, platformInfo.maxHoleCount);
var spacing = ctx.canvas.width / (numHoles); // get spacing
var ypos = platformInfo.lastPlatformY;
platformInfo.lastPlatformY += platformInfo.vertSpacing;
var left = 0; // the starting left edge
for (var i = 1; i <= numHoles; i++) { // create numHoles
var platform = addPlatform();
var holeOffset = randSI(-spacing, 0);
platform.init(left, spacing * i + holeOffset, ypos);
left = spacing * i + holeOffset + randSI(platformInfo.minHorSpacing, platformInfo.maxHorSpacing);
}
// add the last platform
platform = addPlatform();
platform.init(left, ctx.canvas.width, ypos);
}
function testPlayer(player, platform) {
var p, pl; // p for player, pl for platform
p = player;
pl = platform;
// is the player above or below platform
if (!(p.x + p.width < pl.left || p.x > pl.right)) { // yes
if (p.velY > 0 && p.y < pl.yPos) { // is player moving down and above platform
if (p.y + p.height > pl.yPos) { //is bottom of player below top of platform
// must have hit platform
p.jumping = false;
p.y = pl.yPos - p.height; // move player so that it is on the platform
p.velY = 0;
p.hitPlatform = true; // flag a platform has been hit
}
} else if (p.y + p.height > pl.yPos + pl.height) { // player must be moving up so check if below platform
if (p.y < pl.yPos + pl.height) { // is top of player above bottom of platform
// must have hit head on platform
p.velY = 0;
p.y = pl.yPos + pl.height;
p.jumping = false;
p.hitPlatform = true; // flag a platform has been hit
}
}
}
}
#score {
color:white;
font-size:35px;
}
0<html>
<head>
<title>Square Stairs™</title>
</head>
<body bgcolor="#000">
<div id="score">SCORE:</div>
<br><br><br> <!-- line breaks to move canvas away from SO title bar that gets in the way when switching to full page mode -->
<canvas id="canvas" style="border:3px solid #fff"></canvas>
</body>
</html>
This is my code as it stands currently. I made on the websiteCodePenand this is my original code. I have nothing to do with Unity or any other coding platform so if you have any information on how to solve this it has to be able to run on the CodePen website. Thank you for your assistance.
I've added code to your code, look for ////////////////////
I added the following to your source code:
Added the functions checkPlayerBounds(player) and addToScore(x)
checkPlayerBounds(player) checks if player has been pushed/fell off the screen.
Note: You need to add more functionality here to have the Game Over do what you want.
addToScore(x) increases the score variable and the Score HTML element if scoreShouldUpdate is true.
Added global variables updates, score, and scoreShouldUpdate.
updates keeps track of how many times the update() function has been called.
score keeps track of the games score.
Added code inside your update() function.
The first bit keeps adding to the score, but only after the game has been updated a specified amount of times.
The next bit calls the checkPlayerBounds function on every player.
This all works, the only problem is that the player starts off/right on the edge of the screen, so the score won't update until that is changed in your project.
(function() {
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
window.requestAnimationFrame = requestAnimationFrame;
})();
const seeded = (() => {
var seed = 1;
return {
max: 2576436549074795,
reseed(s) {
seed = s
},
random() {
return seed = ((8765432352450986 * seed) + 8507698654323524) % this.max
},
}
})();
const randSeed = (seed) => seeded.reseed(seed);
const randSI = (min, max = min + (min = 0)) => (seeded.random() % (max - min)) + min;
const randS = (min, max = min + (min = 0)) => (seeded.random() / seeded.max) * (max - min) + min;
randSeed(100); // seed the random generators
///////////////////////////
// This function increases the score by 'x' amount.
///////////////////////////
function addToScore(x){
if(scoreShouldUpdate){
score += x;
var scoreElement = document.getElementById("score");
scoreElement.innerHTML = "Score: " + score;
}
}
function checkPlayerBounds(player){
if(player.y >= 0){
scoreShouldUpdate = false;
// Insert game over stuff here.
}
}
function Player(color, keymap, x) {
this.x = (typeof x === 'undefined') ? 1 : x;
this.y = 7;
this.width = 15;
this.height = 15;
this.speed = 10;
this.velX = 0;
this.velY = 0;
this.jumping = false;
this.keymap = {}
for (let key in keymap) {
switch (keymap[key]) {
case 'jump':
this.keymap[key] = this.jump
break;
case 'left':
this.keymap[key] = this.moveLeft
break;
case 'right':
this.keymap[key] = this.moveRight
break;
}
}
this.color = color;
} // Player()
Player.prototype.jump = function() {
if (!this.jumping) {
this.jumping = true;
this.velY = -this.speed * 1.5;
}
}
Player.prototype.moveRight = function() {
if (this.velX < this.speed) {
this.velX++;
}
}
Player.prototype.moveLeft = function() {
if (this.velX > -this.speed) {
this.velX--;
}
}
// Globals
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
width = 700,
height = 600,
keys = [],
friction = .9,
gravity = .9;
//////////////////////////////
//New variables for score increase
//////////////////////////////
var updates = 0;
var score = 0;
var scoreShouldUpdate = true;
canvas.width = width;
canvas.height = height;
// Set up players
var players = [];
players.push(new Player('purple', {
32: 'jump',
37: 'left',
38: 'jump',
39: 'right'
}))
/*players.push(new Player('yellow', {
56: 'jump',
52: 'left',
54: 'right'
}, width-25))*/
players.push(new Player('blue', {
87: 'jump',
65: 'left',
68: 'right'
}, (width-25)/2))
function update() {
/////////////////////////////////////
// You can change the '5' to something else to change the rate of which score is increased.
/////////////////////////////////////
if(updates == 5){
updates = 0;
addToScore(1);
}
updates++;
ctx.clearRect(0, 0, width, height);
addPlatformsToBottom(); // will add platforms if needed
drawPlatforms();
players.forEach(player => {
// check player-specific keys
for (let i in player.keymap) {
if (keys[i] && typeof player.keymap[i] === 'function')
player.keymap[i].bind(player)();
}
player.velX *= friction;
player.velY += gravity;
player.x += player.velX;
player.y += player.velY;
if (player.x >= width - player.width) {
player.x = width - player.width;
} else if (player.x <= 0) {
player.x = 0;
}
if (player.y >= height - player.height) {
player.y = height - player.height;
player.jumping = false;
player.velY = 0;
}
testPlayerForPlatforms(player);
ctx.fillStyle = player.color;
ctx.fillRect(player.x, player.y, player.width, player.height);
//My code
checkPlayerBounds(player);
}) // player.forEach
requestAnimationFrame(update);
}
document.body.addEventListener("keydown", function(e) {
// console.log(e.keyCode);
keys[e.keyCode] = true;
});
document.body.addEventListener("keyup", function(e) {
keys[e.keyCode] = false;
});
window.addEventListener("load", function() {
update();
});
function testPlayerForPlatforms(player) {
player.hitPlatform = false; // reset platform hit flag
for (var i = 0; i < platforms.length; i++) {
var p = platforms[i];
if (p.active) {
testPlayer(player, p);
if (player.hitPlatform) {
break; // stop search as player has hit a platform
}
}
}
}
function drawPlatforms() { // draws all platforms and move up
platformInfo.lastPlatformY += platformInfo.speed;
for (var i = 0; i < platforms.length; i++) {
var p = platforms[i];
if (p.active) {
p.yPos += platformInfo.speed;
if (p.yPos + p.height < 0) { // platform above top
p.active = false; // turn it off
} else {
p.draw();
}
}
}
}
function addPlatformsToBottom() {
while (platformInfo.lastPlatformY < ctx.canvas.height) {
generateLevel();
}
}
// some constants and vars to control random generation of platforms
const platformInfo = {
speed: -2.5,
height: 8, // platform height
minLength: 100, // in pixels
maxLength: 300,
vertSpacing: 100, // distance between platforms
minHorSpacing: 50, // should be larger than player
maxHorSpacing: 80,
lastPlatformY: 100, // y position of last platform created
maxHoleCount: 3,
color: "#FFF",
}
// array object holds platforms
const platforms = [];
// a platform template object that will be used to create platforms from
const platform = {
left: 0,
right: 0,
yPos: 0,
height: 0, // thickness
active: false, // true if platform in use
color: "#F84",
draw() { // function to draw the platform
ctx.fillStyle = this.color;
ctx.fillRect(this.left, this.yPos, this.right - this.left, this.height);
},
init(left, right, yPos) { // function to initialize
// alias to save typing.
const pI = platformInfo
this.yPos = yPos;
this.left = left;
this.right = right;
this.height = pI.height;
this.color = pI.color;
this.active = true;
},
}
// function adds platforms to array. If no inactive platforms a
// new one is created
function addPlatform() {
var platform;
for (var i = 0; i < platforms.length; i++) {
if (!platforms[i].active) { // is the platform inactive
platform = platforms[i];
break; // stop searching
}
}
if (!platform) { // if no inactive platform then create a new one
platform = createPlatform();
platforms.push(platform);
}
return platform;
}
// a function to create a platform object
function createPlatform(customProps = {}) { // custom props can be used to modify the
// platform in future. For now it just defaults to empty
return Object.assign({}, platform, customProps);
}
// creates a set of platforms for a single level
function generateLevel() {
var numHoles = randSI(1, platformInfo.maxHoleCount);
var spacing = ctx.canvas.width / (numHoles); // get spacing
var ypos = platformInfo.lastPlatformY;
platformInfo.lastPlatformY += platformInfo.vertSpacing;
var left = 0; // the starting left edge
for (var i = 1; i <= numHoles; i++) { // create numHoles
var platform = addPlatform();
var holeOffset = randSI(-spacing, 0);
platform.init(left, spacing * i + holeOffset, ypos);
left = spacing * i + holeOffset + randSI(platformInfo.minHorSpacing, platformInfo.maxHorSpacing);
}
// add the last platform
platform = addPlatform();
platform.init(left, ctx.canvas.width, ypos);
}
function testPlayer(player, platform) {
var p, pl; // p for player, pl for platform
p = player;
pl = platform;
// is the player above or below platform
if (!(p.x + p.width < pl.left || p.x > pl.right)) { // yes
if (p.velY > 0 && p.y < pl.yPos) { // is player moving down and above platform
if (p.y + p.height > pl.yPos) { //is bottom of player below top of platform
// must have hit platform
p.jumping = false;
p.y = pl.yPos - p.height; // move player so that it is on the platform
p.velY = 0;
p.hitPlatform = true; // flag a platform has been hit
}
} else if (p.y + p.height > pl.yPos + pl.height) { // player must be moving up so check if below platform
if (p.y < pl.yPos + pl.height) { // is top of player above bottom of platform
// must have hit head on platform
p.velY = 0;
p.y = pl.yPos + pl.height;
p.jumping = false;
p.hitPlatform = true; // flag a platform has been hit
}
}
}
}
#score {
color:white;
font-size:35px;
}
<html>
<head>
<title>Square Stairs™</title>
</head>
<body bgcolor="#000">
<div id="score">SCORE:</div>
<br><br><br> <!-- line breaks to move canvas away from SO title bar that gets in the way when switching to full page mode -->
<canvas id="canvas" style="border:3px solid #fff"></canvas>
</body>
</html>

JavaScript canvas element doesn't display after canvas clear

I have start develop small JavaScript game with canvas.
So i need to display multiple cards in the canvas.
But i seems, after i use gameArea.clear(); method within updateGameArea() function one card isn't display. But without using that gameArea.clear(); method those cards are displaying well. But i need multiple cards.
Here my JavaScript code
var cards = [];
var selectedCards = [];
var select = true;
window.addEventListener('DOMContentLoaded', function () {
startGame();
});
function startGame() {
cards.push(new PlayingCard("blue", 5, 150, 10));
cards.push(new PlayingCard("red", 1, 10, 10));
gameArea.click();
gameArea.start();
}
var gameArea = {
canvas: document.createElement("canvas"),
start: function () {
this.canvas.width = window.innerWidth;
this.canvas.height = window.innerHeight;
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
this.interval = setInterval(updateGameArea, 100);
},
click: function () {
this.canvas.addEventListener('click', getPosition);
},
clear: function () {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
};
function getPosition(e) {
var top = this.offsetTop;
var left = this.offsetLeft;
var x = e.pageX - left;
var y = e.pageY - top;
cards.forEach(function (card) {
if (y > card.y && y < card.y + card.height && x > card.x && x < card.x + card.width) {
card.selected = select;
if (selectedCards.length < 2) {
selectedCards.push(card);
} else {
selectedCards = [];
selectedCards.push(card);
}
if (selectedCards.length === 2) {
selectedCards.forEach(function (selected_card) {
selected_card.x = 400;
if (selected_card.selected === select) {
console.log(selected_card);
}
});
}
}
});
}
function PlayingCard(color, value, x, y) {
this.color = function () {
if (color === 'red') {
return "#E53935";
} else if (color === 'blue') {
return "#0D47A1";
} else {
throw new Error("No Color Code Found!");
}
};
this.value = value;
this.width = 120;
this.height = 160;
this.x = x;
this.y = y;
this.selected = false;
this.update = function () {
var ctx = gameArea.context;
ctx.fillStyle = this.color();
ctx.shadowBlur = 8;
ctx.shadowColor = 'rgba(0, 0, 0, 0.5)';
ctx.fillRect(this.x, this.y, this.width, this.height);
};
}
function updateGameArea() {
cards.forEach(function (card) {
gameArea.clear();
card.update();
});
}
You are calling gameAera.clear() each time you draw a card. So this is why only the last card is displayed.
function updateGameArea() {
gameArea.clear(); // Move the gameArea.clear(); here
cards.forEach(function (card) {
card.update();
});
}

Javascript Html5 canvas problems

This is a game I am making. I cant figure out why it is not working. I have the JS fiddle here http://jsfiddle.net/aa68u/4/
// Create the canvas
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = 512;
canvas.height = 480;
document.body.appendChild(canvas);
// Background image
var bgReady = false;
var bgImage = new Image();
bgImage.onload = function () {
bgReady = true;
};
bgImage.src = "http://6269-9001.zippykid.netdna-cdn.com/wp-content/uploads/2013/11/Woods-Wallpaper.jpg";
// Ship image
var shipReady = false;
var shipImage = new Image();
shipImage.onload = function () {
shipImage = true;
};
shipImage.src = "http://s29.postimg.org/3widtojzn/hero.png";
// Astroid image
var astroidReady = false;
var astroidImage = new Image();
astroidImage.onload = function () {
astroidReady = true;
};
astroidImage.src = "http://s29.postimg.org/4r4xfprub/monster.png";
// Game objects
var ship = {
speed: 256;
};
var astroid = {};
var health = 100;
window.keyStates = {};
addEventListener('keydown', function (e) {
keyStates[e.keyCode || e.key] = true;
e.preventDefault();
e.stopPropagation();
}, true);
addEventListener('keyup', function (e) {
keyStates[e.keyCode || e.key] = false;
e.preventDefault();
e.stopPropagation();
}, true);
var reset = function () {
astroid.width = 10;
astroid.height = 10;
astroid.x = 32 + (Math.random() * (canvas.width - 64));
astroid.y = 32 + (Math.random() * (canvas.height - 64));
ship.speed = 256;
for (var p in keyStates) keyStates[p]= false;
};
// Update game objects
function update (modifier) {
if (keyStates[38] ==true) { // Player holding up
astroid.x -= ship.speed * modifier;
}
if (keyStates[40]==true) { // Player holding down
astroid.x += ship.speed * modifier;
}
if (keyStates[37]==true) { // Player holding left
astroid.y -= ship.speed * modifier;
}
if (keyStates[39]==true) { // Player holding right
astroid.y += ship.speed * modifier;
}
if (astroid.width) < 200{
astroid.width +=10;
astroid.height += 10;
}
if (astroid.width) > 200{
reset();
}
// Are they touching?
if (keyStates[32] == true && ship.x <= (astroid.x + 32) && astroid.x <= (ship.x + 32) && ship.y <= (astroid.y + 32) && astroid.y <= (ship.y + 32)) {
monstersCaught += 1;
reset();
}
};
// Draw everything
var render = function () {
if (bgReady) {
ctx.drawImage(bgImage, 0, 0);
}
if (shipReady) {
ctx.drawImage(heroImage, hero.x, hero.y);
}
if (astroidReady) {
ctx.drawImage(monsterImage, monster.x, monster.y);
}
// Score
ctx.fillStyle = "rgb(250, 250, 250)";
ctx.font = "24px Helvetica";
ctx.textAlign = "left";
ctx.textBaseline = "top";
ctx.fillText("Your Health: " + health, 32, 32);
};
// The main game loop
var main = function () {
var now = Date.now();
var delta = now - then;
if (delta > 20) delta = 20;
update(delta / 1000);
render();
then = now;
};
// Let's play this game!
reset();
var then = Date.now();
setInterval(main, 1); // Execute as fast as possible
The game is supposed to be a ship(shoe image) that is avoiding astroids that get bigger(ants) but when you move your ship(shoe) stays in the same place and the astroids(ants) move. The ants/astroids also get bigger like you are going close to them.
var ship = {
speed: 256;
};
Remove the ; after the value.
if astroid.width < 200{
and
if astroid.width > 200{
Need parentheses around the if conditions.
The error console is helpful! But now it's just stuck in an infinite loop of monsterImage is not defined. Just... go back, write your code more carefully, and use the error console! It's there for a reason!

Simple html5+javascript game flickering

I just started learning javascript, and i already faced some problems. I have a very simple "game" where you move red box with arrow keys and there is black background. I saw some topics about the same question and some of the guys says that make a buffer and other half says that don't do buffer because your browser does it for you. But anyway, I just thought that there is something wrong in my code because it's flickering but it's just so simple that i think it should not.
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
canvas.width = 800;
canvas.height = 600;
var mySprite = {
x: 200,
y: 200,
width: 50,
height: 50,
color: '#c00'
};
var yvel = 0;
var xvel = 0 ;
var moved = false;
var mspeed = 15;
var keysDown = {};
window.addEventListener('keydown', function(e) {
keysDown[e.keyCode] = true;
});
window.addEventListener('keyup', function(e) {
delete keysDown[e.keyCode];
});
function update() {
if (37 in keysDown) {
moved = true;
if(xvel > -mspeed){
xvel -= 0.5;
}
}
if (38 in keysDown) {
moved = true;
if(yvel > -mspeed){
yvel -= 0.5
}
}
if (39 in keysDown) {
moved = true;
if(xvel < mspeed){
xvel += 0.5
}
}
if (40 in keysDown) {
moved = true;
if(yvel < mspeed){
yvel += 0.5
}
}
mySprite.x += xvel;
mySprite.y += yvel;
if(moved == false){
xvel = xvel * 0.95;
yvel = yvel * 0.95;
}
moved = false;
}
function render() {
ctx.fillStyle = '#000';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = mySprite.color;
ctx.fillRect(mySprite.x, mySprite.y, mySprite.width, mySprite.height);
}
function run() {
update();
render();
}
setInterval(run, 1000/60);
You can try it here:w3school
Just copy my code and put it inside tags and change the "MyCanvas" name to "canvas"
The double buffering is in fact allready activated on major browsers.
What you need to do is to get in sync with the screen, that's what's
provide requestAnimationFrame :
https://developer.mozilla.org/en-US/docs/Web/API/window.requestAnimationFrame
here's the polyfill for requestAnimationFrame :
requestAnimationFrame (rAF) is not standard yet : every 'vendor' i.e. browser (Chrome, FF, Safari, ...) has its own naming.
A polyfill is a piece of code that will 'install' a function in your environement whatever the vendor. Here you will be able to access requestAnimationFrame using window.requestAnimationFrame and you will not care any more about the vendor.
The || operator acts as a 'scan' : it will stop on the first 'truthy' ( == true) expression and return it without evaluating the remaining ones. So the last function definition, for instance, won't get evaluated if msRequestAnimationFrame is defined.
I have to add that the fallback in case requestAnimationFrame is not found is awfull : setTimeout has a very poor accuracy, but thankfully rAF will be found : it is allready there on Chrome(without prefix), Safari (webkit), IE >9 (ms), Firefox (moz) and Opera (o). )
// requestAnimationFrame polyfill
var w=window, foundRequestAnimationFrame = w.requestAnimationFrame ||
w.webkitRequestAnimationFrame || w.msRequestAnimationFrame ||
w.mozRequestAnimationFrame || w.oRequestAnimationFrame ||
function(cb) { setTimeout(cb,1000/60); } ;
window.requestAnimationFrame = foundRequestAnimationFrame ;
and after exchanging update and render (way better), your run loop will be :
function run() {
render();
update();
window.requestAnimationFrame(run);
}
run();
in any case you are interested, i discussed the javascript game loop here :
http://gamealchemist.wordpress.com/2013/03/16/thoughts-on-the-javascript-game-loop/
Why would you need a timer ? the code above will call run again and again, since run ends by a defered call to run : run will be called next time display is available (typically 60 times per seconds).
And you can know about the current time with Date.now().
For more insights about the game loop, rAF, and some time handling issues, see my link above.
Here is your code after some refactoring :
(fiddle is here : http://jsbin.com/uvACEVA/2/edit )
var canvasWidth = 800, canvasHeight = 600;
var canvas = document.getElementById('canvas');
canvas.width = canvasWidth; canvas.height = canvasHeight;
var ctx = canvas.getContext('2d');
// player definition
var mySprite = {
x: 200,
y: 200,
xvel : 0,
yvel : 0,
velIncr : 0.5,
velAttenuation : 0.95,
maxVel : 15,
width: 50,
height: 50,
color: '#c00',
moved : false
};
mySprite.update = function (dt) {
if (keysDown[37]) {
this.moved = true;
if(this.xvel > -this.maxVel){
this.xvel -= this.velIncr;
}
}
if (keysDown[38]) {
this.moved = true;
if(this.yvel > -this.maxVel){
this.yvel -= this.velIncr;
}
}
if (keysDown[39]) {
this.moved = true;
if(this.xvel < this.maxVel){
this.xvel += this.velIncr;
}
}
if (keysDown[40]) {
this.moved = true;
if(this.yvel < this.maxVel){
this.yvel += this.velIncr;
}
}
// to have a frame-rate independant game,
// compute the real dt in run() and ...
this.x += this.xvel; // ... use this.x += this.xvel * dt;
this.y += this.yvel; // ... this.y += this.yvel * dt;
if(this.moved == false){
this.xvel *= this.velAttenuation;
this.yvel *= this.velAttenuation;
}
this.moved = false;
};
mySprite.draw = function(ctx) {
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.width, this.height);
};
// Keyboard handling
var keysDown = [];
window.addEventListener('keydown', function(e) {
keysDown[e.keyCode] = true;
e.preventDefault();
e.stopPropagation();
});
window.addEventListener('keyup', function(e) {
keysDown[e.keyCode] = false;
e.preventDefault();
e.stopPropagation();
});
// requestAnimationFrame polyfill
var w=window, foundRequestAnimationFrame = w.requestAnimationFrame ||
w.webkitRequestAnimationFrame || w.msRequestAnimationFrame ||
w.mozRequestAnimationFrame || w.oRequestAnimationFrame ||
function(cb) { setTimeout(cb,1000/60); } ;
window.requestAnimationFrame = foundRequestAnimationFrame ;
// main animation loop
function update(dt) {
mySprite.update(dt); // only one for the moment.
}
function render(ctx) {
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
mySprite.draw(ctx);
}
var dt = 16; // milliseconds elapsed since last call.
// ideally you should compute it in run(), i didn't for simplicity
function run() {
render(ctx);
update(dt);
window.requestAnimationFrame(run);
}
run();

Categories