0

I am trying to make a sonic 2d platformer. However I am struggling with making my sonic entity collide with my platform. Right now my sonic is falling through the platform as if my collisionCheck() method does not work at all. Here is my sonic.js:

class Sonic {

  constructor(game) {
      this.game = game;
      this.game.sonic = this; // special entity
      this.position = {
        x: 0,
        y: 0
      }
      this.velocity = {
        x: 0, //increase as to the right ->
        y: 0 // increase as downwards 
      }
      this.speed = 1300;
      this.jumpSpeed = 200;
      this.spinSpeed = 1400;
      this.spritesheet = ASSET_MANAGER.getAsset("./sprites/realSonicSheet.png");
      this.updateBB();

      this.animations = [];
      this.state = 0;
      this.direction = 0;
      this.loadAnimations();
      this.ground = 550;
      this.onGround = false;
      this.BB = null;
      this.lastBB = null;
  }

  loadAnimations() {
    for (var i = 0; i < 4; i++) { // four states (idle, running, jumping and spinning)
        this.animations.push([]);
        for (var k = 0; k < 2; k++) { // two directions (right or left)
            this.animations[i].push([]);
        }
     }

    // idle animation for state = 0
    // facing right = 0
    this.animations[0][0] = new Animator(this.spritesheet, 5, 723, 45, 45, 1, 0.33, 0, false, true);

    // facing left = 1
    this.animations[0][1] = new Animator(this.spritesheet, 741, 38, -41, 47, 1, 0.33, 0, true, true); // change to true true if issues

    // run animation
    // facing right
    this.animations[1][0]=  new Animator(this.spritesheet, 2, 916, 49, 45, 14, 0.08, 0, false, true);

    // facing left
    this.animations[1][1] = new Animator(this.spritesheet, 745, 230, -49, 47, 14, 0.08, 0, false, true);

    // jump animation
    // facing right
    this.animations[2][0] = new Animator(this.spritesheet, 340, 1160, 47, 56, 8, 0.08, 0, false, true);

    // facing left
    this.animations[2][1] = new Animator(this.spritesheet, 410, 480, -47, 56, 8, 0.08, 0, false, true);

    // spinning animation
    // facing right
    this.animations[3][0] =  new Animator(this.spritesheet, 1, 1113, 47, 40, 10, 0.08, 0, false, true);
    // facing left
    
    this.animations[3][1] = new Animator(this.spritesheet, 746, 427, -47, 40, 10, 0.08, 0, false, true);
  }
  updateBB() {
    this.BB = new BoundingBox(this.position.x, this.position.y, 155, 130, "red");
    this.lastBB = new BoundingBox(this.BB.x, this.BB.y, this.BB.width, this.BB.height, this.BB.color);
  
    console.log("This is this.BB", this.BB);
  }
  
update() {
  const GRAVITY = 0.5;
  this.updateBB();
  let standingOnPlatform = false;
  let canvasHeight = 768;
  // Move left
  if (this.game.left) {
    console.log(this.game.left);
    
    this.position.x -= this.speed * this.game.clockTick;
    this.direction = 1;
    this.state = 1;
    console.log(this.position.x);
  }
  // Move right and spinning left
  if (this.game.spin && this.game.left) {
    this.position.x -= this.spinSpeed * this.game.clockTick;
    this.state = 3;
  } 
  // Move right
  if (this.game.right) {
    console.log(this.game.right);
    this.position.x += this.speed * this.game.clockTick;
    this.direction = 0;
    this.state = 1
    console.log(this.position.x)
  }
  // Jump
  
    if (this.game.jump) {
      console.log(this.game.jump)
      this.position.y -= 20;
      this.state = 2;
      this.direction = 0;
      
  }
  this.velocity.y += GRAVITY; // Gravity to pull sonic down after jumping
  this.position.y += this.velocity.y;

    // Spin
  if (this.game.spin) {
    console.log(this.game.spin)
    this.position.x += this.spinSpeed * this.game.clockTick;
    this.position.y += 10;
    this.state = 3;
  }

  // Set state back to idle if no actions are being performed
  if (!this.game.left && !this.game.right && !this.game.jump && !this.game.spin) {
    this.state = 0;
  }
  // If Sonic is not standing on a platform, check if he has fallen off the screen
  if (!standingOnPlatform) {
    this.velocity.y += GRAVITY;
    this.position.y += this.velocity.y;

    // // Check if Sonic has fallen off the screen
    // if (this.position.y > canvasHeight) {
    //   // Reload the game
    //   window.location.reload();
    //   this.position.y = 300; // start at y position 300
    // }
}

// Update the bounding box for Sonic's new position
this.updateBB();
this.collisionCheck();
}

collisionCheck() {
  this.game.entities.forEach(entity => {
    if (this !== entity && entity.BB && this.BB.collide(entity.BB)) {
      if (entity instanceof Platform) {
        if (this.velocity.y > 0 && this.lastBB.bottom <= entity.BB.top) {
          this.position.y = entity.BB.top - this.BB.height;
          this.velocity.y = 0;
          this.onGround = true;
          return;
        }
        if (this.velocity.y < 0 && this.lastBB.top >= entity.BB.bottom) {
          this.position.y = entity.BB.bottom;
          this.velocity.y = 0;
          return;
        }
        if (this.velocity.x > 0 && this.lastBB.right <= entity.BB.left) {
          this.position.x = entity.BB.left - this.BB.width;
          this.velocity.x = 0;
          return;
        }
        if (this.velocity.x < 0 && this.lastBB.left >= entity.BB.right) {
          this.position.x = entity.BB.right;
          this.velocity.x = 0;
          return;
        }
      }
    }
  });
}

  draw(ctx) {
    if(this.state < 0 || this.state > 3) this.state = 0;
    let done = this.animations[this.state][this.direction].drawFrame(this.game.clockTick, ctx, this.position.x - this.game.camera.x , this.position.y);
    if (done) {
      this.animations[this.state][this.direction].elapsedTime = 0;
      this.state = 0;
    }
    if (PARAMS.DEBUG) {
      this.game.ctx.strokeStyle = "red";
      this.game.ctx.strokeRect(this.BB.x - this.game.camera.x, this.BB.y, this.BB.width, this.BB.height);
    }
  }
}

Here is my platform.js

class Platform {
  constructor(game, x, y, width, height) {
    this.game = game;
    this.position = {
      x: x,
      y: y
    };
    this.width = width;
    this.height = height;
    this.boundingBox = {
      x: this.position.x,
      y: this.position.y,
      width: this.width,
      height: this.height
    };
    this.spritesheet = ASSET_MANAGER.getAsset("./sprites/floor.png");
  }

  updateBB() {
    this.boundingBox.x = this.position.x;
    this.boundingBox.y = this.position.y;
  }

  update() {
    this.updateBB();
  }

  draw(ctx) {
    ctx.drawImage(this.spritesheet, this.position.x - this.game.camera.x, this.position.y, this.width, this.height);

    if (PARAMS.DEBUG) {
      ctx.strokeStyle = "lime";
      ctx.strokeRect(
        this.boundingBox.x - this.game.camera.x,
        this.boundingBox.y,
        this.boundingBox.width,
        this.boundingBox.height
      );
    }
  }
}

I have tried debugging my collisionCheck method (line 142 of sonic.js)and seeing if my bounding boxes are drawn correctly around my sonic and platforms and they are drawn correctly.

J45
  • 1
  • A couple things I noticed at first glance, in Sonic the standingOnPlatform variable needs to be outside of the update method, and within the if statement using that variable should be the only time you apply gravity and velocity y. Also in updateBB instead of creating new BouningBoxes just update each property of this.BB and this.lastBB separately like in the platform updateBB method. – mrall Feb 20 '23 at 20:22

1 Answers1

0

If I interpret this code correctly, you want the player to collide with an object only when it isn't already inside it. ("this.lastBB.bottom <= entity.BB.top", checking if the last position was outside or next to the collision). The problem is, however, that lastBB is always the same as BB so this check only pass when lassBB.bottom is equal to BB.top and will immediately fail at any movement towards the collision.

To fix this you should update the bboxes in this order:
this.lastBB
this.BB

You should therefore add a function to create the original BB before calling this.updateBB

createBB() {
    this.BB = new BoundingBox(this.position.x, this.position.y, 155, 130, "red");
}
updateBB() {
    this.lastBB = new BoundingBox(this.BB.x, this.BB.y, this.BB.width, this.BB.height, this.BB.color);
    this.BB = new BoundingBox(this.position.x, this.position.y, 155, 130, "red");
}

With these changes, lastBB will correspond to the player's last position and the collision check will pass