@@ -1,33 +1,50 @@ | |||
#include "EntPlayer.h" | |||
EntPlayer::EntPlayer(const Swan::Vec2 &pos): | |||
EntPlayer::EntPlayer(Swan::World &world, const Swan::Vec2 &pos): | |||
body_(pos, SIZE, MASS) { | |||
texture_.create(animation_still_.width_, animation_still_.height_); | |||
sprite_ = sf::Sprite(texture_); | |||
anims_[(int)State::IDLE].init(32, 64, 0.8, | |||
world.getAsset("core::player-still")); | |||
anims_[(int)State::RUNNING_R].init(32, 64, 1, | |||
world.getAsset("core::player-running")); | |||
anims_[(int)State::RUNNING_L].init(32, 64, 1, | |||
world.getAsset("core::player-running"), (int)Swan::Animation::Flags::HFLIP); | |||
} | |||
void EntPlayer::draw(Swan::Win &win) { | |||
body_.outline(win); | |||
if (animation_still_.fill(texture_)) | |||
sprite_.setTexture(texture_); | |||
win.setPos(body_.pos_); | |||
win.draw(sprite_); | |||
win.setPos(body_.pos_ - Swan::Vec2(0.2, 0.1)); | |||
anims_[(int)state_].draw(win); | |||
} | |||
void EntPlayer::update(Swan::WorldPlane &plane, float dt) { | |||
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A) || sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) | |||
State oldState = state_; | |||
state_ = State::IDLE; | |||
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A) || sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) { | |||
body_.force_ += Swan::Vec2(-FORCE, 0); | |||
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D) || sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) | |||
state_ = State::RUNNING_L; | |||
} | |||
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D) || sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) { | |||
body_.force_ += Swan::Vec2(FORCE, 0); | |||
if (body_.on_ground_ && sf::Keyboard::isKeyPressed(sf::Keyboard::Space)) | |||
if (state_ == State::RUNNING_L) | |||
state_ = State::IDLE; | |||
else | |||
state_ = State::RUNNING_R; | |||
} | |||
if (body_.on_ground_ && sf::Keyboard::isKeyPressed(sf::Keyboard::Space)) { | |||
body_.vel_.y_ = -JUMP_FORCE; | |||
} | |||
if (state_ != oldState) | |||
anims_[(int)state_].reset(); | |||
anims_[(int)state_].tick(dt); | |||
body_.friction(FRICTION); | |||
body_.gravity(); | |||
body_.update(dt); | |||
body_.collide(plane); | |||
animation_still_.tick(dt); | |||
} |
@@ -6,10 +6,12 @@ class EntPlayer: public Swan::Entity { | |||
public: | |||
class Factory: public Swan::Entity::Factory { | |||
public: | |||
Swan::Entity *create(const Swan::Vec2 &pos) override { return new EntPlayer(pos); } | |||
Swan::Entity *create(Swan::World &world, const Swan::Vec2 &pos) override { | |||
return new EntPlayer(world, pos); | |||
} | |||
}; | |||
EntPlayer(const Swan::Vec2 &pos); | |||
EntPlayer(Swan::World &world, const Swan::Vec2 &pos); | |||
const Swan::Vec2 &getPos() override { return body_.pos_; } | |||
@@ -21,11 +23,17 @@ private: | |||
static constexpr float JUMP_FORCE = 7; | |||
static constexpr float MASS = 80; | |||
static constexpr Swan::Vec2 FRICTION = Swan::Vec2(400, 0); | |||
static constexpr Swan::Vec2 SIZE = Swan::Vec2(1, 2); | |||
static constexpr Swan::Vec2 SIZE = Swan::Vec2(0.6, 1.9); | |||
enum class State { | |||
IDLE, | |||
RUNNING_L, | |||
RUNNING_R, | |||
COUNT, | |||
}; | |||
State state_ = State::IDLE; | |||
Swan::Animation anims_[(int)State::COUNT]; | |||
Swan::Animation animation_still_ = Swan::Animation( | |||
32, 64, 1.3, "core.mod/assets/entities/player-still.png"); | |||
sf::Texture texture_; | |||
sf::Sprite sprite_; | |||
Swan::Body body_; | |||
}; |
@@ -14,6 +14,9 @@ extern "C" void mod_init(Swan::Mod &mod) { | |||
mod.registerWorldGen("default", new WGDefault::Factory()); | |||
mod.registerEntity("player", new EntPlayer::Factory()); | |||
mod.registerAsset("player-running", new Swan::Asset("assets/entities/player-running.png")); | |||
mod.registerAsset("player-still", new Swan::Asset("assets/entities/player-still.png")); | |||
} | |||
int main() { |
@@ -1,27 +1,39 @@ | |||
#pragma once | |||
#include <SFML/Graphics/Image.hpp> | |||
#include <SFML/Graphics/Texture.hpp> | |||
#include <SFML/Graphics/Sprite.hpp> | |||
#include "common.h" | |||
#include "Asset.h" | |||
namespace Swan { | |||
class Animation { | |||
public: | |||
Animation(int w, int h, double freq, const sf::Image &img); | |||
Animation(int w, int h, double freq, const std::string &path); | |||
enum class Flags { | |||
HFLIP = 1, | |||
}; | |||
Animation() = default; | |||
Animation(int w, int h, double interval, const Asset &asset, int flags = 0) { | |||
init(w, h, interval, asset, flags); | |||
} | |||
void init(int w, int h, double interval, const Asset &asset, int flags = 0); | |||
void tick(double dt); | |||
bool fill(sf::Texture &tex, bool force = false); | |||
void draw(Win &win); | |||
void reset(); | |||
int width_, height_; | |||
private: | |||
sf::Image img_; | |||
double interval_; | |||
const Asset *asset_; | |||
int fcount_; | |||
int frame_ = 0; | |||
bool dirty_ = true; | |||
double interval_; | |||
double time_ = 0; | |||
sf::Sprite sprite_; | |||
}; | |||
} |
@@ -0,0 +1,28 @@ | |||
#pragma once | |||
#include <SFML/Graphics/Image.hpp> | |||
#include <SFML/Graphics/Texture.hpp> | |||
namespace Swan { | |||
class Asset { | |||
public: | |||
Asset(std::string path): path_(path) {} | |||
bool load(std::string pfx) { | |||
if (!img_.loadFromFile(pfx + "/" + path_)) | |||
return false; | |||
auto size = img_.getSize(); | |||
tex_.create(size.x, size.y); | |||
tex_.update(img_); | |||
return true; | |||
} | |||
std::string name_; | |||
std::string path_; | |||
sf::Image img_; | |||
sf::Texture tex_; | |||
}; | |||
} |
@@ -6,6 +6,7 @@ | |||
namespace Swan { | |||
class World; | |||
class WorldPlane; | |||
class Entity { | |||
@@ -13,7 +14,7 @@ public: | |||
class Factory { | |||
public: | |||
virtual ~Factory() = default; | |||
virtual Entity *create(const Vec2 &pos) = 0; | |||
virtual Entity *create(World &world, const Vec2 &pos) = 0; | |||
std::string name_; | |||
}; | |||
@@ -8,6 +8,7 @@ | |||
#include "Tile.h" | |||
#include "WorldGen.h" | |||
#include "Entity.h" | |||
#include "Asset.h" | |||
namespace Swan { | |||
@@ -19,12 +20,14 @@ public: | |||
void registerTile(const std::string &name, Tile *tile); | |||
void registerWorldGen(const std::string &name, WorldGen::Factory *gen); | |||
void registerEntity(const std::string &name, Entity::Factory *ent); | |||
void registerAsset(const std::string &name, Asset *asset); | |||
std::string name_; | |||
std::string path_; | |||
std::vector<std::shared_ptr<Tile>> tiles_; | |||
std::vector<std::shared_ptr<WorldGen::Factory>> worldgens_; | |||
std::vector<std::shared_ptr<Entity::Factory>> entities_; | |||
std::vector<std::shared_ptr<Asset>> assets_; | |||
bool inited_ = false; | |||
}; | |||
@@ -9,6 +9,7 @@ | |||
#include "WorldPlane.h" | |||
#include "WorldGen.h" | |||
#include "Entity.h" | |||
#include "Asset.h" | |||
namespace Swan { | |||
@@ -22,6 +23,9 @@ public: | |||
void registerTile(std::shared_ptr<Tile> t); | |||
void registerWorldGen(std::shared_ptr<WorldGen::Factory> gen); | |||
void registerEntity(std::shared_ptr<Entity::Factory> ent); | |||
void registerAsset(std::shared_ptr<Asset> asset); | |||
Asset &getAsset(const std::string &name); | |||
void draw(Win &win); | |||
void update(float dt); | |||
@@ -29,6 +33,7 @@ public: | |||
std::map<std::string, std::shared_ptr<WorldGen::Factory>> worldgens_; | |||
std::map<std::string, std::shared_ptr<Entity::Factory>> ents_; | |||
std::map<std::string, std::shared_ptr<Asset>> assets_; | |||
TileMap tile_map_; | |||
Entity *player_; | |||
@@ -15,6 +15,8 @@ static constexpr int CHUNK_WIDTH = 8; | |||
using TilePos = Vec2i; | |||
using ChunkPos = Vec2i; | |||
class WorldPlane; | |||
struct Win { | |||
public: | |||
sf::RenderWindow *window_; |
@@ -1,6 +1,7 @@ | |||
#pragma once | |||
#include <swan/Animation.h> | |||
#include <swan/Asset.h> | |||
#include <swan/Body.h> | |||
#include <swan/Chunk.h> | |||
#include <swan/Entity.h> | |||
@@ -10,7 +11,7 @@ | |||
#include <swan/TileMap.h> | |||
#include <swan/Timer.h> | |||
#include <swan/Vector2.h> | |||
#include <swan/WorldGen.h> | |||
#include <swan/World.h> | |||
#include <swan/WorldGen.h> | |||
#include <swan/WorldPlane.h> | |||
#include <swan/common.h> |
@@ -2,17 +2,19 @@ | |||
namespace Swan { | |||
Animation::Animation(int w, int h, double freq, const sf::Image &img): | |||
width_(w), height_(h), img_(img) { | |||
fcount_ = img_.getSize().y / height_; | |||
interval_ = 1.0 / freq; | |||
} | |||
Animation::Animation(int w, int h, double freq, const std::string &path): | |||
width_(w), height_(h) { | |||
img_.loadFromFile(path); | |||
fcount_ = img_.getSize().y / height_; | |||
interval_ = 1.0 / freq; | |||
void Animation::init(int w, int h, double interval, const Asset &asset, int flags) { | |||
width_ = w; | |||
height_ = h; | |||
interval_ = interval; | |||
asset_ = &asset; | |||
fcount_ = asset_->img_.getSize().y / height_; | |||
sprite_.setTexture(asset_->tex_); | |||
sprite_.setTextureRect(sf::IntRect(0, 0, width_, height_)); | |||
if (flags & (int)Flags::HFLIP) { | |||
sprite_.setOrigin(Vec2(width_, 0)); | |||
sprite_.setScale(Vec2(-1, 1)); | |||
} | |||
} | |||
void Animation::tick(double dt) { | |||
@@ -22,19 +24,21 @@ void Animation::tick(double dt) { | |||
time_ = 0; | |||
if (frame_ >= fcount_) | |||
frame_ = 0; | |||
sprite_.setTextureRect(sf::IntRect(0, height_ * frame_, width_, height_)); | |||
} | |||
time_ += dt; | |||
} | |||
bool Animation::fill(sf::Texture &tex, bool force) { | |||
if (!force && !dirty_) | |||
return false; | |||
void Animation::draw(Win &win) { | |||
win.draw(sprite_); | |||
} | |||
const sf::Uint8 *data = img_.getPixelsPtr() + 4 * width_ * height_ * frame_; | |||
tex.update(data); | |||
dirty_ = false; | |||
return true; | |||
void Animation::reset() { | |||
time_ = 0; | |||
frame_ = 0; | |||
dirty_ = true; | |||
} | |||
} |
@@ -1,5 +1,7 @@ | |||
#include "Body.h" | |||
#include <math.h> | |||
namespace Swan { | |||
void Body::friction(Vec2 coef) { | |||
@@ -11,8 +13,8 @@ void Body::gravity(Vec2 g) { | |||
} | |||
void Body::collide(WorldPlane &plane) { | |||
int startx = (int)pos_.x_; | |||
int endx = (int)(pos_.x_ + size_.x_); | |||
int startx = (int)floor(pos_.x_); | |||
int endx = (int)floor(pos_.x_ + size_.x_); | |||
int y = (int)(pos_.y_ + size_.y_); | |||
on_ground_ = false; | |||
@@ -32,7 +34,7 @@ void Body::outline(Win &win) { | |||
sf::RectangleShape rect(size_ * TILE_SIZE); | |||
rect.setFillColor(sf::Color::Transparent); | |||
rect.setOutlineColor(sf::Color(128, 128, 128)); | |||
rect.setOutlineThickness(2); | |||
rect.setOutlineThickness(1); | |||
win.draw(rect); | |||
} | |||
@@ -34,6 +34,8 @@ void Game::createWorld(std::string worldgen) { | |||
world_->registerWorldGen(worldgen); | |||
for (auto &entity: mod.entities_) | |||
world_->registerEntity(entity); | |||
for (auto &asset: mod.assets_) | |||
world_->registerAsset(asset); | |||
} | |||
world_->setWorldGen(worldgen); |
@@ -34,4 +34,15 @@ void Mod::registerEntity(const std::string &name, Entity::Factory *ent) { | |||
entities_.push_back(std::shared_ptr<Entity::Factory>(ent)); | |||
} | |||
void Mod::registerAsset(const std::string &name, Asset *asset) { | |||
asset->name_ = name_ + "::" + name; | |||
if (!asset->load(path_)) { | |||
fprintf(stderr, "Asset %s: Failed to load image %s", name.c_str(), (path_ + "/" + asset->path_).c_str()); | |||
abort(); | |||
} | |||
assets_.push_back(std::shared_ptr<Asset>(asset)); | |||
} | |||
} |
@@ -53,6 +53,20 @@ void World::registerEntity(std::shared_ptr<Entity::Factory> ent) { | |||
ents_[ent->name_] = ent; | |||
} | |||
void World::registerAsset(std::shared_ptr<Asset> asset) { | |||
assets_[asset->name_] = asset; | |||
} | |||
Asset &World::getAsset(const std::string &name) { | |||
auto iter = assets_.find(name); | |||
if (iter == assets_.end()) { | |||
fprintf(stderr, "Tried to get non-existant asset ''%s'!\n", name.c_str()); | |||
abort(); | |||
} | |||
return *iter->second; | |||
} | |||
WorldPlane &World::addPlane(std::string gen) { | |||
WorldPlane::ID id = planes_.size(); | |||
if (worldgens_.find(gen) == worldgens_.end()) { |
@@ -28,7 +28,7 @@ Entity &WorldPlane::spawnEntity(const std::string &name, const Vec2 &pos) { | |||
abort(); | |||
} | |||
Entity *ent = world_->ents_[name]->create(pos); | |||
Entity *ent = world_->ents_[name]->create(*world_, pos); | |||
entities_.push_back(std::unique_ptr<Entity>(ent)); | |||
fprintf(stderr, "Spawned %s at %f,%f.\n", name.c_str(), pos.x_, pos.y_); | |||
return *ent; |