Aftersun Lotion
Aftersun Lotion

Reputation: 55

Phaser 3 how to setup collision to multiple layers

strangely enough, I am not able to setup collision on multiple layers in Phaser 3. I've setup collision for specific indexes in walls layer and everythng works but I am not able to setup collision to waterLayer as a whole. Waterlayer renders correctly and I am able to log the waterLayer properties. For some reason still, player always is able to run trough the waterlayer. Here is relevant code:

  preload() {
    // Load spritesheet for the protagonist
    this.load.spritesheet('protagonist', '/assets/mainCH.png', { frameWidth: 100, frameHeight: 100 });
    this.load.spritesheet('enemy', '/assets/waterspirit.png', { frameWidth: 150, frameHeight: 150 });
   
   
   
    
  
    // Load tileset and tilemap
    this.load.tilemapTiledJSON('map', '/assets/maps/worldmap.json');

    
    
    this.load.image('spruce', '/assets/spruce.png', { frameWidth: 150, frameHeight: 150 });
    this.load.scenePlugin('AnimatedTiles', '/phaser-animated-tiles/src/plugin/AnimatedTiles.js', 'animatedTiles', 'animatedTiles');
    this.load.image('dark_tiles', 'assets/maps/terrain_dark.png');
  }

  create() {

    //resize canvas when coming from scene-two
    const gameConfig = this.sys.game.config;
            // Create the weather effects
            this.renderer.pipelines.addPostPipeline('rainPostFX', RainFX);
            this.cameras.main.setPostPipeline(RainFX);
    

    // Resize the game canvas
    this.scale.resize(sizes.width, sizes.height);
  // Create the protagonist sprite
    this.protagonist = this.physics.add.sprite(characterPositionInWorldMap, 250, 'protagonist');
    this.protagonist.body.setCollideWorldBounds(true);

    // Set the size and offset of the hitbox

    this.protagonist.body.setSize(hitboxWidth, hitboxHeight);
    this.protagonist.body.setOffset(hitboxOffsetX, hitboxOffsetY);
    
     // Initialize the hitbox sprite for collision detection

    this.enemy = this.physics.add.sprite(200, 100, 'enemy');
 

    // Set up properties for the water spirit
    this.enemy.speed = 100; // Adjust the speed as needed
    this.protagonist.setDepth(4);
   
    this.enemy.setDepth(1);
    const map = this.make.tilemap({ key: 'map' });
  
    this.animatedTiles.init(map);
    this.physics.world.createDebugGraphic();

// Add the tilesets
const darkTileset = map.addTilesetImage('dark_tiles', 'dark_tiles');

// Create layers from tilemap data using different tilesets
const groundLayer = map.createLayer('Groundlayer', darkTileset, 0, 0);
const waterLayer = map.createLayer('waterlayer', darkTileset, 0, 0);
const grassLayer = map.createLayer('grass_and_tree_layer', darkTileset, 0, 0);
const stoneLayer = map.createLayer('stones_n_stuff', darkTileset, 0, 0);

// Create hut layer using the hut tileset
const hutLayer = map.createLayer('hutLayer', darkTileset, 0, 0);
const transportlayer = map.createLayer('transportlayer', darkTileset, 0, 0);
const walls = map.createLayer('walls', darkTileset, 0, 0);


    // Adjust the depth of layers as needed
    groundLayer.setDepth(1);
    waterLayer.setDepth(1);
    grassLayer.setDepth(1);
    stoneLayer.setDepth(2);
    hutLayer.setDepth(30);
    walls.setDepth(2);
    transportlayer.setDepth(2);
   
// Enable collision for the specified tile indexes
// Set collision for specified tile indexes in the waterLayer
waterIndex.forEach(index => {
  map.setCollision(index, true, this.waterLayer);
});

    collidableTileIndexes.forEach(index => {
      map.setCollision(index, true, this.walls);
  });


    // Define animations.....
  
   
    // Set up keyboard input
    this.cursors = this.input.keyboard.createCursorKeys();
   
    this.physics.world.setBounds(0, 0, map.widthInPixels, map.heightInPixels);
 

 // Enable debug rendering for the tilemap layer representing water
waterLayer.renderDebug = true;
 
 this.groundLayer = groundLayer;
 this.waterLayer = waterLayer;
 this.grassLayer = grassLayer;
 this.stoneLayer = stoneLayer;
 this.hutLayer = hutLayer;
 this.walls = walls;
 this.transportlayer = transportlayer;


  // Listen for collision between protagonist and walls
  this.physics.add.collider(this.protagonist, this.walls, () => {
    // Disable movement controls for the protagonist
    //this.protagonist.setVelocity(0); // Stop the protagonist's movement
    console.log("wall hit")
    });
 // Set up collision detection between the protagonist and the waterLayer
 this.physics.add.collider(this.protagonist, this.waterLayer);
   // Set up camera to follow the player
   this.cameras.main.startFollow(this.protagonist);
this.enterHutText = this.add.text(this.protagonist.x, this.protagonist.y, 'Press f to enter the hut', { font: '24px Arial', fill: '#ffffff' });
this.enterHutText.setDepth(100);
this.physics.add.existing(this.protagonist);
this.physics.add.existing(this.waterLayer);
this.physics.add.collider(this.protagonist, this.waterLayer);

  }

  update() {
    
    // Reset velocity
    this.protagonist.setVelocity(0);
    this.physics.collide(this.protagonist, this.waterIndex, () => {
      console.log("hit");
  }, null, this);
 
   //some irrelevant logic....
   


    // Handle keyboard input......



 
    this.physics.moveToObject(this.enemy, this.protagonist, this.enemy.speed);
     // Play the appropriate animation based on the collision result





}



}

Upvotes: 1

Views: 175

Answers (2)

Aftersun Lotion
Aftersun Lotion

Reputation: 55

Instead of writing:

// Set up collision detection for water layer
map.setCollisionBetween(1, 1000, true, 'waterlayer'); // Adjust tile indexes as needed
// Set up collision detection for walls layer
map.setCollisionBetween(1, 1000, true, 'walls'); // Adjust tile indexes as needed

Write:

walls.setCollisionBetween(1, 1000, true);
waterLayer.setCollisionBetween(1, 1000, true);

Upvotes: 0

winner_joiner
winner_joiner

Reputation: 14870

The issue is that you are adding the water layer to the "physics world", with the line

this.physics.add.existing(this.waterLayer);

If you remove that line, it should work. Since this is not needed for the tiles/layers, Similar as the other layers in your code.

Here a short demo,...
... if this doesn't work you would have to narrow the program

document.body.style = 'margin:0;';

var config = {
  width: 400,
  height: 180,
  physics: {
    default: 'arcade',
    arcade: {
      gravity: {
        y: 100
      },
      debug: false,
    }
  },
  scene: {
    create,
    update,
  },
  banner: false,
};

function create() {
  this.add.text(10, 10, 'Green Layer is configured wrong\nRed is configured correct');

  // Creating Graphics for the DEMO ->
  let graphics = this.make.graphics();
  graphics.fillStyle(0x00ff00);
  graphics.fillRect(8, 0, 8, 8);

  graphics.generateTexture('tiles', 8 * 4, 8);
  graphics.fillStyle(0xff0000);
  graphics.fillRect(8, 0, 8, 8);

  graphics.generateTexture('tiles2', 8 * 4, 8);
  // Creating Graphics for the DEMO <-

  // Creating map data for the demo 
  var mapData = '00000010000'.split('').map(rowValue => rowValue.repeat(50).split(''))

  // Map1 will not be added to th physics world
  var map1 = this.make.tilemap({
    data: mapData,
    tileWidth: 8,
    tileHeight: 8
  });
  var tiles = map1.addTilesetImage('tiles');
  var layer1 = map1.createLayer(0, tiles, 0, 0);
  layer1.setCollision(1);


  // Map2 will be added to th physics world
  var tiles2 = map1.addTilesetImage('tiles2');
  var map2 = this.make.tilemap({
    data: mapData,
    tileWidth: 8,
    tileHeight: 8
  });
  var layer2 = map2.createLayer(0, tiles2, 0, 50);
  layer2.setCollision(1);
  
  // Simple Player that just falls
  this.player = this.add.circle(16, 16, 4, 0xffffff)
    .setDepth(2);
  this.physics.add.existing(this.player);

  this.physics.add.collider(layer1, this.player);
  // following line breaks the collision logic, ...
  // ... but enables `collide` checks
  this.physics.add.existing(layer1, true);
  
  
  this.physics.add.collider(layer2, this.player);
  // following line breaks the collision logic, ...
  // ... but enables `collide` checks
  // this.physics.add.existing(layer2, true);

  this.layer1 = layer1;
  this.layer2 = layer2;

}

function update() {

  // this will work
  this.physics.collide(this.player,  this.layer1, () => {
     console.log("hit - 1");
  }, null, this);
  
  // this won't work
  this.physics.collide(this.player,  this.layer2, () => {
     console.log("hit - 2");
  }, null, this);

}

new Phaser.Game(config);
console.clear();
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/phaser.js"></script>

btw.: you could alternatively use collideTiles, but this is a whole other can of worms.

Upvotes: 0

Related Questions