scene_test.cxx 6.4 KB

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