简体   繁体   中英

Javascript canvas animation unable to be used more than once

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.

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.

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/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM