Raycaster now controls the sprite locations with SpatialMap rather than the old way. Quick hack job in main.cpp that shows how they can move too.

master
Zed A. Shaw 1 month ago
parent a67d25ee10
commit cbf0955786
  1. 4
      levelmanager.hpp
  2. 14
      main.cpp
  3. 3
      point.hpp
  4. 54
      raycaster.cpp
  5. 6
      raycaster.hpp
  6. 16
      spatialmap.cpp
  7. 8
      spatialmap.hpp
  8. 14
      tests/matrix.cpp
  9. 27
      tests/spatialmap.cpp
  10. 8
      texture.cpp
  11. 4
      texture.hpp

@ -18,8 +18,8 @@ struct GameLevel {
}; };
struct LevelScaling { struct LevelScaling {
int map_width=40; int map_width=20;
int map_height=50; int map_height=20;
}; };
class LevelManager { class LevelManager {

@ -53,14 +53,16 @@ int main() {
TexturePack textures; TexturePack textures;
textures.load_tiles(); textures.load_tiles();
textures.load_sprites(); textures.load_sprites();
textures.position_sprite(4.0, 3.55, "evil_eye");
auto map = generate_map(textures, cur_level, player); auto map = generate_map(textures, cur_level, player);
Point evil_eye_pos{player.x+1, player.y+1};
Raycaster rayview(window, textures, map, RAY_VIEW_WIDTH, RAY_VIEW_HEIGHT); Raycaster rayview(window, textures, map, RAY_VIEW_WIDTH, RAY_VIEW_HEIGHT);
rayview.set_position(RAY_VIEW_X, RAY_VIEW_Y); rayview.set_position(RAY_VIEW_X, RAY_VIEW_Y);
rayview.position_camera(player.x, player.y); rayview.position_camera(player.x, player.y);
rayview.init_shaders(); rayview.init_shaders();
DinkyECS::Entity evil_ent = rayview.position_sprite(evil_eye_pos, "evil_eye");
double moveSpeed = 0.1; double moveSpeed = 0.1;
double rotSpeed = 0.1; double rotSpeed = 0.1;
@ -76,6 +78,9 @@ int main() {
window.setVerticalSyncEnabled(VSYNC); window.setVerticalSyncEnabled(VSYNC);
window.setFramerateLimit(FRAME_LIMIT); window.setFramerateLimit(FRAME_LIMIT);
double new_x = evil_eye_pos.x+0.1;
double new_y = evil_eye_pos.y+0.1;
while(window.isOpen()) { while(window.isOpen()) {
auto start = std::chrono::high_resolution_clock::now(); auto start = std::chrono::high_resolution_clock::now();
rayview.render(); rayview.render();
@ -113,6 +118,13 @@ int main() {
} }
if(sf::Mouse::isButtonPressed(sf::Mouse::Button::Left)) { if(sf::Mouse::isButtonPressed(sf::Mouse::Button::Left)) {
new_x += 0.1;
new_y += 0.1;
rayview.$collision.move(evil_eye_pos, {size_t(new_x), size_t(new_y)}, evil_ent);
evil_eye_pos = {size_t(new_x), size_t(new_y)};
rayview.$sprites[evil_ent].x = new_x;
rayview.$sprites[evil_ent].y = new_y;
rayview.$anim.play(false); rayview.$anim.play(false);
rotation = -30.0f; rotation = -30.0f;
} else { } else {

@ -17,6 +17,7 @@ typedef std::vector<Point> PointList;
template<> struct std::hash<Point> { template<> struct std::hash<Point> {
size_t operator()(const Point& p) const { size_t operator()(const Point& p) const {
return std::hash<int>()(p.x) ^ std::hash<int>()(p.y); auto hasher = std::hash<int>();
return hasher(p.x) ^ hasher(p.y);
} }
}; };

@ -34,8 +34,6 @@ Raycaster::Raycaster(sf::RenderWindow& window, TexturePack &textures, Matrix &ma
$width(width), $height(height), $width(width), $height(height),
$window(window), $window(window),
$map(map), $map(map),
spriteOrder(NUM_SPRITES),
spriteDistance(NUM_SPRITES),
ZBuffer(width), ZBuffer(width),
$anim(256, 256, 10, "assets/monster-1.ogg") $anim(256, 256, 10, "assets/monster-1.ogg")
{ {
@ -77,22 +75,11 @@ void Raycaster::sprite_casting() {
const int halfHeight = TEXTURE_HEIGHT / 2; const int halfHeight = TEXTURE_HEIGHT / 2;
// sort sprites from far to close // sort sprites from far to close
for(int i = 0; i < NUM_SPRITES; i++) { auto sprite_order = $collision.distance_sorted({(size_t)$posX, (size_t)$posY});
auto& sprite = $textures.get_sprite(i);
spriteOrder[i] = i;
// this is just the distance calculation
spriteDistance[i] = (($posX - sprite.x) *
($posX - sprite.x) +
($posY - sprite.y) *
($posY - sprite.y));
}
sort_sprites(spriteOrder, spriteDistance, NUM_SPRITES);
// after sorting the sprites, do the projection // after sorting the sprites, do the projection
for(int i = 0; i < NUM_SPRITES; i++) { for(auto& rec : sprite_order) {
int sprite_index = spriteOrder[i]; Sprite& sprite_rec = $sprites[rec.second];
Sprite& sprite_rec = $textures.get_sprite(sprite_index);
// TODO: this must die // TODO: this must die
auto sf_sprite = sprite_rec.sprite.sprite; auto sf_sprite = sprite_rec.sprite.sprite;
@ -317,13 +304,15 @@ void Raycaster::draw_ceiling_floor() {
int cellX = int(floorX); int cellX = int(floorX);
int cellY = int(floorY); int cellY = int(floorY);
// get the texture coordinat from the fractional part // get the texture coordinate from the fractional part
int tx = int(textureWidth * (floorX - cellX)) & (textureWidth - 1); int tx = int(textureWidth * (floorX - cellX)) & (textureWidth - 1);
int ty = int(textureWidth * (floorY - cellY)) & (textureHeight - 1); int ty = int(textureWidth * (floorY - cellY)) & (textureHeight - 1);
floorX += floorStepX; floorX += floorStepX;
floorY += floorStepY; floorY += floorStepY;
double d = std::sqrt(($posX - floorX) * ($posX - floorX) + ($posY - floorY) * ($posY - floorY));
// now get the pixel from the texture // now get the pixel from the texture
uint32_t color; uint32_t color;
// this uses the previous ty/tx fractional parts of // this uses the previous ty/tx fractional parts of
@ -331,11 +320,11 @@ void Raycaster::draw_ceiling_floor() {
// FLOOR // FLOOR
color = floor_texture[textureWidth * ty + tx]; color = floor_texture[textureWidth * ty + tx];
$pixels[pixcoord(x, y)] = color; $pixels[pixcoord(x, y)] = dumb_lighting(color, d);
// CEILING // CEILING
color = ceiling_texture[textureWidth * ty + tx]; color = ceiling_texture[textureWidth * ty + tx];
$pixels[pixcoord(x, $height - y - 1)] = color; $pixels[pixcoord(x, $height - y - 1)] = dumb_lighting(color, d);
} }
} }
} }
@ -357,24 +346,6 @@ bool Raycaster::empty_space(int new_x, int new_y) {
} }
void Raycaster::sort_sprites(std::vector<int>& order, std::vector<double>& dist, int amount)
{
std::vector<std::pair<double, int>> sprites(amount);
for(int i = 0; i < amount; i++) {
sprites[i].first = dist[i];
sprites[i].second = order[i];
}
std::sort(sprites.begin(), sprites.end());
// restore in reverse order
for(int i = 0; i < amount; i++) {
dist[i] = sprites[amount - i - 1].first;
order[i] = sprites[amount - i - 1].second;
}
}
void Raycaster::run(double speed, int dir) { void Raycaster::run(double speed, int dir) {
double speed_and_dir = speed * dir; double speed_and_dir = speed * dir;
if(empty_space(int($posX + $dirX * speed_and_dir), int($posY))) { if(empty_space(int($posX + $dirX * speed_and_dir), int($posY))) {
@ -396,3 +367,12 @@ void Raycaster::rotate(double speed, int dir) {
$planeX = $planeX * cos(speed_and_dir) - $planeY * sin(speed_and_dir); $planeX = $planeX * cos(speed_and_dir) - $planeY * sin(speed_and_dir);
$planeY = oldPlaneX * sin(speed_and_dir) + $planeY * cos(speed_and_dir); $planeY = oldPlaneX * sin(speed_and_dir) + $planeY * cos(speed_and_dir);
} }
DinkyECS::Entity Raycaster::position_sprite(Point pos, string name) {
auto sprite_txt = $textures.sprite_textures[name];
$sprites.emplace_back(pos.x, pos.y, sprite_txt);
DinkyECS::Entity ent = $sprites.size() - 1;
$collision.insert({pos.x, pos.y}, ent);
return ent;
}

@ -13,6 +13,7 @@
#include "texture.hpp" #include "texture.hpp"
#include <SFML/System/Clock.hpp> #include <SFML/System/Clock.hpp>
#include "animator.hpp" #include "animator.hpp"
#include "spatialmap.hpp"
using matrix::Matrix; using matrix::Matrix;
using RGBA = uint32_t; using RGBA = uint32_t;
@ -41,8 +42,8 @@ struct Raycaster {
int $height; int $height;
sf::RenderWindow& $window; sf::RenderWindow& $window;
Matrix& $map; Matrix& $map;
std::vector<int> spriteOrder; SpatialMap $collision;
std::vector<double> spriteDistance; std::vector<Sprite> $sprites;
std::vector<double> ZBuffer; // width std::vector<double> ZBuffer; // width
Animator $anim; Animator $anim;
sf::Shader $paused; sf::Shader $paused;
@ -66,6 +67,7 @@ struct Raycaster {
void set_position(int x, int y); void set_position(int x, int y);
void init_shaders(); void init_shaders();
DinkyECS::Entity position_sprite(Point pos, string name);
inline size_t pixcoord(int x, int y) { inline size_t pixcoord(int x, int y) {
if(!(x >=0 && x < $width)) { if(!(x >=0 && x < $width)) {

@ -64,3 +64,19 @@ FoundEntities SpatialMap::neighbors(Point cell, bool diag) const {
return {!result.empty(), result}; return {!result.empty(), result};
} }
SortedEntities SpatialMap::distance_sorted(Point from) {
SortedEntities sprite_distance;
for(const auto &rec : table) {
Point sprite = rec.first;
int inside = (from.x - sprite.x) * (from.x - sprite.x) +
(from.y - sprite.y) * (from.y - sprite.y);
sprite_distance.push_back({inside, rec.second});
}
std::sort(sprite_distance.begin(), sprite_distance.end());
return sprite_distance;
}

@ -8,7 +8,8 @@
typedef std::vector<DinkyECS::Entity> EntityList; typedef std::vector<DinkyECS::Entity> EntityList;
// Point's has is in point.hpp // Point's has is in point.hpp
typedef std::unordered_map<Point, DinkyECS::Entity> PointEntityMap; using PointEntityMap = std::unordered_map<Point, DinkyECS::Entity>;
using SortedEntities = std::vector<std::pair<int, DinkyECS::Entity>>;
struct FoundEntities { struct FoundEntities {
bool found; bool found;
@ -18,6 +19,7 @@ struct FoundEntities {
class SpatialMap { class SpatialMap {
public: public:
SpatialMap() {} SpatialMap() {}
PointEntityMap table;
void insert(Point pos, DinkyECS::Entity obj); void insert(Point pos, DinkyECS::Entity obj);
void move(Point from, Point to, DinkyECS::Entity ent); void move(Point from, Point to, DinkyECS::Entity ent);
@ -26,6 +28,6 @@ class SpatialMap {
DinkyECS::Entity get(Point at) const; DinkyECS::Entity get(Point at) const;
FoundEntities neighbors(Point position, bool diag=false) const; FoundEntities neighbors(Point position, bool diag=false) const;
private: SortedEntities distance_sorted(Point from);
PointEntityMap table; size_t size() { return table.size(); }
}; };

@ -44,13 +44,13 @@ TEST_CASE("basic matrix iterator", "[matrix:basic]") {
row_count += box.x == box.left; row_count += box.x == box.left;
walls[box.y][box.x] = 3; walls[box.y][box.x] = 3;
} }
matrix::dump("2,2 WALLS", walls, 2, 2); //matrix::dump("2,2 WALLS", walls, 2, 2);
REQUIRE(row_count == 3); REQUIRE(row_count == 3);
} }
{ {
matrix::dump("1:1 POINT", walls, 1,1); // matrix::dump("1:1 POINT", walls, 1,1);
// confirm boxes have the right number of rows // confirm boxes have the right number of rows
// when x goes to 0 on first next call // when x goes to 0 on first next call
row_count = 0; row_count = 0;
@ -68,7 +68,7 @@ TEST_CASE("basic matrix iterator", "[matrix:basic]") {
println("START IS {},{}=={}", star.x, star.y, walls[star.y][star.x]); println("START IS {},{}=={}", star.x, star.y, walls[star.y][star.x]);
walls[star.y][star.x] = 11; walls[star.y][star.x] = 11;
} }
matrix::dump("STAR POINT", walls, 1,1); // matrix::dump("STAR POINT", walls, 1,1);
} }
} }
@ -115,10 +115,10 @@ TEST_CASE("thrash box distance iterators", "[matrix:distance]") {
result[box.y][box.x] = box.distance(); result[box.y][box.x] = box.distance();
} }
matrix::dump(format("MAP {}x{} @ {},{}; BOX {}x{}; size: {}", // matrix::dump(format("MAP {}x{} @ {},{}; BOX {}x{}; size: {}",
matrix::width(result), matrix::height(result), // matrix::width(result), matrix::height(result),
target.x, target.y, box.right - box.left, box.bottom - box.top, size), // target.x, target.y, box.right - box.left, box.bottom - box.top, size),
result, target.x, target.y); // result, target.x, target.y);
} }
TEST_CASE("thrash box iterators", "[matrix]") { TEST_CASE("thrash box iterators", "[matrix]") {

@ -3,6 +3,7 @@
#include <string> #include <string>
#include "spatialmap.hpp" #include "spatialmap.hpp"
#include "dinkyecs.hpp" #include "dinkyecs.hpp"
#include "rand.hpp"
using DinkyECS::Entity; using DinkyECS::Entity;
using namespace fmt; using namespace fmt;
@ -135,3 +136,29 @@ TEST_CASE("check all diagonal works", "[collision]") {
} }
} }
} }
TEST_CASE("confirm can iterate through all", "[spatialmap-sort]") {
DinkyECS::World world;
SpatialMap collider;
Point player{10,10};
for(int i = 0; i < 10; i++) {
size_t max = Random::uniform<size_t>(2,30);
for(size_t i = 0; i < max; i++) {
size_t x = Random::uniform<size_t>(0, 213);
size_t y = Random::uniform<size_t>(0, 251);
Entity ent = world.entity();
collider.insert({x,y}, ent);
}
auto sprite_distance = collider.distance_sorted(player);
int prev_dist = 0;
for(auto dist : sprite_distance) {
REQUIRE(prev_dist <= dist.first);
prev_dist = dist.first;
}
}
}

@ -34,10 +34,6 @@ void TexturePack::load_sprites() {
ceiling = load_image(assets["sprites"]["ceiling"]); ceiling = load_image(assets["sprites"]["ceiling"]);
} }
void TexturePack::position_sprite(double x, double y, string name) {
sprites.emplace_back(x, y, sprite_textures[name]);
}
void TexturePack::load_tiles() { void TexturePack::load_tiles() {
Config assets("assets/tiles.json"); Config assets("assets/tiles.json");
auto &tiles = assets.json(); auto &tiles = assets.json();
@ -58,10 +54,6 @@ const uint32_t* TexturePack::get_surface(size_t num) {
return (const uint32_t *)surfaces[num].getPixelsPtr(); return (const uint32_t *)surfaces[num].getPixelsPtr();
} }
Sprite &TexturePack::get_sprite(size_t sprite_num) {
return sprites[sprite_num];
}
matrix::Matrix TexturePack::convert_char_to_texture(matrix::Matrix &tile_ids) { matrix::Matrix TexturePack::convert_char_to_texture(matrix::Matrix &tile_ids) {
auto result = matrix::make(matrix::width(tile_ids), matrix::height(tile_ids)); auto result = matrix::make(matrix::width(tile_ids), matrix::height(tile_ids));

@ -21,7 +21,6 @@ struct Sprite {
struct TexturePack { struct TexturePack {
std::vector<sf::Image> surfaces; std::vector<sf::Image> surfaces;
std::vector<Sprite> sprites;
std::unordered_map<std::string, SpriteTexture> sprite_textures; std::unordered_map<std::string, SpriteTexture> sprite_textures;
std::unordered_map<wchar_t, int> char_to_texture; std::unordered_map<wchar_t, int> char_to_texture;
sf::Image floor; sf::Image floor;
@ -31,10 +30,7 @@ struct TexturePack {
void load_tiles(); void load_tiles();
void load_sprites(); void load_sprites();
sf::Image load_image(std::string filename); sf::Image load_image(std::string filename);
Sprite& get_sprite(size_t sprite_num);
const uint32_t* get_surface(size_t num); const uint32_t* get_surface(size_t num);
// this needs to go into a map place
void position_sprite(double x, double y, std::string name);
// ZED: this is ugly so maybe you should like rewrite it or something // ZED: this is ugly so maybe you should like rewrite it or something
matrix::Matrix convert_char_to_texture(matrix::Matrix &from); matrix::Matrix convert_char_to_texture(matrix::Matrix &from);

Loading…
Cancel
Save