Skip to content

Commit

Permalink
End of Episode 70
Browse files Browse the repository at this point in the history
  • Loading branch information
Christopher Hebert committed Dec 1, 2014
1 parent af7993e commit 3b4b8f6
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 46 deletions.
44 changes: 27 additions & 17 deletions CaveStory/src/game.cc
Expand Up @@ -48,10 +48,12 @@ void Game::eventLoop() {
damage_texts_.addDamageable(bat_);
map_.reset(Map::createSlopeTestMap(graphics));

pickups_.add(boost::shared_ptr<Pickup>(new PowerDoritoPickup(
graphics,
bat_->center_x(), bat_->center_y(),
PowerDoritoPickup::MEDIUM)));
for (int i = 0; i < 10; ++i) {
pickups_.add(boost::shared_ptr<Pickup>(new PowerDoritoPickup(
graphics,
bat_->center_x(), bat_->center_y(),
PowerDoritoPickup::MEDIUM)));
}

bool running = true;
units::MS last_update_time = SDL_GetTicks();
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -167,29 +173,33 @@ 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();

map_->drawBackground(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);
Expand Down
1 change: 1 addition & 0 deletions CaveStory/src/game.h
Expand Up @@ -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> player_;
boost::shared_ptr<FirstCaveBat> bat_;
Expand Down
100 changes: 71 additions & 29 deletions CaveStory/src/map_collidable.cc
Expand Up @@ -16,38 +16,78 @@ namespace {
Tile2D tile_position;
tiles::TileType tile_type;
};
optional<CollisionInfo> testMapCollision(
const Map& map,
const Rectangle& rectangle,
sides::SideType direction,
const boost::optional<tiles::TileType>& maybe_ground_tile) {
std::vector<CollisionTile> 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<CollisionInfo> MapCollisionFunc(
const Map& map,
const Rectangle& rectangle,
sides::SideType direction,
const boost::optional<tiles::TileType>& maybe_ground_tile);

optional<CollisionInfo> testMapStickyCollision(
const Map& map,
const Rectangle& rectangle,
sides::SideType direction,
const boost::optional<tiles::TileType>& maybe_ground_tile) {
std::vector<CollisionTile> 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<CollisionInfo> testMapBouncingCollision(
const Map& map,
const Rectangle& rectangle,
sides::SideType direction,
const boost::optional<tiles::TileType>&) {
std::vector<CollisionTile> tiles(map.getCollidingTiles(rectangle, direction));
optional<CollisionInfo> 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;
}
}

Expand Down Expand Up @@ -87,6 +127,8 @@ void MapCollidable::update(
units::MS elapsed_time_ms, const Map& map,
const boost::optional<tiles::TileType>& 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;
Expand All @@ -95,7 +137,7 @@ void MapCollidable::update(
(delta > 0 ? sides::RIGHT_SIDE : sides::LEFT_SIDE) :
(delta > 0 ? sides::BOTTOM_SIDE : sides::TOP_SIDE);
{
optional<CollisionInfo> maybe_info = testMapCollision(
optional<CollisionInfo> maybe_info = test_map_collision(
map,
collision_rectangle.collision(direction, kinematics_x.position, kinematics_y.position, delta),
direction,
Expand All @@ -113,7 +155,7 @@ void MapCollidable::update(

// Check collision in other direction.
const sides::SideType opposite_direction = sides::opposite_side(direction);
optional<CollisionInfo> maybe_info = testMapCollision(
optional<CollisionInfo> maybe_info = test_map_collision(
map,
collision_rectangle.collision(opposite_direction, kinematics_x.position, kinematics_y.position, 0),
opposite_direction,
Expand Down
9 changes: 9 additions & 0 deletions CaveStory/src/map_collidable.h
Expand Up @@ -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,
Expand Down Expand Up @@ -46,6 +53,8 @@ struct MapCollidable {
units::MS elapsed_time_ms, const Map& map,
const boost::optional<tiles::TileType>& maybe_ground_tile,
Kinematics& kinematics, AxisType axis);

CollisionType collision_type_;
};

#endif // MAP_COLLIDABLE_H_
1 change: 1 addition & 0 deletions CaveStory/src/player.cc
Expand Up @@ -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),
Expand Down
1 change: 1 addition & 0 deletions CaveStory/src/power_dorito_pickup.cc
Expand Up @@ -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,
Expand Down
15 changes: 15 additions & 0 deletions 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.

0 comments on commit 3b4b8f6

Please sign in to comment.