scene_test.cxx 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. //
  2. // scene_test.cxx
  3. // engine-test
  4. //
  5. // Created by Sam Jaffe on 7/12/19.
  6. // Copyright © 2019 Sam Jaffe. All rights reserved.
  7. //
  8. #include "game/engine/scene.hpp"
  9. #include <game/util/env.hpp>
  10. #include <testing/xcode_gtest_helper.h>
  11. #include "game/engine/entity.hpp"
  12. #include "game/engine/game_dispatch.hpp"
  13. #include "mock_renderer.h"
  14. using testing::Values;
  15. struct test_scene : engine::scene {
  16. using engine::scene::scene;
  17. void update(float) override { check_collisions(); }
  18. void render() override {}
  19. void handle_key_event(engine::event::key_event) override {}
  20. void handle_mouse_event(engine::event::mouse_event) override {}
  21. bool in_bounds(math::dim2::point c) const {
  22. return engine::scene::in_bounds(c);
  23. }
  24. bool in_bounds(engine::collidable * c) const {
  25. return engine::scene::in_bounds(c);
  26. }
  27. graphics::manager const & graphics_manager() const {
  28. return engine::scene::graphics_manager();
  29. }
  30. void add_with(engine::collision_t t, engine::collidable & c) {
  31. colliders[t].push_back(&c);
  32. }
  33. void add_as(engine::collision_t t, engine::collidable & c) {
  34. collidables[t].push_back(&c);
  35. }
  36. };
  37. struct mock_collidable : engine::collidable {
  38. mock_collidable(math::dim2::rectangle bounds)
  39. : engine::collidable({bounds, bounds, cast<graphics::material>(1), {}}) {}
  40. MOCK_METHOD1(collide, void(engine::collidable const &));
  41. };
  42. class SceneTest : public testing::Test {
  43. protected:
  44. void SetUp() override;
  45. void TearDown() override;
  46. test_scene & scene() const { return *scene_; }
  47. engine::game_dispatch & game() const { return *dispatch_; }
  48. std::shared_ptr<stub_renderer> renderer_;
  49. std::shared_ptr<engine::game_dispatch> dispatch_;
  50. std::shared_ptr<test_scene> scene_;
  51. };
  52. void SceneTest::SetUp() {
  53. renderer_.reset(new stub_renderer);
  54. math::vec2 screen{{1600.f, 900.f}};
  55. env::resize_screen(math::vec2i(screen));
  56. dispatch_.reset(new engine::game_dispatch(renderer_));
  57. scene_.reset(new test_scene("test", screen, dispatch_));
  58. }
  59. void SceneTest::TearDown() {
  60. scene_.reset();
  61. dispatch_.reset();
  62. renderer_.reset();
  63. }
  64. using testing::Eq;
  65. using testing::Ref;
  66. TEST_F(SceneTest, SharedGraphicsManagerWithDispatch) {
  67. EXPECT_THAT(&scene().graphics_manager(), &game().graphics_manager());
  68. }
  69. TEST_F(SceneTest, WillCollideOverlappingObjects) {
  70. math::dim2::rectangle bnds{{{0.f, 0.f}}, {{1.f, 1.f}}};
  71. mock_collidable one{bnds}, two{bnds};
  72. scene().add_with(1, one);
  73. scene().add_as(1, two);
  74. EXPECT_CALL(one, collide(Ref(two))).Times(1);
  75. scene().update(0.f);
  76. }
  77. TEST_F(SceneTest, NonOverlappingDontCollide) {
  78. mock_collidable one{{{{0.f, 0.f}}, {{1.f, 1.f}}}};
  79. mock_collidable two{{{{2.f, 2.f}}, {{1.f, 1.f}}}};
  80. scene().add_with(1, one);
  81. scene().add_as(1, two);
  82. EXPECT_CALL(one, collide(Ref(two))).Times(0);
  83. scene().update(0.f);
  84. }
  85. TEST_F(SceneTest, CollisionIsOneWay) {
  86. math::dim2::rectangle bnds{{{0.f, 0.f}}, {{1.f, 1.f}}};
  87. mock_collidable one{bnds}, two{bnds};
  88. scene().add_with(1, one);
  89. scene().add_as(1, two);
  90. EXPECT_CALL(one, collide(Ref(two))).Times(1);
  91. EXPECT_CALL(two, collide(Ref(one))).Times(0);
  92. scene().update(0.f);
  93. }
  94. TEST_F(SceneTest, ObjectCannotCollideSelf) {
  95. math::dim2::rectangle bnds{{{0.f, 0.f}}, {{1.f, 1.f}}};
  96. mock_collidable one{bnds};
  97. scene().add_with(1, one);
  98. scene().add_as(1, one);
  99. EXPECT_CALL(one, collide(Ref(one))).Times(0);
  100. scene().update(0.f);
  101. }
  102. TEST_F(SceneTest, CollisionMatchesAsWithKeys) {
  103. math::dim2::rectangle bnds{{{0.f, 0.f}}, {{1.f, 1.f}}};
  104. mock_collidable one{bnds}, two{bnds}, three{bnds};
  105. scene().add_with(2, one);
  106. scene().add_as(1, two);
  107. scene().add_as(2, three);
  108. EXPECT_CALL(one, collide(Ref(two))).Times(0);
  109. EXPECT_CALL(one, collide(Ref(three))).Times(1);
  110. scene().update(0.f);
  111. }
  112. TEST_F(SceneTest, ObjectCanBeInMultipleCollidesWithGroups) {
  113. math::dim2::rectangle bnds{{{0.f, 0.f}}, {{1.f, 1.f}}};
  114. mock_collidable one{bnds}, two{bnds}, three{bnds};
  115. scene().add_with(1, one);
  116. scene().add_with(2, one);
  117. scene().add_as(1, two);
  118. scene().add_as(2, three);
  119. EXPECT_CALL(one, collide(Ref(two))).Times(1);
  120. EXPECT_CALL(one, collide(Ref(three))).Times(1);
  121. scene().update(0.f);
  122. }
  123. TEST_F(SceneTest, ObjectCanBeInMultipleCollidableAsGroups) {
  124. math::dim2::rectangle bnds{{{0.f, 0.f}}, {{1.f, 1.f}}};
  125. mock_collidable one{bnds}, two{bnds}, three{bnds};
  126. scene().add_with(1, one);
  127. scene().add_with(2, three);
  128. scene().add_as(1, two);
  129. scene().add_as(2, two);
  130. EXPECT_CALL(one, collide(Ref(two))).Times(1);
  131. EXPECT_CALL(three, collide(Ref(two))).Times(1);
  132. scene().update(0.f);
  133. }
  134. // TODO: Solve double-collision bug?
  135. TEST_F(SceneTest, DoubleCollisionCanOccur) {
  136. math::dim2::rectangle bnds{{{0.f, 0.f}}, {{1.f, 1.f}}};
  137. mock_collidable one{bnds}, two{bnds};
  138. scene().add_with(1, one);
  139. scene().add_with(2, one);
  140. scene().add_as(1, two);
  141. scene().add_as(2, two);
  142. EXPECT_CALL(one, collide(Ref(two))).Times(2);
  143. scene().update(0.f);
  144. }
  145. struct BoundsTest : SceneTest, testing::WithParamInterface<math::vec2> {};
  146. TEST_F(BoundsTest, BoundsCheckIsPointInScreenZone) {
  147. // Confirm that the size is as expected...
  148. EXPECT_THAT(scene().size(), Eq(math::vec2(1600.f, 900.f)));
  149. // Lower-Left Corner
  150. EXPECT_FALSE(scene().in_bounds(math::vec2(-1.f, 0.f)));
  151. EXPECT_FALSE(scene().in_bounds(math::vec2(0.f, -1.f)));
  152. EXPECT_TRUE(scene().in_bounds(math::vec2(0.f, 0.f)));
  153. // Lower-Right Corner
  154. EXPECT_FALSE(scene().in_bounds(math::vec2(1600.f, -1.f)));
  155. EXPECT_FALSE(scene().in_bounds(math::vec2(1601.f, 0.f)));
  156. EXPECT_TRUE(scene().in_bounds(math::vec2(1600.f, 0.f)));
  157. // Upper-Right Corner
  158. EXPECT_FALSE(scene().in_bounds(math::vec2(1601.f, 900.f)));
  159. EXPECT_FALSE(scene().in_bounds(math::vec2(1600.f, 901.f)));
  160. EXPECT_TRUE(scene().in_bounds(math::vec2(1600.f, 900.f)));
  161. // Upper-Left Corner
  162. EXPECT_FALSE(scene().in_bounds(math::vec2(0.f, 901.f)));
  163. EXPECT_FALSE(scene().in_bounds(math::vec2(-1.f, 900.f)));
  164. EXPECT_TRUE(scene().in_bounds(math::vec2(0.f, 900.f)));
  165. }
  166. TEST_P(BoundsTest, BoundsCheckOnCollidableIsAnyPointInBounds) {
  167. math::dim2::square bounds = {GetParam(), 2.f};
  168. engine::collidable collide{{{}, bounds, cast<graphics::material>(1), {}}};
  169. EXPECT_TRUE(scene().in_bounds(&collide));
  170. }
  171. INSTANTIATE_TEST_SUITE_P(Collidable, BoundsTest,
  172. Values(math::vec2(-1.f, -1.f),
  173. math::vec2(1599.f, -1.f),
  174. math::vec2(1599.f, 899.f),
  175. math::vec2(-1.f, 899.f)));