I am trying to create a duck hunting game using JavaScript. The following code should move duck images from the left side to the right side of the canvas. There doesn't seem to be any syntax error but nothing happens when I test the code. I would appreciate any help.
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
var time = Math.round(Math.random()*100);
var ducs = [];
canvas.width = 500;
canvas.height = 500;
document.body.appendChild(canvas);
// Background image
var bgReady = false;
var bgImage = new Image();
bgImage.onload = function () {
bgReady = true;
};
bgImage.src = "images/DHbackground.jpg";
// Duck image
var duckReady = false;
var duckImage = new Image();
duckImage.onload = function () {
duckReady = true;
};
duckImage.src = "images/duck.png";
// Handle mouse and keyboard controls
var mouseDown = {
x: 0,
y: 0,
};
function getClickPosition(e) {
mouseDown.x = e.clientX;
mouseDown.y = e.clientY;
};
canvas.addEventListener("click", getClickPosition, false);
var reset = function(){
// To do: resets the game
};
// Draw everything
var render = function () {
if (bgReady) {
ctx.drawImage(bgImage, 0, 0);
}
time = time-1;
if (time < 0){
var duck = {
cur_X: 0,
cur_Y: Math.round(Math.random()*500),
final_X: 500,
final_Y: Math.round(Math.random()*500),
};
time = Math.round(Math.random()*100);
ducs.push(duck);
for (var i = 0; i < ducs.Lenght; i++){
ctx.drawImage(duckImage, ducs[i].cur_X, ducs[i].cur_Y);
console.log(ducs[i].cur_X);
}
}
// Score
ctx.fillStyle = "rgb(250, 250, 250)";
ctx.font = "24px Helvetica";
ctx.textAlign = "left";
ctx.textBaseline = "top";
ctx.fillText("Ducks killed: " + 3, 10, 10);
};
var update = function (modifier) {
for (var i = 0; i < ducs.Lenght; i++){
ducs[i].cur_X = ducs[i].cur_X + Math.floor(((ducs[i].final_X - ducs[i].cur_X)/500)+1);
ducs[i].cur_Y = ducs[i].cur_Y + Math.floor(((ducs[i].final_Y - ducs[i].cur_Y)/500)+1);
if (ducs[i].cur_X > 500){
ducs.splice(i, 1);
}
}
};
// The main game loop
var main = function () {
var now = Date.now();
var delta = now - then;
render();
update(delta / 1000);
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;
var then = Date.now();
reset();
main();
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Duck Hunt Pandy</title>
</head>
<body>
<script src="js/game.js"> </script>
</body>
</html>
I found a typo:
var update = function (modifier) {
for (var i = 0; i < ducs.Lenght; i++){
Length is spelled incorrectly
First problem. You misspelled length.
for (var i = 0; i < ducs.length; i++){
Second is that you need to make sure to draw the ducks each time the loop runs.
if (time < 0){
var duck = {
cur_X: 0,
cur_Y: Math.round(Math.random()*500),
final_X: 500,
final_Y: Math.round(Math.random()*400),
};
time = Math.round(Math.random()*100);
ducs.push(duck);
}
for (var i = 0; i < ducs.length; i++){
ctx.drawImage(duckImage, ducs[i].cur_X, ducs[i].cur_Y);
console.log(ducs[i].cur_X);
}
third is that you need to remove the ducks when they reach the end (you were checking for 500, but their flight final was 400).
var duck = {
cur_X: 0,
cur_Y: Math.round(Math.random()*500),
final_X: 500,
final_Y: Math.round(Math.random()*400),
};
if (ducs[i].cur_X > 500){
ducs.splice(i, 1);
}
https://jsfiddle.net/ygh6mfpw/6/
Edit: Fix for duck movement
Related
How to set on click event in moving object in canvas? Also how to move the object bottom to top in canvas.I am newly in javascript i am going to develop the sample like when the page open, objects like square and circle randomly come from bottom of the page and move to top automatically.
You need to establish an array that will have your moving objects in it. When the onclick handler fires, check to see if the coordinates of the click are inside any of the objects in the array.
On each animation frame, move your objects up by subtracting some of the y coordinate from each object.
//width and height of canvas...
var rW = 400;
var rH = 500;
var coinImage = getCoinImage();
var coinsOnScreen = [];
var risingSpeed = 100; //pixels per second...
var coinSize = 75;
var lastAnimationTime = 0;
var howLongUntilNextCoin = 1000;
var nextCoinOnScreen = 0;
function doDraw() {
var can = document.getElementById("myCanvas");
can.width = rW;
can.height = rH;
var context = can.getContext("2d");
//Erase the canvas
context.fillStyle = "#FFFFFF";
context.fillRect(0, 0, rW, rH);
if (new Date().getTime() - nextCoinOnScreen > 0) {
var newX = Math.floor(Math.random() * rW) + 1;
var newY = rH + 50;
var newCoin = {
x: newX,
y: newY
};
coinsOnScreen.push(newCoin);
nextCoinOnScreen = new Date().getTime() + howLongUntilNextCoin;
}
//Now draw the coins
if (lastAnimationTime != 0) {
var deltaTime = new Date().getTime() - lastAnimationTime;
var coinRisePixels = Math.floor((deltaTime * risingSpeed) / 1000);
var survivingCoins = [];
for (var i = 0; i < coinsOnScreen.length; i++) {
var coin = coinsOnScreen[i];
coin.y = coin.y - coinRisePixels;
//the stl variable controlls the alpha of the image
if (coin.y + 50 > 0) {
context.drawImage(coinImage, coin.x, coin.y);
//this coin is still on the screen, so promote it to the new array...
survivingCoins.push(coin);
}
}
coinsOnScreen = survivingCoins;
}
lastAnimationTime = new Date().getTime();
//Wait, and then call this function again to animate:
setTimeout(function() {
doDraw();
}, 30);
}
function setupClickHandler() {
var can = document.getElementById("myCanvas");
//Here is the onclick handler
can.onclick = function(e) {
var x = e.clientX;
var y = e.clientY;
var survivingCoins = [];
for (var i = 0; i < coinsOnScreen.length; i++) {
var coin = coinsOnScreen[i];
//check to see if this coin has been clicked...
if (x > coin.x && x < coin.x + coinSize && y > coin.y && y < coin.y + coinSize) {
//ths coin will disappear because it is not inserted into the new array...
console.log("Coin was clicked!! " + x + " " + y);
} else {
survivingCoins.push(coin);
}
}
coinsOnScreen = survivingCoins;
};
}
doDraw();
setupClickHandler();
function getCoinImage() {
var image = new Image(50, 50);
image.src = "data:image/png;base64,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";
return image;
}
<canvas id="myCanvas"></canvas>
in this HTML5 code, I try to fire particles from the Emitter in objects[0].
This can be run with objects[0].play in the console.
However, the Emitter follows the Particle fired.
My question is, why?
HTML Code
<html>
<head>
<style>
#canv{
border: 1px solid black;
}
</style>
<script src = "setup.js"></script>
<script src = "main.js"></script>
</head>
<body onLoad = "start()">
<canvas width = "500" height = "500" id = "canv"></canvas>
</body>
</html>
setup.js
var objects = [];
var sprites = [];
var c;
var ctx;
var time;
var timeInterval;
function newSprite(url){
var a = sprites.length;
var b = new Image();
b.src = url;
b.onload = function(){
sprites[a] = b;
};
}
function randomN(min, max){
return Math.floor((Math.random()*max) - min);
}
function Vector2(x,y){
this.x = x;
this.y = y;
}
function Particle(pos, life, vel, accel){
this.pos = pos;
this.life = life || Infinity;
this.vel = vel || new Vector2(0,0);
this.accel = accel || new Vector2(0,0);
this.update = function(){
this.pos.x += this.vel.x;
this.pos.y += this.vel.y;
this.vel.x += this.accel.x;
this.vel.y += this.accel.y;
this.life--;
if(this.life <= 0){
return false;
}else{
return true;
}
};
}
function Emitter(pos){
this.pos = pos;
this.actualPos = this.pos;
this.particles = [];
this.forces = [];
this.playing = false;
this.newParticle = function(life, vel, accel){
var a = this.particles.length;
this.particles[a] = new Particle(this.pos, life, vel, accel);
};
this.update = function(){
console.log("(" + this.actualPos.x + ", " + this.actualPos.y + ") " + "(" + this.pos.x + ", " + this.pos.y + ")");
for(var a = 0; a < this.particles.length; a++){
for(var b = 0; b < this.forces.length; b++){
this.forces[b](this.particles[a]);
}
var that = this.particles[a];
var particleAlive = that.update();
if(particleAlive == false){
this.particles.splice(a, 1);
a--;
}
}
};
this.play = function(){
this.playing = true;
};
}
function timeStep(){
for(var a = 0; a < objects.length; a++){
if(objects[a].__proto__.constructor.name == "Emitter"){
if(objects[a].playing == true){
objects[a].update();
}
}
}
objects[1].newParticle(1000, new Vector2(1, 0), new Vector2(0.1, 0));
time++;
}
function gravity(p){
//p.vel.y += 0.1;
}
main.js
function start(){
c = document.getElementById("canv");
ctx = c.getContext('2d');
newSprite("spark.png");
objects[0] = new Emitter(new Vector2(50, 60));
objects[0].forces.push(gravity);
objects[0].newParticle(1000, new Vector2(1, 0), new Vector2(0.1, 0));
objects[1] = new Emitter(new Vector2(100, 100));
objects[1].forces.push(gravity);
time = 0;
timeInterval = window.setInterval(timeStep, 10);
reDraw();
}
function reDraw(){
ctx.clearRect(0, 0, c.width, c.height);
for(var a = 0; a < objects.length; a++){
if(objects[a].__proto__.constructor.name == "Emitter"){
ctx.beginPath();
ctx.arc(objects[a].pos.x, objects[a].pos.y, 5, 0, 2*Math.PI);
ctx.fillStyle = "black";
ctx.fill();
ctx.closePath();
if(objects[a].playing == true){
for(var b = 0; b < objects[a].particles.length; b++){
ctx.beginPath();
ctx.drawImage(sprites[0], objects[a].particles[b].pos.x, objects[a].particles[b].pos.y, 8,8);
//ctx.arc(objects[a].particles[b].pos.x, objects[a].particles[b].pos.y, 5, 0, 2*Math.PI);
ctx.fillStyle = "black";
ctx.fill();
ctx.closePath();
}
}
}
}
requestAnimationFrame(reDraw);
}
Your mistake is a quite classical error of using an object reference rather than using the object's values : when you create a new particle, you set its position to be the very position of the emitter.
So any latter change to the particle's position changes the emitter's position : again, the position (pos) Object is the very same object.
What you want is each particle to have its own position, that has the initial value of the emitter's position.
Done, for instance, with :
function Particle(pos, life, vel, accel){
this.pos = new Vector2(pos.x, pos.y);
//...
Notice that velocity and acceleration are also references, which here is not an issue since you call the function calling the constructor with a new Vector2.
However you might want to protect your code against future possible errors by performing a copy also for those two properties.
I havne't followed the full logic so sorry if this isn't the cause, but there's something odd about this :
function newSprite(url){
var a = sprites.length;
var b = new Image();
b.src = url;
b.onload = function(){
sprites[a] = b;
};
}
At the time when onload runs, a and b are lno longer in scope (I believe): The onload event would be fired as a new function call outside of newSprite.
Wouldn't you need to do something like this ...
b.onload = function(){
sprites[sprites.length] = this;
};
so that the function runs correctly when it's called ?
I'm having problems setting up a listener that will pause and start a canvas animation based on HasClass. Basically I want the animation to pause when a <a href="#"> has a certain class. Using jQuery I know enough how to add and remove but not tie it all together so they work together nicely. This is a little out of my comfort zone and appreciate any help.
Below is my simple HTML code:
<a id="eY" href="#" class="paused">
<span class="pause">Pause</span>
<span class="resume">Resume</span>
</a>
<canvas id="world"> </canvas>
Below is my JavaScript:
jQuery(function($) {
!+-+-+!+-+-+!+-+-+!+-+-+!+-+-+!+-+-+!+-+-+!+-+-+!
function(d, w){
var FPS = 30;
var F = 300;
var N = 3;
var VERTEX_MAX = 10;
var TRAIL_QUALITY = 4000;
var mu = 0.5;
var bmRandom = function(mu, sigma){
var x, y, r, tmp=null, tmp2;
return function(){
if(tmp !== null){
tmp2 = tmp;
tmp = null;
return y*tmp2+mu;
}
do{
x = Math.random()*2-1;
y = Math.random()*2-1;
r = x*x+y*y;
}while(r>=1);
tmp = sigma*Math.sqrt(-2*Math.log(r)/r);
return x*tmp+mu;
};
};
pointCopy = function(src, dst){
dst.x = src.x;
dst.y = src.y;
dst.z = src.z;
return dst;
};
Trail = function(pos, t, color_f){
this.pos={x:0,y:0,z:0};
this.start={x:0,y:0,z:0};
this.goal={x:0,y:0,z:0};
this.anchor_1={x:0,y:0,z:0};
this.anchor_2={x:0,y:0,z:0};
this.start_time = 0;
this.take_time = 1;
this.vertexes = [];
this.anchors_1 = [];
this.anchors_2 = [];
this.color_f = color_f;
pointCopy(pos, this.pos);
pointCopy(pos, this.start);
pointCopy(pos, this.goal);
this.setNextGoal(t);
};
Trail.prototype.setNextGoal = function(t, target){
pointCopy(this.goal, this.start);
this.anchor_1.x = this.start.x+(this.start.x-this.anchor_2.x)*mu;
this.anchor_1.y = this.start.y+(this.start.y-this.anchor_2.y)*mu;
this.anchor_1.z = this.start.z+(this.start.z-this.anchor_2.z)*mu;
if(target){
this.anchor_2.x = (this.anchor_1.x+target.x)/2+myrand();
this.anchor_2.y = (this.anchor_1.y+target.y)/2+myrand();
this.anchor_2.z = (this.anchor_1.z+target.z)/2+myrand();
this.goal.x = target.x;
this.goal.y = target.y;
this.goal.z = target.z;
}else{
this.anchor_2.x = this.anchor_1.x+myrand();
this.anchor_2.y = this.anchor_1.y+myrand();
this.anchor_2.z = this.anchor_1.z+myrand();
this.goal.x = this.anchor_2.x+myrand();
this.goal.y = this.anchor_2.y+myrand();
this.goal.z = this.anchor_2.z+myrand();
}
this.start_time = t;
this.take_time = 200+Math.random()*200;
this.vertexes.push(pointCopy(this.start, {x:0,y:0,z:0}));
this.anchors_1.push(pointCopy(this.anchor_1, {x:0,y:0,z:0}));
this.anchors_2.push(pointCopy(this.anchor_2, {x:0,y:0,z:0}));
if(this.vertexes.length > VERTEX_MAX){
this.vertexes.splice(0,this.vertexes.length-VERTEX_MAX);
this.anchors_1.splice(0,this.anchors_1.length-VERTEX_MAX);
this.anchors_2.splice(0,this.anchors_2.length-VERTEX_MAX);
}
};
Trail.prototype.update = function(t, target){
bezier3(
t-this.start_time,
this.start,
this.anchor_1,
this.anchor_2,
this.goal,
this.take_time,
this.pos
);
if(t-this.start_time > this.take_time){
this.setNextGoal(this.start_time+this.take_time, target);
this.update(t, target);
}
};
Trail.prototype.draw = function(ctx, camera, t){
var i, dz, dt, ddt, rt, a, v={x:0, y:0, z:0};
var ps = {x:0, y:0};
ctx.beginPath();
if(perspective(this.vertexes[0], camera, ps)){
ctx.moveTo(ps.x, ps.y);
}
var x0 = ps.x;
rt = (t-this.start_time)/this.take_time;
for(i=1; i<this.vertexes.length; i++){
ddt = 0.01;
for(dt=0; dt<1; dt+=ddt){
bezier3(dt,
this.vertexes[i-1],
this.anchors_1[i-1],
this.anchors_2[i-1],
this.vertexes[i],
1,
v);
if(perspective(v, camera, ps)){
dz = v.z-camera.z;
a = 1-(this.vertexes.length-i+1-dt+rt)/VERTEX_MAX;
this.color_f(ctx, a, dz);
ctx.lineTo(ps.x, ps.y);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(ps.x, ps.y);
ddt = dz/TRAIL_QUALITY+0.01;
}
}
}
ddt = 0.01;
for(dt=0; dt<rt; dt+=ddt){
bezier3(dt,
this.start,
this.anchor_1,
this.anchor_2,
this.goal,
1,
v);
if(perspective(v, camera, ps)){
dz = v.z-camera.z;
a = 1-(1-dt+rt)/VERTEX_MAX;
this.color_f(ctx, a, dz);
ctx.lineTo(ps.x, ps.y);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(ps.x, ps.y);
ddt = dz/TRAIL_QUALITY+0.01;
}
}
if(perspective(this.pos, camera, ps)){
dz = this.pos.z-camera.z;
a = 1-1/VERTEX_MAX;
this.color_f(ctx, a, dz);
ctx.lineTo(ps.x, ps.y);
ctx.stroke();
}
};
bezier3 = function(t, a, b, c, d, e, dst){
t /= e;
dst.x =
a.x*(1-t)*(1-t)*(1-t)+
b.x*3*t*(1-t)*(1-t)+
c.x*3*t*t*(1-t)+
d.x*t*t*t;
dst.y =
a.y*(1-t)*(1-t)*(1-t)+
b.y*3*t*(1-t)*(1-t)+
c.y*3*t*t*(1-t)+
d.y*t*t*t;
dst.z =
a.z*(1-t)*(1-t)*(1-t)+
b.z*3*t*(1-t)*(1-t)+
c.z*3*t*t*(1-t)+
d.z*t*t*t;
};
perspective = function(point, camera, dst){
var dx = point.x-camera.x;
var dy = point.y-camera.y;
var dz = point.z-camera.z;
if(dz > 0){
dst.x = F*dx/dz;
dst.y = F*dy/dz;
return true;
}
return false;
};
updateScene = function(ctx){
var i, goal;
time_now = new Date().getTime();
var time_d = time_now-time_pre;
trails[0].update(time_now);
for(i=1; i<trails.length; i++){
trails[i].update(time_now, trails[i-1].pos);
}
camera.x += (trails[0].pos.x-camera.x)*0.0005*time_d;
camera.y += (trails[0].pos.y-camera.y)*0.0005*time_d;
camera.z += (trails[0].pos.z-camera.z-100)*0.0005*time_d;
time_pre = time_now;
};
drawScene = function(ctx){
var i;
ctx.clearRect(-canvas.width/2, -canvas.height/2, canvas.width, canvas.height);
for(i=0; i<trails.length; i++){
trails[i].draw(ctx, camera, time_now);
}
};
var myrand = bmRandom(0,20);
var canvas = d.getElementById("world");
var ctx = canvas.getContext("2d");
var trails = [];
var i;
var time_now = new Date().getTime();
var time_pre = time_now;
var camera = {x:0, y:0, z:-200};
for(i=0; i<N; i++){
trails.push(new Trail({x:myrand(), y:myrand(), z:myrand()},
time_now,
function(a,z){return "#FFFFFF";}));
}
for(i=0; i<N; i++){
switch(i%3){
case 0:
trails[i].color_f=function(ctx, a, dz){
var b = dz<10?0:a*F/dz;
b = (b>1?1:b)*(dz<30?(dz-10)/20:1);
ctx.strokeStyle = "rgba(230,230,230,"+b+")";
ctx.lineWidth = F/dz;
ctx.lineCap = b>0.8?"round":"butt";
};
break;
case 1:
trails[i].color_f=function(ctx, a, dz){
var b = dz<10?0:a*F/dz;
b = (b>1?1:b)*(dz<30?(dz-10)/20:1);
ctx.strokeStyle = "rgba(230, 230,230,"+b+")";
ctx.lineWidth = F/dz;
ctx.lineCap = b>0.8?"round":"butt";
};
break;
default:
trails[i].color_f=function(ctx, a, dz){
var b = dz<10?0:a*F/dz;
b = (b>1?1:b)*(dz<30?(dz-10)/20:1);
ctx.strokeStyle = "rgba(132,232,251,"+b+")";
ctx.lineWidth = F/dz;
ctx.lineCap = b>0.8?"round":"butt";
};
break;
}
}
var loop = function(){
canvas.width = w.innerWidth;
canvas.height = w.innerHeight;
ctx.translate(canvas.width/2, canvas.height/2);
updateScene();
drawScene(ctx);
w.requestAnimationFrame(loop);
}
loop();
}(document, window);
$("#eY").click(function(){
$("#eY").toggleClass("start");
});
});
And here you can see my JsFiddle to make things easier. The other solution I've thought about is using CSS to hide the canvas but am I right in saying using display:none; on a canvas doesn't stop the calculations which effectively will put load on the browser?
Hiding the canvas will only hide the element itself, but it won't stop the loop from running. You need something to tell the animation loop to stop from inside it. You can for example use a boolean flag.
Example:
var isRunning = true; // this will keep animation running or stop it
var loop = function(){
canvas.width = w.innerWidth;
canvas.height = w.innerHeight;
ctx.translate(canvas.width/2, canvas.height/2);
updateScene();
drawScene(ctx);
if (isRunning) w.requestAnimationFrame(loop); // check if we're running...
}
loop();
// helper function to restart the loop when toggled from not running, to running
function toggle() {
isRunning = !isRunning;
if (isRunning) loop(); // if new status is running, start loop
};
// move this inside the animation scope so we have access to the loop etc.
$("#eY").click(function(){
$("#eY").toggleClass("start");
toggle(); // also call this
});
Updated fiddle
There may be other issues, I only addressed this one. Just open new question if there should be.
Off-topic: cool animation, reminds me of TrapCode's Strokes in AE/Combustion.
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!
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;
}