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 11 months 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);