@@ -1,14 +1,38 @@ | |||
#include <swan/Mod.h> | |||
#include <swan/Game.h> | |||
class DefaultWorldGen: public Swan::WorldGen { | |||
public: | |||
class Factory: public Swan::WorldGen::Factory { | |||
public: | |||
Factory(): Swan::WorldGen::Factory("Default") {} | |||
WorldGen *create(Swan::TileMap &tmap) { return new DefaultWorldGen(tmap); } | |||
}; | |||
Swan::Tile::ID tGrass_, tAir_; | |||
DefaultWorldGen(Swan::TileMap &tmap): | |||
tGrass_(tmap.getID("core::grass")), tAir_(tmap.getID("core::air")) {} | |||
void genChunk(Swan::Chunk &chunk, int x, int y) { | |||
fprintf(stderr, "genChunk at %i, %i\n", x, y); | |||
for (int x = 0; x < Swan::CHUNK_WIDTH; ++x) { | |||
for (int y = 0; y < Swan::CHUNK_HEIGHT; ++y) { | |||
chunk.tiles_[x][y] = y == 3 ? tGrass_ : tAir_; | |||
} | |||
} | |||
} | |||
}; | |||
extern "C" void mod_init(Swan::Mod &mod) { | |||
mod.init("core"); | |||
mod.registerTile("air", "assets/tiles/air.png", Swan::Tile::Opts() | |||
.transparent()); | |||
.solid(false)); | |||
mod.registerTile("stone", "assets/tiles/stone.png", Swan::Tile::Opts()); | |||
mod.registerTile("dirt", "assets/tiles/dirt.png", Swan::Tile::Opts()); | |||
mod.registerTile("grass", "assets/tiles/grass.png", Swan::Tile::Opts()); | |||
mod.registerWorldGen(new DefaultWorldGen::Factory()); | |||
} | |||
int main() { |
@@ -4,6 +4,7 @@ add_library(libswan SHARED | |||
src/Game.cc | |||
src/Mod.cc | |||
src/Player.cc | |||
src/Tile.cc | |||
src/World.cc | |||
src/WorldPlane.cc) | |||
target_include_directories(libswan PUBLIC "include/swan") |
@@ -28,12 +28,12 @@ public: | |||
drawBlock(tmap, x, y, id); | |||
} | |||
Tile *getTile(TileMap &tmap, int x, int y) { | |||
Tile &getTile(TileMap &tmap, int x, int y) { | |||
return tmap.get(tiles_[x][y]); | |||
} | |||
void drawBlock(int x, int y, Tile *t) { | |||
texture_.update(t->image_, x * TILE_SIZE, y * TILE_SIZE); | |||
void drawBlock(int x, int y, const Tile &t) { | |||
texture_.update(t.image_, x * TILE_SIZE, y * TILE_SIZE); | |||
dirty_ = true; | |||
} | |||
@@ -42,7 +42,6 @@ public: | |||
} | |||
void redraw(TileMap &tmap); | |||
void fill(TileMap &tmap, Tile::ID id); | |||
void draw(Win &win); | |||
}; | |||
@@ -22,6 +22,8 @@ public: | |||
void draw(Win &win); | |||
void update(float dt); | |||
void tick(); | |||
static void initGlobal(); | |||
}; | |||
} |
@@ -3,8 +3,10 @@ | |||
#include <stdint.h> | |||
#include <string> | |||
#include <vector> | |||
#include <memory> | |||
#include "Tile.h" | |||
#include "WorldGen.h" | |||
namespace Swan { | |||
@@ -14,11 +16,13 @@ public: | |||
std::string name_; | |||
std::string path_; | |||
std::vector<Tile> tiles_; | |||
std::vector<std::shared_ptr<Tile>> tiles_; | |||
std::vector<std::shared_ptr<WorldGen::Factory>> worldgens_; | |||
bool inited_ = false; | |||
void init(const std::string &name); | |||
void registerTile(const std::string &name, const std::string &asset, const Tile::Opts &opts); | |||
void registerWorldGen(WorldGen::Factory *gen); | |||
}; | |||
} |
@@ -11,14 +11,17 @@ public: | |||
using ID = uint16_t; | |||
struct Opts { | |||
bool transparent_ = false; | |||
Opts &transparent() { transparent_ = true; return *this; } | |||
bool solid_ = true; | |||
Opts &solid(bool b) { solid_ = b; return *this; } | |||
}; | |||
std::string name_; | |||
sf::Image image_; | |||
Opts opts_; | |||
static sf::Image invalid_image; | |||
static Tile invalid_tile; | |||
static void initInvalid(); | |||
}; | |||
} |
@@ -1,23 +1,27 @@ | |||
#pragma once | |||
#include <memory> | |||
#include "Tile.h" | |||
namespace Swan { | |||
class TileMap { | |||
public: | |||
std::vector<Tile *> tiles_; | |||
std::vector<std::shared_ptr<Tile>> tiles_; | |||
std::map<std::string, Tile::ID> id_map_; | |||
Tile::ID getID(const std::string &name) { | |||
return id_map_[name]; | |||
} | |||
Tile *get(Tile::ID id) { | |||
return tiles_[id]; | |||
Tile &get(Tile::ID id) { | |||
if (id >= tiles_.size()) | |||
return Tile::invalid_tile; | |||
return *tiles_[id]; | |||
} | |||
void registerTile(Tile *t) { | |||
void registerTile(std::shared_ptr<Tile> t) { | |||
Tile::ID id = tiles_.size(); | |||
tiles_.push_back(t); | |||
id_map_[t->name_] = id; |
@@ -1,5 +1,9 @@ | |||
#pragma once | |||
#include <memory> | |||
#include <vector> | |||
#include <string> | |||
#include "common.h" | |||
#include "Player.h" | |||
#include "Tile.h" | |||
@@ -16,9 +20,12 @@ public: | |||
WorldPlane::ID current_plane_; | |||
std::vector<WorldPlane> planes_; | |||
WorldGen::ID default_worldgen_; | |||
std::vector<std::shared_ptr<WorldGen::Factory>> worldgens_; | |||
TileMap tile_map_; | |||
WorldPlane::ID addPlane(); | |||
WorldPlane::ID addPlane(WorldGen::ID gen); | |||
WorldPlane::ID addPlane() { return addPlane(default_worldgen_); } | |||
void setCurrentPlane(WorldPlane::ID id) { current_plane_ = id; } | |||
WorldPlane &getPlane(WorldPlane::ID id) { return planes_[id]; } | |||
@@ -26,10 +33,14 @@ public: | |||
return tile_map_.getID(name); | |||
} | |||
void registerTile(Tile *t) { | |||
void registerTile(std::shared_ptr<Tile> t) { | |||
tile_map_.registerTile(t); | |||
} | |||
void registerWorldGen(std::shared_ptr<WorldGen::Factory> gen) { | |||
worldgens_.push_back(gen); | |||
} | |||
void draw(Win &win); | |||
void update(float dt); | |||
void tick(); |
@@ -0,0 +1,26 @@ | |||
#pragma once | |||
#include <memory> | |||
#include "Chunk.h" | |||
#include "TileMap.h" | |||
namespace Swan { | |||
class WorldGen { | |||
public: | |||
using ID = int; | |||
class Factory { | |||
public: | |||
std::string name_; | |||
Factory(const std::string &name): name_(name) {} | |||
virtual WorldGen *create(TileMap &tmap) = 0; | |||
}; | |||
virtual ~WorldGen() = default; | |||
virtual void genChunk(Chunk &chunk, int x, int y) = 0; | |||
}; | |||
} |
@@ -2,11 +2,13 @@ | |||
#include <vector> | |||
#include <utility> | |||
#include <memory> | |||
#include "common.h" | |||
#include "Chunk.h" | |||
#include "Tile.h" | |||
#include "TileMap.h" | |||
#include "WorldGen.h" | |||
namespace Swan { | |||
@@ -20,6 +22,10 @@ public: | |||
std::map<Coord, Chunk> chunks_; | |||
ID id_; | |||
World *world_; | |||
std::shared_ptr<WorldGen> gen_; | |||
WorldPlane(ID id, World *world, std::shared_ptr<WorldGen> gen): | |||
id_(id), world_(world), gen_(gen) {} | |||
Chunk &getChunk(int x, int y); | |||
void setTileID(int x, int y, Tile::ID id); |
@@ -17,9 +17,10 @@ void Body::collide(WorldPlane &plane) { | |||
int y = (int)(pos_.y_ + size_.y_); | |||
for (int x = startx; x <= endx; ++x) { | |||
Tile &tile = plane.getTile(x, y); | |||
if (!tile.opts_.transparent_) { | |||
if (tile.opts_.solid_) { | |||
pos_.y_ = y - size_.y_; | |||
vel_.y_ = 0; | |||
break; | |||
} | |||
} | |||
} |
@@ -10,16 +10,6 @@ void Chunk::redraw(TileMap &tmap) { | |||
} | |||
} | |||
void Chunk::fill(TileMap &tmap, Tile::ID id) { | |||
Tile *air = tmap.get(0); | |||
for (int x = 0; x < CHUNK_WIDTH; ++x) { | |||
for (int y = 0; y < CHUNK_HEIGHT; ++y) { | |||
tiles_[x][y] = id; | |||
drawBlock(x, y, air); | |||
} | |||
} | |||
} | |||
void Chunk::draw(Win &win) { | |||
if (dirty_) { | |||
sprite_.setTexture(texture_); |
@@ -2,6 +2,8 @@ | |||
#include <dlfcn.h> | |||
#include "Tile.h" | |||
namespace Swan { | |||
void Game::loadMod(const std::string &path) { | |||
@@ -26,9 +28,10 @@ void Game::loadMod(const std::string &path) { | |||
void Game::createWorld() { | |||
world_.reset(new World()); | |||
for (auto &mod: registered_mods_) { | |||
for (auto &tile: mod.tiles_) { | |||
world_->registerTile(&tile); | |||
} | |||
for (auto &tile: mod.tiles_) | |||
world_->registerTile(tile); | |||
for (auto &worldgen: mod.worldgens_) | |||
world_->registerWorldGen(worldgen); | |||
} | |||
} | |||
@@ -47,4 +50,8 @@ void Game::tick() { | |||
world_->tick(); | |||
} | |||
void Game::initGlobal() { | |||
Tile::initInvalid(); | |||
} | |||
} |
@@ -12,16 +12,22 @@ void Mod::init(const std::string &name) { | |||
} | |||
void Mod::registerTile(const std::string &name, const std::string &asset, const Tile::Opts &opts) { | |||
tiles_.push_back(Tile()); | |||
Tile &t = tiles_.back(); | |||
t.name_ = name_ + "::" + name; | |||
t.opts_ = opts; | |||
fprintf(stderr, "Adding tile: %s\n", t.name_.c_str()); | |||
Tile *t = new Tile(); | |||
t->name_ = name_ + "::" + name; | |||
t->opts_ = opts; | |||
fprintf(stderr, "Adding tile: %s\n", t->name_.c_str()); | |||
std::string asset_path = path_ + "/" + asset; | |||
if (!t.image_.loadFromFile(asset_path)) { | |||
fprintf(stderr, "Tile %s: Failed to load image %s\n", t.name_.c_str(), asset_path.c_str()); | |||
if (!t->image_.loadFromFile(asset_path)) { | |||
fprintf(stderr, "Tile %s: Failed to load image %s\n", t->name_.c_str(), asset_path.c_str()); | |||
t->image_ = Tile::invalid_image; | |||
} | |||
tiles_.push_back(std::shared_ptr<Tile>(t)); | |||
} | |||
void Mod::registerWorldGen(WorldGen::Factory *gen) { | |||
worldgens_.push_back(std::shared_ptr<WorldGen::Factory>(gen)); | |||
} | |||
} |
@@ -0,0 +1,16 @@ | |||
#include "Tile.h" | |||
#include "common.h" | |||
namespace Swan { | |||
sf::Image Tile::invalid_image; | |||
Tile Tile::invalid_tile; | |||
void Tile::initInvalid() { | |||
invalid_image.create((int)TILE_SIZE, (int)TILE_SIZE, sf::Color(245, 66, 242)); | |||
invalid_tile.name_ = "INVALID"; | |||
invalid_tile.image_ = invalid_image; | |||
invalid_tile.opts_ = Opts().solid(false); | |||
} | |||
} |
@@ -2,12 +2,10 @@ | |||
namespace Swan { | |||
WorldPlane::ID World::addPlane() { | |||
WorldPlane::ID World::addPlane(WorldGen::ID gen) { | |||
WorldPlane::ID id = planes_.size(); | |||
planes_.push_back(WorldPlane()); | |||
WorldPlane &plane = planes_.back(); | |||
plane.id_ = id; | |||
plane.world_ = this; | |||
WorldGen *g = worldgens_[gen]->create(tile_map_); | |||
planes_.push_back(WorldPlane(id, this, std::shared_ptr<WorldGen>(g))); | |||
return id; | |||
} | |||
@@ -10,7 +10,8 @@ Chunk &WorldPlane::getChunk(int x, int y) { | |||
if (it == chunks_.end()) { | |||
it = chunks_.emplace(coord, Chunk(coord.first, coord.second)).first; | |||
it->second.fill(world_->tile_map_, 0); | |||
gen_->genChunk(it->second, coord.first, coord.second); | |||
it->second.redraw(world_->tile_map_); | |||
} | |||
return it->second; | |||
@@ -21,7 +22,7 @@ void WorldPlane::setTileID(int x, int y, Tile::ID id) { | |||
} | |||
Tile &WorldPlane::getTile(int x, int y) { | |||
return *getChunk(x, y).getTile(world_->tile_map_, x % CHUNK_WIDTH, y % CHUNK_HEIGHT); | |||
return getChunk(x, y).getTile(world_->tile_map_, x % CHUNK_WIDTH, y % CHUNK_HEIGHT); | |||
} | |||
void WorldPlane::draw(Win &win) { |
@@ -20,6 +20,8 @@ int main() { | |||
window.setVerticalSyncEnabled(true); | |||
Win win(&window); | |||
Game::initGlobal(); | |||
Game game; | |||
game.loadMod("core.mod"); | |||
@@ -27,18 +29,6 @@ int main() { | |||
game.world_->setCurrentPlane(game.world_->addPlane()); | |||
game.world_->player_ = new Player(Vec2(1, 1)); | |||
Tile::ID tStone = game.world_->getTileID("core::stone"); | |||
Tile::ID tGrass = game.world_->getTileID("core::grass"); | |||
WorldPlane &plane = game.world_->getPlane(game.world_->current_plane_); | |||
for (int x = 1; x < 10; ++x) { | |||
for (int y = 3; y < 10; ++y) { | |||
if (y == 3) | |||
plane.setTileID(x, y, tGrass); | |||
else | |||
plane.setTileID(x, y, tStone); | |||
} | |||
} | |||
double prevtime = getTime(); | |||
double fpsAcc = 0; | |||
double tickAcc = 0; |