level.cxx 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. //
  2. // level.cxx
  3. // danmaku
  4. //
  5. // Created by Sam Jaffe on 5/26/19.
  6. // Copyright © 2019 Sam Jaffe. All rights reserved.
  7. //
  8. #include "danmaku/level.hpp"
  9. #include <json/json.h>
  10. #include "danmaku/actor.hpp"
  11. #include "danmaku/bullet.hpp"
  12. #include "danmaku/player.hpp"
  13. #include "danmaku/serial.hpp"
  14. #include "game/graphics/renderer.hpp"
  15. #include "game/math/common.hpp"
  16. #include "game/util/env.hpp"
  17. #include "resource_factory/prototype_factory.hpp"
  18. using namespace danmaku;
  19. struct wave_helper {
  20. using wave_t = std::vector<std::unique_ptr<actor>>;
  21. wave_t get_wave(Json::Value const & json) {
  22. wave_t out;
  23. for (int i = 0; i < json.size(); ++i) {
  24. std::string file = mappings[json[i]["id"].asString()].asString();
  25. std::string path = env::resource_file("scripts/entity/" + file);
  26. Json::Value actor = engine::read_file(path);
  27. actor["position"] = json[i]["position"];
  28. out.emplace_back(to_actor(actor, manager));
  29. }
  30. return out;
  31. }
  32. std::deque<wave_t> operator()() {
  33. std::deque<wave_t> out;
  34. for (int i = 0; i < waves.size(); ++i) {
  35. out.emplace_back(get_wave(waves[i]));
  36. }
  37. return out;
  38. }
  39. wave_helper(Json::Value const & json, graphics::manager const & mgr)
  40. : waves(json["waves"]), mappings(json["mappings"]), manager(mgr) {}
  41. Json::Value const & waves;
  42. Json::Value const & mappings;
  43. graphics::manager const & manager;
  44. };
  45. level::level(Json::Value const & json,
  46. std::shared_ptr<engine::game_dispatch> dispatch)
  47. : engine::scene(json["id"].asString(), dispatch),
  48. player_(), wave_timer_{json["timeBetweenWaves"].asFloat()},
  49. waves_(wave_helper{json, graphics_manager()}()) {}
  50. level::level(std::string const & id, Json::Value const & json,
  51. std::shared_ptr<engine::game_dispatch> dispatch)
  52. : engine::scene(id, dispatch),
  53. player_(), wave_timer_{json["timeBetweenWaves"].asFloat()},
  54. waves_(wave_helper{json, graphics_manager()}()) {}
  55. level::~level() {}
  56. void level::add_bullet(bullet b) {
  57. bullets_.emplace_back(std::make_unique<bullet>(std::move(b)));
  58. // TODO: Add to correct collision boxes...
  59. collidables[0].emplace_back(bullets_.back().get());
  60. }
  61. template <typename T>
  62. void level::perform_oob_culling_impl(std::vector<std::unique_ptr<T>> & data) {
  63. // TODO: Aquire screen size correctly...?
  64. math::dim2::rectangle bound{{{0.f, 0.f}}, {{3840.f, 2160.f}}};
  65. auto is_oob = [&bound](std::unique_ptr<T> & ptr) {
  66. return !math::intersects(ptr->render_info().points, bound);
  67. };
  68. auto it = std::remove_if(data.begin(), data.end(), is_oob);
  69. auto remove_collider = [this](std::unique_ptr<T> & ptr) {
  70. // TODO: colliders, use the collision enums.
  71. collidables[0].erase(
  72. std::remove(collidables[0].begin(), collidables[0].end(), ptr.get()),
  73. collidables[0].end());
  74. };
  75. std::for_each(it, data.end(), remove_collider);
  76. data.erase(it, data.end());
  77. }
  78. void level::perform_oob_culling() {
  79. // perform_oob_culling_impl(actors_);
  80. perform_oob_culling_impl(bullets_);
  81. }
  82. void level::update(float delta) {
  83. perform_oob_culling();
  84. update_waves(delta);
  85. update_object(delta);
  86. check_collisions();
  87. }
  88. void level::update_object(float delta) {
  89. player_->update(delta);
  90. for (auto & a : actors_) {
  91. a->update(delta);
  92. }
  93. for (auto & b : bullets_) {
  94. b->update(delta);
  95. }
  96. }
  97. void level::check_collisions() {
  98. engine::scene::check_collisions();
  99. // TODO: This is a bad hack until I can properly disassociate collision info
  100. for (auto & b : bullets_) {
  101. if (math::intersects(player_->render_info().points,
  102. b->render_info().points)) {
  103. player_->hit(*b);
  104. }
  105. }
  106. }
  107. void level::update_waves(float delta) {
  108. if (waves_.empty()) { return; }
  109. if ((wave_timer_.remainder -= delta) <= 0.f) {
  110. wave_timer_.remainder = wave_timer_.interval;
  111. for (auto & actor : waves_.front()) {
  112. actor->level(this);
  113. actors_.emplace_back(std::move(actor));
  114. }
  115. waves_.pop_front();
  116. }
  117. }
  118. void level::render(graphics::renderer & renderer) {
  119. renderer.draw(player_->render_info());
  120. for (auto & a : actors_) {
  121. renderer.draw(a->render_info());
  122. }
  123. for (auto & b : bullets_) {
  124. renderer.draw(b->render_info());
  125. }
  126. }