Професионална програма
Loading...
Smeshan avatar Smeshan 89 Точки

Timers

Здравейте,

ясно как с един таймер да местя един обект, но какво правя ако имам няколко от този обект?
Да предположим примерно, че искам да направя падащи снежинки:
Имам си мембър:
std::vector<SnowFlake> _snowFlakes;
и в инициализацията на Game:

_snowFlakes.resize(SNOWFLAKE_COUNT);
for (int32_t i = 0; i < SNOWFLAKE_COUNT; ++i) {
    _snowFlakes[i].init(i, config.fallingTimerId);
    _snowFlakes[i].startAnim();
}

 В обекта съответно:

int32_t SnowFlake::init(const int32_t indx, int32_t timerId) {
    _fallingTimerId = timerId;
    _snowFlakeImg.create(TextureId::SNOWFLAKE_ID, Point(0 + indx* 50, 0));
    return EXIT_SUCCESS;
}
void SnowFlake::startAnim() {
    Timer::startTimer(25, _fallingTimerId, TimerType::PULSE);
}

И съответно само първата тръгва да пада, а за другите изписва грешка "Error, trying to start an already existing timer with ID: " 0 .. Което е логично, но как тогава да го направя да работи за примерно 100 такива обекта? Ако трябва в CommonDefines да напиша 100 ID-та и после да ги попълня в EngingeConfigLoader-a, a след това да ги подавам за всеки обект ми се струва нелогично?

Нещо не ми става ясно как да процедирам при повече обекти.. Ще се радвам ако някой ми помогне.

Поздрави,
Илиян

Тагове:
1
C++ Applications Development
j.petrov_90 avatar j.petrov_90 372 Точки

Привет, Илиян,

MartinBG ти е дал страхотен отговор.
Аз лично обичам да си имам user defined range от timerId според броя на специфичните обекти.
По този начин имам видимост и пълен контрол на коя част от системата ми, кои id-та използвам.

Това може да се постигне по следния начин:

enum Internals {
  MAX_SNOWFLAKE_TIMERS = 100
}

enum TimerId {
  SOME_TIMER_ID,
  ANOTHER_TIMER_ID,
  SNOWFLAKE_FIRST_TIMER_ID,

  //reserved

  SNOWFLAKE_LAST_TIMER_ID = SNOWFLAKE_FIRST_TIMER_ID + MAX_SNOWFLAKE_TIMERS,
  YET_ANOTHER_TIMER_ID
}

Като ще спазвам ограничението, че мога да имам максимум MAX_SNOWFLAKE_TIMERS активни снежинки.

Относто самите снежинки:
Не е проблем всяка да си има собствен таймер.
Просто трябва да се погрижиш, че този таймер е уникален. Също обекта правилно да стартира/пуска този таймер.

Тук вече си пред архитектурна дилема:
Ако имаш 10-20 снежинки - направи 10-20 обекта с индивидуални таймери.

Ако обаче имаш 50, 100, 1000 обекта - не е ОК да пускаш толкова таймери.
Да приемем, че всичките ти обекти работят на една и съща честота.
Тогава можеш да имаш един обект, който управлява всички снежинки. Той ще има само 1 таймер и когато тикне - ще update-ва всички активни снежинки.

class ParticleHandler {
  void onTimeout(int32_t timerId) {
    if (notMyTimer) return;
    
    for (auto& snowflake : _activeSnowflakes) {
      snowflake.process();
    }
  }

  std::vector<Snowflake> _activeSnowflakes;
}


Ако пък имаш нужда от няколко таймера с различни честоти - просто твоя обект може да управлява няколко таймера като предварително си групира обектите си в контейнери спрямо честотите.
Например:

class Particle {};
class SnowFlake : public Particle {};
class Raindrop : public Particle {};

class ParticleHandler {
  void onTimeout(int32_t timerId) {
    if (timerId == frequentId) {
      for (auto& particle : _frequentParticles) {
        particle->process();
      }
    }
    
    else if (timerId == notSoFrequentId) {
      for (auto& particle : _notSoFrequentParticles) {
        particle->process();
      }
    }
  }

  std::vector<std::unique_ptr<Particle>> _frequentParticles;
  std::vector<std::unique_ptr<Particle>> _notSoFrequentParticles;
}


Поздрави

1