135 lines
No EOL
4.4 KiB
C++
135 lines
No EOL
4.4 KiB
C++
#ifndef _H_RAYCASTER_H
|
|
#define _H_RAYCASTER_H
|
|
|
|
#include <glm/glm.hpp>
|
|
#include <vector>
|
|
#include <memory>
|
|
|
|
#include "utility/debugdraw.h"
|
|
|
|
class Raycaster {
|
|
public:
|
|
Raycaster(
|
|
float FOV,
|
|
float viewDist,
|
|
const std::vector<std::vector<int>>& collisionMap,
|
|
float tileSize)
|
|
:
|
|
FOV(FOV),
|
|
viewDist(viewDist),
|
|
collisionMap(collisionMap),
|
|
tileSize(tileSize)
|
|
{}
|
|
bool bresenhamRaycast(const glm::vec3& origin, const float rotation, const glm::vec3& target)
|
|
{
|
|
float rayAngle = rotation - (FOV / 2);
|
|
float angleIncrement = 2.0f;
|
|
bool hitTarget = false;
|
|
glm::ivec2 lastEnd = glm::ivec2(0);
|
|
for (int rayCount = 0; rayCount <= FOV / 2; rayCount++)
|
|
{
|
|
float endX = (origin.x + (glm::cos(glm::radians(rayAngle)) * viewDist));
|
|
float endY = (origin.y + (glm::sin(glm::radians(rayAngle)) * viewDist));
|
|
|
|
glm::ivec2 targetTile= glm::ivec2(static_cast<int>(target.x / tileSize), static_cast<int>(target.y / tileSize));
|
|
glm::ivec2 startTile = glm::ivec2(static_cast<int>((origin.x + tileSize * 0.1f) / tileSize), static_cast<int>((origin.y + tileSize * 0.1f) / tileSize));
|
|
glm::ivec2 endTile = glm::ivec2(static_cast<int>(endX / tileSize), static_cast<int>(endY / tileSize));
|
|
|
|
int dx = glm::abs(endTile.x - startTile.x);
|
|
int dy = glm::abs(endTile.y - startTile.y);
|
|
int sx = startTile.x < endTile.x ? 1 : -1;
|
|
int sy = startTile.y < endTile.y ? 1 : -1;
|
|
|
|
int err = (dx > dy ? dx : -dy) / 2;
|
|
|
|
glm::ivec2 step = startTile;
|
|
|
|
while (step != endTile)
|
|
{
|
|
if (step.x < 0 || step.x >= collisionMap[0].size() ||
|
|
step.y < 0 || step.y >= collisionMap.size())
|
|
{
|
|
if (glm::abs(rayAngle - rotation) <= 2)
|
|
distFromWall = distFromWall < glm::distance(glm::vec2(startTile), glm::vec2(step)) ?
|
|
distFromWall : glm::distance(glm::vec2(startTile), glm::vec2(step));
|
|
break;
|
|
}
|
|
if (collisionMap[step.y][step.x] != 0)
|
|
{
|
|
if (glm::abs(rayAngle - rotation) <= 2)
|
|
distFromWall = distFromWall < glm::distance(glm::vec2(startTile), glm::vec2(step)) ?
|
|
distFromWall : glm::distance(glm::vec2(startTile), glm::vec2(step));
|
|
break;
|
|
}
|
|
if (step == targetTile)
|
|
hitTarget = true;
|
|
int e2 = err;
|
|
if (e2 > -dx)
|
|
{
|
|
err -= dy;
|
|
step.x += sx;
|
|
}
|
|
if (e2 < dy)
|
|
{
|
|
err += dx;
|
|
step.y += sy;
|
|
}
|
|
}
|
|
//LineDrawer::getInstance().addLine(origin, glm::vec3(step.x * tileSize, step.y * tileSize, 0.f), glm::vec4(1.0 - (1.0f / rayCount), 1.0f / rayCount, 0.0f, 0.7f));
|
|
if (step == endTile)
|
|
distFromWall = std::numeric_limits<float>::infinity();
|
|
rayAngle += angleIncrement;
|
|
}
|
|
return hitTarget;
|
|
}
|
|
// We need to collision map and tile size so we can hide behind tiles
|
|
// returns true if the raycast lands on the targets tile
|
|
bool performRaycast(const glm::vec3& origin, const float rotation, const glm::vec3& target) {
|
|
float rayStepSize = 0.05f;
|
|
float rayAngle = rotation - (FOV / 2);
|
|
float angleInc = 2.0f;
|
|
glm::ivec2 targetTile = glm::ivec2(static_cast<int>(target.x / tileSize), static_cast<int>(target.y / tileSize));
|
|
bool hitTarget = false;
|
|
for (int rayCount = 0; rayCount <= FOV / 2; rayCount++)
|
|
{
|
|
glm::vec2 ray = glm::vec2(origin);
|
|
while (glm::distance(ray, glm::vec2(origin)) < viewDist)
|
|
{
|
|
ray.x += cos(glm::radians(rayAngle)) * rayStepSize;
|
|
ray.y += sin(glm::radians(rayAngle)) * rayStepSize;
|
|
glm::ivec2 rayTile = glm::ivec2(static_cast<int>(ray.x / tileSize), static_cast<int>(ray.y / tileSize));
|
|
if (rayTile.x < 0 || rayTile.x >= collisionMap[0].size() ||
|
|
rayTile.y < 0 || rayTile.y >= collisionMap.size())
|
|
{
|
|
if (rayCount == FOV / 2)
|
|
distFromWall = glm::distance(glm::vec2(origin), ray);
|
|
break;
|
|
}
|
|
if (collisionMap[rayTile.y][rayTile.x] != 0)
|
|
{
|
|
if (rayCount == FOV / 2)
|
|
distFromWall = glm::distance(glm::vec2(origin), ray);
|
|
break;
|
|
}
|
|
if (rayTile == targetTile)
|
|
hitTarget = true;
|
|
}
|
|
DebugDrawer::getInstance().addLine(origin, glm::vec3(ray.x, ray.y, 0.f), glm::vec4(1.0f, 0.0f, 0.0f, 0.2f));
|
|
if (glm::distance(ray, glm::vec2(origin)) >= viewDist)
|
|
distFromWall = std::numeric_limits<float>::infinity();
|
|
rayAngle += angleInc;
|
|
}
|
|
return hitTarget;
|
|
}
|
|
float getDistanceFromWall() const { return distFromWall; }
|
|
float getTileSize() const { return tileSize; }
|
|
private:
|
|
float FOV;
|
|
float viewDist;
|
|
float distFromWall = std::numeric_limits<float>::infinity();
|
|
std::vector<std::vector<int>> collisionMap;
|
|
float tileSize;
|
|
|
|
};
|
|
|
|
#endif // _H_RAYCASTER_H
|