Moved raycast from TileManager to World.
This commit is contained in:
parent
0fc271495d
commit
3ee0c71857
5 changed files with 46 additions and 44 deletions
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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:
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Reference in a new issue