enemy_entity.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. #include "enemy_entity.h"
  2. #include "../../engine/game_manager.h"
  3. #include "../../game.h"
  4. #include "level_game.h"
  5. #include "player_entity.h"
  6. static Vector
  7. random_pos(Entity* player_entity)
  8. {
  9. const int full_size = ceilf(ENEMY_SIZE);
  10. const int half_size = ceilf(HALF_ENEMY_SIZE);
  11. Vector player_pos = entity_pos_get(player_entity);
  12. Vector pos;
  13. do {
  14. pos.x = half_size + rand() % (SCREEN_WIDTH - full_size);
  15. } while (fabsf(pos.x - player_pos.x) < 3 * ENEMY_SIZE);
  16. do {
  17. pos.y = half_size + rand() % (SCREEN_HEIGHT - full_size);
  18. } while (fabsf(pos.y - player_pos.y) < 3 * ENEMY_SIZE);
  19. return pos;
  20. }
  21. static EnemyDirection
  22. random_direction(Vector enemy_pos, Entity* player_entity)
  23. {
  24. Vector player_pos = entity_pos_get(player_entity);
  25. EnemyDirection direction = rand() % 4;
  26. if (direction == EnemyDirectionUp && enemy_pos.y > player_pos.y)
  27. direction = EnemyDirectionDown;
  28. else if (direction == EnemyDirectionDown && enemy_pos.y < player_pos.y)
  29. direction = EnemyDirectionUp;
  30. else if (direction == EnemyDirectionLeft && enemy_pos.x > player_pos.x)
  31. direction = EnemyDirectionRight;
  32. else if (direction == EnemyDirectionRight && enemy_pos.x < player_pos.x)
  33. direction = EnemyDirectionLeft;
  34. return direction;
  35. }
  36. void
  37. spawn_enemy(GameManager* manager)
  38. {
  39. GameContext* game_context = game_manager_game_context_get(manager);
  40. Level* level = game_manager_current_level_get(manager);
  41. // Add enemyh to level
  42. Entity* enemy = level_add_entity(level, &enemy_description);
  43. EnemyContext* enemy_context = entity_context_get(enemy);
  44. // Add to enemies list
  45. GameLevelContext* level_context = level_context_get(level);
  46. EntityList_push_back(level_context->enemies, enemy);
  47. // Set enemy position
  48. Vector enemy_pos = random_pos(level_context->player);
  49. entity_pos_set(enemy, enemy_pos);
  50. enemy_context->direction =
  51. random_direction(enemy_pos, level_context->player);
  52. // Add collision rect to enemy entity
  53. entity_collider_add_rect(enemy, ENEMY_SIZE, ENEMY_SIZE);
  54. // Load target sprite
  55. enemy_context->sprite = game_manager_sprite_load(manager, "enemy.fxbm");
  56. float speed;
  57. switch (game_context->difficulty) {
  58. case DifficultyEasy:
  59. speed = 0.25f;
  60. break;
  61. case DifficultyHard:
  62. speed = 1.0f;
  63. break;
  64. case DifficultyInsane:
  65. speed = 0.5f * (1 + rand() % 3);
  66. break;
  67. default:
  68. speed = 0.5f;
  69. break;
  70. }
  71. enemy_context->speed = speed;
  72. }
  73. static void
  74. enemy_update(Entity* self, GameManager* manager, void* context)
  75. {
  76. // Check pause
  77. Level* level = game_manager_current_level_get(manager);
  78. GameLevelContext* level_context = level_context_get(level);
  79. if (level_context->is_paused) {
  80. return;
  81. }
  82. EnemyContext* enemy_context = context;
  83. Vector pos = entity_pos_get(self);
  84. // Control player movement
  85. if (enemy_context->direction == EnemyDirectionUp)
  86. pos.y -= enemy_context->speed;
  87. if (enemy_context->direction == EnemyDirectionDown)
  88. pos.y += enemy_context->speed;
  89. if (enemy_context->direction == EnemyDirectionLeft)
  90. pos.x -= enemy_context->speed;
  91. if (enemy_context->direction == EnemyDirectionRight)
  92. pos.x += enemy_context->speed;
  93. // Clamp enemy position to screen bounds, and set it
  94. pos.x = CLAMP(pos.x, SCREEN_WIDTH - HALF_ENEMY_SIZE, HALF_ENEMY_SIZE);
  95. pos.y = CLAMP(pos.y, SCREEN_HEIGHT - HALF_ENEMY_SIZE, HALF_ENEMY_SIZE);
  96. entity_pos_set(self, pos);
  97. // Switching direction
  98. if (enemy_context->direction == EnemyDirectionUp &&
  99. pos.y <= HALF_ENEMY_SIZE)
  100. enemy_context->direction = EnemyDirectionDown;
  101. else if (enemy_context->direction == EnemyDirectionDown &&
  102. pos.y >= SCREEN_HEIGHT - HALF_ENEMY_SIZE)
  103. enemy_context->direction = EnemyDirectionUp;
  104. else if (enemy_context->direction == EnemyDirectionLeft &&
  105. pos.x <= HALF_ENEMY_SIZE)
  106. enemy_context->direction = EnemyDirectionRight;
  107. else if (enemy_context->direction == EnemyDirectionRight &&
  108. pos.x >= SCREEN_WIDTH - HALF_ENEMY_SIZE)
  109. enemy_context->direction = EnemyDirectionLeft;
  110. }
  111. static void
  112. enemy_render(Entity* self, GameManager* manager, Canvas* canvas, void* context)
  113. {
  114. UNUSED(context);
  115. UNUSED(manager);
  116. // Get enemy position
  117. Vector pos = entity_pos_get(self);
  118. // Draw enemy
  119. EnemyContext* enemy_context = entity_context_get(self);
  120. canvas_draw_sprite(canvas,
  121. enemy_context->sprite,
  122. pos.x - HALF_ENEMY_SIZE,
  123. pos.y - HALF_ENEMY_SIZE);
  124. }
  125. static void
  126. enemy_collision(Entity* self,
  127. Entity* other,
  128. GameManager* manager,
  129. void* context)
  130. {
  131. UNUSED(self);
  132. UNUSED(context);
  133. if (entity_description_get(other) != &player_description) {
  134. return;
  135. }
  136. // Game over
  137. GameContext* game_context = game_manager_game_context_get(manager);
  138. game_manager_next_level_set(manager, game_context->levels.game_over);
  139. }
  140. const EntityDescription enemy_description = {
  141. .start = NULL,
  142. .stop = NULL,
  143. .update = enemy_update,
  144. .render = enemy_render,
  145. .collision = enemy_collision,
  146. .event = NULL,
  147. .context_size = sizeof(EnemyContext),
  148. };