Synchronize a lots of tweens

Hi!

I’m new at Phaser, and game development.

I’m creating a card game using Phaser 3 and I have runned into trubble when I need to synchronize the movement of a lot of cards. I tried to use the .on(‘complete’) but realized that I have to wait for .on(‘complete’) for all cards in some way. I can think of a model when I have a counter for each tween started and send an emit signal when the counter has reach it’s goal. But I thinks that maybe there is a Phaser 3 solution to this problem.

My code looks like this:

showAllPointCards() {
    for (let key in this.sprites_hash) {
      this.sprites_hash[key].setScale(0.5);
    }

let lastUpperMatadorTween = [];
let lastLowerMatadorTween = [];
let lastUpperCourtTween = [];
let lastLowerCourtTween = [];

let upper_matadors = this.judge.getUpperHandMatadors();
let x = 0;
upper_matadors.forEach(e => {
  let current_sprite = this.sprites_hash[e];
  lastUpperMatadorTween.push(this.tweens.add({
    targets: current_sprite,
    //        x: HAND_DIST_FROM_VERTICAL_BORDERS + x * current_sprite.width
    //        + 20,
    x: () => {return HAND_DIST_FROM_VERTICAL_BORDERS + x * current_sprite.width + 20},
    y: HAND_DIST_FROM_HORISONTAL_BORDERS,
    ease: 'Linear',
    duration: SPEED * 5,
    angle: 0
  }));
  x += 1;
  this.showFront(e);
});

let lower_matadors = this.judge.getLowerHandMatadors();
x = 0;
lower_matadors.forEach(e => {
  let current_sprite = this.sprites_hash[e];
  lastLowerMatadorTween.push(this.tweens.add({
    targets: current_sprite,
    x: HAND_DIST_FROM_VERTICAL_BORDERS + x * current_sprite.width + 20,
    y: this.game.renderer.height - HAND_DIST_FROM_HORISONTAL_BORDERS,
    ease: 'Linear',
    duration: SPEED * 5,
    angle: 0
  }));
  x += 1;
  this.showFront(e);
});

let upper_courts = this.judge.getUpperHandCourts();
x = 0;
upper_courts.forEach(e => {
  let current_sprite = this.sprites_hash[e];
  lastUpperCourtTween.push(this.tweens.add({
    targets: current_sprite,
    x: HAND_DIST_FROM_VERTICAL_BORDERS + x * current_sprite.width + 20,
    y: HAND_DIST_FROM_HORISONTAL_BORDERS + current_sprite.height + 20,
    ease: 'Linear',
    duration: SPEED * 5,
    angle: 0
  }));
  x += 1;
  this.showFront(e);
});

let lower_courts = this.judge.getLowerHandCourts();
x = 0;
lower_courts.forEach(e => {
  let current_sprite = this.sprites_hash[e];
  lastLowerCourtTween.push(this.tweens.add({
    targets: current_sprite,
    x: HAND_DIST_FROM_VERTICAL_BORDERS + x * current_sprite.width + 20,
    y: this.game.renderer.height - HAND_DIST_FROM_HORISONTAL_BORDERS -
        current_sprite.height - 20,
    ease: 'Linear',
    duration: SPEED * 5,
    angle: 0
  }));
  x += 1;
  this.showFront(e);
});

// What to do here?
// lastUpperMatadorTween.forEach(e => {e.on('complete', () => {})});
// lastLowerMatadorTween.forEach(f => {f.on('complete', () => {})});
// lastUpperCourtTween.forEach(g => {g.on('complete', () => {})});
// lastLowerCourtTween.forEach(h => {h.on('complete', () => {})});
// this.newSingleDeal();
  }

Anyone that have some advices for me?

If all the tweens have the same duration, you could add a callback for the last tween, or add a timer event of the same duration.

Otherwise, you can probably rewrite each loop into a single tween with multiple targets. The x function receives the current target and current target index.

Otherwise, you can use a timeline and give all tweens offset: 0, then use the timeline’s complete event.

Thank you very much for taking your time Samme!

The tweens takes different time, since the cards have different distance to travel. (EDIT: I guess, but maybe that not the case)

I have been thinking of a way to have multiple targets in a tween but I didn’t know how to extract the index. But I still would need to syncronize four tweens.

I must look into this timeline way, It seems interresting if one can collect all tweens into the same complete event. Thats what I hoped the Phaser 3 could provide.

If the tweens have equal durations and equal delays, then they will complete at the same time.

For multiple targets, see tweens/stagger. You would use target instead of currentSprite and targetIndex instead of x.

For timelines, see tweens/timelines/create timeline.

Thank you again Samme!

I first tried to just waiting on the last tweens ‘oncomplete’ and that was not enough because I saw that some cards where left on the table. Then I tried to wait for the last tween of all four but still got cards left on the table (the code runned just after my tweens is collecting all sprites together).

I will dig in to these examples you have given me because they seems to solve my problem I think.

Wrap tween task into promise if promise is supported in your environment.

Then using Promise.all to run next command after all tweens are completed.

Thank’s for the reply rexrainbow. I will keep this in mind. I’m not sure if it will work on my IPad 4 but that I can check when I run into this kind of problem in the future.

I have solved the problem with the timeline method I got from Samme, the problem however turned out not to be the one I tought, because it was a bug in the first place (my deck of cards contained too many cards, after a refactorization of the code that I didn’t test enough). A little bit annoying but now I have learned some stuff and my code looks a little bit better I think.