2

I have an animation for a game that I am working on that won't seem to repeat. When the space bar is pressed, it triggers an event that "shoots" a circle to the top of a canvas. The problem is that when the key is pressed again it will not initiate the animation. Here is the sample code that I wrote:

var canvas, ctx,
    spaceKey = false,
    upKey = false,
    downKey = false,
    canvas = document.getElementById('canvas'),
    ctx = canvas.getContext('2d'),
    shotX = 150, shotY = 280;

function loop() {
    if (spaceKey) shoot();
}

function keyDown(e) {
    if (e.keyCode == 32) spaceKey = true;
}
function keyUp(e) {
    if (e.keyCode == 32) spaceKey = false;
}

function shoot() {
    setTimeout(function() { if (shotY > 0) {
        ctx.clearRect(shotX-5,shotY-5,600,20);
        ctx.beginPath();
        ctx.arc(shotX, shotY,4,0,Math.PI * 2, false);
        ctx.fillStyle = "yellow";
        ctx.fill();
        ctx.closePath();

        shotY = shotY - 1;

        shoot();

    } else
        ctx.clearRect(shotX-5,shotY-5,600,20);
    }, 100);
}

(function init() {
    setInterval(loop, 10);
    document.addEventListener('keydown', keyDown, false);
    document.addEventListener('keyup', keyUp, false);
})();
//init();

The reason I use keyUp and keyDown is because I have other functions that use different keys. This code was modified to show only this feature. To make it easier to see what I'm talking about, I created a JSFiddle. The other features I have are similarly structured and work, the only difference being that its duration isn't directly controlled by a key press.

Michael Garrison
  • 941
  • 2
  • 15
  • 31
  • 1
    If you hold down the spacebar, you will get **multiple** keydown events being fired. In your code, this causes the yellow ball to speed up as it goes up the screen. Are you trying to speed up the ball or are you trying to fire multiple balls at the same speed? – markE Mar 22 '13 at 05:43
  • It should be multiple bullets. I thought I noticed it getting faster. – Michael Garrison Mar 22 '13 at 05:58
  • If a bullet is in motion up the screen, can the user press the spacebar and fire another bullet? Or must the user wait until the current bullet exits the screen? – markE Mar 22 '13 at 06:13
  • the user can press the space bar as many times as they want. When I combine this with the other elements of my program, the user will move a sprite and shoot the bullets relative to the sprite location. – Michael Garrison Mar 22 '13 at 06:17

2 Answers2

2

I don't find your code much re-usable. You should consider using objects to represents the entities on the canvas. I've created simple code which does your job, but it is also not much re-usable (though you can re-use it to create a simple entity like the ball you created). Check this jsFiddle.

The problem with your code is, when that yellow ball reaches the to of the screen, the shotY is 0, then you erase the ball from the screen, but don't reset the shotY and don't redraw the ball at its home (original position).

I've created a simple Ball object to get this done-

function Ball() {
    this.x = 150;
    this.y = 295;
}
Ball.prototype.draw = function(newx, newy) {
    ctx.clearRect(this.x-5,this.y-5,600,20);
    newx = newx || this.x;
    newy = newy || this.y;
    this.x = newx; this.y = newy;
    var ball = this;
    ctx.beginPath( );
    ctx.arc(ball.x, ball.y,4,0,Math.PI * 2, false);
    ctx.fillStyle = "yellow";
    ctx.fill();
    ctx.closePath();
}
Ball.prototype.shootUp = function() {
    var ball = this;
    inter = setInterval(function () {
        if(ball.x <= 0) clearInterval(inter);
        ball.draw(ball.x, ball.y-20);
    }, 100);
}

and modified your shoot function -

function shoot() {
    var currentBall = new Ball();
    currentBall.draw();
    currentBall.shootUp();
}

And once again, this was just a simple example. You can make a lot of improvements in it. First of all, you should have an input engine to manage all the inputs. Then you should have a generic entity class to represent all the objects you have on the canvas. Like the Ball. And finally you should have a game engine to bind all those things.

ShuklaSannidhya
  • 8,572
  • 9
  • 32
  • 45
  • This is exactly what I was looking for! A big problem of mine is that I don't create objects when I code, which probably explains half of the issues I have. I will definitely keep all of you suggestions in mind as well! – Michael Garrison Mar 22 '13 at 06:21
2

You only have one "bullet". Your bullets should be separate objects that are instantiated on shoot().

The way that I usually handle "particles" is to create a singleton object to store each instance and update all of them in the main loop.

Here's a simple Bullet object:

function Bullet(){
    this.x = 150;
    this.y = 280;
    this.velX = 0;
    this.velY = -1;

    this.update = function(){
        this.y += this.velY;
    };

    this.draw = function(){
        ctx.beginPath();
        ctx.arc(this.x, this.y,4,0,Math.PI * 2, false);
        ctx.fillStyle = "yellow";
        ctx.fill();
        ctx.closePath();
    };
};

And here is a BulletRenderer singleton that handles the bullets:

BulletRenderer = function(){
    var bullets = [];

    this.push = function(bullet){
        bullets.push(bullet);
    };

    this.render = function(){
        for (var i in bullets){
            if (bullets[i].active){
                bullets[i].update();
                bullets[i].draw();
            } else {
                delete bullets[i];
            }
        }
    };

    return this;
}();

In the example I'm just clearing the canvas each frame. The shooting mechanism acts like a laser right now. Personally I would change this behavior.

http://jsfiddle.net/NAJus/18/

slamborne
  • 1,185
  • 11
  • 16
  • +1 for nomenclature... I called it `Ball`, you call it `Bullet`!! Tip - You should assign methods to the constructor's prototype not the object itself. – ShuklaSannidhya Mar 22 '13 at 05:41
  • @Saan - Haha. `"You should assign methods to the constructor's prototype not the object itself."` Why is that? – slamborne Mar 22 '13 at 05:50
  • 1
    Because defining methods every time an object is instantiated is a major performance issue. You should rather add them to it's prototype so that all the instances can share those methods from the prototype rather than having their own copy of those methods. - http://stackoverflow.com/questions/15497259/overriding-methods-in-javascript/15497685#15497685 – ShuklaSannidhya Mar 22 '13 at 06:03