1

I want to build a tower stacking game. A click triggers the block to fall down. I need to listen on when the falling stone goes to sleep and trigger an event afterwards to get the next round started.

To enable the sleep listeners I need to specify in the config matter: {enableSleeping: true}. But as soon as I set this my block doesn't fall any longer. When I remove the line 63 block.setStatic(true);, the block falls. But it falls without my interaction. Also, if block.setStatic(true); is set, the block goes to sleep. I need to prevent it from doing so, while I haven't interacted yet.

Does anybody know how I can fix this?

https://codepen.io/Wizardsmegid/pen/LYXKXEr

const sceneWidth = 380;
const sceneHeight = 600;
const stageOffset = 100;
const stageWidth = sceneWidth + stageOffset * 2;
const stageHeight = 2000;
const craneHeight = 100;
const craneDistance = 400;
const blockHeight = 100;
let craneSpeed = 1500;

const cameraPositionLeft = (stageWidth - sceneWidth) / 2;
const cameraPositionTop = stageHeight - sceneHeight;
let cranePositionTop = stageHeight - craneDistance;
let blockPositionTop = cranePositionTop;

let camera;

const config = {
  type: Phaser.AUTO,
  width: sceneWidth,
  height: sceneHeight,
  physics: {
    default: 'matter',
    matter: {
      enableSleeping: true
    }
  },
  scene: {
    preload: preload,
    create: create,
    update: update
  }
};

const game = new Phaser.Game(config);

function preload() {
  const background = this.load.image('sky', `https://fakeimg.pl/${stageWidth}x${stageHeight}/cfe1ff/`);
  const crane = this.load.image('crane', `https://fakeimg.pl/100x${craneHeight}/6e6e6e/`);
  const block = this.load.image('block', `https://fakeimg.pl/${blockHeight}x${blockHeight}/e7812f/`);
  this.load.image('steadyBlock', `https://fakeimg.pl/100x50/e7812f/`);
}

const enableGravity = () => {
  background.disableInteractive();
  block.setStatic(false);
}

function create() {
  camera = this.cameras.main;
  background = this.add.image(0, 0, 'sky').setOrigin(0);
  crane = this.add.image(300, cranePositionTop, 'crane').setOrigin(.5, 1);
  steadyBlock = this.matter.add.image(stageWidth / 2, stageHeight, 'steadyBlock').setOrigin(.5, .5).setBounce(0).setMass(100);
  
  camera.setBounds(cameraPositionLeft, 0, stageWidth, stageHeight);
  camera.scrollY = cameraPositionTop;
  this.matter.world.setBounds(0, 0, stageWidth, stageHeight);
  
  const startRound = () => {
    background.setInteractive();
    
    block = this.matter.add.image(300, blockPositionTop, 'block').setOrigin(.5, .5).setBounce(0).setMass(10);
    // block.setStatic(true);
    block.setSleepEvents(true, true)
  }
  
  startRound();
  
  background.on('pointerdown', enableGravity);
  
  this.matter.world.on('sleepstart', (event, body) => {
    console.log('block went to sleep');
  })
  
}

function update() {
  
}
Wiz
  • 61
  • 5

1 Answers1

0

An easier solution is, to simply create the block on the click-event, like this you don't have to interact so much with the physics-engine.

Here a small Demo:

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

let canvas = document.querySelector('#app');

const sceneWidth = 380;
const sceneHeight = 600;
const stageOffset = 100;
const stageWidth = sceneWidth + stageOffset * 2;
const stageHeight = 2000;
const craneHeight = 100;
const craneDistance = 400;
const blockHeight = 100;
let craneSpeed = 1500;

const cameraPositionLeft = (stageWidth - sceneWidth) / 2;
const cameraPositionTop = stageHeight - sceneHeight;
let cranePositionTop = stageHeight - craneDistance;
let blockPositionTop = cranePositionTop;

let camera;

const config = {
  canvas: canvas,
  type: Phaser.WEBGL,
  width: sceneWidth,
  height: sceneHeight,
  physics: {
    default: 'matter',
    matter: { enableSleeping: true }
  },
  scene: {
    preload: preload,
    create: create
  }
};


function preload() {
  const background = this.load.image('sky', `https://fakeimg.pl/${stageWidth}x${stageHeight}/cfe1ff/`);
  const crane = this.load.image('crane', `https://fakeimg.pl/100x${craneHeight}/6e6e6e/`);
  const block = this.load.image('block', `https://fakeimg.pl/${blockHeight}x${blockHeight}/e7812f/`);
  this.load.image('steadyBlock', `https://fakeimg.pl/100x50/e7812f/`);
}

function createBlock(){
    block = this.matter.add.image(300, blockPositionTop, 'block').setOrigin(.5, .5).setBounce(0).setMass(10);
    block.setSleepEvents(true, true);
}

function create() {
  camera = this.cameras.main;
  background = this.add.image(0, 0, 'sky')
      .setInteractive()
      .setOrigin(0);

  crane = this.add.image(300, cranePositionTop, 'crane').setOrigin(.5, 1);
  steadyBlock = this.matter.add.image(stageWidth / 2, stageHeight, 'steadyBlock').setOrigin(.5, .5).setBounce(0).setMass(100);
  
  camera.setBounds(cameraPositionLeft, 0, stageWidth, stageHeight);
  camera.scrollY = cameraPositionTop;
  this.matter.world.setBounds(0, 0, stageWidth, stageHeight);
  
  background.on('pointerdown', createBlock, this);
  
  this.matter.world.on('sleepstart', (event, body) => {
    console.log(event.source.gameObject);
  });
}

new Phaser.Game(config);
console.clear();
<script src="//cdn.jsdelivr.net/npm/phaser/dist/phaser.min.js"></script>
<canvas id="app" style="width:124px;"></canvas>

Update Code Example with sleep:
For the demo: On click the block will be awake for 500ms,then go to sleep.

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

let canvas = document.querySelector('#app');

const sceneWidth = 380;
const sceneHeight = 600;
const stageOffset = 100;
const stageWidth = sceneWidth + stageOffset * 2;
const stageHeight = 2000;
const craneHeight = 100;
const craneDistance = 400;
const blockHeight = 100;
let craneSpeed = 1500;

const cameraPositionLeft = (stageWidth - sceneWidth) / 2;
const cameraPositionTop = stageHeight - sceneHeight;
let cranePositionTop = stageHeight - craneDistance;
let blockPositionTop = cranePositionTop;

let camera;

const config = {
  canvas: canvas,
  type: Phaser.WEBGL,
  width: sceneWidth,
  height: sceneHeight,
  physics: {
    default: 'matter',
    matter: { enableSleeping: true }
  },
  scene: {
    preload: preload,
    create: create
  }
};


function preload() {
  const background = this.load.image('sky', `https://fakeimg.pl/${stageWidth}x${stageHeight}/cfe1ff/`);
  const crane = this.load.image('crane', `https://fakeimg.pl/100x${craneHeight}/6e6e6e/`);
  const block = this.load.image('block', `https://fakeimg.pl/${blockHeight}x${blockHeight}/e7812f/`);
  this.load.image('steadyBlock', `https://fakeimg.pl/100x50/e7812f/`);
}

function createBlock(){
    block = this.matter.add.image(300, blockPositionTop, 'block').setOrigin(.5, .5).setBounce(0).setMass(10);
    block.setSleepEvents(true, true);
}

function create() {
  camera = this.cameras.main;
  background = this.add.image(0, 0, 'sky')
      .setInteractive()
      .setOrigin(0);

  crane = this.add.image(300, cranePositionTop, 'crane').setOrigin(.5, 1);
  steadyBlock = this.matter.add.image(stageWidth / 2, stageHeight, 'steadyBlock').setOrigin(.5, .5).setBounce(0).setMass(100);
  
  camera.setBounds(cameraPositionLeft, 0, stageWidth, stageHeight);
  camera.scrollY = cameraPositionTop;
  this.matter.world.setBounds(0, 0, stageWidth, stageHeight);
  
  createBlock.bind(this)() 
  
  block.setToSleep();
  background.on('pointerdown', () => {
  
      block.setAwake();
      setTimeout( () => block.setToSleep(), 500 );
   }, this);
  
  this.matter.world.on('sleepstart', (event, body) => {
    console.log(event.source.gameObject);
  });
}

new Phaser.Game(config);
console.clear();
<script src="//cdn.jsdelivr.net/npm/phaser/dist/phaser.min.js"></script>
<canvas id="app" style="width:124px;"></canvas>
winner_joiner
  • 12,173
  • 4
  • 36
  • 61
  • Thanks for your answer. Your idea to create the block on click, could work for my case. It's a workaround. I will try this out tomorrow. Thank you! – Wiz Aug 13 '23 at 20:05
  • @Wiz if my answer work consider accepting it with the green checkmark next to the up votes. Or is there still something missing? – winner_joiner Aug 23 '23 at 04:39
  • Well. it is a workaround for my specific case. Not a real solution to the problem. I would love to have a possibility where I can say "I can toggle gravity for an object but am able to make use of the sleep functionality" – Wiz Aug 24 '23 at 16:47
  • If you really need or want a solution with the sleep property, I updated my answer with a demo showing how you could use sleep, nevertheless for a game it is sometimes better to fake stuff, to make it work more efficient. In any case I the question is somehow answered/solved please consider accepting it with the green checkmark. Or if you have a better solution sharing it. Thanks – winner_joiner Aug 25 '23 at 05:33