Search code examples
spritep5.jsskspritenodeglitch-framework

Sprite/P5- count how many times an object hits another


I'm trying to build pong where after the ball hits the paddle x amount of times, a Christmas animation will appear. I'm not sure how to register this though, as well as if I should use an if else to switch to the animation. Stackoverflow won't let me post my question because it says it is "mostly code" so this is me trying to take up more text space. Here is my code so far:

function setup() {
  createCanvas(windowWidth, windowHeight);
  //frameRate(6);

  paddleA = createSprite(30, height / 2, 10, 100);
  paddleA.immovable = true;

  paddleB = createSprite(width - 28, height / 2, 10, 100);
  paddleB.immovable = true;

  wallTop = createSprite(width / 2, -30 / 2, width, 30);
  wallTop.immovable = true;

  wallBottom = createSprite(width / 2, height + 30 / 2, width, 30);
  wallBottom.immovable = true;

  ball = createSprite(width / 2, height / 2, 10, 10);
  ball.maxSpeed = MAX_SPEED;

  paddleA.shapeColor = paddleB.shapeColor = ball.shapeColor = color(
    255,
    0,
    255
  );

  ball.setSpeed(MAX_SPEED, -180);
}

function draw() {
  background(0);

  paddleA.position.y = constrain(
    mouseY,
    paddleA.height / 2,
    height - paddleA.height / 2
  );
  paddleB.position.y = constrain(
    mouseY,
    paddleA.height / 2,
    height - paddleA.height / 2
  );

  ball.bounce(wallTop);
  ball.bounce(wallBottom);

  var swing;
  if (ball.bounce(paddleA)) {
    swing = (ball.position.y - paddleA.position.y) / 3;
    ball.setSpeed(MAX_SPEED, ball.getDirection() + swing);
  }

  if (ball.bounce(paddleB)) {
    swing = (ball.position.y - paddleB.position.y) / 3;
    ball.setSpeed(MAX_SPEED, ball.getDirection() - swing);
  }

  if (ball.position.x < 0) {
    ball.position.x = width / 2;
    ball.position.y = height / 2;
    ball.setSpeed(MAX_SPEED, 0);
  }

  if (ball.position.x > width) {
    ball.position.x = width / 2;
    ball.position.y = height / 2;
    ball.setSpeed(MAX_SPEED, 180);
  }
  
  drawSprites();

  //switch to Xmas animation
  //if (ball.bounce(paddleA)) {
    //background("brown");

Solution

  • Based on your comment here is a way you could go:

    You said you want to show the animation after the ball bounces on the paddle for a certain amount of time, to do that you can create a variable which will contain this count and be updated each time the ball touches a paddle.

    So you can create for example let hitCount=0; outside of setup() and draw() this way you'll have a variable you can access from everywhere.

    You already check when the ball touches a paddle with your conditions if (ball.bounce(paddleA)) { and if (ball.bounce(paddleB)) { so you can use these blocks of code to update hitCount:

    if (ball.bounce(paddleA)) {
        hitCount++;
        swing = (ball.position.y - paddleA.position.y) / 3;
        ball.setSpeed(MAX_SPEED, ball.getDirection() + swing);
    }
    
    if (ball.bounce(paddleB)) {
        hitCount++;
        swing = (ball.position.y - paddleB.position.y) / 3;
        ball.setSpeed(MAX_SPEED, ball.getDirection() - swing);
    }
    

    And then you want to hide your sprites and run the animation. I think the simplest way to do that is to stop calling drawSprites() you can add the following to your draw() function:

    if (hitCount < HITS_BEFORE_ANIMATION) {
        // Show the game if we didn't reach the number of hits
        drawSprites();        
    } else {
        // Show the animation
        text('Merry christmas', width/2, height/2);
    }
    

    That requires that you create a const HITS_BEFORE_ANIMATION=10 next to where you declared hitCount. What you are doing here is to show the sprites if the ball bounced less than X times and otherwise show the animation (here a simple text).

    Finally you want to show the game again when the animation is over. There are a lot of different ways to do it and that will depend mostly on how you code your animation. For the sake of this answer I will say that we want to show the animation for 50 frames and then go back to the game.

    So let's declare let animationCount=0 which will hold the number of frames the animation has been shown so far and const ANIMATION_FRAMES=50 which will hold the number of frames to show the animation. We can then update the previous code like this:

    if (hitCount < HITS_BEFORE_ANIMATION) {
        // Show the game if we didn't reach the number of hits
        drawSprites();        
    } else {
        // Show the animation
        text('Merry christmas', width/2, height/2);
        animationCount++;
        
        // Stop showing the animation and go back to the game after some time
        if (animationCount === ANIMATION_FRAMES) {
            hitCount=0; // Return to game
            animationCount = 0;
        }
    }
    

    This way when you're done with the animation hitCount is reset to zero which reenable drawSprites() and we also reset animationCount otherwise next time it should be shown if (animationCount === ANIMATION_FRAMES) would be immediately true and we would show it only for one frame.

    I created a codepen with your code and what I added so that you can see it working. It is available here I think it should give you what you need to get started, you will probably need to do some adjustments once you code your animation but at least you'll have an idea of how to proceed.