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.
This commit is contained in:
parent
a67d25ee10
commit
cbf0955786
11 changed files with 93 additions and 65 deletions
|
@ -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 {
|
||||||
|
|
14
main.cpp
14
main.cpp
|
@ -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…
Add table
Add a link
Reference in a new issue