enemy.c 5.5 KB

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