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 {
int map_width=40;
int map_height=50;
int map_width=20;
int map_height=20;
};
class LevelManager {

@ -53,14 +53,16 @@ int main() {
TexturePack textures;
textures.load_tiles();
textures.load_sprites();
textures.position_sprite(4.0, 3.55, "evil_eye");
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);
rayview.set_position(RAY_VIEW_X, RAY_VIEW_Y);
rayview.position_camera(player.x, player.y);
rayview.init_shaders();
DinkyECS::Entity evil_ent = rayview.position_sprite(evil_eye_pos, "evil_eye");
double moveSpeed = 0.1;
double rotSpeed = 0.1;
@ -76,6 +78,9 @@ int main() {
window.setVerticalSyncEnabled(VSYNC);
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()) {
auto start = std::chrono::high_resolution_clock::now();
rayview.render();
@ -113,6 +118,13 @@ int main() {
}
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);
rotation = -30.0f;
} else {

@ -17,6 +17,7 @@ typedef std::vector<Point> PointList;
template<> struct std::hash<Point> {
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),
$window(window),
$map(map),
spriteOrder(NUM_SPRITES),
spriteDistance(NUM_SPRITES),
ZBuffer(width),
$anim(256, 256, 10, "assets/monster-1.ogg")
{
@ -77,22 +75,11 @@ void Raycaster::sprite_casting() {
const int halfHeight = TEXTURE_HEIGHT / 2;
// sort sprites from far to close
for(int i = 0; i < NUM_SPRITES; i++) {
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);
auto sprite_order = $collision.distance_sorted({(size_t)$posX, (size_t)$posY});
// after sorting the sprites, do the projection
for(int i = 0; i < NUM_SPRITES; i++) {
int sprite_index = spriteOrder[i];
Sprite& sprite_rec = $textures.get_sprite(sprite_index);
for(auto& rec : sprite_order) {
Sprite& sprite_rec = $sprites[rec.second];
// TODO: this must die
auto sf_sprite = sprite_rec.sprite.sprite;
@ -317,13 +304,15 @@ void Raycaster::draw_ceiling_floor() {
int cellX = int(floorX);
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 ty = int(textureWidth * (floorY - cellY)) & (textureHeight - 1);
floorX += floorStepX;
floorY += floorStepY;
double d = std::sqrt(($posX - floorX) * ($posX - floorX) + ($posY - floorY) * ($posY - floorY));
// now get the pixel from the texture
uint32_t color;
// this uses the previous ty/tx fractional parts of
@ -331,11 +320,11 @@ void Raycaster::draw_ceiling_floor() {
// FLOOR
color = floor_texture[textureWidth * ty + tx];
$pixels[pixcoord(x, y)] = color;
$pixels[pixcoord(x, y)] = dumb_lighting(color, d);
// CEILING
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) {
double speed_and_dir = speed * dir;
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);
$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 <SFML/System/Clock.hpp>
#include "animator.hpp"
#include "spatialmap.hpp"
using matrix::Matrix;
using RGBA = uint32_t;
@ -41,8 +42,8 @@ struct Raycaster {
int $height;
sf::RenderWindow& $window;
Matrix& $map;
std::vector<int> spriteOrder;
std::vector<double> spriteDistance;
SpatialMap $collision;
std::vector<Sprite> $sprites;
std::vector<double> ZBuffer; // width
Animator $anim;
sf::Shader $paused;
@ -66,6 +67,7 @@ struct Raycaster {
void set_position(int x, int y);
void init_shaders();
DinkyECS::Entity position_sprite(Point pos, string name);
inline size_t pixcoord(int x, int y) {
if(!(x >=0 && x < $width)) {

@ -64,3 +64,19 @@ FoundEntities SpatialMap::neighbors(Point cell, bool diag) const {
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;
// 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 {
bool found;
@ -18,6 +19,7 @@ struct FoundEntities {
class SpatialMap {
public:
SpatialMap() {}
PointEntityMap table;
void insert(Point pos, DinkyECS::Entity obj);
void move(Point from, Point to, DinkyECS::Entity ent);
@ -26,6 +28,6 @@ class SpatialMap {
DinkyECS::Entity get(Point at) const;
FoundEntities neighbors(Point position, bool diag=false) const;
private:
PointEntityMap table;
SortedEntities distance_sorted(Point from);
size_t size() { return table.size(); }
};

@ -44,13 +44,13 @@ TEST_CASE("basic matrix iterator", "[matrix:basic]") {
row_count += box.x == box.left;
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);
}
{
matrix::dump("1:1 POINT", walls, 1,1);
// matrix::dump("1:1 POINT", walls, 1,1);
// confirm boxes have the right number of rows
// when x goes to 0 on first next call
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]);
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();
}
matrix::dump(format("MAP {}x{} @ {},{}; BOX {}x{}; size: {}",
matrix::width(result), matrix::height(result),
target.x, target.y, box.right - box.left, box.bottom - box.top, size),
result, target.x, target.y);
// matrix::dump(format("MAP {}x{} @ {},{}; BOX {}x{}; size: {}",
// matrix::width(result), matrix::height(result),
// target.x, target.y, box.right - box.left, box.bottom - box.top, size),
// result, target.x, target.y);
}
TEST_CASE("thrash box iterators", "[matrix]") {

@ -3,6 +3,7 @@
#include <string>
#include "spatialmap.hpp"
#include "dinkyecs.hpp"
#include "rand.hpp"
using DinkyECS::Entity;
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"]);
}
void TexturePack::position_sprite(double x, double y, string name) {
sprites.emplace_back(x, y, sprite_textures[name]);
}
void TexturePack::load_tiles() {
Config assets("assets/tiles.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();
}
Sprite &TexturePack::get_sprite(size_t sprite_num) {
return sprites[sprite_num];
}
matrix::Matrix TexturePack::convert_char_to_texture(matrix::Matrix &tile_ids) {
auto result = matrix::make(matrix::width(tile_ids), matrix::height(tile_ids));

@ -21,7 +21,6 @@ struct Sprite {
struct TexturePack {
std::vector<sf::Image> surfaces;
std::vector<Sprite> sprites;
std::unordered_map<std::string, SpriteTexture> sprite_textures;
std::unordered_map<wchar_t, int> char_to_texture;
sf::Image floor;
@ -31,10 +30,7 @@ struct TexturePack {
void load_tiles();
void load_sprites();
sf::Image load_image(std::string filename);
Sprite& get_sprite(size_t sprite_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
matrix::Matrix convert_char_to_texture(matrix::Matrix &from);

Loading…
Cancel
Save