Skip to content

Commit

Permalink
end of episode 66
Browse files Browse the repository at this point in the history
  • Loading branch information
Christopher Hebert committed Apr 5, 2014
1 parent d6aa717 commit 060bbe7
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 23 deletions.
59 changes: 57 additions & 2 deletions CaveStory/src/collision_tile.cc
Original file line number Diff line number Diff line change
@@ -1,18 +1,73 @@
#include "collision_tile.h"

using namespace sides;
using namespace tiles;

namespace {
inline float get_slope(const TileType& tile_type) {
const TileType right_top = TileType().set(RIGHT_SLOPE).set(TOP_SLOPE);
const TileType left_bottom = TileType().set(LEFT_SLOPE).set(BOTTOM_SLOPE);
const bool is_positive =
((right_top & tile_type) == right_top) ||
((left_bottom & tile_type) == left_bottom);
return is_positive ? 0.5f : -0.5f;
}

inline units::Game get_offset(const TileType& tile_type) {
{
const TileType left_top_tall =
TileType().set(LEFT_SLOPE).set(TOP_SLOPE).set(TALL_SLOPE);
const TileType right_bottom_short =
TileType().set(RIGHT_SLOPE).set(BOTTOM_SLOPE).set(SHORT_SLOPE);
if ((left_top_tall & tile_type) == left_top_tall ||
(right_bottom_short & tile_type) == right_bottom_short) {
return units::tileToGame(1);
}
}

const TileType left_bottom_tall =
TileType().set(LEFT_SLOPE).set(BOTTOM_SLOPE).set(TALL_SLOPE);
const TileType right_top_short =
TileType().set(RIGHT_SLOPE).set(TOP_SLOPE).set(SHORT_SLOPE);
if ((left_bottom_tall & tile_type) == left_bottom_tall ||
(right_top_short & tile_type) == right_top_short) {
return 0.0f;
}

return units::kHalfTile;
}
}

boost::optional<units::Game> CollisionTile::testCollision(
sides::SideType side,
units::Game /*position*/) const {
if (tile_type_[tiles::WALL]) {
units::Game perpendicular_position,
units::Game leading_position,
bool should_test_slopes) const {
if (tile_type_[WALL]) {
if (side == TOP_SIDE)
return units::tileToGame(row_);
if (side == BOTTOM_SIDE)
return units::tileToGame(row_ + 1);
if (side == LEFT_SIDE)
return units::tileToGame(col_);
return units::tileToGame(col_ + 1);
} else if (should_test_slopes &&
tile_type_[SLOPE] &&
!tile_type_[slope_flag_from_side(side)]) {
const units::Game row = units::tileToGame(row_);
const units::Game col = units::tileToGame(col_);
const float slope = get_slope(tile_type_);
const units::Game offset = get_offset(tile_type_);
const units::Game calculated_position = sides::vertical(side) ?
slope * (perpendicular_position - col) + offset + row :
(perpendicular_position - row - offset) / slope + col;

const bool is_colliding = is_max(side) ?
leading_position <= calculated_position :
leading_position >= calculated_position;

if (is_colliding)
return calculated_position;
}
return boost::none;
}
8 changes: 6 additions & 2 deletions CaveStory/src/collision_tile.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,14 @@ struct CollisionTile {
// otherwise the position of the collision on the same axis of side
//
// side: the side of the tile that is being collided with
// position: the position on the tile on the opposite axis of side
// perpendicular_position: the position on the tile on the opposite axis of side
// leading_position: position of the leading edge of the colliding entity
// should_test_slopes: whether slopes should be considered for collision
boost::optional<units::Game> testCollision(
sides::SideType side,
units::Game position) const;
units::Game perpendicular_position,
units::Game leading_position,
bool should_test_slopes) const;

private:
units::Tile row_, col_;
Expand Down
2 changes: 2 additions & 0 deletions CaveStory/src/game.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,14 @@ void Game::eventLoop() {
damage_texts_.addDamageable(bat_);
map_.reset(Map::createSlopeTestMap(graphics));

/*
for (int i = 0; i < 3; ++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
3 changes: 1 addition & 2 deletions CaveStory/src/map.cc
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,7 @@ vector<CollisionTile> Map::getCollidingTiles(
const units::Tile last_primary =
units::gameToTile(rectangle.side(direction));
const units::Tile primary_incr =
direction == sides::BOTTOM_SIDE || direction == sides::RIGHT_SIDE ?
1 : -1;
sides::is_max(direction) ? 1 : -1;

const bool horizontal = sides::horizontal(direction);
const units::Tile s_min =
Expand Down
7 changes: 5 additions & 2 deletions CaveStory/src/map_collidable.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@ optional<units::Game> testMapCollision(
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 position = sides::vertical(side) ?
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 optional<units::Game> maybe_position(
tiles[i].testCollision(side, position));
tiles[i].testCollision(
side, perpendicular_position, leading_position, should_test_slopes));
if (maybe_position) {
return maybe_position;
}
Expand Down
10 changes: 7 additions & 3 deletions CaveStory/src/player.cc
Original file line number Diff line number Diff line change
Expand Up @@ -334,10 +334,14 @@ void Player::updateY(units::MS elapsed_time_ms, const Map& map) {
void Player::onCollision(sides::SideType side, bool is_delta_direction) {
switch (side) {
case sides::TOP_SIDE:
if (is_delta_direction)
if (is_delta_direction) {
kinematics_y_.velocity = 0.0f;
particle_tools_.front_system.addNewParticle(boost::shared_ptr<Particle>(
new HeadBumpParticle(particle_tools_.graphics, center_x(), kinematics_y_.position + kCollisionRectangle.boundingBox().top())));
particle_tools_.front_system.addNewParticle(boost::shared_ptr<Particle>(
new HeadBumpParticle(
particle_tools_.graphics,
center_x(),
kinematics_y_.position + kCollisionRectangle.boundingBox().top())));
}
break;
case sides::BOTTOM_SIDE:
on_ground_ = true;
Expand Down
30 changes: 18 additions & 12 deletions CaveStory/src/polar_star.cc
Original file line number Diff line number Diff line change
Expand Up @@ -250,25 +250,31 @@ bool PolarStar::Projectile::update(units::MS elapsed_time, const Map& map, Parti

const sides::SideType direction = sides::from_facing(
horizontal_direction_, vertical_direction_);
const Rectangle rectangle(collisionRectangle());
std::vector<CollisionTile> colliding_tiles(
map.getCollidingTiles(collisionRectangle(), direction));
map.getCollidingTiles(rectangle, direction));
for (size_t i = 0; i < colliding_tiles.size(); ++i) {
const sides::SideType side = sides::opposite_side(direction);
const units::Game position = sides::vertical(side) ?
getX() :
getY();
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 = true;
const boost::optional<units::Game> maybe_position(
colliding_tiles[i].testCollision(side, position));
colliding_tiles[i].testCollision(
side, perpendicular_position, leading_position, should_test_slopes));

if (maybe_position) {
const units::Game particle_x = sides::vertical(side) ?
position :
*maybe_position - units::kHalfTile;
const units::Game particle_y = sides::vertical(side) ?
*maybe_position - units::kHalfTile :
position;
const units::Game collision_x = sides::vertical(side) ?
perpendicular_position :
*maybe_position;
const units::Game collision_y = sides::vertical(side) ?
*maybe_position :
perpendicular_position;
particle_tools.front_system.addNewParticle(boost::shared_ptr<Particle>(
new ProjectileWallParticle(particle_tools.graphics, particle_x, particle_y)));
new ProjectileWallParticle(particle_tools.graphics,
collision_x - units::kHalfTile,
collision_y - units::kHalfTile)));
return false;
}
}
Expand Down
7 changes: 7 additions & 0 deletions CaveStory/src/side_type.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ namespace sides {
return LEFT_SIDE;
return RIGHT_SIDE;
}

inline bool is_max(SideType side) {
return side == RIGHT_SIDE || side == BOTTOM_SIDE;
}
inline bool is_min(SideType side) {
return !is_max(side);
}
}

#endif // SIDE_TYPE_H_
12 changes: 12 additions & 0 deletions CaveStory/src/tile_type.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

#include <bitset>

#include "side_type.h"

namespace tiles {
enum TileFlag {
EMPTY,
Expand All @@ -20,6 +22,16 @@ namespace tiles {
LAST_TILE_FLAG
};
typedef std::bitset<LAST_TILE_FLAG> TileType;

inline TileFlag slope_flag_from_side(sides::SideType side) {
if (side == sides::LEFT_SIDE)
return LEFT_SLOPE;
if (side == sides::RIGHT_SIDE)
return RIGHT_SLOPE;
if (side == sides::TOP_SIDE)
return TOP_SLOPE;
return BOTTOM_SLOPE;
}
}

#endif // TILE_TYPE_H_
49 changes: 49 additions & 0 deletions slides/66-slopes.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
Episode 66 - General Slopes
===========================

Problem:
- Implement General Formula for slopes

Solution:
- General Formulas (from Episode 61)
y = slope * (x - col) + offset + row
|- perpendicular_position
x = (y - row - offset) / slope + col
|- perpendicular_position

row,col,tile_type: stored in CollisionTile
offset,slope: calculated from tile_type

- one of two checks for collision
calculated_position=calculated position (y or x)
leading_position=position of the leading edge of the colliding entity
side=the side of the TILE being collided with
is_max_side?=side is BOTTOM or RIGHT (further along in the axis)

if is_max_side? side
leading_position <= calculated_position
else
leading_position >= calculated_position

example:
Projectile is going LEFT
Projectile's leading position is its LEFT side
side we are checking is RIGHT
calculated position represents the right side
since RIGHT is the max of (LEFT|RIGHT)
collision occurs if leading position is <= calculated position

slope Tiles
+0.5 RIGHT-TOP, LEFT-BOTTOM
-0.5 LEFT-TOP , RIGHT-BOTTOM

offset Tiles
1T LEFT-TOP-TALL , RIGHT-BOTTOM-SHORT
0T LEFT-BOTTOM-TALL, RIGHT-TOP-SHORT
0.5T (Everything else)

|\
| \
___\
LEFT-BOTTOM
LEFT and BOTTOM Sides are invalid

0 comments on commit 060bbe7

Please sign in to comment.