Add Rng class, lots of progress on mapgen

This commit is contained in:
Adrian Hedqvist 2017-12-30 00:08:09 +01:00
parent 469dccfd48
commit a83a60de0c
13 changed files with 333 additions and 135 deletions

View file

@ -11,7 +11,7 @@ execute_process(
file(WRITE "src/gitparams.h" "#define GIT_CUR_COMMIT ${GIT_COMMIT}")
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -static-libgcc -static-libstdc++")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
set(TARGET dungeon)
project(${TARGET} LANGUAGES CXX)
@ -25,6 +25,6 @@ include_directories("libs/kaguya-1.3.2/include")
file(GLOB SOURCES "src/*.cpp" "src/*.c" "src/*.h")
add_executable(${TARGET} ${SOURCES})
target_link_libraries(${TARGET} PUBLIC glbinding::glbinding)
target_link_libraries(${TARGET} PUBLIC SDL2)
target_link_libraries(${TARGET} PUBLIC OpenGL)
target_link_libraries(${TARGET} PUBLIC lua)
target_link_libraries(${TARGET} PUBLIC ${SDL2_LIBRARY})
target_link_libraries(${TARGET} PUBLIC ${OPENGL_LIBRARY})
target_link_libraries(${TARGET} PUBLIC ${LUA_LIBRARY})

View file

@ -81,7 +81,7 @@
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<AdditionalDependencies>opengl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@ -98,7 +98,7 @@
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>opengl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
@ -137,6 +137,7 @@
<ClCompile Include="src\RangedAttackNode.cpp" />
<ClCompile Include="src\Renderer.cpp" />
<ClCompile Include="src\RestNode.cpp" />
<ClCompile Include="src\Rng.cpp" />
<ClCompile Include="src\Shaman.cpp" />
<ClCompile Include="src\Tilemap.cpp" />
<ClCompile Include="src\Tileset.cpp" />
@ -212,6 +213,7 @@
<ClInclude Include="src\RangedAttackNode.h" />
<ClInclude Include="src\Renderer.h" />
<ClInclude Include="src\RestNode.h" />
<ClInclude Include="src\Rng.h" />
<ClInclude Include="src\Shaman.h" />
<ClInclude Include="src\Stats.h" />
<ClInclude Include="src\stb_rect_pack.h" />

View file

@ -135,6 +135,9 @@
<ClCompile Include="src\World.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Rng.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="libs\kaguya-1.3.2\include\kaguya\another_binding_api.hpp">
@ -374,5 +377,8 @@
<ClInclude Include="src\World.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\Rng.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View file

@ -22,7 +22,7 @@ bool Entity::move(vec2i dpos) {
bool Entity::move(int dx, int dy) {
vec2i newpos = position + vec2i(dx, dy);
if (!collision || !map->IsBlocked(newpos.x, newpos.y)) {
if (!collision || !map->is_blocked(newpos.x, newpos.y)) {
position = newpos;
return true;
}

View file

@ -12,7 +12,7 @@ FieldOfView::FieldOfView() {
FieldOfView::FieldOfView(Tilemap *map) {
this->map = map;
seen = Tilemap(map->GetWidth(), map->GetHeight());
seen = Tilemap(map->get_width(), map->get_height());
counter = 0;
}
@ -58,7 +58,7 @@ void FieldOfView::cast_light(int row, float start, float end, int xx, int xy, in
float leftSlope = (deltaX - 0.5f) / (deltaY + 0.5f);
float rightSlope = (deltaX + 0.5f) / (deltaY - 0.5f);
if (!(currentX >= 0 && currentY >= 0 && currentX < map->GetWidth() && currentY < map->GetHeight()) || start < rightSlope) {
if (!(currentX >= 0 && currentY >= 0 && currentX < map->get_width() && currentY < map->get_height()) || start < rightSlope) {
continue;
}
else if (end > leftSlope) {

View file

@ -1,18 +1,224 @@
#include "Mapgen.h"
#include "Mapgen.h"
#include "vec2i.h"
#include <vector>
#include <queue>
#include <random>
#include "Rng.h"
#include <chrono>
struct Room {
vec2i pos;
vec2i size;
};
const char walltile = '#';
const char floortile = '.';
const char doortile = '+';
bool aabb(Room &a, Room &b) {
return a.pos.x <= b.pos.x + b.size.x && a.pos.x + a.size.x >= b.pos.x &&
a.pos.y <= b.pos.y + b.size.y && a.pos.y + a.size.y >= b.pos.y;
}
void maze_fill(Tilemap& map, int x, int y, Rng &rng) {
if (map.get_tile(x, y) != walltile) return;
const std::vector<vec2i> dirs { vec2i(0,1), vec2i(1,0), vec2i(0,-1), vec2i(-1,0) };
std::vector<vec2i> stack { vec2i(x,y) };
while (!stack.empty()) {
vec2i pos = stack.back();
map.set_tile(pos.x, pos.y, floortile);
std::vector<vec2i> options;
for (vec2i dir : dirs) {
vec2i next = { pos.x + dir.x, pos.y + dir.y };
if (map.get_tile(next.x, next.y) != walltile) continue;
if (next.x == 0 || next.x == map.get_width() - 1 || next.y == 0 || next.y == map.get_height() - 1) continue;
int up = dir.y <= 0 ? 1 : 0;
int down = dir.y >= 0 ? 1 : 0;
int left = dir.x <= 0 ? 1 : 0;
int right = dir.x >= 0 ? 1 : 0;
std::vector<vec2i> neigh = map.get_neighbours(next.x, next.y, up, down, left, right);
bool enclosed = true;
for (vec2i n : neigh) {
if (map.get_tile(n.x, n.y) != walltile) {
enclosed = false;
break;
}
}
if (enclosed) {
options.emplace_back(next.x, next.y);
}
}
if (!options.empty()) {
stack.emplace_back(options.at(rng.get_int(options.size() - 1)));
}
else {
stack.pop_back();
}
}
}
Tilemap generate_level(int seed, int width, int height) {
Tilemap generate_dungeon(int width, int height) {
return generate_dungeon(std::random_device()(), width, height);
}
Tilemap generate_dungeon(unsigned int seed, int width, int height) {
Tilemap map = Tilemap(width, height);
// Set the whole map to walls
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
if (x == 0 || x == width-1 || y == 0 || y == height-1) {
map.set_tile(x,y, '#');
}
else {
map.set_tile(x,y, '.');
}
map.set_tile(x, y, walltile);
}
}
Rng rng = Rng(seed);
// Room placement
std::vector<Room> rooms;
for (int i = 0; i < sqrt(width*height) * 6; i++) {
Room room;
room.size = vec2i(rng.get_int(6, 12), rng.get_int(6, 12));
room.pos = vec2i(rng.get_int(width - room.size.x), rng.get_int(height - room.size.y));
// Check if the room overlaps with some other room
bool coll = false;
for (Room r : rooms) {
if (aabb(room, r)) {
coll = true;
break;
}
}
if (!coll) {
rooms.emplace_back(room);
}
}
// Fill the rooms with floor tiles
for (Room r : rooms) {
for (int x = r.pos.x+1; x < r.pos.x + r.size.x-1; x++) {
for (int y = r.pos.y+1; y < r.pos.y + r.size.y-1; y++) {
map.set_tile(x, y, floortile);
}
}
}
// Maze generation
std::vector<vec2i> maze_start_points;
for (int x = 0; x < map.get_width(); x++) {
for (int y = 0; y < map.get_height(); y++) {
std::vector<vec2i> neigh = map.get_neighbours(x, y, 1);
int count = 0;
for (vec2i n : neigh) {
if (map.get_tile(n.x, n.y) == walltile) count++;
}
// If this tile is a wall and is completely surrounded by other walls, start generating a maze here.
if (count >= 8) {
maze_fill(map, x, y, rng);
maze_start_points.emplace_back(vec2i(x, y));
}
}
}
// Door placement
for (Room r : rooms) {
std::vector<vec2i> potential_doors;
for (int y = 0; y < r.size.y; y++) {
for (int x = 0; x < r.size.x; x++) {
// if we are at the rooms walls, but not the corners
if ((x == 0 || x == r.size.x-1) != (y == 0 || y == r.size.y - 1)) {
int dx = 0;
if (x == 0) {
dx = -1;
}
else if (x == r.size.x) {
dx = 1;
}
int dy = 0;
if (y == 0) {
dy = -1;
}
else if (y == r.size.y) {
dy = 1;
}
// If there is a floor tile on the other side of this room wall
if (map.get_tile(r.pos.x+x+dx, r.pos.y+y+dy) == floortile) {
potential_doors.emplace_back(r.pos.x + x, r.pos.y + y);
}
}
}
}
/* Debug thing, place doors at all potential spots
for (vec2i pos : potential_doors) {
map.set_tile(pos.x, pos.y, doortile);
}
/*/
if (potential_doors.empty()) continue;
// Pick up to 3 spots and place doorss
int doors_amount = potential_doors.size() < 3 ? potential_doors.size() : 3;
doors_amount = rng.get_int(1, doors_amount);
for (int i = 0; i < doors_amount; i++) {
int r = rng.get_int(potential_doors.size()-1);
vec2i pos = potential_doors.at(r);
map.set_tile(pos.x, pos.y, doortile);
potential_doors.erase(r + potential_doors.begin());
}
//*/
}
// Clean up dead ends in the maze
std::vector<vec2i> dead_ends;
for (int y = 0; y < map.get_height(); y++) {
for (int x = 0; x < map.get_width(); x++) {
std::vector<vec2i> neigh{vec2i(x + 1, y), vec2i(x, y + 1), vec2i(x - 1, y), vec2i(x, y - 1) };
int count = 0;
for (vec2i pos : neigh) {
if (map.get_tile(pos.x, pos.y) == walltile) {
count++;
}
}
if (count >= neigh.size() - 1) {
dead_ends.emplace_back(vec2i(x, y));
}
}
}
int pass_amount = sqrt(width*height)*2;
for (int pass = 0; pass < pass_amount; pass++) {
if (dead_ends.empty()) break;
std::vector<vec2i> new_dead_ends;
for (vec2i pos : dead_ends) {
map.set_tile(pos.x, pos.y, walltile);
std::vector<vec2i> neigh { vec2i(pos.x + 1, pos.y), vec2i(pos.x, pos.y + 1), vec2i(pos.x - 1, pos.y), vec2i(pos.x, pos.y - 1) };
for (int i = neigh.size() - 1; i >= 0; i--) {
vec2i p = neigh[i];
if (map.get_tile(p.x, p.y) == walltile) {
neigh.erase(neigh.begin() + i);
}
}
if (neigh.size() == 1) {
std::vector<vec2i> neigh2{ vec2i(pos.x + 1, pos.y), vec2i(pos.x, pos.y + 1), vec2i(pos.x - 1, pos.y), vec2i(pos.x, pos.y - 1) };
int count = 0;
for (vec2i pos : neigh2) {
if (map.get_tile(pos.x, pos.y) == walltile) {
count++;
}
}
if (count >= neigh2.size() - 1) {
new_dead_ends.emplace_back(vec2i(pos.x, pos.y));
}
}
}
dead_ends = new_dead_ends;
}
return map;
}

View file

@ -1,4 +1,5 @@
#pragma once
#include "Tilemap.h"
Tilemap generate_level(int seed, int width, int height);
Tilemap generate_dungeon(int width, int height);
Tilemap generate_dungeon(unsigned int seed, int width, int height);

View file

@ -144,12 +144,12 @@ namespace Pathfinder
if (out->tilemap != nullptr) {
delete out->tilemap;
}
out->tilemap = new float[map->GetWidth() * map->GetHeight()];
for (int i = 0; i < map->GetWidth() * map->GetHeight(); i++) {
out->tilemap = new float[map->get_width() * map->get_height()];
for (int i = 0; i < map->get_width() * map->get_height(); i++) {
out->tilemap[i] = maxValue;
}
out->height = map->GetHeight();
out->width = map->GetWidth();
out->height = map->get_height();
out->width = map->get_width();
for (vec2i pos : *goals) {
out->setValue(pos.x, pos.y, 0);
}
@ -192,4 +192,4 @@ namespace Pathfinder
}
return;
}
}
}

View file

@ -14,6 +14,7 @@
#include "Hero.h"
#include "Goblin.h"
#include "Shaman.h"
#include "Rng.h"
const int mapwidth = 32;
@ -69,80 +70,16 @@ void PlayState::new_game() {
hero = nullptr;
}
std::string map =
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
"# @ . . . # # # # # # # # . . . . . . . . . . . . . . . . . # #"
"# . . . . . . . . # # # # . # # . # # # # # # . # # # # # . # #"
"# . . . . # # # . . . . . . # . g . # # # # # . # # # . . g . #"
"# . . . . # # # # # # # # . # . . . # # . . . . . . . . . . . #"
"# # # . # # # # # # # # # . . . . g # # . # # # . # # . . g . #"
"# . . . . . . . . . . . . . # # # # # . . . # # . # # # # # # #"
"# . # # # # # # # # . # # . # # # # # . g . # # . # . . g . . #"
"# . . . . g # # . . . # . . . # # # # . . . # # . # . . . . . #"
"# . . g . . # # . # # # . s . . . # # # # # # # . . . . s . . #"
"# . . . . . # # . . . # . . . # . . . . . . . . . # . g . . . #"
"# # . # # # # # . # . # # # # # # # # # . # # # # # # # # . # #"
"# . . . . . . . . # . . . . . . . . . . . . . . . . . . . . . #"
"# . # # # # # # # # # # . # . # # # # # # # # # # . # # # # . #"
"# . . . . . . . . . . . . # . # . . . . # . . . . . # # # . . #"
"# # # # # # . # # # . # # # . # . . . . # . . . # . # # # . # #"
"# . . . . # . # . . . . . # . . . . . . . . . . # . # # . . . #"
"# . . . . # . # . . . . . # . # . . . . # # # # # . . . . . . #"
"# . . . . . . # . . . . . # . # # # # # # . . . . . # # . . . #"
"# . . . . # . # # # # # # # . . . . . . . . # # # # # # # # # #"
"# . . . . # . . . . . . . . . # # # # # # # # # # # # # # # # #"
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #";
SDL_LogVerbose(SDL_LOG_CATEGORY_SYSTEM, "Creating tilemap...\n");
/*
tilemap = new Tilemap(32, 32);
int y = 0;
int x = 0;
for (char i : map) {
if (y >= 32) {
break;
}
if (x >= mapwidth) {
y++;
x = 0;
}
if (i == ' ' || i == '\t' || i == '\n') {
continue;
}
if (i == '@') {
hero = new Hero(tilemap, vec2i(x, y));
tilemap.add_entity(hero);
tilemap.set_tile(x, y, '.');
}
else if (i == 'g') {
tilemap.add_entity(new Goblin(tilemap, vec2i(x, y)));
tilemap.set_tile(x, y, '.');
}
else if (i == 's') {
tilemap.add_entity(new Shaman(tilemap, vec2i(x, y)));
tilemap.set_tile(x, y, '.');
}
else {
tilemap.set_tile(x, y, i);
}
x++;
}
*/
tilemap = generate_level(1, 32, 32);
hero = new Hero(&tilemap, vec2i(4,4));
Rng rng;
tilemap = generate_dungeon(64, 64);
vec2i heropos;
do {
heropos.x = rng.get_int(1, tilemap.get_width() - 1);
heropos.y = rng.get_int(1, tilemap.get_width() - 1);
} while (tilemap.get_tile(heropos.x, heropos.y) == '#');
hero = new Hero(&tilemap, vec2i(heropos.x,heropos.y));
tilemap.add_entity(hero);
SDL_LogVerbose(SDL_LOG_CATEGORY_SYSTEM, "Done.\n");
SDL_LogVerbose(SDL_LOG_CATEGORY_SYSTEM, "Calculating initial FOV...\n");
@ -217,6 +154,7 @@ Gamestate *PlayState::update(double delta) {
bool debug_actors = false;
bool debug_settings = false;
bool debug_disable_fov = true;
void PlayState::draw(double delta) {
if (debug) {
@ -241,6 +179,8 @@ void PlayState::draw(double delta) {
ImGui::Checkbox("VSync", &vsync);
app->renderer->set_vsync_enabled(vsync);
ImGui::Checkbox("Disable FoV", &debug_disable_fov);
ImGui::End();
}
if (debug_actors) {
@ -287,7 +227,7 @@ void PlayState::draw(double delta) {
(tilesize.x/2-heropos.x),
(tilesize.y/2-heropos.y),
};
tilemap.draw(app->renderer, ascii, margin.x, margin.y, -offset.x, -offset.y, tilesize.x, tilesize.y, &fov);
tilemap.draw(app->renderer, ascii, margin.x, margin.y, -offset.x, -offset.y, tilesize.x, tilesize.y, debug_disable_fov ? nullptr : &fov);
auto entities = tilemap.get_entity_list();
@ -296,7 +236,7 @@ void PlayState::draw(double delta) {
if (var->entity_type() == ENTITY_ACTOR && ((Actor*)var)->is_alive()) continue;
vec2i pos = var->get_position();
if (fov.can_see(pos)) {
if (debug_disable_fov || fov.can_see(pos)) {
app->renderer->set_color(0, 0, 0, 1);
app->renderer->draw_sprite(ascii->get_sprite(219), margin.x + (offset.x + pos.x) * asciisize.x, margin.y + (offset.y + pos.y) * asciisize.y);
@ -314,7 +254,7 @@ void PlayState::draw(double delta) {
if (var->entity_type() == ENTITY_ACTOR && !((Actor*)var)->is_alive()) continue;
vec2i pos = var->get_position();
if (fov.can_see(pos)) {
if (debug_disable_fov || fov.can_see(pos)) {
app->renderer->set_color(0, 0, 0, 1);
app->renderer->draw_sprite(ascii->get_sprite(219), margin.x + (offset.x + pos.x) * asciisize.x, margin.y + (offset.y + pos.y) * asciisize.y);

29
src/Rng.cpp Normal file
View file

@ -0,0 +1,29 @@
#include "Rng.h"
#include <random>
#include <chrono>
Rng::Rng() {
std::random_device rd;
Rng(rd(), 0);
}
Rng::Rng(unsigned int seed, unsigned int step) {
this->seed = seed;
this->step = step;
mte = std::mt19937(seed);
for (unsigned int i = 0; i < step; i++) {
get_int(100);
}
}
Rng::~Rng() {}
int Rng::get_int(int max) {
return get_int(0, max);
}
int Rng::get_int(int min, int max) {
step++;
return std::uniform_int_distribution<int>{min, max}(mte);
}

17
src/Rng.h Normal file
View file

@ -0,0 +1,17 @@
#pragma once
#include <random>
class Rng {
unsigned int seed = 0;
unsigned int step = 0;
std::mt19937 mte;
public:
Rng();
Rng(unsigned int seed, unsigned int step = 0);
~Rng();
int get_int(int max);
int get_int(int min, int max);
};

View file

@ -6,7 +6,7 @@
#include "FieldOfView.h"
#include <SDL2/SDL.h>
int Tilemap::GetIndex(int x, int y)
int Tilemap::get_index(int x, int y)
{
return y * width + x;
}
@ -25,36 +25,32 @@ Tilemap::~Tilemap()
}
}
int Tilemap::GetWidth()
int Tilemap::get_width()
{
return width;
}
int Tilemap::GetHeight()
int Tilemap::get_height()
{
return height;
}
bool Tilemap::IsInsideBounds(int x, int y)
bool Tilemap::is_inside_bounds(int x, int y)
{
return x >= 0 && x < width && y >= 0 && y < height;
}
std::vector<vec2i> Tilemap::get_neighbours(int x, int y, int range)
{
return get_neighbours(x,y,range,range,range,range);
}
std::vector<vec2i> Tilemap::get_neighbours(int x, int y, int up, int down, int left, int right) {
std::vector<vec2i> neigh;
if (range == 0)
{
neigh.emplace_back(x,y);
return neigh;
}
for (int dx = -range; dx <= range; dx++)
{
for (int dy = -range; dy <= range; dy++)
{
if ((dx != 0 || dy != 0) && IsInsideBounds(x + dx, y + dy))
{
neigh.emplace_back(x+dx,y+dy);
for (int dx = -left; dx <= right; dx++) {
for (int dy = -up; dy <= down; dy++) {
if ((dx != 0 || dy != 0) && is_inside_bounds(x + dx, y + dy)) {
neigh.emplace_back(x + dx, y + dy);
}
}
}
@ -63,26 +59,26 @@ std::vector<vec2i> Tilemap::get_neighbours(int x, int y, int range)
void Tilemap::set_tile(int x, int y, unsigned int tile)
{
if (IsInsideBounds(x, y))
if (is_inside_bounds(x, y))
{
tilemap[GetIndex(x, y)] = tile;
tilemap[get_index(x, y)] = tile;
}
}
int Tilemap::get_tile(int x, int y)
{
if (IsInsideBounds(x, y))
if (is_inside_bounds(x, y))
{
return tilemap[GetIndex(x, y)];
return tilemap[get_index(x, y)];
}
return -1;
}
bool Tilemap::IsBlocked(int x, int y)
bool Tilemap::is_blocked(int x, int y)
{
if (IsInsideBounds(x, y))
if (is_inside_bounds(x, y))
{
if (tilemap[GetIndex(x,y)] == '#') { // TODO: Replace hardcoded tiles
if (tilemap[get_index(x,y)] == '#') { // TODO: Replace hardcoded tiles
return true;
}
for (Entity* var : entities) {
@ -154,15 +150,15 @@ void Tilemap::draw(Renderer *renderer, Tileset* tileset, int x, int y, int tx, i
for (int iy = 0; iy < th; iy++) {
int ax = tx + ix;
int ay = ty + iy;
if (IsInsideBounds(ax, ay)) {
if (is_inside_bounds(ax, ay)) {
if (view == nullptr || view->has_seen({ax, ay})) {
renderer->set_color(1, 1, 1, 1);
renderer->draw_sprite(tileset->get_sprite(get_tile(ax, ay)), x + ix * w, y + iy * h);
if (view != nullptr && !view->can_see({ax, ay})) {
renderer->set_color(0, 0, 0, .6f);
renderer->draw_sprite(tileset->get_sprite(219), x + ix * w, y + iy * h);
if (view != nullptr && !view->can_see({ ax, ay })) {
renderer->set_color(1, 1, 1, .3f);
}
else {
renderer->set_color(1, 1, 1, 1);
}
renderer->draw_sprite(tileset->get_sprite(get_tile(ax, ay)), x + ix * w, y + iy * h);
}
}
}

View file

@ -16,14 +16,15 @@ class Tilemap {
public:
Tilemap(int width = 1, int height = 1);
~Tilemap();
int GetWidth();
int GetHeight();
int GetIndex(int x, int y); // Converts [x,y] to a 1D index.
bool IsInsideBounds(int x, int y);
int get_width();
int get_height();
int get_index(int x, int y); // Converts [x,y] to a 1D index.
bool is_inside_bounds(int x, int y);
std::vector<vec2i> get_neighbours(int x, int y, int range = 1);
std::vector<vec2i> get_neighbours(int x, int y, int up, int down, int left, int right);
void set_tile(int x, int y, unsigned int tile); // "Tile" is inteded for tile ids, but can be anything really.
int get_tile(int x, int y);
bool IsBlocked(int x, int y); // Checks if there is an actor blocking the tile.
bool is_blocked(int x, int y); // Checks if there is an actor blocking the tile.
void draw(Renderer *renderer, Tileset *tileset, int x, int y, int tx, int ty, int tw, int th, FieldOfView* view);