Javascript Html5 canvas problems - javascript

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!

Related

Canvas: Movement only allowed on X axis?

The Problem
I am creating a game where you have to move away from or dodge projectiles coming towards you, I have enabled the user to move the image they are controlling but at the moment the user can place the image anywhere on the canvas.
The Question
How can I only allow the user to move along designated part of the canvas and only along the X axis? for example:
Here is my game, "working progress":
The user is in control of the ship, they should only be able to move left or right like this for example:
The Code
<script>
var game = create_game();
game.init();
//music
var snd = new Audio("menu.mp3");
snd.play();
document.getElementById('mute').addEventListener('click', function (evt) {
if ( snd.muted ) {
snd.muted = false
evt.target.innerHTML = 'mute'
}
else {
snd.muted = true
evt.target.innerHTML = 'unmute'
}
})
function create_game() {
debugger;
var level = 1;
var projectiles_per_level = 1;
var min_speed_per_level = 1;
var max_speed_per_level = 2;
var last_projectile_time = 0;
var next_projectile_time = 0;
var width = 600;
var height = 500;
var delay = 1000;
var item_width = 30;
var item_height = 30;
var total_projectiles = 0;
var projectile_img = new Image();
var projectile_w = 30;
var projectile_h = 30;
var player_img = new Image();
var c, ctx;
var projectiles = [];
var player = {
x: 200,
y: 400,
score: 0
};
function init() {
projectile_img.src = "apple.png";
player_img.src = "basket.png";
level = 1;
total_projectiles = 0;
projectiles = [];
c = document.getElementById("c");
ctx = c.getContext("2d");
ctx.fillStyle = "#ff6600";
ctx.fillRect(0, 0, 500, 600);
c.addEventListener("mousemove", function (e) {
//moving over the canvas.
var bounding_box = c.getBoundingClientRect();
player.x = (e.clientX - bounding_box.left) * (c.width / bounding_box.width) - player_img.width / 2;
player.y = (e.clientY - bounding_box.top) * (c.height / bounding_box.height) - player_img.height / 2;
}, false);
setupProjectiles();
requestAnimationFrame(tick);
}
function setupProjectiles() {
var max_projectiles = level * projectiles_per_level;
while (projectiles.length < max_projectiles) {
initProjectile(projectiles.length);
}
}
function initProjectile(index) {
var max_speed = max_speed_per_level * level;
var min_speed = min_speed_per_level * level;
projectiles[index] = {
x: Math.round(Math.random() * (width - 2 * projectile_w)) + projectile_w,
y: -projectile_h,
v: Math.round(Math.random() * (max_speed - min_speed)) + min_speed,
delay: Date.now() + Math.random() * delay
}
total_projectiles++;
}
function collision(projectile) {
if (projectile.y + projectile_img.height < player.y + 74) {
return false;
}
if (projectile.y > player.y + 74) {
return false;
}
if (projectile.x + projectile_img.width < player.x + 177) {
return false;
}
if (projectile.x > player.x + 177) {
return false;
}
return true;
}
function maybeIncreaseDifficulty() {
level = Math.max(1, Math.ceil(player.score / 10));
setupProjectiles();
}
function tick() {
var i;
var projectile;
var dateNow = Date.now();
c.width = c.width;
for (i = 0; i < projectiles.length; i++) {
projectile = projectiles[i];
if (dateNow > projectile.delay) {
projectile.y += projectile.v;
if (collision(projectile)) {
initProjectile(i);
player.score++;
} else if (projectile.y > height) {
initProjectile(i);
} else {
ctx.drawImage(projectile_img, projectile.x, projectile.y);
}
}
}
ctx.font = "bold 24px sans-serif";
ctx.fillStyle = "#ff6600";
ctx.fillText(player.score, c.width - 50, 50);
ctx.fillText("Level: " + level, 20, 50);
ctx.drawImage(player_img, player.x, player.y);
maybeIncreaseDifficulty();
requestAnimationFrame(tick);
}
return {
init: init
};
}
</script>
JSFiddle (Broken)
https://jsfiddle.net/3oc4jsf6/10/
If your ship is tied to mouse movement, and you want to only allow movement across the X-axis you can simply avoid changing its .y property in your mousemove listener.
Remove this line:
player.y = (e.clientY - bounding_box.top) * (c.height / bounding_box.height) - player_img.height / 2;

Why isn't the "crab" (an entity) touchable like the "monster" (also an entity)?

I'm developing a game and I was wondering why isn't the "crab" (an entity) killable like the "monster" (also an entity). What I mean is that if I touch the goblin monster, I get a point, but I just walk across the crab.
I attempted to add an if..else, but then the player got thousands of points per second.
What have I done wrong?
// 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 = "images/background.png";
// Hero image
var heroReady = false;
var heroImage = new Image();
heroImage.onload = function() {
heroReady = true;
};
heroImage.src = "images/hero.png";
// Monster image
var monsterReady = false;
var monsterImage = new Image();
monsterImage.onload = function() {
monsterReady = true;
};
monsterImage.src = "images/monster.png";
// Crab image
var crabReady = false;
var crabImage = new Image();
crabImage.onload = function() {
crabReady = true;
};
crabImage.src = "images/old/hero.png";
// Game objects
var hero = {
speed: 300 // movement in pixels per second
};
var monster = {};
var crab = {};
var monstersCaught = 0;
// Handle keyboard controls
var keysDown = {};
addEventListener("keydown", function(e) {
keysDown[e.keyCode] = true;
}, false);
addEventListener("keyup", function(e) {
delete keysDown[e.keyCode];
}, false);
// Reset the game when the player catches a monster
var reset = function() {
hero.x = canvas.width / 2;
hero.y = canvas.height / 2;
// Throw the monster somewhere on the screen randomly
monster.x = 32 + (Math.random() * (canvas.width - 64));
monster.y = 32 + (Math.random() * (canvas.height - 64));
// Throw the crab somewhere on the screen randomly
crab.x = 32 + (Math.random() * (canvas.width - 64));
crab.y = 32 + (Math.random() * (canvas.height - 64));
};
// Update game objects
var update = function(modifier) {
if (38 in keysDown) { // Player holding up
hero.y -= hero.speed * modifier;
}
if (40 in keysDown) { // Player holding down
hero.y += hero.speed * modifier;
}
if (37 in keysDown) { // Player holding left
hero.x -= hero.speed * modifier;
}
if (39 in keysDown) { // Player holding right
hero.x += hero.speed * modifier;
}
// Are they touching?
if (
hero.x <= (monster.x + 32) && monster.x <= (hero.x + 32) && hero.y <= (monster.y + 32) && monster.y <= (hero.y + 32)
) {
++monstersCaught;
reset();
}
};
// Draw everything
var render = function() {
if (bgReady) {
ctx.drawImage(bgImage, 0, 0);
}
if (heroReady) {
ctx.drawImage(heroImage, hero.x, hero.y);
}
if (monsterReady) {
ctx.drawImage(monsterImage, monster.x, monster.y);
}
if (crabReady) {
ctx.drawImage(crabImage, crab.x, crab.y);
}
// Score
ctx.fillStyle = "rgb(250, 250, 250)";
ctx.font = "24px Helvetica";
ctx.textAlign = "left";
ctx.textBaseline = "top";
ctx.fillText("Mobs killed: " + monstersCaught, 32, 32);
};
// The main game loop
var main = function() {
var now = Date.now();
var delta = now - then;
update(delta / 1000);
render();
then = now;
// Request to do this again ASAP
requestAnimationFrame(main);
};
// Cross-browser support for requestAnimationFrame
var w = window;
requestAnimationFrame = w.requestAnimationFrame || w.webkitRequestAnimationFrame || w.msRequestAnimationFrame || w.mozRequestAnimationFrame;
// Let's play this game!
var then = Date.now();
reset();
main();
<!DOCTYPE html>
<html>
<head>
<title>Underbound</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div class="game">
<script src="js/game.js"></script>
</div>
</body>
</html>
Because you're only checking if the hero collides with monster.
hero.x <= (monster.x + 32) && monster.x <= (hero.x + 32) && hero.y <= (monster.y + 32) && monster.y <= (hero.y + 32)
Instead, you should probably create a function for checking if they collide:
function isColliding(a, b) {
return a.x <= (b.x + 32) && b.x <= (a.x + 32) &&
a.y <= (b.y + 32) && b.y <= (a.y + 32);
}
if (isColliding(hero, monster)) { ...
Then use also check if they collide with crab.
if (isColliding(hero, crab)) { ...
It'd be more sustainable (until you have a whole lot of monsters) if you put all of your "monsters" into an array then check against each monster in the array.
As for the issue with gaining lots of points quickly: you have to remove the monster (or crab) from the play area and stop checking for collisions during the update phase or the player will continue to collide with the crab and gain points.
One solution for this would be to give your monsters an active (or similar property). By default, this will be true but when the player collides with them, this will be false. Then you will only draw them and check for collisions if active is true.

What is the benefit of requestAnimationFrame(...paramList...)?

Question:
Why is the requestAnimationFrame called with this function? For example, if I was building a game what benefit would requestAnimationFrame be over just repainting the canvas.
code:
function main() {
var now = Date.now();
var delta = now - then;
update(delta / 1000);
render();
then = now;
// Request to do this again ASAP
requestAnimationFrame(main);
};
All Code Below: (You would need 3 .jpg files)
<html>
<head>
<title>test</title>
</head>
<body>
<script>
// 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 = "background.png";
// Hero image
var heroReady = false;
var heroImage = new Image();
heroImage.onload = function () {
heroReady = true;
};
heroImage.src = "hero.png";
// Monster image
var monsterReady = false;
var monsterImage = new Image();
monsterImage.onload = function () {
monsterReady = true;
};
monsterImage.src = "monster.png";
// Game objects
var hero = {
speed: 256 // movement in pixels per second
};
var monster = {};
var monstersCaught = 0;
// Handle keyboard controls
var keysDown = {};
addEventListener("keydown", function (e) {
keysDown[e.keyCode] = true;
}, false);
addEventListener("keyup", function (e) {
delete keysDown[e.keyCode];
}, false);
// Reset the game when the player catches a monster
var reset = function () {
hero.x = canvas.width / 2;
hero.y = canvas.height / 2;
// Throw the monster somewhere on the screen randomly
monster.x = 32 + (Math.random() * (canvas.width - 64));
monster.y = 32 + (Math.random() * (canvas.height - 64));
};
// Update game objects
var update = function (modifier) {
if (38 in keysDown) { // Player holding up
hero.y -= hero.speed * modifier;
}
if (40 in keysDown) { // Player holding down
hero.y += hero.speed * modifier;
}
if (37 in keysDown) { // Player holding left
hero.x -= hero.speed * modifier;
}
if (39 in keysDown) { // Player holding right
hero.x += hero.speed * modifier;
}
// Are they touching?
if (hero.x <= (monster.x + 32) &&
monster.x <= (hero.x + 32) &&
hero.y <= (monster.y + 32) &&
monster.y <= (hero.y + 32)
) {
++monstersCaught;
reset();
}
};
// Draw everything
var render = function () {
if (bgReady) {
ctx.drawImage(bgImage, 0, 0);
}
if (heroReady) {
ctx.drawImage(heroImage, hero.x, hero.y);
}
if (monsterReady) {
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("Goblins caught: " + monstersCaught, 32, 32);
};
// The main game loop
/*var main = function () {
var now = Date.now();
var delta = now - then;
update(delta / 1000);
render();
then = now;
// Request to do this again ASAP
requestAnimationFrame(main);
};*/
// The main game loop -- This is the second way of doing this
function main() {
var now = Date.now();
var delta = now - then;
update(delta / 1000);
render();
then = now;
// Request to do this again ASAP
requestAnimationFrame(main);
};
// Cross-browser support for requestAnimationFrame
var w = window;
requestAnimationFrame = w.requestAnimationFrame || w.webkitRequestAnimationFrame || w.msRequestAnimationFrame || w.mozRequestAnimationFrame;
// Let's play this game!
var then = Date.now();
reset();
main();
</script>
</body>
</html>
Because repeatedly calling main would cause the browser to hang until it gave up with a stack overflow error.
requestAnimationFrame simply says "do this when the browser is ready to render another frame".

Canvas wont hide?

My HTML5 Canvas element doesn't seem to hide.
I created a timer that should hide the element when the timer reaches 0, I tested this with an alert flag and that worked fine.
Issue:
if (TotalSeconds <= 0)
{
ctx.clearRect(0, 0, canvas.width, canvas.height)
}
Entire code:
// 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 = "images/background.png";
// Hero image
var heroReady = false;
var heroImage = new Image();
heroImage.onload = function () {
heroReady = true;
};
heroImage.src = "images/hero.png";
// Monster image
var monsterReady = false;
var monsterImage = new Image();
monsterImage.onload = function () {
monsterReady = true;
};
monsterImage.src = "images/flamingo.png";
// Game objects
var hero = {
speed: 256 // movement in pixels per second
};
var monster = {};
var monstersCaught = 0;
// Handle keyboard controls
var keysDown = {};
addEventListener("keydown", function (e) {
keysDown[e.keyCode] = true;
}, false);
addEventListener("keyup", function (e) {
delete keysDown[e.keyCode];
}, false);
// Reset the game when the player catches a monster
var reset = function () {
hero.x = canvas.width / 2;
hero.y = canvas.height / 2;
// Throw the monster somewhere on the screen randomly
monster.x = 32 + (Math.random() * (canvas.width - 64));
monster.y = 32 + (Math.random() * (canvas.height - 64));
};
// Update game objects
var update = function (modifier) {
if (38 in keysDown) { // Player holding up
hero.y -= hero.speed * modifier;
}
if (40 in keysDown) { // Player holding down
hero.y += hero.speed * modifier;
}
if (37 in keysDown) { // Player holding left
hero.x -= hero.speed * modifier;
}
if (39 in keysDown) { // Player holding right
hero.x += hero.speed * modifier;
}
// Are they touching?
if (
hero.x <= (monster.x + 32)
&& monster.x <= (hero.x + 32)
&& hero.y <= (monster.y + 32)
&& monster.y <= (hero.y + 32)
)
{
++monstersCaught;
reset();
}
if (hero.x <= 0)
{
hero.x = 510
}
if (hero.y <= 0)
{
hero.y = 478
}
};
CreateTimer(5);
var Timer;
var TotalSeconds;
function CreateTimer(Time) {
Timer = $("#timer").text();
TotalSeconds = Time;
UpdateTimer()
window.setTimeout("Tick()", 1000);
}
function Tick() {
TotalSeconds -= 1;
UpdateTimer()
window.setTimeout("Tick()", 1000);
}
function UpdateTimer() {
$("#timer").text(TotalSeconds);
if (TotalSeconds <= 0)
{
ctx.clearRect(0, 0, canvas.width, canvas.height)
}
}
// Draw everything
var render = function () {
if (bgReady) {
ctx.drawImage(bgImage, 0, 0);
}
if (heroReady) {
ctx.drawImage(heroImage, hero.x, hero.y);
}
if (monsterReady) {
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("Flamingos slaughtered: " + monstersCaught, 32, 32);
ctx.textAlign = "right";
ctx.textBaseline = "bottom";
ctx.fillText("Time left: " + TotalSeconds, 150,32);
};
// The main game loop
var main = function () {
var now = Date.now();
var delta = now - then;
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 html is just <canvas></canvas>
Pretty new to this so any help would be appreciated.
Thanks!
This does not hide the canvas but clear the context, which means it's clear the drawn shape on canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
You can hide it by appying a CSS style for it:
if (TotalSeconds <= 0) {
ctx.canvas.style.display = 'none';
}
and to reveal it again simple use block or inline-block instead of none.
If you want to hide it but keep its space you can use:
ctx.canvas.style.visibility = 'hidden';
You can also remove it completely from the DOM tree by using:
parent.removeChild(canvasElement);
where parent is the container element (for example document.body as you are using now) and canvasElement is a reference is your canvas.
All that being said - if you want to just clear the canvas then you need to stop the loop you have running. You can use for example a flag to do this:
function Tick() {
TotalSeconds--;
UpdateTimer();
if (TotalSeconds > 0) setTimeout(Tick, 1000); // only loop if sec > 0
}
and then clear it as you already do.
Hope this helps!

Simple memory game doesn't update its state. Bad game loop?

I'm trying to make a simple (or so I thought) memory game. Unfortunately it does not update state of cards when user clicks on them. I'm running out of ideas, probably because it's my first javascript game. I suppose there is a problem with game loop. Could anyone at least point me in the right direction and help me understand what needs to be changed/rewritten?
//HTML5 Memory Game implementation
//main variables
var cards = [1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8];
var exposed = [makeArray("false",16)];
var first_card = 0;
var second_card = 0;
var moves = 0;
var WIDTH = 800;
var HEIGHT = 100;
var state = 0;
var mouseX = 0;
var mouseY = 0;
//creating canvas
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = WIDTH;
canvas.height = HEIGHT;
document.getElementById("game").appendChild(canvas);
//filling empty array with number,character,object
function makeArray(value, length) {
var newArray = [];
var i = 0;
while (i<length) {
newArray[i] = value;
i++;
}
return newArray;
}
//shuffling algorithm
function shuffle(array) {
var copy = [];
var n = array.length;
var i;
while (n) {
i = Math.floor(Math.random() * n--);
copy.push(array.splice(i, 1)[0]);
}
return copy;
}
//where user clicks
function getClickPosition(event) {
var X = event.pageX - canvas.offsetLeft;
var Y = event.pageY - canvas.offsetTop;
return mouse = [X, Y];
}
//read click position
function readPos(event) {
mousePos = getClickPosition(event);
mouseX = mousePos[0];
mouseY = mousePos[1];
}
//initializing
function init() {
state = 0;
moves = 0;
exposed = [makeArray("false",16)];
cards = shuffle(cards);
}
//drawing cards
function draw() {
ctx.clearRect(0, 0, WIDTH, HEIGHT);
for (var i in cards) {
if (exposed[i] === true) {
ctx.fillStyle = "rgb(250, 250, 250)";
ctx.font = "50px Courier New";
ctx.fillText(cards[i], (i*50+12), 65);
} else {
ctx.strokeStyle = "rgb(250, 0, 0)";
ctx.fillStyle = "rgb(0, 0, 250)";
ctx.fillRect(i*50, 0, 50, 100);
ctx.strokeRect(i*50, 0, 50, 100);
}
}
};
//update cards
function update() {
if (exposed[parseInt(mouseX / 50)] === false) {
if (state == 0) {
state = 1;
first_card = parseInt(mouseX / 50);
exposed[parseInt(mouseX / 50)] = true;
} else if (state == 1) {
state = 2;
second_card = parseInt(mouseX / 50);
exposed[parseInt(mouseX / 50)] = true;
} else {
if (cards[first_card] != cards[second_card]) {
exposed[first_card] = false;
exposed[second_card] = false;
}
state = 1;
first_card = parseInt(mouseX / 50);
exposed[parseInt(mouseX / 50)] = true;
}
}
}
addEventListener('click', readPos, false);
setInterval(function() {
update();
draw();
}, 16);
I would check your addEventListener method: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget.addEventListener
I also recommend you look into using jQuery.
After copy and pasting your code I found a couple of things:
You didn't add an event listener to anything, you should add it to something so I added it to document.
You initialize the exposed array with values "false" and later check if they are false. These are not the same, the string "false" isn't the Boolean false.
You initializes the exposed array as a multi dimensional array [[false,false,false ...]] this should be a single dimension array because later you check exposed[1] (1 depending on the mouse x position.
No need to call draw and update every 16 milliseconds, you can call it after someone clicked.
Wrapped the whole thing up in a function so there are no global variables created.
Here is the code after changing these obvious errors. There might be room for optimization but for now I've gotten the problems out.
<!DOCTYPE html>
<html>
<head>
<title>test</title>
</head>
<body>
<div id="game"></div>
<script type="text/javascript">
(function(){
//HTML5 Memory Game implementation
//main variables
var cards = [1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8];
var exposed = makeArray(false, 16);
var first_card = 0;
var second_card = 0;
var moves = 0;
var WIDTH = 800;
var HEIGHT = 100;
var state = 0;
var mouseX = 0;
var mouseY = 0;
//creating canvas
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = WIDTH;
canvas.height = HEIGHT;
document.getElementById("game").appendChild(canvas);
//filling empty array with number,character,object
function makeArray(value, length) {
var newArray = [];
var i = 0;
while (i < length) {
newArray.push(value);
i++;
}
return newArray;
}
//shuffling algorithm
function shuffle(array) {
var copy = [];
var n = array.length;
var i;
while (n) {
i = Math.floor(Math.random() * n--);
copy.push(array.splice(i, 1)[0]);
}
return copy;
}
//where user clicks
function getClickPosition(event) {
var X = event.pageX - canvas.offsetLeft;
var Y = event.pageY - canvas.offsetTop;
return mouse = [X, Y];
}
//read click position
function readPos(event) {
mousePos = getClickPosition(event);
mouseX = mousePos[0];
mouseY = mousePos[1];
update();
draw();
}
//initializing
function init() {
state = 0;
moves = 0;
exposed = makeArray(false, 16);
cards = shuffle(cards);
}
//drawing cards
function draw() {
ctx.clearRect(0, 0, WIDTH, HEIGHT);
for (var i in cards) {
if (exposed[i] === true) {
ctx.fillStyle = "rgb(150, 150, 150)";
ctx.font = "50px Courier New";
ctx.fillText(cards[i], (i * 50 + 12), 65);
} else {
ctx.strokeStyle = "rgb(250, 0, 0)";
ctx.fillStyle = "rgb(0, 0, 250)";
ctx.fillRect(i * 50, 0, 50, 100);
ctx.strokeRect(i * 50, 0, 50, 100);
}
}
};
//update cards
function update() {
if (exposed[parseInt(mouseX / 50)] === false) {
if (state == 0) {
state = 1;
first_card = parseInt(mouseX / 50);
exposed[parseInt(mouseX / 50)] = true;
} else if (state == 1) {
state = 2;
second_card = parseInt(mouseX / 50);
exposed[parseInt(mouseX / 50)] = true;
} else {
if (cards[first_card] != cards[second_card]) {
exposed[first_card] = false;
exposed[second_card] = false;
}
state = 1;
first_card = parseInt(mouseX / 50);
exposed[parseInt(mouseX / 50)] = true;
}
}
}
document.body.addEventListener('click', readPos, false);
init();
draw();
})();
</script>
</body>
</html>
Your overall logic was good.
The point that was 'bad' was the way you handle the event :
the event handler should store some valuable information that
the update will later process and clear.
Here you mix your update with event handling, which cannot work
especially since the event will not fire on every update.
So i did a little fiddle to show you, the main change is
the click event handler, which update the var last_clicked_card :
http://jsfiddle.net/wpymH/
//read click position
function readPos(event) {
last_clicked_card = -1;
mousePos = getClickPosition(event);
mouseX = mousePos[0];
mouseY = mousePos[1];
// on canvas ?
if ((mouseY>100)||(mouseX<0)||(mouseX>WIDTH)) return;
// now yes : which card clicked ?
last_clicked_card = Math.floor(mouseX/50);
}
and then update is the processing of this information :
//update cards
function update() {
// return if no new card clicked
if (last_clicked_card == -1) return;
// read and clear last card clicked
var newCard = last_clicked_card;
last_clicked_card=-1;
// flip, store it as first card and return
// if there was no card flipped
if (state==0) { exposed[newCard] = true;
first_card = newCard;
state = 1 ;
return; }
// just unflip card if card was flipped
if ((state = 1) && exposed[newCard]) {
exposed[newCard]=false ;
state=0;
return;
}
// we have a second card now
second_card = newCard;
exposed[second_card] = true;
draw();
// ... i don't know what you want to do ...
if (cards[first_card] == cards[second_card]) {
alert('win'); }
else {
alert('loose'); }
exposed[first_card]=false;
exposed[second_card]=false;
state=0;
}

Categories