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 {
|
||||
int map_width=40;
|
||||
int map_height=50;
|
||||
int map_width=20;
|
||||
int map_height=20;
|
||||
};
|
||||
|
||||
class LevelManager {
|
||||
|
|
14
main.cpp
14
main.cpp
|
@ -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…
Add table
Add a link
Reference in a new issue