StePe

Untitled

Mar 8th, 2026
41
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.21 KB | None | 0 0
  1. // ── bouncing discs: random diameters, floor bounce, side ejection ───────────
  2. // 5 discs always active. They fall with gravity, bounce on the ground, collide
  3. // with each other, and can be kicked sideways. If a disc exits left/right,
  4. // it respawns at the top with a new random size/color/velocity.
  5. static uint8_t demoBouncingDiscs(coord cx, coord cy, coord tScale, bool reinit) {
  6. static constexpr uint8_t kN = 6;
  7. static coord px[kN], py[kN], vx[kN], vy[kN], rad[kN];
  8. static uint8_t hue[kN];
  9.  
  10. static const coord kGravity = coord::from_raw(5898); // 0.09 px/frame^2
  11. static const coord kAirDampX = coord::from_raw(64880); // ~0.99
  12. static const coord kAirDampY = coord::from_raw(65405); // ~0.998
  13. static const coord kGroundBounce= coord::from_raw(52429); // 0.80
  14. static const coord kCollMix = coord::from_raw(49152); // 0.75
  15. static const coord kRollDamp = coord::from_raw(64225); // ~0.98
  16.  
  17. const coord xLeft = coord::from_raw(0);
  18. const coord xRight = coord::from_raw((int32_t)(kMatrixWidth - 1) << 16);
  19. const coord yGround= coord::from_raw((int32_t)(kMatrixHeight - 1) << 16);
  20.  
  21. auto spawn = [&](uint8_t i) {
  22. // Radius in [1.0 .. 2.8] px (random diameter)
  23. rad[i] = coord::from_raw(130000 + (int32_t)(random8() & 0x7F) * 921);
  24.  
  25. // Spawn at random X, slightly above top
  26. px[i] = coord::from_raw((int32_t)(random8() % kMatrixWidth) << 16);
  27. py[i] = coord::from_raw(-rad[i].raw() - ((int32_t)(random8() & 0x1F) << 10));
  28.  
  29. // Small random initial velocities
  30. vx[i] = coord::from_raw(((int32_t)(int8_t)random8()) * 320); // about ±0.6 px/frame
  31. vy[i] = coord::from_raw(9830 + (int32_t)(random8() & 0x3F) * 120); // ~0.15..0.27 down
  32. hue[i] = random8();
  33. };
  34.  
  35. if (reinit) {
  36. for (uint8_t i = 0; i < kN; ++i) spawn(i);
  37. }
  38.  
  39. // Integrate + ground bounce + side-exit recycle
  40. for (uint8_t i = 0; i < kN; ++i) {
  41. vy[i] = (vy[i] + kGravity) * kAirDampY;
  42. vx[i] = vx[i] * kAirDampX;
  43.  
  44. px[i] = px[i] + vx[i];
  45. py[i] = py[i] + vy[i];
  46.  
  47. // Ground bounce
  48. coord floorY = yGround - rad[i];
  49. if (py[i] > floorY) {
  50. py[i] = floorY;
  51. if (vy[i].raw() > 0) vy[i] = coord::from_raw(-vy[i].raw()) * kGroundBounce;
  52. vx[i] = vx[i] * kRollDamp;
  53. if (vy[i].raw() > -2500 && vy[i].raw() < 2500) vy[i] = coord{}; // settle tiny jitter
  54. }
  55.  
  56. // If disc is kicked fully out of screen to either side -> respawn from top
  57. if (px[i] < xLeft - rad[i] * coord(2) || px[i] > xRight + rad[i] * coord(2)) {
  58. spawn(i);
  59. }
  60. }
  61.  
  62. // Disc-disc collisions (biased to create sideways kick-outs)
  63. for (uint8_t i = 0; i < kN; ++i) {
  64. for (uint8_t j = i + 1; j < kN; ++j) {
  65. int32_t dx = px[j].raw() - px[i].raw();
  66. int32_t dy = py[j].raw() - py[i].raw();
  67. int32_t adx = dx < 0 ? -dx : dx;
  68. int32_t ady = dy < 0 ? -dy : dy;
  69. int32_t sumR = (rad[i] + rad[j]).raw();
  70.  
  71. if (adx < sumR && ady < sumR) {
  72. int32_t overlapX = sumR - adx;
  73. if (overlapX < 0) overlapX = 0;
  74.  
  75. // Separate mostly along X so contacts eject sideways
  76. int32_t push = (overlapX >> 1) + 256;
  77. if (dx >= 0) {
  78. px[i] = coord::from_raw(px[i].raw() - push);
  79. px[j] = coord::from_raw(px[j].raw() + push);
  80. } else {
  81. px[i] = coord::from_raw(px[i].raw() + push);
  82. px[j] = coord::from_raw(px[j].raw() - push);
  83. }
  84.  
  85. // Size-weighted horizontal impulse (smaller discs get kicked more)
  86. int32_t mi = rad[i].raw();
  87. int32_t mj = rad[j].raw();
  88. int32_t denom = mi + mj;
  89. if (denom <= 0) denom = 1;
  90.  
  91. coord dvx = (vx[j] - vx[i]) * kCollMix;
  92. coord wi = coord::from_raw((int32_t)((int64_t)mj * 65536 / denom));
  93. coord wj = coord::from_raw((int32_t)((int64_t)mi * 65536 / denom));
  94.  
  95. vx[i] = vx[i] + dvx * wi;
  96. vx[j] = vx[j] - dvx * wj;
  97.  
  98. // Extra lateral kick from compression
  99. int32_t kickRaw = overlapX * 2;
  100. if (kickRaw > 65536) kickRaw = 65536;
  101. coord kick = coord::from_raw(kickRaw);
  102. if (dx >= 0) {
  103. vx[i] = vx[i] - kick;
  104. vx[j] = vx[j] + kick;
  105. } else {
  106. vx[i] = vx[i] + kick;
  107. vx[j] = vx[j] - kick;
  108. }
  109.  
  110. // Light vertical damping to avoid explosive stacks
  111. vy[i] = vy[i] * coord::from_raw(64225); // ~0.98
  112. vy[j] = vy[j] * coord::from_raw(64225);
  113. }
  114. }
  115. }
  116.  
  117. // Draw
  118. for (uint8_t i = 0; i < kN; ++i) {
  119. hue[i] += 1;
  120. coord sx = cx + (px[i] - cx) * tScale;
  121. coord sy = cy + (py[i] - cy) * tScale;
  122. drawDisc(sx, sy, rad[i] * tScale, CHSV(hue[i], 220, 255));
  123. }
  124.  
  125. return 255;
  126. }
  127.  
Advertisement
Add Comment
Please, Sign In to add comment