enemy.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. // enemy.c
  2. #include <game/enemy.h>
  3. static EnemyContext *enemy_context_generic;
  4. // Allocation function
  5. static EnemyContext *enemy_generic_alloc(const char *id, int index, float x, float y, float width, float height)
  6. {
  7. if (!enemy_context_generic)
  8. {
  9. enemy_context_generic = malloc(sizeof(EnemyContext));
  10. }
  11. if (!enemy_context_generic)
  12. {
  13. FURI_LOG_E("Game", "Failed to allocate EnemyContext");
  14. return NULL;
  15. }
  16. snprintf(enemy_context_generic->id, sizeof(enemy_context_generic->id), "%s", id);
  17. enemy_context_generic->index = index;
  18. enemy_context_generic->x = x;
  19. enemy_context_generic->y = y;
  20. enemy_context_generic->width = width;
  21. enemy_context_generic->height = height;
  22. // Initialize other fields as needed
  23. enemy_context_generic->trajectory = (Vector){0, 0}; // Default trajectory
  24. enemy_context_generic->sprite_right = NULL; // Assign appropriate sprite
  25. enemy_context_generic->sprite_left = NULL; // Assign appropriate sprite
  26. enemy_context_generic->is_looking_left = false;
  27. enemy_context_generic->radius = 3.0f; // Default collision radius
  28. return enemy_context_generic;
  29. }
  30. // Free function
  31. static void enemy_generic_free(void *context)
  32. {
  33. if (context != NULL)
  34. {
  35. EnemyContext *enemy_context = (EnemyContext *)context;
  36. // Free sprites if they were dynamically loaded
  37. if (enemy_context->sprite_right)
  38. {
  39. sprite_free(enemy_context->sprite_right);
  40. }
  41. if (enemy_context->sprite_left)
  42. {
  43. sprite_free(enemy_context->sprite_left);
  44. }
  45. free(context);
  46. }
  47. }
  48. // Enemy start function
  49. static void enemy_start(Entity *self, GameManager *manager, void *context)
  50. {
  51. UNUSED(manager);
  52. if (!self || !context)
  53. {
  54. FURI_LOG_E("Game", "Enemy start: Invalid parameters");
  55. }
  56. if (!enemy_context_generic)
  57. {
  58. FURI_LOG_E("Game", "Enemy start: Enemy context not set");
  59. }
  60. EnemyContext *enemy_context = (EnemyContext *)context;
  61. snprintf(enemy_context->id, sizeof(enemy_context->id), "%s", enemy_context_generic->id);
  62. enemy_context->index = enemy_context_generic->index;
  63. enemy_context->x = enemy_context_generic->x;
  64. enemy_context->y = enemy_context_generic->y;
  65. enemy_context->width = enemy_context_generic->width;
  66. enemy_context->height = enemy_context_generic->height;
  67. enemy_context->trajectory = enemy_context_generic->trajectory;
  68. enemy_context->sprite_right = enemy_context_generic->sprite_right;
  69. enemy_context->sprite_left = enemy_context_generic->sprite_left;
  70. enemy_context->is_looking_left = enemy_context_generic->is_looking_left;
  71. enemy_context->radius = enemy_context_generic->radius;
  72. // Set enemy's initial position based on context
  73. entity_pos_set(self, (Vector){enemy_context->x, enemy_context->y});
  74. // Add collision circle based on the enemy's radius
  75. entity_collider_add_circle(self, enemy_context->radius);
  76. }
  77. // Enemy render function
  78. static void enemy_render(Entity *self, GameManager *manager, Canvas *canvas, void *context)
  79. {
  80. UNUSED(manager);
  81. if (!self || !context || !canvas)
  82. return;
  83. EnemyContext *enemy_context = (EnemyContext *)context;
  84. // Get the position of the enemy
  85. Vector pos = entity_pos_get(self);
  86. // Draw enemy sprite relative to camera, centered on the enemy's position
  87. canvas_draw_sprite(
  88. canvas,
  89. enemy_context->is_looking_left ? enemy_context->sprite_left : enemy_context->sprite_right,
  90. pos.x - camera_x - 5, // Center the sprite horizontally
  91. pos.y - camera_y - 5 // Center the sprite vertically
  92. );
  93. }
  94. // Enemy collision function
  95. static void enemy_collision(Entity *self, Entity *other, GameManager *manager, void *context)
  96. {
  97. UNUSED(self);
  98. UNUSED(context);
  99. // Check if the enemy collided with the player
  100. if (entity_description_get(other) == &player_desc)
  101. {
  102. // Increase score
  103. GameContext *game_context = game_manager_game_context_get(manager);
  104. if (game_context)
  105. {
  106. game_context->xp++;
  107. }
  108. // Move enemy to original position or handle respawn logic
  109. EnemyContext *enemy_context = (EnemyContext *)context;
  110. if (enemy_context)
  111. {
  112. entity_pos_set(self, (Vector){enemy_context->x, enemy_context->y});
  113. }
  114. }
  115. }
  116. // Enemy update function (optional)
  117. static void enemy_update(Entity *self, GameManager *manager, void *context)
  118. {
  119. if (!self || !context)
  120. return;
  121. UNUSED(manager);
  122. EnemyContext *enemy_context = (EnemyContext *)context;
  123. // Update position based on trajectory
  124. Vector pos = entity_pos_get(self);
  125. pos.x += enemy_context->trajectory.x;
  126. pos.y += enemy_context->trajectory.y;
  127. entity_pos_set(self, pos);
  128. // Example: Change direction if hitting boundaries
  129. if (pos.x < 0 || pos.x > WORLD_WIDTH)
  130. {
  131. enemy_context->trajectory.x *= -1;
  132. enemy_context->is_looking_left = !enemy_context->is_looking_left;
  133. }
  134. if (pos.y < 0 || pos.y > WORLD_HEIGHT)
  135. {
  136. enemy_context->trajectory.y *= -1;
  137. }
  138. }
  139. // Free function for the entity
  140. static void enemy_free(Entity *self, GameManager *manager, void *context)
  141. {
  142. UNUSED(self);
  143. UNUSED(manager);
  144. enemy_generic_free(context);
  145. }
  146. // Enemy behavior structure
  147. static const EntityDescription _generic_enemy = {
  148. .start = enemy_start,
  149. .stop = enemy_free,
  150. .update = enemy_update,
  151. .render = enemy_render,
  152. .collision = enemy_collision,
  153. .event = NULL,
  154. .context_size = sizeof(EnemyContext),
  155. };
  156. // Enemy function to return the entity description
  157. const EntityDescription *enemy(GameManager *manager, const char *id, int index, float x, float y, float width, float height, bool moving_left)
  158. {
  159. // Allocate a new EnemyContext with provided parameters
  160. enemy_context_generic = enemy_generic_alloc(id, index, x, y, width, height);
  161. if (!enemy_context_generic)
  162. {
  163. FURI_LOG_E("Game", "Failed to allocate EnemyContext");
  164. return NULL;
  165. }
  166. char right_edited[64];
  167. char left_edited[64];
  168. snprintf(right_edited, sizeof(right_edited), "%s_right.fxbm", id);
  169. snprintf(left_edited, sizeof(left_edited), "%s_left.fxbm", id);
  170. enemy_context_generic->sprite_right = game_manager_sprite_load(manager, right_edited);
  171. enemy_context_generic->sprite_left = game_manager_sprite_load(manager, left_edited);
  172. // Set initial direction
  173. enemy_context_generic->is_looking_left = moving_left; // Default direction
  174. // set trajectory
  175. enemy_context_generic->trajectory = !moving_left ? (Vector){1.0f, 0.0f} : (Vector){-1.0f, 0.0f}; // Default trajectory
  176. return &_generic_enemy;
  177. }