GameBoy (Color) port of the GTA San Andreas arcade game Duality
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

obj.c 4.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. /*
  2. * obj.c
  3. * Duality
  4. *
  5. * Copyright (C) 2025 Thomas Buck <thomas@xythobuz.de>
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * See <http://www.gnu.org/licenses/>.
  18. */
  19. #include <gbdk/platform.h>
  20. #include <string.h>
  21. #include <stdlib.h>
  22. #include "gb/hardware.h"
  23. #include "sprites.h"
  24. #include "game.h"
  25. #include "obj.h"
  26. /*
  27. * sprite budget:
  28. *
  29. * fixed:
  30. * ship: 4
  31. * thruster: 1
  32. * health: 4
  33. * power: 4
  34. * --> 13 fixed
  35. *
  36. * hardware tiles: 40 - 13 = 27
  37. *
  38. * dynamic:
  39. * shot: 1
  40. * light: 4
  41. * dark: 4
  42. * --> 2x dark & 2x light = 16
  43. * --> 5x shot & 6x small = 11
  44. * --> 16 + 11 = 27
  45. */
  46. #define MAX_DARK 2
  47. #define MAX_LIGHT 2
  48. #define MAX_SHOT 5
  49. #define MAX_SHOT_DARK 3
  50. #define MAX_SHOT_LIGHT 3
  51. #define MAX_OBJ ((4 * MAX_DARK) + (4 * MAX_LIGHT) + MAX_SHOT + MAX_SHOT_DARK + MAX_SHOT_LIGHT)
  52. #define MAX_TRAVEL 32
  53. struct obj {
  54. uint8_t active;
  55. enum SPRITES sprite;
  56. int16_t off_x;
  57. int16_t off_y;
  58. int16_t spd_x;
  59. int16_t spd_y;
  60. uint8_t travel;
  61. };
  62. static struct obj objs[MAX_OBJ];
  63. void obj_init(void) {
  64. memset(objs, 0, sizeof(objs));
  65. }
  66. static uint8_t cnt_sprite(enum SPRITES sprite) {
  67. uint8_t cnt = 0;
  68. for (uint8_t i = 0; i < MAX_OBJ; i++) {
  69. if (!objs[i].active) {
  70. continue;
  71. }
  72. if (objs[i].sprite == sprite) {
  73. cnt++;
  74. }
  75. }
  76. return cnt;
  77. }
  78. enum OBJ_STATE obj_add(enum SPRITES sprite, int16_t off_x, int16_t off_y, int16_t spd_x, int16_t spd_y) {
  79. uint8_t obj_cnt = 0xFF;
  80. for (uint8_t i = 0; i < MAX_OBJ; i++) {
  81. if (!objs[i].active) {
  82. obj_cnt = i;
  83. break;
  84. }
  85. }
  86. if (obj_cnt >= MAX_OBJ) {
  87. return OBJ_LIST_FULL;
  88. }
  89. if (((sprite == SPR_DARK) && (cnt_sprite(sprite) >= MAX_DARK))
  90. || ((sprite == SPR_LIGHT) && (cnt_sprite(sprite) >= MAX_LIGHT))
  91. || ((sprite == SPR_SHOT) && (cnt_sprite(sprite) >= MAX_SHOT))
  92. || ((sprite == SPR_SHOT_DARK) && (cnt_sprite(sprite) >= MAX_SHOT_DARK))
  93. || ((sprite == SPR_SHOT_LIGHT) && (cnt_sprite(sprite) >= MAX_SHOT_LIGHT))) {
  94. return OBJ_TYPE_FULL;
  95. }
  96. objs[obj_cnt].active = 1;
  97. objs[obj_cnt].sprite = sprite;
  98. objs[obj_cnt].off_x = off_x << POS_SCALE_OBJS;
  99. objs[obj_cnt].off_y = off_y << POS_SCALE_OBJS;
  100. objs[obj_cnt].spd_x = spd_x;
  101. objs[obj_cnt].spd_y = spd_y;
  102. objs[obj_cnt].travel = 0;
  103. obj_cnt += 1;
  104. return OBJ_ADDED;
  105. }
  106. void obj_act(int16_t pos_x, int16_t pos_y, int16_t *spd_off_x, int16_t *spd_off_y) {
  107. pos_x += DEVICE_SPRITE_PX_OFFSET_X + (DEVICE_SCREEN_PX_WIDTH / 2) - 16;
  108. pos_y += DEVICE_SPRITE_PX_OFFSET_Y + (DEVICE_SCREEN_PX_HEIGHT / 2);
  109. for (uint8_t i = 0; i < MAX_OBJ; i++) {
  110. if (!objs[i].active) {
  111. continue;
  112. }
  113. switch (objs[i].sprite) {
  114. case SPR_DARK: {
  115. *spd_off_x += (objs[i].off_x - pos_x) >> 8;
  116. *spd_off_y += (objs[i].off_y - pos_y) >> 8;
  117. } break;
  118. default:
  119. break;
  120. }
  121. }
  122. }
  123. void obj_draw(int16_t spd_x, int16_t spd_y, uint8_t *hiwater) {
  124. for (uint8_t i = 0; i < MAX_OBJ; i++) {
  125. if (!objs[i].active) {
  126. continue;
  127. }
  128. // move objects by their speed and compensate for movement of the background / ship
  129. objs[i].off_x += objs[i].spd_x - spd_x;
  130. objs[i].off_y += objs[i].spd_y - spd_y;
  131. // only update travel time if we're actually moving
  132. if ((objs[i].spd_x != 0) || (objs[i].spd_y != 0)) {
  133. objs[i].travel += 1;
  134. }
  135. // remove objects that have traveled for too long
  136. if (objs[i].travel >= MAX_TRAVEL) {
  137. objs[i].active = 0;
  138. }
  139. spr_draw(objs[i].sprite, FLIP_NONE, objs[i].off_x >> POS_SCALE_OBJS, objs[i].off_y >> POS_SCALE_OBJS, hiwater);
  140. }
  141. }