collision.ino 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. #include <SPI.h>
  2. #include <GD.h>
  3. void readn(byte *dst, unsigned int addr, int c)
  4. {
  5. GD.__start(addr);
  6. while (c--)
  7. *dst++ = SPI.transfer(0);
  8. GD.__end();
  9. }
  10. #define NBALLS 80
  11. static byte coll[NBALLS];
  12. static void load_coll()
  13. {
  14. while (GD.rd(VBLANK) == 0) // Wait until vblank
  15. ;
  16. while (GD.rd(VBLANK) == 1) // Wait until display
  17. ;
  18. while (GD.rd(VBLANK) == 0) // Wait until vblank
  19. ;
  20. readn(coll, COLLISION, NBALLS);
  21. }
  22. struct ball {
  23. int x, y;
  24. char vx, vy;
  25. byte lasthit;
  26. };
  27. static struct ball balls[NBALLS];
  28. #include "stone_wall_texture.h" // texture from 3dmd.net project
  29. #include "sphere.h"
  30. static void plot_balls()
  31. {
  32. byte i;
  33. for (i = 0; i < NBALLS; i++)
  34. GD.sprite(i, balls[i].x >> 4, balls[i].y >> 4, 0, 0, 0);
  35. }
  36. // Place all balls so that none collide. Do this by placing all at
  37. // random, then moving until there are no collisions
  38. static byte anycolliding()
  39. {
  40. plot_balls();
  41. load_coll();
  42. byte i;
  43. for (i = 0; i < NBALLS; i++)
  44. if (coll[i] != 0xff)
  45. return 1;
  46. return 0;
  47. }
  48. static void place_balls()
  49. {
  50. byte i;
  51. for (i = 0; i < NBALLS; i++) {
  52. balls[i].x = (2 + random(380)) << 4;
  53. balls[i].y = (2 + random(280)) << 4;
  54. balls[i].vx = random(-128,127);
  55. balls[i].vy = random(-128,127);
  56. balls[i].lasthit = 255;
  57. }
  58. while (anycolliding()) {
  59. for (i = 0; i < NBALLS; i++) {
  60. if (coll[i] != 0xff) {
  61. balls[i].x = (2 + random(380)) << 4;
  62. balls[i].y = (2 + random(280)) << 4;
  63. }
  64. }
  65. }
  66. }
  67. void setup()
  68. {
  69. int i;
  70. Serial.begin(1000000); // JCB
  71. GD.begin();
  72. GD.wr(JK_MODE, 0);
  73. GD.copy(RAM_CHR, stone_wall_texture_chr, sizeof(stone_wall_texture_chr));
  74. GD.copy(RAM_PAL, stone_wall_texture_pal, sizeof(stone_wall_texture_pal));
  75. for (i = 0; i < 4096; i++)
  76. GD.wr(RAM_PIC + i, (i & 15) + ((i >> 6) << 4));
  77. GD.copy(RAM_SPRIMG, sphere_img, sizeof(sphere_img));
  78. GD.copy(RAM_SPRPAL, sphere_pal, sizeof(sphere_pal));
  79. for (i = 0; i < 256; i++)
  80. GD.sprite(i, 400, 400, 0, 0, 0);
  81. place_balls();
  82. }
  83. float dot(float x1, float y1, float x2, float y2)
  84. {
  85. return (x1 * x2) + (y1 * y2);
  86. }
  87. // Collide ball a with ball b, compute new velocities.
  88. // Algorithm from
  89. // http://stackoverflow.com/questions/345838/ball-to-ball-collision-detection-and-handling
  90. void collide(struct ball *a, struct ball *b)
  91. {
  92. float collision_x, collision_y;
  93. collision_x = a->x - b->x;
  94. collision_y = a->y - b->y;
  95. float distance = sqrt(collision_x * collision_x + collision_y * collision_y);
  96. float rdistance = 1.0 / distance;
  97. collision_x *= rdistance;
  98. collision_y *= rdistance;
  99. float aci = dot(a->vx, a->vy, collision_x, collision_y);
  100. float bci = dot(b->vx, b->vy, collision_x, collision_y);
  101. float acf = bci;
  102. float bcf = aci;
  103. a->vx += int((acf - aci) * collision_x);
  104. a->vy += int((acf - aci) * collision_y);
  105. b->vx += int((bcf - bci) * collision_x);
  106. b->vy += int((bcf - bci) * collision_y);
  107. }
  108. #define LWALL (0 << 4)
  109. #define RWALL (384 << 4)
  110. #define TWALL (0 << 4)
  111. #define BWALL (284 << 4)
  112. static int timer;
  113. void loop()
  114. {
  115. int i;
  116. plot_balls();
  117. load_coll();
  118. struct ball *pb;
  119. for (i = NBALLS, pb = balls; i; pb++, i--) {
  120. if ((pb->x <= LWALL)) {
  121. pb->x = LWALL;
  122. pb->vx = -pb->vx;
  123. }
  124. if ((pb->x >= RWALL)) {
  125. pb->x = RWALL;
  126. pb->vx = -pb->vx;
  127. }
  128. if ((pb->y <= TWALL)) {
  129. pb->y = TWALL;
  130. pb->vy = -pb->vy;
  131. }
  132. if ((pb->y >= BWALL)) {
  133. pb->y = BWALL;
  134. pb->vy = -pb->vy;
  135. }
  136. }
  137. for (i = 1; i < NBALLS; i++) {
  138. byte other = coll[i];
  139. if ((balls[i].lasthit != other) && other != 0xff) {
  140. collide(&balls[i], &balls[other]);
  141. }
  142. balls[i].lasthit = other;
  143. }
  144. for (i = NBALLS, pb = balls; i; pb++, i--) {
  145. pb->x += pb->vx;
  146. pb->y += pb->vy;
  147. }
  148. if (++timer == 2000) {
  149. place_balls();
  150. delay(1000);
  151. timer = 0;
  152. }
  153. static int ss; // JCB
  154. GD.screenshot(ss++); // JCB
  155. }