1
\$\begingroup\$

I'm trying to achieve multiple animations in a game that I am creating using Canvas (it is a simple ping-pong game). This is my first game and I am new to canvas but have created a few experiments before so I have a good knowledge about how canvas work.

First, take a look at the game here. The problem is, when the ball hits the paddle, I want a burst of n particles at the point of contact but that doesn't came right. Even if I set the particles number to 1, they just keep coming from the point of contact and then hides automatically after some time.

Also, I want to have the burst on every collision but it occurs on first collision only. I am pasting the code here:

//Initialize canvas
var canvas = document.getElementById("canvas"),
    ctx = canvas.getContext("2d"),
    W = window.innerWidth, 
    H = window.innerHeight,
    particles = [],
    ball = {},
    paddles = [2],
    mouse = {},
    points = 0,
    fps = 60,
    particlesCount = 50,
    flag = 0,
    particlePos = {}; 

canvas.addEventListener("mousemove", trackPosition, true);

//Set it's height and width to full screen
canvas.width = W;
canvas.height = H;

//Function to paint canvas
function paintCanvas() {
    ctx.globalCompositeOperation = "source-over";
    ctx.fillStyle = "black";
    ctx.fillRect(0, 0, W, H);
}

//Create two paddles
function createPaddle(pos) {
    //Height and width
    this.h = 10;
    this.w = 100;

    this.x = W/2 - this.w/2;
    this.y = (pos == "top") ? 0 : H - this.h;

}

//Push two paddles into the paddles array
paddles.push(new createPaddle("bottom"));
paddles.push(new createPaddle("top"));

//Setting up the parameters of ball
ball = {
    x: 2,
    y: 2,
    r: 5,
    c: "white",
    vx: 4,
    vy: 8,
    draw: function() {
        ctx.beginPath();
        ctx.fillStyle = this.c;
        ctx.arc(this.x, this.y, this.r, 0, Math.PI*2, false);
        ctx.fill();
    }
};

//Function for creating particles
function createParticles(x, y) {
    this.x = x || 0;
    this.y = y || 0;

    this.radius = 0.8;

    this.vx = -1.5 + Math.random()*3;
    this.vy = -1.5 + Math.random()*3;
}

//Draw everything on canvas
function draw() {
    paintCanvas();
    for(var i = 0; i < paddles.length; i++) {
        p = paddles[i];

        ctx.fillStyle = "white";
        ctx.fillRect(p.x, p.y, p.w, p.h);
    }

    ball.draw();
    update();
}

//Mouse Position track
function trackPosition(e) {
    mouse.x = e.pageX;
    mouse.y = e.pageY;
}

//function to increase speed after every 5 points
function increaseSpd() {
    if(points % 4 == 0) {
        ball.vx += (ball.vx < 0) ? -1 : 1;
        ball.vy += (ball.vy < 0) ? -2 : 2;
    }
}

//function to update positions
function update() {

    //Move the paddles on mouse move
    if(mouse.x && mouse.y) {
        for(var i = 1; i < paddles.length; i++) {
            p = paddles[i];
            p.x = mouse.x - p.w/2;
        }       
    }

    //Move the ball
    ball.x += ball.vx;
    ball.y += ball.vy;

    //Collision with paddles
    p1 = paddles[1];
    p2 = paddles[2];

    if(ball.y >= p1.y - p1.h) {
        if(ball.x >= p1.x && ball.x <= (p1.x - 2) + (p1.w + 2)){ 
            ball.vy = -ball.vy;
            points++;
            increaseSpd();

            particlePos.x = ball.x,
            particlePos.y = ball.y;
            flag = 1;
        }
    }

    else if(ball.y <= p2.y + 2*p2.h) {
        if(ball.x >= p2.x && ball.x <= (p2.x - 2) + (p2.w + 2)){ 
            ball.vy = -ball.vy;
            points++;
            increaseSpd();

            particlePos.x = ball.x,
            particlePos.y = ball.y;
            flag = 1;
        }
    }

    //Collide with walls
    if(ball.x >= W || ball.x <= 0)
        ball.vx = -ball.vx;

    if(ball.y > H || ball.y < 0) {
        clearInterval(int);
    }

    if(flag == 1) {
        setInterval(emitParticles(particlePos.x, particlePos.y), 1000/fps);
    }

}

function emitParticles(x, y) {

    for(var k = 0; k < particlesCount; k++) {
        particles.push(new createParticles(x, y));
    }

    counter = particles.length;

    for(var j = 0; j < particles.length; j++) {
        par = particles[j];

        ctx.beginPath(); 
        ctx.fillStyle = "white";
        ctx.arc(par.x, par.y, par.radius, 0, Math.PI*2, false);
        ctx.fill();  

        par.x += par.vx; 
        par.y += par.vy;

        par.radius -= 0.02; 

        if(par.radius < 0) {
            counter--;
            if(counter < 0) particles = [];
        }

    } 
}

var int = setInterval(draw, 1000/fps);

Now, my function for emitting particles is on line 156, and I have called this function on line 151. The problem here can be because of I am not resetting the flag variable but I tried doing that and got more weird results. You can check that out here.

By resetting the flag variable, the problem of infinite particles gets resolved but now they only animate and appear when the ball collides with the paddles. So, I am now out of any solution.

\$\endgroup\$
1
  • \$\begingroup\$ Hey, you might wanna check out this engine I'm making: vidyadev.com/wiki/Irenic. It's still in development stage, though, but it would help you a lot. \$\endgroup\$
    – jcora
    Jul 7, 2012 at 0:17

2 Answers 2

2
\$\begingroup\$

This for next loop is italising the particle every frame, this needs to be outside the function

function emitParticles(x, y) {

    for(var k = 0; k < particlesCount; k++) {
        particles.push(new createParticles(x, y));
    }

You need to wrap an if statement around this otherwise an exception error occurs

 if (par.radius > 0) {
     ctx.arc(par.x, par.y, par.radius, 0, Math.PI*2, false);
 }

You don't need do it like this.

if(flag == 1) {
    setInterval(emitParticles(particlePos.x, particlePos.y), 1000/fps);
}

Do this instead:

if(flag == 1) {
    // initalise particles here, see first comment above
}
emitParticles();

Reason for this is that you will not time your interval with the main loop which is clearing the screen which prevents you from seeing the 'sparks'

Finally, probably harmless, but to be safe, change the comma to a semi-colon here

particlePos.x = ball.x,

You can see the above changes working here

\$\endgroup\$
1
0
\$\begingroup\$

I don't see why you are putting it into a separate animation. Why not just have a main game loop and 'inject' the code into the loop? Then you can have a ParticleManager class that can handle the magnitude of created particles, etc.

I think the fact that you are putting it in a separate animation is causing issues, but is not necessarily the problem.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .