Peoplemon  0.1.0
Peoplemon 3 game source documentation
PeoplemonAnimation.cpp
Go to the documentation of this file.
2 
3 #include <BLIB/Math.hpp>
4 #include <BLIB/Util/Random.hpp>
6 #include <Core/Properties.hpp>
7 #include <Core/Resources.hpp>
8 #include <cmath>
9 
10 namespace core
11 {
12 namespace battle
13 {
14 namespace view
15 {
16 namespace
17 {
18 constexpr float PlayerPosX = 88.f;
19 constexpr float PlayerPosY = 265.f;
20 constexpr float OpponentPosX = 508.f;
21 constexpr float OpponentPosY = 25.f;
22 static constexpr float SquareSize = 200.f;
23 const glm::vec2 PlayerPos(PlayerPosX, PlayerPosY);
24 const glm::vec2 OpponentPos(OpponentPosX, OpponentPosY);
25 const glm::vec2 ViewSize(SquareSize, SquareSize);
26 constexpr float SlideRate = 285.f;
27 constexpr float ShakesPerSecond = 18.f;
28 constexpr float ShakeOffMultiple = ShakesPerSecond * 360.f;
29 constexpr float ShakeXMag = 10.f;
30 constexpr float ShakeYMag = 5.f;
31 constexpr float ShakeTime = 0.75f;
32 constexpr float ExpandRate = 600.f;
33 constexpr float ContractRate = 325.f;
34 constexpr float BallFlashRadius = 200.f;
35 constexpr float ArrowOscillations = 4.f;
36 constexpr float ArrowShowTime = 2.5f;
37 constexpr float ArrowShakeAmount = 10.f;
38 constexpr std::uint8_t ScreenFlashAlpha = 100;
39 constexpr float ThrowStartX = -25.f;
40 constexpr float ThrowStartY = PlayerPosY + SquareSize * 0.5f;
41 constexpr float ThrowEndX = OpponentPosX + SquareSize * 0.5f;
42 constexpr float ThrowEndY = OpponentPosY;
43 constexpr float ThrowTime = 1.f;
44 constexpr float ThrowXVel = (ThrowEndX - ThrowStartX) / ThrowTime;
45 constexpr float ThrowMiddle = ThrowStartX + (ThrowEndX - ThrowStartX) * 0.75f;
46 constexpr float ThrowSecondHalfWidth = ThrowEndX - ThrowMiddle;
47 constexpr float ThrowTop = 10.f;
48 constexpr float ThrowA = (ThrowEndY - ThrowTop) / (ThrowSecondHalfWidth * ThrowSecondHalfWidth);
49 constexpr float ThrowSpins = 3.f;
50 constexpr float ThrowSpinRate = ThrowSpins / ThrowTime * 360.f;
51 constexpr float BallBounceHeight = ThrowEndY + SquareSize * 0.75f - OpponentPosY - 20.f;
52 constexpr float BallBounceTime = 1.4f;
53 const glm::vec2 BallFinalPos(ThrowEndX, OpponentPosY + BallBounceHeight);
54 constexpr float BallShakeTime = 0.5f;
55 constexpr float ShakeRestTime = 0.65f;
56 constexpr float ShakeXAmount = 10.f;
57 constexpr float ShakeYAmount = 2.f;
58 constexpr float ShakeCount = 6.f;
59 constexpr float ShakeSpeed = 360.f * ShakeCount;
60 constexpr float GreenRate = 255.f / 0.5f;
61 constexpr glm::vec3 FlashColor(252.f / 256.f, 230.f / 256.f, 30.f / 256.f);
62 
63 constexpr float PeoplemonFlashOn = 0.08f;
64 constexpr float PeoplemonFlashOff = 0.05f;
65 
66 using Animation = cmd::Animation;
67 
68 glm::vec4 makeColor(float alpha) { return glm::vec4(FlashColor, alpha / 256.f); }
69 
70 VkViewport makeViewport(bl::engine::Engine& engine, PeoplemonAnimation::Position pos) {
71  const glm::vec2 corner = pos == PeoplemonAnimation::Player ? PlayerPos : OpponentPos;
72  VkViewport vp{};
73  vp.x = corner.x;
74  vp.y = corner.y;
75  vp.width = engine.renderer().getObserver().getRegionSize().x;
76  vp.height = engine.renderer().getObserver().getRegionSize().y;
77  vp.minDepth = 0.f;
78  vp.maxDepth = 1.f;
79  return vp;
80 }
81 
82 VkRect2D makeScissor(PeoplemonAnimation::Position pos) {
83  const glm::vec2 corner = pos == PeoplemonAnimation::Player ? PlayerPos : OpponentPos;
84  VkRect2D scissor{};
85  scissor.offset.x = corner.x;
86  scissor.offset.y = corner.y;
87  scissor.extent.width = ViewSize.x;
88  scissor.extent.height = ViewSize.y;
89  return scissor;
90 }
91 
92 glm::vec4 sfcol(const sf::Color& c) {
93  return glm::vec4(static_cast<float>(c.r),
94  static_cast<float>(c.g),
95  static_cast<float>(c.b),
96  static_cast<float>(c.a)) /
97  256.f;
98 }
99 } // namespace
100 
101 PeoplemonAnimation::PeoplemonAnimation(bl::engine::Engine& engine, Position pos)
102 : engine(engine)
103 , position(pos)
104 , viewport(makeViewport(engine, pos))
105 , scissor(makeScissor(pos))
106 , renderBall(false) {}
107 
109  if (sparks) { engine.particleSystem().removeRepeatedSystems<PeoplemonSpark>(); }
110 }
111 
112 void PeoplemonAnimation::init(bl::rc::scene::CodeScene* s) {
113  const auto join = bl::util::FileUtil::joinPath;
114  scene = s;
115 
116  const glm::vec2 boxCorner = position == Position::Player ? PlayerPos : OpponentPos;
117 
118  peoplemon.create(engine, engine.renderer().texturePool().getBlankTexture());
119  peoplemon.getTransform().setPosition(ViewSize.x * 0.5f, ViewSize.y);
120  peoplemon.addToScene(scene, bl::rc::UpdateSpeed::Static);
121 
122  ballOpenTxtr = engine.renderer().texturePool().getOrLoadTexture(
123  join(Properties::ImagePath(), "Battle/Balls/peopleball_open.png"));
124  // TODO - consider using multiple graphics based on what ball it was caught in
125  ballTxtr = engine.renderer().texturePool().getOrLoadTexture(
126  join(Properties::ImagePath(), "Battle/Balls/peopleball.png"));
127  ball.create(engine, ballTxtr);
128  setBallTexture(ballTxtr);
129  ball.getTransform().setPosition(ViewSize.x * 0.5f, ViewSize.y * 0.75f);
130  ball.addToScene(scene, bl::rc::UpdateSpeed::Dynamic);
131 
132  ballFlash.create(engine, 100.f);
133  ballFlash.getTransform().setOrigin(100.f, 100.f);
134  ballFlash.getTransform().setPosition(boxCorner + ball.getTransform().getLocalPosition() +
135  glm::vec2(0.f, 15.f));
136  ballFlash.setColorGradient(glm::vec4(FlashColor, 1.f), sfcol(sf::Color::Transparent));
137  ballFlash.addToScene(scene, bl::rc::UpdateSpeed::Static);
138 
139  statTxtr = engine.renderer().texturePool().getOrLoadTexture(
140  join(Properties::ImagePath(), "Battle/statArrow.png"));
141  statArrow.create(engine, statTxtr);
142  statArrow.getTransform().setOrigin(statTxtr->size().x * 0.5f, statTxtr->size().y * 0.5f);
143  statArrow.getTransform().setPosition(ViewSize.x, ViewSize.y * 0.5f);
144  statArrow.addToScene(scene, bl::rc::UpdateSpeed::Dynamic);
145 
146  annoySrc =
147  AnimationManager::load(join(Properties::AnimationPath(), "Battle/Ailments/Annoyed.anim"));
148  confuseSrc =
149  AnimationManager::load(join(Properties::AnimationPath(), "Battle/Ailments/Confusion.anim"));
150  frozenSrc =
151  AnimationManager::load(join(Properties::AnimationPath(), "Battle/Ailments/Frozen.anim"));
152  frustrationSrc = AnimationManager::load(
153  join(Properties::AnimationPath(), "Battle/Ailments/Frustration.anim"));
154  sleepSrc =
155  AnimationManager::load(join(Properties::AnimationPath(), "Battle/Ailments/Sleep.anim"));
156  stickySrc =
157  AnimationManager::load(join(Properties::AnimationPath(), "Battle/Ailments/Sticky.anim"));
158  trappedSrc =
159  AnimationManager::load(join(Properties::AnimationPath(), "Battle/Ailments/Trapped.anim"));
160  // TODO - update to jumped anim when we have it
161  jumpedSrc =
162  AnimationManager::load(join(Properties::AnimationPath(), "Battle/Ailments/Trapped.anim"));
163  recreateAilmentAnimation(trappedSrc);
164  ailmentAnim.getTransform().setPosition(ViewSize * 0.5f);
165 
166  throwBallTxtr = engine.renderer().texturePool().getOrLoadTexture(
167  join(Properties::ImagePath(), "Battle/Balls/peopleball_centered.png"));
168  throwBall.create(engine, throwBallTxtr);
169  setThrowBallTxtr(throwBallTxtr);
170  throwBall.addToScene(scene, bl::rc::UpdateSpeed::Dynamic);
171 
172  sparks = &engine.particleSystem().addRepeatedSystem<PeoplemonSpark>();
173  sparks->addAffector<SparkAffector>();
174  sparks->addSink<SparkSink>();
175  sparkExplosionEmitter = sparks->addEmitter<SparkExplosionEmitter>(boxCorner);
176  sparks->addToScene(scene);
177 
178  implosion = &engine.particleSystem().addRepeatedSystem<PeoplemonSpark>();
179  implosion->addAffector<SparkAffector>();
180  implosion->addSink<SparkSink>();
181  sparkImplosionEmitter = implosion->addEmitter<SparkImplosionEmitter>();
182  implosion->addToScene(scene);
183 
184  screenFlash.create(engine, glm::vec2(Properties::WindowWidth(), Properties::WindowHeight()));
185  screenFlash.addToScene(scene, bl::rc::UpdateSpeed::Static);
186 }
187 
189  const auto path = position == Position::Player ? pplmn::Peoplemon::playerImage :
191  txtr = engine.renderer().texturePool().getOrLoadTexture(path(ppl));
192 
193  const glm::vec2 ts(txtr->size());
194  peoplemon.setTexture(txtr, true);
195  peoplemon.getTransform().setOrigin(ts.x * 0.5f, ts.y);
196  peoplemon.setColor(sf::Color::White);
197  scale.x = ViewSize.x / ts.x;
198  scale.y = ViewSize.y / ts.y;
199  peoplemon.getTransform().setScale(scale);
200  state = State::Hidden;
201 }
202 
204  state = State::Playing;
205  type = anim;
206 
207  switch (anim) {
208  case Animation::Type::ComeBack:
209  alpha = 255.f;
210  sparkImplosionEmitter->setEnabled(true,
211  glm::vec2(viewport.x, viewport.y) + ViewSize * 0.5f);
212  setBallTexture(ballOpenTxtr);
213  ball.setColor(sf::Color::White);
214  break;
215 
216  case Animation::Type::SendOut:
217  ballTime = 0.f;
218  peoplemon.setColor(sf::Color(255, 255, 255, 0));
219  ball.setColor(sf::Color::White);
220  setBallTexture(ballTxtr);
221  screenFlash.setFillColor(sf::Color::Transparent);
222  renderBall = false;
223  break;
224 
225  case Animation::Type::ShakeAndFlash:
226  shakeTime = 0.f;
227  peoplemon.flash(0.08f, 0.05f);
228  break;
229 
230  case Animation::Type::SlideDown:
231  slideAmount = 0.f;
232  break;
233 
234  case Animation::Type::SlideOut:
235  slideAmount = 0.f;
236  break;
237 
238  case Animation::Type::MultipleStateDecrease:
239  statArrow.setColor(sf::Color(70, 70, 70));
240  [[fallthrough]];
241 
242  case Animation::Type::StatDecrease:
243  arrowTime = 0.f;
244  statArrow.getTransform().setScale(1.f, 1.f);
245  break;
246 
247  case Animation::Type::MultipleStateIncrease:
248  statArrow.setColor(sf::Color(70, 70, 70));
249  [[fallthrough]];
250 
251  case Animation::Type::StatIncrease:
252  arrowTime = 0.f;
253  statArrow.getTransform().setScale(1.f, -1.f);
254  break;
255 
258  ailmentAnim.getPlayer().play(true);
259  break;
260 
261  case Animation::Type::MakeWildVisible:
262  state = State::Static;
263  break;
264 
265  case Animation::Type::ThrowCloneBall:
266  case Animation::Type::ThrowPeopleball:
267  throwX = ThrowStartX;
268  throwState = BallThrowState::Arcing;
269  setThrowBallTxtr(throwBallTxtr);
270  throwBall.getTransform().setPosition(ThrowStartX, ThrowStartY);
271  throwBall.getTransform().setRotation(0.f);
272  throwBall.setColor(sf::Color::White);
273  renderBall = true;
274  toEat = &peoplemon;
275  if (anim == Animation::Type::ThrowCloneBall) {
276  clone.create(engine, peoplemon.getTexture());
277  clone.getTransform().setPosition(peoplemon.getTransform().getLocalPosition());
278  clone.addToScene(scene, bl::rc::UpdateSpeed::Dynamic);
279  toEat = &clone;
280  }
281  break;
282 
283  case Animation::Type::PeopleballShake:
284  shakeTime = 0.f;
285  break;
286 
287  case Animation::Type::PeopleballCaught:
288  alpha = 0.f;
289  break;
290 
291  default:
292  BL_LOG_ERROR << "Invalid animation type for peoplemon: " << anim;
293  state = State::Static;
294  break;
295  }
296 }
297 
298 void PeoplemonAnimation::triggerAnimation(const Animation& anim) {
299  switch (anim.getType()) {
300  case Animation::Type::StatDecrease:
301  case Animation::Type::StatIncrease:
302  switch (anim.getStat()) {
304  statArrow.setColor(sf::Color(50, 50, 180));
305  break;
306  case pplmn::Stat::Attack:
308  statArrow.setColor(sf::Color(180, 50, 50));
309  break;
312  statArrow.setColor(sf::Color(50, 180, 50));
313  break;
314  case pplmn::Stat::Speed:
315  statArrow.setColor(sf::Color(120, 120, 50));
316  break;
319  statArrow.setColor(sf::Color(70, 70, 70));
320  break;
321  default:
322  BL_LOG_ERROR << "Invalid stat for animation: " << anim.getStat();
323  break;
324  }
325  break;
326 
328  updateAilmentAnimation(anim.getAilment());
329  break;
330 
332  updateAilmentAnimation(anim.getPassiveAilment());
333  break;
334 
335  default:
336  break;
337  }
338 
339  triggerAnimation(anim.getType());
340 }
341 
342 bool PeoplemonAnimation::completed() const { return state != State::Playing; }
343 
345  if (state == State::Playing) {
346  switch (type) {
347  case Animation::Type::ComeBack: {
348  // open ball state
349  if (ball.getTexture().id() == ballOpenTxtr.id()) {
350  alpha -= ContractRate * dt;
351  if (alpha <= 0.f) {
352  ballTime = 0.f;
353  setBallTexture(ballTxtr);
354  }
355  else if (alpha <= 140.f) { sparkImplosionEmitter->setEnabled(false); }
356  const std::uint8_t a = static_cast<std::uint8_t>(alpha);
357  const float p = alpha / 255.f;
358  const float ps = std::sqrt(p);
359  peoplemon.setColor(sf::Color(255, 255, 255, static_cast<std::uint8_t>(alpha)));
360  peoplemon.getTransform().setScale(ps * scale.x, ps * scale.y);
361  if (a <= ScreenFlashAlpha) {
362  screenFlash.setFillColor(sf::Color(255, 255, 255, a));
363  }
364  else if (a >= 255 - ScreenFlashAlpha) {
365  screenFlash.setFillColor(sf::Color(255, 255, 255, 255 - a));
366  }
367  else { screenFlash.setFillColor(sf::Color(255, 255, 255, ScreenFlashAlpha)); }
368  }
369  // closed ball state
370  else {
371  ballTime += dt;
372  if (ballTime >= 0.75f) { state = State::Static; }
373  }
374  } break;
375 
376  case Animation::Type::SendOut:
377  // closed ball state
378  if (ball.getTexture().id() == ballTxtr.id()) {
379  ballTime += dt;
380  if (ballTime >= 0.75f) {
381  setBallTexture(ballOpenTxtr);
382  ballFlash.scaleToSize({1.f, 1.f});
383  ballFlash.setColorGradient(makeColor(255.f), {0.f, 0.f, 0.f, 0.f});
384  alpha = 0.f;
385  sparkExplosionEmitter->setEnabled(true);
386  }
387  }
388  // ball open and expanding ppl state
389  else {
390  alpha += ExpandRate * dt;
391  if (alpha > 180.f) { sparkExplosionEmitter->setEnabled(false); }
392  if (alpha >= 255.f) {
393  alpha = 255.f;
394  if (sparks->getParticleCountLocked() == 0) { state = State::Static; }
395  }
396  const float p = alpha / 255.f;
397  const float ps = std::sqrt(p);
398  const float pss = std::sqrt(ps);
399  const float ns = BallFlashRadius * pss * 2.f;
400  const std::uint8_t a = static_cast<std::uint8_t>(alpha);
401  ballFlash.setColorGradient(makeColor(255.f - 255.f * p), {0.f, 0.f, 0.f, 0.f});
402  ballFlash.scaleToSize({ns, ns});
403  if (a < 255) {
404  peoplemon.setColor(sf::Color(122, 8, 128, std::max(a, ScreenFlashAlpha)));
405  }
406  else { peoplemon.setColor(sf::Color::White); }
407  peoplemon.getTransform().setScale(ps * scale.x, ps * scale.y);
408  ball.setColor(sf::Color(255, 255, 255, 255 - a));
409  if (a <= ScreenFlashAlpha) {
410  screenFlash.setFillColor(sf::Color(255, 255, 255, a));
411  }
412  else if (a >= 255 - ScreenFlashAlpha) {
413  screenFlash.setFillColor(sf::Color(255, 255, 255, 255 - a));
414  }
415  else { screenFlash.setFillColor(sf::Color(255, 255, 255, ScreenFlashAlpha)); }
416  }
417  break;
418 
419  case Animation::Type::ShakeAndFlash:
420  shakeTime += dt;
421  if (shakeTime >= ShakeTime) {
422  peoplemon.stopFlashing();
423  state = State::Static;
424  }
425  break;
426 
427  case Animation::Type::SlideOut:
428  slideAmount += SlideRate * dt;
429  if (slideAmount >= peoplemon.getGlobalSize().x) {
430  state = State::Static;
431  peoplemon.setColor(sf::Color(255, 255, 255, 0)); // prevent showing
432  }
433  break;
434 
435  case Animation::Type::SlideDown:
436  slideAmount += SlideRate * dt;
437  if (slideAmount >= peoplemon.getGlobalSize().y) {
438  state = State::Static;
439  peoplemon.setColor(sf::Color(255, 255, 255, 0)); // prevent showing
440  }
441  break;
442 
443  case Animation::Type::MultipleStateDecrease:
444  case Animation::Type::MultipleStateIncrease:
445  case Animation::Type::StatDecrease:
446  case Animation::Type::StatIncrease:
447  arrowTime += dt;
448  arrowOffset = ArrowShakeAmount *
449  bl::math::sin(arrowTime / ArrowShowTime * 360.f * ArrowOscillations);
450  if (arrowTime >= ArrowShowTime) {
451  arrowOffset = 0.f;
452  state = State::Static;
453  }
454  statArrow.getTransform().setPosition(statArrow.getTransform().getLocalPosition().x,
455  ViewSize.y * 0.5f + arrowOffset);
456  break;
457 
460  if (!ailmentAnim.getPlayer().playing()) { state = State::Static; }
461  break;
462 
463  case Animation::Type::ThrowCloneBall:
464  case Animation::Type::ThrowPeopleball: {
465  switch (throwState) {
466  case BallThrowState::Arcing: {
467  throwX += ThrowXVel * dt;
468  const float xp = throwX - ThrowMiddle;
469  throwBall.getTransform().setPosition(throwX, ThrowA * xp * xp + ThrowTop);
470  throwBall.getTransform().rotate(ThrowSpinRate * dt);
471  if (throwX >= ThrowEndX) {
472  alpha = 255.f;
473  throwBall.getTransform().setPosition(ThrowEndX, ThrowEndY);
474  setThrowBallTxtr(ballOpenTxtr);
475  throwState = BallThrowState::Eating;
476  sparkImplosionEmitter->setEnabled(true, {ThrowEndX, ThrowEndY});
477  // move to global for render
478  if (type == Animation::Type::ThrowCloneBall) {
479  peoplemon.getTransform().setPosition(OpponentPosX + SquareSize * 0.5f,
480  OpponentPosY + SquareSize);
481  peoplemon.setColor(sf::Color(255, 255, 255, 128));
482  }
483  }
484  } break;
485 
486  case BallThrowState::Eating:
487  if (throwBall.getTexture().id() == ballOpenTxtr.id()) {
488  alpha -= ContractRate * dt;
489  if (alpha <= 0.f) {
490  ballTime = 0.f;
491  setThrowBallTxtr(ballTxtr);
492  }
493  else if (alpha <= 140.f) { sparkImplosionEmitter->setEnabled(false); }
494  const std::uint8_t a = static_cast<std::uint8_t>(alpha);
495  const float p = alpha / 255.f;
496  const float ps = std::sqrt(p);
497  toEat->setColor(sf::Color(255, 255, 255, static_cast<std::uint8_t>(alpha)));
498  toEat->getTransform().setScale(ps * scale.x, p * scale.y);
499  toEat->getTransform().setPosition(
500  OpponentPosX + SquareSize * 0.5f,
501  OpponentPosY - (BallBounceHeight + 35.f) * (255.f - alpha) / 255.f +
502  SquareSize);
503  if (a <= ScreenFlashAlpha) {
504  screenFlash.setFillColor(sf::Color(255, 255, 255, a));
505  }
506  else if (a >= 255 - ScreenFlashAlpha) {
507  screenFlash.setFillColor(sf::Color(255, 255, 255, 255 - a));
508  }
509  else { screenFlash.setFillColor(sf::Color(255, 255, 255, ScreenFlashAlpha)); }
510  }
511  else {
512  ballTime += dt;
513  if (ballTime >= 0.5f) {
514  peoplemon.getTransform().setPosition(ViewSize.x * 0.5f, ViewSize.y);
515  if (type == Animation::Type::ThrowCloneBall) {
516  throwState = BallThrowState::CloneFading;
517  alpha = 255.f;
518  peoplemon.setColor(sf::Color::White);
519  }
520  else {
521  throwState = BallThrowState::Bouncing;
522  bounceTime = 0.f;
523  }
524  }
525  }
526  break;
527 
528  case BallThrowState::Bouncing:
529  bounceTime = std::min(BallBounceTime, bounceTime + dt);
530  throwBall.getTransform().setPosition(
531  throwBall.getTransform().getLocalPosition().x,
532  OpponentPosY + BallBounceHeight -
533  std::abs(bl::math::cos(bl::math::radiansToDegrees(
534  3.5f * bl::math::Pi / BallBounceTime * bounceTime))) /
535  std::max(4.f * bounceTime, 1.f) * BallBounceHeight);
536  if (bounceTime >= BallBounceTime) {
537  throwBall.getTransform().setPosition(BallFinalPos);
538  state = State::Static;
539  }
540  break;
541 
542  case BallThrowState::CloneFading:
543  alpha = std::max(alpha - dt * GreenRate, 0.f);
544  throwBall.setColor(sf::Color(255, 255, 255, static_cast<int>(alpha)));
545  if (alpha <= 0.f) {
546  renderBall = false;
547  state = State::Static;
548  }
549  break;
550  }
551  } break;
552 
553  case Animation::Type::PeopleballShake:
554  shakeTime += dt;
555  if (shakeTime <= BallShakeTime) {
556  throwBall.getTransform().setPosition(
557  BallFinalPos +
558  glm::vec2(ShakeXAmount * bl::math::cos(ShakeSpeed * shakeTime * 2.f),
559  ShakeYAmount * bl::math::cos(ShakeSpeed * shakeTime)));
560  }
561  else {
562  throwBall.getTransform().setPosition(BallFinalPos);
563  if (shakeTime >= BallShakeTime + ShakeRestTime) { state = State::Static; }
564  }
565  break;
566 
567  case Animation::Type::PeopleballCaught:
568  alpha = std::min(alpha + dt * GreenRate, 255.f);
569  throwBall.setColor(
570  sf::Color(255 - static_cast<int>(alpha), static_cast<int>(alpha), 0));
571  if (alpha >= 255.f) { state = State::Static; }
572  break;
573 
574  case Animation::Type::PlayerFirstSendout:
575  case Animation::Type::OpponentFirstSendout:
576  case Animation::Type::UseMove:
577  case Animation::Type::MakeWildVisible:
578  case Animation::Type::_ERROR:
579  // do nothing
580  break;
581  }
582  }
583 }
584 
585 void PeoplemonAnimation::render(bl::rc::scene::CodeScene::RenderContext& ctx) {
586  if (state == State::Hidden) return;
587 
588  const auto setViewport = [this, &ctx]() {
589  ctx.setViewport(viewport, false);
590  ctx.setScissor(scissor, false);
591  };
592  setViewport();
593 
594  if (state == State::Playing) {
595  switch (type) {
596  case Animation::Type::ComeBack:
597  peoplemon.draw(ctx);
598  ball.draw(ctx);
599  ctx.resetViewportAndScissor();
600  screenFlash.draw(ctx);
601  implosion->draw(ctx);
602  break;
603 
604  case Animation::Type::SendOut:
605  ball.draw(ctx);
606  peoplemon.draw(ctx);
607  ctx.resetViewportAndScissor();
608  screenFlash.draw(ctx);
609  if (ball.getTexture().id() == ballOpenTxtr.id()) {
610  ballFlash.draw(ctx);
611  sparks->draw(ctx);
612  }
613  break;
614 
615  case Animation::Type::ShakeAndFlash: {
616  const float t = shakeTime * ShakeOffMultiple;
617  const float m = bl::math::sin(t / ShakeTime * 180.f);
618  VkViewport vp = viewport;
619  vp.x += m * ShakeXMag * bl::math::sin(t);
620  vp.y += m * ShakeYMag * bl::math::cos(-t);
621  ctx.setViewport(vp, false);
622  peoplemon.draw(ctx);
623  } break;
624 
625  case Animation::Type::SlideDown: {
626  VkViewport vp = viewport;
627  vp.y += slideAmount;
628  ctx.setViewport(vp, false);
629  peoplemon.draw(ctx);
630  } break;
631 
632  case Animation::Type::SlideOut: {
633  VkViewport vp = viewport;
634  vp.x += slideAmount * (position == Position::Player ? -1.f : 1.f);
635  ctx.setViewport(vp, false);
636  peoplemon.draw(ctx);
637  } break;
638 
639  case Animation::Type::MultipleStateDecrease:
640  case Animation::Type::MultipleStateIncrease:
641  case Animation::Type::StatDecrease:
642  case Animation::Type::StatIncrease:
643  peoplemon.draw(ctx);
644  ctx.resetScissor();
645  statArrow.draw(ctx);
646  break;
647 
650  peoplemon.draw(ctx);
651  ailmentAnim.draw(ctx);
652  break;
653 
654  case Animation::Type::ThrowCloneBall:
655  case Animation::Type::ThrowPeopleball:
656  switch (throwState) {
657  case BallThrowState::Arcing:
658  peoplemon.draw(ctx);
659  ctx.resetViewportAndScissor();
660  throwBall.draw(ctx);
661  break;
662 
663  case BallThrowState::Eating:
664  // in global coords
665  ctx.resetViewportAndScissor();
666  peoplemon.draw(ctx);
667  if (type == Animation::Type::ThrowCloneBall) { clone.draw(ctx); }
668  throwBall.draw(ctx);
669  screenFlash.draw(ctx);
670  implosion->draw(ctx);
671  break;
672 
673  case BallThrowState::CloneFading:
674  peoplemon.draw(ctx);
675  [[fallthrough]];
676 
677  case BallThrowState::Bouncing:
678  default:
679  // in global coords
680  ctx.resetViewportAndScissor();
681  throwBall.draw(ctx);
682  break;
683  }
684  break;
685 
686  case Animation::Type::PeopleballShake:
687  // in global coords
688  ctx.resetViewportAndScissor();
689  throwBall.draw(ctx);
690  break;
691 
692  case Animation::Type::PeopleballCaught:
693  // in global coords
694  ctx.resetViewportAndScissor();
695  throwBall.draw(ctx);
696  break;
697 
698  case Animation::Type::PlayerFirstSendout:
699  case Animation::Type::OpponentFirstSendout:
700  case Animation::Type::UseMove:
701  case Animation::Type::MakeWildVisible:
702  case Animation::Type::_ERROR:
703  // do nothing
704  break;
705  }
706  }
707  else if (state == State::Static) {
708  peoplemon.draw(ctx);
709  if (renderBall) {
710  ctx.resetViewportAndScissor();
711  throwBall.draw(ctx);
712  }
713  }
714 
715  ctx.resetViewportAndScissor();
716 }
717 
718 void PeoplemonAnimation::setBallTexture(bl::rc::res::TextureRef& t) {
719  ball.setTexture(t, true);
720  ball.getTransform().setOrigin(t->size().x / 2.f, t->size().y);
721 }
722 
723 void PeoplemonAnimation::setThrowBallTxtr(bl::rc::res::TextureRef& t) {
724  throwBall.setTexture(t, true);
725  throwBall.getTransform().setOrigin(t->size() * 0.5f);
726 }
727 
728 void PeoplemonAnimation::updateAilmentAnimation(pplmn::Ailment ail) {
729  switch (ail) {
731  recreateAilmentAnimation(annoySrc);
732  break;
734  recreateAilmentAnimation(frozenSrc);
735  break;
737  recreateAilmentAnimation(frustrationSrc);
738  break;
740  recreateAilmentAnimation(sleepSrc);
741  break;
743  recreateAilmentAnimation(stickySrc);
744  break;
745  default:
746  BL_LOG_WARN << "Invalid ailment: " << ail;
747  break;
748  }
749 }
750 
751 void PeoplemonAnimation::updateAilmentAnimation(pplmn::PassiveAilment ail) {
752  switch (ail) {
754  recreateAilmentAnimation(confuseSrc);
755  break;
757  recreateAilmentAnimation(trappedSrc);
758  break;
760  recreateAilmentAnimation(jumpedSrc);
761  break;
762  default:
763  BL_LOG_WARN << "Invalid ailment animation: " << ail;
764  break;
765  }
766 }
767 
768 void PeoplemonAnimation::recreateAilmentAnimation(
769  bl::resource::Ref<bl::gfx::a2d::AnimationData>& src) {
770  ailmentAnim.createWithUniquePlayer(engine, src);
771  ailmentAnim.addToScene(scene, bl::rc::UpdateSpeed::Static);
772 }
773 
774 } // namespace view
775 } // namespace battle
776 } // namespace core
Type
The type classification of an item. This is used to determine when an item may be used and how to use...
Definition: Type.hpp:17
PassiveAilment
Represents a passive ailment a Peoplemon can have.
Ailment
Represents an ailment that a Peoplemon can have.
Definition: Ailment.hpp:16
Id
The id of a peoplemon.
Definition: Id.hpp:16
Core classes and functionality for both the editor and game.
void init(bl::rc::scene::CodeScene *scene)
Initializes rendering resources.
Position
Which position the peoplemon is in.
PeoplemonAnimation(bl::engine::Engine &engine, Position position)
Construct a new Peoplemon Animation utility.
void render(bl::rc::scene::CodeScene::RenderContext &ctx)
Renders the peoplemon animation.
void triggerAnimation(const cmd::Animation &anim)
Begins playing the given animation.
bool completed() const
Returns true if the animation has completed, false if in progress.
void update(float dt)
Updates the playing animation.
void setPeoplemon(pplmn::Id ppl)
Sets the specific peoplemon graphic and resets to hidden state.
Particle system spark for peoplemon animations.
Particle system spark emitter for explosions.
Particle system spark emitter for implosions.
void setEnabled(bool e, const glm::vec2 &origin={})
Particle system spark affector.
Particle system spark sink.
static std::string playerImage(Id id)
Returns the full path to the image to use in battle for the player peoplemon.
Definition: Peoplemon.cpp:219
static std::string opponentImage(Id id)
Returns the full path to the image to use in battle for the opponent peoplemon.
Definition: Peoplemon.cpp:228
static const std::string & AnimationPath()
Definition: Properties.cpp:327
static int WindowWidth()
Definition: Properties.cpp:250
static int WindowHeight()
Definition: Properties.cpp:256
static const std::string & ImagePath()
Definition: Properties.cpp:333