diff --git a/CaveStory/src/game.cc b/CaveStory/src/game.cc index 1afe202..92d27c5 100755 --- a/CaveStory/src/game.cc +++ b/CaveStory/src/game.cc @@ -48,10 +48,12 @@ void Game::eventLoop() { damage_texts_.addDamageable(bat_); map_.reset(Map::createSlopeTestMap(graphics)); - pickups_.add(boost::shared_ptr(new PowerDoritoPickup( - graphics, - bat_->center_x(), bat_->center_y(), - PowerDoritoPickup::MEDIUM))); + for (int i = 0; i < 10; ++i) { + pickups_.add(boost::shared_ptr(new PowerDoritoPickup( + graphics, + bat_->center_x(), bat_->center_y(), + PowerDoritoPickup::MEDIUM))); + } bool running = true; units::MS last_update_time = SDL_GetTicks(); @@ -117,7 +119,11 @@ void Game::eventLoop() { update(std::min(elapsed_time, kMaxFrameTime), graphics); last_update_time = current_time_ms; */ - if (input.isKeyHeld(SDLK_p) || input.wasKeyPressed(SDLK_n)) { + static bool should_play = true; + if (input.wasKeyPressed(SDLK_p)) { + should_play = !should_play; + } + if (should_play || input.wasKeyPressed(SDLK_n)) { MapCollidable::_debug_colliding_tiles.clear(); MapCollidable::_debug_opposite_colliding_tiles.clear(); update(1000 / kFps, graphics); @@ -167,6 +173,20 @@ void Game::update(units::MS elapsed_time_ms, Graphics& graphics) { } } +void Game::debugDraw(Graphics& graphics) { + for (size_t i = 0; i < MapCollidable::_debug_colliding_tiles.size(); ++i) { + Position2D position = MapCollidable::_debug_colliding_tiles[i].convert(units::tileToGame); + Rectangle rect(position, Tile2D(1).convert(units::tileToGame)); + graphics.drawRectOutline(rect, 4, 255, 0, 0); + } + for (size_t i = 0; i < MapCollidable::_debug_opposite_colliding_tiles.size(); ++i) { + Position2D position = MapCollidable::_debug_opposite_colliding_tiles[i].convert(units::tileToGame); + Rectangle rect(position, Tile2D(1).convert(units::tileToGame)); + graphics.drawRectOutline(rect, 4, 0, 255, 0); + } + pickups_.draw(graphics); +} + void Game::draw(Graphics& graphics) { graphics.clear(); @@ -174,22 +194,12 @@ void Game::draw(Graphics& graphics) { if (bat_) bat_->draw(graphics); entity_particle_system_.draw(graphics); - //pickups_.draw(graphics); + pickups_.draw(graphics); player_->draw(graphics); map_->draw(graphics); front_particle_system_.draw(graphics); - pickups_.draw(graphics); - for (size_t i = 0; i < MapCollidable::_debug_colliding_tiles.size(); ++i) { - Position2D position = MapCollidable::_debug_colliding_tiles[i].convert(units::tileToGame); - Rectangle rect(position, Tile2D(1).convert(units::tileToGame)); - graphics.drawRectOutline(rect, 4, 255, 0, 0); - } - for (size_t i = 0; i < MapCollidable::_debug_opposite_colliding_tiles.size(); ++i) { - Position2D position = MapCollidable::_debug_opposite_colliding_tiles[i].convert(units::tileToGame); - Rectangle rect(position, Tile2D(1).convert(units::tileToGame)); - graphics.drawRectOutline(rect, 4, 0, 255, 0); - } + //debugDraw(graphics); damage_texts_.draw(graphics); player_->drawHUD(graphics); diff --git a/CaveStory/src/game.h b/CaveStory/src/game.h index 7835c92..c2be174 100755 --- a/CaveStory/src/game.h +++ b/CaveStory/src/game.h @@ -24,6 +24,7 @@ struct Game { void eventLoop(); void update(units::MS elapsed_time_ms, Graphics& graphics); void draw(Graphics& graphics); + void debugDraw(Graphics& graphics); boost::shared_ptr player_; boost::shared_ptr bat_; diff --git a/CaveStory/src/map_collidable.cc b/CaveStory/src/map_collidable.cc index 5ba7a62..1f8c9da 100644 --- a/CaveStory/src/map_collidable.cc +++ b/CaveStory/src/map_collidable.cc @@ -16,38 +16,78 @@ namespace { Tile2D tile_position; tiles::TileType tile_type; }; - optional testMapCollision( - const Map& map, - const Rectangle& rectangle, - sides::SideType direction, - const boost::optional& maybe_ground_tile) { - std::vector tiles(map.getCollidingTiles(rectangle, direction)); - for (size_t i = 0; i < tiles.size(); ++i) { - const sides::SideType side = sides::opposite_side(direction); - const units::Game perpendicular_position = sides::vertical(side) ? - rectangle.center_x() : - rectangle.center_y(); - const units::Game leading_position = rectangle.side(direction); - const bool should_test_slopes = sides::vertical(side); - const CollisionTile::TestCollisionInfo test_info( + + typedef optional MapCollisionFunc( + const Map& map, + const Rectangle& rectangle, + sides::SideType direction, + const boost::optional& maybe_ground_tile); + + optional testMapStickyCollision( + const Map& map, + const Rectangle& rectangle, + sides::SideType direction, + const boost::optional& maybe_ground_tile) { + std::vector tiles(map.getCollidingTiles(rectangle, direction)); + for (size_t i = 0; i < tiles.size(); ++i) { + const sides::SideType side = sides::opposite_side(direction); + const units::Game perpendicular_position = sides::vertical(side) ? + rectangle.center_x() : + rectangle.center_y(); + const units::Game leading_position = rectangle.side(direction); + const bool should_test_slopes = sides::vertical(side); + const CollisionTile::TestCollisionInfo test_info( tiles[i].testCollision( - side, perpendicular_position, leading_position, should_test_slopes)); - if (test_info.is_colliding) { - const CollisionInfo info = { test_info.position, tiles[i].position(), tiles[i].tile_type() }; - return info; - } else if (maybe_ground_tile && direction == sides::BOTTOM_SIDE) { - const tiles::TileType tall_slope = - tiles::TileType().set(tiles::SLOPE).set(tiles::TALL_SLOPE); - if ((maybe_ground_tile->test(tiles::SLOPE) && - tiles[i].tile_type()[tiles::SLOPE]) || - (maybe_ground_tile->test(tiles::WALL) && - (tall_slope & tiles[i].tile_type()) == tall_slope)) { + side, perpendicular_position, leading_position, should_test_slopes)); + if (test_info.is_colliding) { const CollisionInfo info = { test_info.position, tiles[i].position(), tiles[i].tile_type() }; return info; + } else if (maybe_ground_tile && direction == sides::BOTTOM_SIDE) { + const tiles::TileType tall_slope = + tiles::TileType().set(tiles::SLOPE).set(tiles::TALL_SLOPE); + if ((maybe_ground_tile->test(tiles::SLOPE) && + tiles[i].tile_type()[tiles::SLOPE]) || + (maybe_ground_tile->test(tiles::WALL) && + (tall_slope & tiles[i].tile_type()) == tall_slope)) { + const CollisionInfo info = { test_info.position, tiles[i].position(), tiles[i].tile_type() }; + return info; + } } } - } - return boost::none; + return boost::none; + } + + optional testMapBouncingCollision( + const Map& map, + const Rectangle& rectangle, + sides::SideType direction, + const boost::optional&) { + std::vector tiles(map.getCollidingTiles(rectangle, direction)); + optional result; + for (size_t i = 0; i < tiles.size(); ++i) { + const sides::SideType side = sides::opposite_side(direction); + const units::Game perpendicular_position = sides::vertical(side) ? + rectangle.center_x() : + rectangle.center_y(); + const units::Game leading_position = rectangle.side(direction); + const bool should_test_slopes = sides::vertical(side); + const CollisionTile::TestCollisionInfo test_info( + tiles[i].testCollision( + side, perpendicular_position, leading_position, should_test_slopes)); + if (test_info.is_colliding) { + bool should_replace_result = true; + if (result) { + should_replace_result = sides::is_min(side) ? + test_info.position < result->position : + test_info.position > result->position; + } + if (should_replace_result) { + const CollisionInfo info = { test_info.position, tiles[i].position(), tiles[i].tile_type() }; + result = info; + } + } + } + return result; } } @@ -87,6 +127,8 @@ void MapCollidable::update( units::MS elapsed_time_ms, const Map& map, const boost::optional& maybe_ground_tile, Kinematics& kinematics, AxisType axis) { + MapCollisionFunc* test_map_collision = collision_type_ == BOUNCING_COLLISION ? + testMapBouncingCollision : testMapStickyCollision; accelerator.updateVelocity(kinematics, elapsed_time_ms); // Calculate delta const units::Game delta = kinematics.velocity * elapsed_time_ms; @@ -95,7 +137,7 @@ void MapCollidable::update( (delta > 0 ? sides::RIGHT_SIDE : sides::LEFT_SIDE) : (delta > 0 ? sides::BOTTOM_SIDE : sides::TOP_SIDE); { - optional maybe_info = testMapCollision( + optional maybe_info = test_map_collision( map, collision_rectangle.collision(direction, kinematics_x.position, kinematics_y.position, delta), direction, @@ -113,7 +155,7 @@ void MapCollidable::update( // Check collision in other direction. const sides::SideType opposite_direction = sides::opposite_side(direction); - optional maybe_info = testMapCollision( + optional maybe_info = test_map_collision( map, collision_rectangle.collision(opposite_direction, kinematics_x.position, kinematics_y.position, 0), opposite_direction, diff --git a/CaveStory/src/map_collidable.h b/CaveStory/src/map_collidable.h index 8a7aae7..15a5d4f 100644 --- a/CaveStory/src/map_collidable.h +++ b/CaveStory/src/map_collidable.h @@ -14,6 +14,13 @@ struct Kinematics; struct Map; struct MapCollidable { + enum CollisionType { + BOUNCING_COLLISION, + STICKY_COLLISION + }; + + MapCollidable(CollisionType collision_type) : collision_type_(collision_type) {} + void updateX( const CollisionRectangle& collision_rectangle, const Accelerator& accelerator, @@ -46,6 +53,8 @@ struct MapCollidable { units::MS elapsed_time_ms, const Map& map, const boost::optional& maybe_ground_tile, Kinematics& kinematics, AxisType axis); + + CollisionType collision_type_; }; #endif // MAP_COLLIDABLE_H_ diff --git a/CaveStory/src/player.cc b/CaveStory/src/player.cc index 9f07fbc..d6bc8fe 100755 --- a/CaveStory/src/player.cc +++ b/CaveStory/src/player.cc @@ -65,6 +65,7 @@ const units::MS kInvincibleTime = 3000; } Player::Player(Graphics& graphics, ParticleTools& particle_tools, units::Game x, units::Game y) : + MapCollidable(MapCollidable::STICKY_COLLISION), particle_tools_(particle_tools), kinematics_x_(x, 0.0f), kinematics_y_(y, 0.0f), diff --git a/CaveStory/src/power_dorito_pickup.cc b/CaveStory/src/power_dorito_pickup.cc index 07f28f2..b98274e 100644 --- a/CaveStory/src/power_dorito_pickup.cc +++ b/CaveStory/src/power_dorito_pickup.cc @@ -30,6 +30,7 @@ const SimpleCollisionRectangle kCollisionRectangles[] = { PowerDoritoPickup::PowerDoritoPickup(Graphics& graphics, units::Game center_x, units::Game center_y, SizeType size) : + MapCollidable(MapCollidable::BOUNCING_COLLISION), kinematics_x_(center_x - units::kHalfTile, (rand() % 11 - 5) * 0.025f), kinematics_y_(center_y - units::kHalfTile, (rand() % 11 - 5) * 0.025f), sprite_(graphics, kSpriteName, diff --git a/slides/070-fix-bounce-collisions.txt b/slides/070-fix-bounce-collisions.txt new file mode 100644 index 0000000..a122063 --- /dev/null +++ b/slides/070-fix-bounce-collisions.txt @@ -0,0 +1,15 @@ +Episode 70 - Fixing Bounce Collisions/Cleanup +============================================= + +Problem: + - Doritos fall through because of our collision check order + +Solution: + - Make sure to check the furthest collision out, rather than favoring + the tiles we are centered over/beside. + +Test: + - Many doritos! for test. + +Small Cleanup: + - Remove (comment out) our debug code until we decide what to do with it. \ No newline at end of file