Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Default timer doesn't stop when calling .stop() #64

Open
theseamusjames opened this issue Sep 7, 2021 · 3 comments
Open

Default timer doesn't stop when calling .stop() #64

theseamusjames opened this issue Sep 7, 2021 · 3 comments

Comments

@theseamusjames
Copy link

theseamusjames commented Sep 7, 2021

Issue:
At run time, from a system, I'm calling engine.stop() but the timer doesn't stop.

Expected behavior:
The timer and subsequently all the systems should stop.

Digging into this problem I found that this.loopId in stop() and this.loopId in loop() were exactly one apart, ie. 2047 in stop and 2048 in loop.

There's some issue with the callback passed into requestAnimationFrame. It seems to preserve the state from one iteration before, and thus, even though we set loopId to null in stop, the previous state is executed on the next call of 'loop' and loopId is reset at the end of the function.

You can see this by setting breakpoints in stop and loop and watching the loopId.

Remedy:
I added a flag called this.stopOnNextFrame. Code below:

export default class DefaultTimer {
  constructor() {
    this.subscribers = [];
    this.loopId = null;
    this.stopOnNextFrame = false;
  }

  loop = time => {
    if (this.stopOnNextFrame ) {
      this.stopOnNextFrame = false;
      return;
    }

    if (this.loopId) {
      this.subscribers.forEach(callback => {
        callback(time);
      });
    }

    this.loopId = requestAnimationFrame(this.loop);
  };

  start() {
    if (!this.loopId) {
      this.loop();
    }
  }

  stop() {
    if (this.loopId) {
      this.stopOnNextFrame = true;
      cancelAnimationFrame(this.loopId);
    }
  }

  subscribe(callback) {
    if (this.subscribers.indexOf(callback) === -1)
      this.subscribers.push(callback);
  }

  unsubscribe(callback) {
    this.subscribers = this.subscribers.filter(s => s !== callback)
  }
}```
@bberak
Copy link
Owner

bberak commented Sep 7, 2021

Hey @theseamusjames,

Thanks for submitting this bug.. I'll try reproduce this over the weekend.. In the mean time, if you haven't already done do, you can replace the default timer with your own implementation:

<GameEngine /* Other props */ timer={new CustomTimer()} />

@StarPleb
Copy link

StarPleb commented Nov 7, 2021

I have an unrelated question, and I'm sorry if I should be asking this somewhere else, but using the timer code you have written is there a way to manually set how often it fires? I'm having an issue with a game I've written where it works as intended on most devices, but on my iPad or a phone with a 120 hz screen everything on screen moves twice as fast.

@bberak
Copy link
Owner

bberak commented Nov 7, 2021

Hey @StarPleb,

You can override the default timer which uses requestAnimationFrame to your own custom timer. You can find an example here: https://github.com/bberak/react-native-game-engine-template/blob/master/src/game/utils/perf-timer.js

And you can integrate it into your GameEngine component like so:

<GameEngine /* Other props */ timer={new CustomTimer()} />

Hope that helps!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants