1
0
Fork 0

Compare commits

..

3 commits

Author SHA1 Message Date
a0b6536432 World: make CastRay generic
Previously CastRay did the scale computation and used the player view statistics.
This makes it quite specialized, and the rest of the computations are made outside.

Move the computations in the render function and make castRay generic.
2024-01-25 22:31:39 +00:00
ddb01d0509 World: Clean warnings, optimize GetBlock
World has a lot of type conversion warnings. Take care of most of them,
for a slight performance hit ( :( ).
Re-order constructor parameters to match declaration.
Move FillColumn to a more appropriate place.

GetBlock gets called a lot : use direct memory access of the vector
rather than going through bounds checks with .at().
Introduce an integer overload to remove warnings.
2024-01-24 23:16:59 +00:00
4a95664342 main: Clean up, handle resize
Handle window resizes by resizing the view frame as well.

Clean up the event handling to allow interleaving other code between
different checks.
Remove early first frame, handle it like the others.
2024-01-24 23:09:59 +00:00
3 changed files with 56 additions and 35 deletions

View file

@ -6,8 +6,9 @@
#include <cmath> #include <cmath>
World::World(int w, int h, sf::Color groundColor, sf::Color ceilingColor, std::vector<BlockType> worldMap) : w(w), h(h), World::World(int w, int h, sf::Color groundColor, sf::Color ceilingColor, std::vector<BlockType> worldMap) :
groundColor(groundColor), ceilingColor(ceilingColor), map(std::move(worldMap)), player(0,0,0) player(0,0,0), w(w), h(h), map(std::move(worldMap)),
groundColor(groundColor), ceilingColor(ceilingColor)
{ {
map.resize(w*h,BlockType::WALL); map.resize(w*h,BlockType::WALL);
} }
@ -22,9 +23,14 @@ int World::getH() const
return h; return h;
} }
BlockType World::getBlock(int x, int y) const
{
return map[x + w*y];
}
BlockType World::getBlock(float x, float y) const BlockType World::getBlock(float x, float y) const
{ {
return(map.at(static_cast<int>(x)+w* static_cast<int>(y))); return map[static_cast<int>(x) + w*static_cast<int>(y)];
} }
void World::setBlock(BlockType block, int x, int y, int width, int height) void World::setBlock(BlockType block, int x, int y, int width, int height)
@ -83,16 +89,6 @@ std::ostream& operator<<(std::ostream& ostream, World const& world)
return(ostream); return(ostream);
} }
void World::fillColumn(sf::RenderWindow& window, int column, float scale, sf::Color wallColor) const
{
float columnHeight = window.getSize().y*scale;
sf::RectangleShape pixelColumn(sf::Vector2f(1,columnHeight));
pixelColumn.setPosition(column,(window.getSize().y-columnHeight)/2.0);
pixelColumn.setFillColor(wallColor);
window.draw(pixelColumn);
}
float World::castRay(float originX, float originY, float orientation) const float World::castRay(float originX, float originY, float orientation) const
{ {
/* /*
@ -169,7 +165,8 @@ float World::castRay(float originX, float originY, float orientation) const
float hCheckX = originX + hOffsetX; float hCheckX = originX + hOffsetX;
float hCheckY = hOffsetY; float hCheckY = hOffsetY;
/* Bounds + sanity check. */ /* Bounds + sanity check. */
while (hCheckX >= 0 && hCheckX <= w && hCheckY >= 0 && hCheckY <= h && i < h) { while (hCheckX >= 0 && hCheckX <= static_cast<float>(w) &&
hCheckY >= 0 && hCheckY <= static_cast<float>(h) && i < h) {
if (getBlock(floorf(hCheckX), floorf(hCheckY) + hRound) == BlockType::WALL) { if (getBlock(floorf(hCheckX), floorf(hCheckY) + hRound) == BlockType::WALL) {
break; break;
} }
@ -184,7 +181,8 @@ float World::castRay(float originX, float originY, float orientation) const
float vCheckY = originY + vOffsetY; float vCheckY = originY + vOffsetY;
/* Bounds + sanity check. */ /* Bounds + sanity check. */
while (vCheckX >= 0 && vCheckX < w && vCheckY >= 0 && vCheckY < h && i < w) { while (vCheckX >= 0 && vCheckX < static_cast<float>(w) &&
vCheckY >= 0 && vCheckY < static_cast<float>(h) && i < w) {
if (getBlock(floorf(vCheckX) + vRound, floorf(vCheckY)) == BlockType::WALL) { if (getBlock(floorf(vCheckX) + vRound, floorf(vCheckY)) == BlockType::WALL) {
break; break;
} }
@ -202,24 +200,36 @@ float World::castRay(float originX, float originY, float orientation) const
(originY - hCheckY)*(originY - hCheckY)); (originY - hCheckY)*(originY - hCheckY));
float vDist = sqrtf((originX - vCheckX)*(originX - vCheckX) + float vDist = sqrtf((originX - vCheckX)*(originX - vCheckX) +
(originY - vCheckY)*(originY - vCheckY)); (originY - vCheckY)*(originY - vCheckY));
float finalDist = hDist > vDist ? vDist : hDist;
/* 2 Is wall height in meters. */ return hDist > vDist ? vDist : hDist;
return player.focalLength*2/finalDist; }
void World::fillColumn(sf::RenderWindow& window, unsigned int column,
float scale, sf::Color wallColor) const
{
float columnHeight = static_cast<float>(window.getSize().y)*scale;
sf::RectangleShape pixelColumn(sf::Vector2f(1,columnHeight));
pixelColumn.setPosition(static_cast<float>(column),
(static_cast<float>(window.getSize().y)-columnHeight)/2.0f);
pixelColumn.setFillColor(wallColor);
window.draw(pixelColumn);
} }
void World::render(sf::RenderWindow& window) const void World::render(sf::RenderWindow& window) const
{ {
float windowX = static_cast<float>(window.getSize().x);
float windowY = static_cast<float>(window.getSize().y);
/* /*
* Draw ground and sky planes through half of the screen, as the walls * Draw ground and sky planes through half of the screen, as the walls
* will get drawn over them. * will get drawn over them.
* This doesn't work if we support textures/levels. * This doesn't work if we support textures/levels.
*/ */
sf::RectangleShape ground = sf::RectangleShape(sf::Vector2f(window.getSize().x,window.getSize().y/2.0)); sf::RectangleShape ground = sf::RectangleShape(sf::Vector2f(windowX,windowY/2.0f));
ground.setFillColor(groundColor); ground.setFillColor(groundColor);
ground.setPosition(0,window.getSize().y/2.0); ground.setPosition(0,windowY/2.0f);
sf::RectangleShape ceiling = sf::RectangleShape(sf::Vector2f(window.getSize().x,window.getSize().y/2.0)); sf::RectangleShape ceiling = sf::RectangleShape(sf::Vector2f(windowX,windowY/2.0f));
ceiling.setFillColor(ceilingColor); ceiling.setFillColor(ceilingColor);
window.draw(ground); window.draw(ground);
@ -229,16 +239,17 @@ void World::render(sf::RenderWindow& window) const
* Throw rays and draw walls over the ceiling and ground. * Throw rays and draw walls over the ceiling and ground.
* Only throws in the plane, which doesn't work for levels/3D. * Only throws in the plane, which doesn't work for levels/3D.
*/ */
for(int i = 0;i<window.getSize().x;i++) for(unsigned int i = 0 ; i < window.getSize().x ; i++)
{ {
float deltaAngle = (player.fov/window.getSize().x) * (i-window.getSize().x/2.0); float deltaAngle = (player.fov/windowX) * (static_cast<float>(i)-windowX/2.0f);
float rayAngle = player.orientation + deltaAngle; float rayAngle = player.orientation + deltaAngle;
if (rayAngle < 0) { if (rayAngle < 0) {
rayAngle += 360; rayAngle += 360;
} else if (rayAngle > 360) { } else if (rayAngle > 360) {
rayAngle -= 360; rayAngle -= 360;
} }
float obstacleScale = castRay(player.x, player.y, rayAngle)/player.sensorSize; float obstacleScale = player.focalLength*2/(castRay(player.x, player.y, rayAngle)*player.sensorSize);
/* 2 Is wall height in meters. */
fillColumn(window, i, obstacleScale); fillColumn(window, i, obstacleScale);
} }
} }
@ -247,7 +258,7 @@ void World::step(const float& stepTime) {
player.move(player.currentMoveSpeedX*stepTime, player.move(player.currentMoveSpeedX*stepTime,
player.currentMoveSpeedY*stepTime); player.currentMoveSpeedY*stepTime);
/* Undo last move if the player would end up in a wall. */ /* Undo last move if the player would end up in a wall. */
if (getBlock((int)player.x, (int)player.y) != BlockType::AIR) { if (getBlock(player.x, player.y) != BlockType::AIR) {
player.move(-player.currentMoveSpeedX*stepTime, player.move(-player.currentMoveSpeedX*stepTime,
-player.currentMoveSpeedY*stepTime); -player.currentMoveSpeedY*stepTime);
} }

11
World.h
View file

@ -30,8 +30,9 @@ public:
int getW() const; int getW() const;
int getH() const; int getH() const;
inline BlockType getBlock(float x, float y) const; inline BlockType getBlock(int x, int y) const;
void setBlock(BlockType block, int x, int y, int width = 1, int height = 1); inline BlockType getBlock(float x, float y) const;
void setBlock(BlockType block, int x, int y, int width = 1, int height = 1);
void render(sf::RenderWindow&) const; void render(sf::RenderWindow&) const;
@ -50,14 +51,14 @@ private:
sf::Color groundColor; sf::Color groundColor;
sf::Color ceilingColor; sf::Color ceilingColor;
void fillColumn(sf::RenderWindow&, int column, float scale, void fillColumn(sf::RenderWindow&, unsigned int column, float scale,
sf::Color wallColor = sf::Color(84,56,34)) const; sf::Color wallColor = sf::Color(84,56,34)) const;
/** /**
* Cast a ray from a given position and return the on-screen scale. * Cast a ray from a given position and its distance to the origin.
* @param originX Ray X origin, strictly positive * @param originX Ray X origin, strictly positive
* @param originY Ray Y origin, strictly positive * @param originY Ray Y origin, strictly positive
* @param orientation Angle to cast to, in degrees between 0 and 360 * @param orientation Angle to cast to, in degrees between 0 and 360
* @return Scale on the screen of the hit wall. * @return Distance of the hit to the origin.
*/ */
float castRay(float originX, float originY, float orientation) const; float castRay(float originX, float originY, float orientation) const;
}; };

View file

@ -14,8 +14,7 @@ int main()
std::cout << world << std::endl; std::cout << world << std::endl;
sf::RenderWindow window(sf::VideoMode(800,600),"Da raycasting"); sf::RenderWindow window(sf::VideoMode(800,600),"Da raycasting");
world.render(window); sf::RenderWindow window(sf::VideoMode(1000,1000),"Da raycasting");
window.display();
sf::Event event{}; sf::Event event{};
sf::Clock frameTime; sf::Clock frameTime;
@ -23,9 +22,19 @@ int main()
{ {
while (window.pollEvent(event)) while (window.pollEvent(event))
{ {
if (event.type == sf::Event::Closed) if (event.type == sf::Event::Closed) {
window.close(); window.close();
else if (event.type == sf::Event::KeyPressed) { continue;
}
if (event.type == sf::Event::Resized) {
// Keep the view area fit to the window.
sf::FloatRect newView(0, 0,
static_cast<float>(event.size.width),
static_cast<float>(event.size.height));
window.setView(sf::View(newView));
continue;
}
if (event.type == sf::Event::KeyPressed) {
switch (event.key.code) { switch (event.key.code) {
case sf::Keyboard::Key::Escape: case sf::Keyboard::Key::Escape:
window.close(); window.close();