Moved raycast from TileManager to World.

This commit is contained in:
Felix Ableitner 2013-04-29 16:10:22 +02:00
parent 0fc271495d
commit 3ee0c71857
5 changed files with 46 additions and 44 deletions

View file

@ -241,3 +241,46 @@ World::draw(sf::RenderTarget& target, sf::RenderStates states) const {
} }
} }
} }
/*
* Performs a raycast between two points to check if the path between them is
* clear of walls. Does not consider characters, bullets etc.
*
* @param lineStart First point of the line to test.
* @param lineEnd Second point of the line to test.
* @return True if the ray was not blocked.
*/
bool
World::raycast(const sf::Vector2f& lineStart,
const sf::Vector2f& lineEnd) const {
assert(lineStart != lineEnd);
sf::Vector2f lineCenter = lineStart + 0.5f * (lineEnd - lineStart);
for (const auto& it : mDrawables.at(Sprite::Category::CATEGORY_WORLD)) {
if (it->collisionEnabled(Sprite::Category::CATEGORY_WORLD))
continue;
sf::Vector2f axis = it->getPosition() - lineCenter;
if (axis == sf::Vector2f())
return false;
axis = thor::unitVector(axis);
sf::Vector2f halfsize = it->getSize() / 2.0f;
float rectPosProjected = thor::dotProduct(axis, it->getPosition());
float lineStartProjected = thor::dotProduct(axis, lineStart);
float lineEndProjected = thor::dotProduct(axis, lineEnd);
// For corner projections, those on the same line with the rect
// center are equal by value, so we only need one on each axis
// and take the maximum.
float rectHalfWidthProjected = std::max(
abs(thor::dotProduct(axis, halfsize)),
abs(thor::dotProduct(axis,
sf::Vector2f(halfsize.x, -halfsize.y))));
Interval line = Interval::IntervalFromPoints(lineStartProjected,
lineEndProjected);
Interval rect = Interval::IntervalFromRadius(rectPosProjected,
rectHalfWidthProjected);
// Allow movement if sprites are moving apart.
if (line.getOverlap(rect).getLength() > 0.0f)
return false;
}
return true;
}

View file

@ -28,6 +28,8 @@ public:
void think(int elapsed); void think(int elapsed);
std::vector<std::shared_ptr<Character> > std::vector<std::shared_ptr<Character> >
getCharacters(const sf::Vector2f& position, float maxDistance) const; getCharacters(const sf::Vector2f& position, float maxDistance) const;
bool raycast(const sf::Vector2f& lineStart,
const sf::Vector2f& lineEnd) const;
private: private:

View file

@ -156,7 +156,7 @@ Character::isMoving() const {
*/ */
bool bool
Character::isVisible(const sf::Vector2f& target) const { Character::isVisible(const sf::Vector2f& target) const {
return mTileManager.raycast(getPosition(), target); return mWorld.raycast(getPosition(), target);
} }
/** /**

View file

@ -96,44 +96,3 @@ TileManager::insertTile(const TilePosition& position, Type type) {
mTiles.push_back(tile); mTiles.push_back(tile);
mWorld.insert(tile); mWorld.insert(tile);
} }
/*
* Performs a raycast between two points to check if the path between them is
* clear of walls.
*
* @param lineStart First point of the line to test.
* @param lineEnd Second point of the line to test.
* @return True if the ray was not blocked.
*/
bool
TileManager::raycast(const sf::Vector2f& lineStart,
const sf::Vector2f& lineEnd) const {
assert(lineStart != lineEnd);
sf::Vector2f lineCenter = lineStart + 0.5f * (lineEnd - lineStart);
for (auto it : mTiles) {
if (it->getType() == Type::FLOOR)
continue;
sf::Vector2f axis = it->getPosition() - lineCenter;
if (axis == sf::Vector2f())
return false;
axis = thor::unitVector(axis);
sf::Vector2f halfsize = it->getSize() / 2.0f;
float rectPosProjected = thor::dotProduct(axis, it->getPosition());
float lineStartProjected = thor::dotProduct(axis, lineStart);
float lineEndProjected = thor::dotProduct(axis, lineEnd);
// For corner projections, those on the same line with the rect
// center are equal by value, so we only need one on each axis
// and take the maximum.
float rectHalfWidthProjected = std::max(
abs(thor::dotProduct(axis, halfsize)),
abs(thor::dotProduct(axis,
sf::Vector2f(halfsize.x, -halfsize.y))));
Interval line = Interval::IntervalFromPoints(lineStartProjected, lineEndProjected);
Interval rect = Interval::IntervalFromRadius(rectPosProjected, rectHalfWidthProjected);
// Allow movement if sprites are moving apart.
if (line.getOverlap(rect).getLength() > 0.0f)
return false;
}
return true;
}

View file

@ -31,8 +31,6 @@ public:
explicit TileManager(World& world); explicit TileManager(World& world);
void insertTile(const TilePosition& position, Type type); void insertTile(const TilePosition& position, Type type);
bool raycast(const sf::Vector2f& lineStart,
const sf::Vector2f& lineEnd) const;
private: private:
class Tile; class Tile;