@@ -21,6 +21,7 @@ void WGDefault::genChunk(Swan::WorldPlane &plane, Swan::Chunk &chunk) { | |||
} | |||
} | |||
Swan::Entity &WGDefault::spawnPlayer(Swan::WorldPlane &plane) { | |||
return plane.spawnEntity("core::player", Swan::SRFFloatArray{0, 0}); | |||
Swan::BodyTrait::HasBody *WGDefault::spawnPlayer(Swan::WorldPlane &plane) { | |||
return dynamic_cast<Swan::BodyTrait::HasBody *>( | |||
plane.spawnEntity("core::player", Swan::SRFFloatArray{0, 0})); | |||
} |
@@ -16,7 +16,7 @@ public: | |||
tStone_(world.getTileID("core::stone")), tAir_(world.getTileID("core::air")) {} | |||
void genChunk(Swan::WorldPlane &plane, Swan::Chunk &chunk) override; | |||
Swan::Entity &spawnPlayer(Swan::WorldPlane &plane) override; | |||
Swan::BodyTrait::HasBody *spawnPlayer(Swan::WorldPlane &plane) override; | |||
private: | |||
Swan::Tile::ID tGrass_, tDirt_, tStone_, tAir_; |
@@ -1,6 +1,6 @@ | |||
add_library(libswan SHARED | |||
src/traits/BodyTrait.cc | |||
src/Animation.cc | |||
src/Body.cc | |||
src/Chunk.cc | |||
src/Clock.cc | |||
src/Game.cc |
@@ -1,38 +0,0 @@ | |||
#pragma once | |||
#include "common.h" | |||
#include "BoundingBox.h" | |||
namespace Swan { | |||
class WorldPlane; | |||
class Body { | |||
public: | |||
Body(Vec2 size, float mass, Vec2 pos = Vec2::ZERO): | |||
size_(size), mass_(mass), pos_(pos) {}; | |||
void friction(Vec2 coef = Vec2(400, 50)); | |||
void gravity(Vec2 g = Vec2(0, 20)); | |||
void outline(Win &win); | |||
void update(WorldPlane &plane, float dt); | |||
void updateWithoutCollision(float dt); | |||
BoundingBox getBounds() { return { pos_, size_ }; } | |||
Vec2 force_ = { 0, 0 }; | |||
Vec2 vel_ = { 0, 0 }; | |||
bool on_ground_ = false; | |||
Vec2 size_; | |||
float mass_; | |||
Vec2 pos_; | |||
float bounciness_ = 0; | |||
float mushyness_ = 2; | |||
private: | |||
void collideX(WorldPlane &plane); | |||
void collideY(WorldPlane &plane); | |||
}; | |||
} |
@@ -1,17 +0,0 @@ | |||
#pragma once | |||
#include "Vector2.h" | |||
namespace Swan { | |||
struct BoundingBox { | |||
Vec2 pos; | |||
Vec2 size; | |||
double left() { return pos.x; } | |||
double right() { return pos.x + size.x; } | |||
double top() { return pos.y; } | |||
double bottom() { return pos.y + size.y; } | |||
}; | |||
} |
@@ -5,9 +5,8 @@ | |||
#include "common.h" | |||
#include "log.h" | |||
#include "traits/BodyTrait.h" | |||
#include "SRF.h" | |||
#include "BoundingBox.h" | |||
#include "Body.h" | |||
namespace Swan { | |||
@@ -26,24 +25,21 @@ public: | |||
virtual ~Entity() = default; | |||
virtual std::optional<BoundingBox> getBounds() { return std::nullopt; } | |||
virtual void draw(const Context &ctx, Win &win) {} | |||
virtual void update(const Context &ctx, float dt) {} | |||
virtual void tick(const Context &ctx, float dt) {} | |||
virtual void move(const Vec2 &pos) {} | |||
virtual void moveTo(const Vec2 &pos) {} | |||
virtual void despawn() {} | |||
virtual void readSRF(const Swan::Context &ctx, const SRF &srf) {} | |||
virtual SRF *writeSRF(const Swan::Context &ctx) { return new SRFNone(); } | |||
}; | |||
class PhysicsEntity: public Entity { | |||
class PhysicsEntity: public Entity, public BodyTrait::HasBody { | |||
public: | |||
PhysicsEntity(Vec2 size, float mass): | |||
body_(size, mass) {} | |||
virtual std::optional<BoundingBox> getBounds() override { return body_.getBounds(); } | |||
virtual BodyTrait::Body &getBody() override { return body_; } | |||
virtual void update(const Context &ctx, float dt) override { | |||
body_.friction(); | |||
@@ -51,11 +47,8 @@ public: | |||
body_.update(ctx.plane, dt); | |||
} | |||
virtual void move(const Vec2 &rel) override { body_.pos_ += rel; } | |||
virtual void moveTo(const Vec2 &pos) override { body_.pos_ = pos; } | |||
protected: | |||
Body body_; | |||
BodyTrait::PhysicsBody body_; | |||
}; | |||
} |
@@ -51,7 +51,7 @@ public: | |||
std::unordered_map<std::string, WorldGen::Factory *> worldgens_; | |||
std::unordered_map<std::string, Entity::Factory *> ents_; | |||
Entity *player_; | |||
BodyTrait::HasBody *player_; | |||
Game *game_; | |||
std::mt19937 random_; |
@@ -4,6 +4,7 @@ | |||
#include "Chunk.h" | |||
#include "Entity.h" | |||
#include "traits/BodyTrait.h" | |||
namespace Swan { | |||
@@ -22,7 +23,7 @@ public: | |||
virtual ~WorldGen() = default; | |||
virtual void genChunk(WorldPlane &plane, Chunk &chunk) = 0; | |||
virtual Entity &spawnPlayer(WorldPlane &plane) = 0; | |||
virtual BodyTrait::HasBody *spawnPlayer(WorldPlane &plane) = 0; | |||
}; | |||
} |
@@ -7,6 +7,7 @@ | |||
#include <set> | |||
#include "common.h" | |||
#include "traits/BodyTrait.h" | |||
#include "Chunk.h" | |||
#include "Tile.h" | |||
#include "WorldGen.h" | |||
@@ -24,7 +25,7 @@ public: | |||
WorldPlane(ID id, World *world, std::shared_ptr<WorldGen> gen): | |||
id_(id), world_(world), gen_(std::move(gen)) {} | |||
Entity &spawnEntity(const std::string &name, const SRF ¶ms); | |||
Entity *spawnEntity(const std::string &name, const SRF ¶ms); | |||
void despawnEntity(Entity &ent); | |||
Context getContext(); | |||
@@ -36,7 +37,7 @@ public: | |||
Tile::ID getTileID(TilePos pos); | |||
Tile &getTile(TilePos pos); | |||
Entity &spawnPlayer(); | |||
BodyTrait::HasBody *spawnPlayer(); | |||
void breakBlock(TilePos pos); | |||
void draw(Win &win); |
@@ -1,8 +1,7 @@ | |||
#pragma once | |||
#include <swan/traits/BodyTrait.h> | |||
#include <swan/Animation.h> | |||
#include <swan/Body.h> | |||
#include <swan/BoundingBox.h> | |||
#include <swan/Chunk.h> | |||
#include <swan/Clock.h> | |||
#include <swan/Entity.h> |
@@ -0,0 +1,68 @@ | |||
#pragma once | |||
#include "../Vector2.h" | |||
namespace Swan { | |||
class WorldPlane; | |||
class Win; | |||
namespace BodyTrait { | |||
class Body; | |||
class HasBody { | |||
public: | |||
virtual Body &getBody() = 0; | |||
}; | |||
struct Bounds { | |||
Vec2 pos; | |||
Vec2 size; | |||
double left() { return pos.x; } | |||
double right() { return pos.x + size.x; } | |||
double top() { return pos.y; } | |||
double bottom() { return pos.y + size.y; } | |||
}; | |||
class Body { | |||
public: | |||
virtual Bounds getBounds() = 0; | |||
virtual void move(Vec2 rel) = 0; | |||
virtual void moveTo(Vec2 pos) = 0; | |||
}; | |||
// PhysicsBody is an implementation of BodyTrait::Body which implements | |||
// a bunch of physics stuff. | |||
class PhysicsBody: public Body { | |||
public: | |||
PhysicsBody(Vec2 size, float mass, Vec2 pos = Vec2::ZERO): | |||
size_(size), mass_(mass), pos_(pos) {}; | |||
BodyTrait::Bounds getBounds() override { return BodyTrait::Bounds{ pos_, size_ }; }; | |||
void move(Vec2 rel) { pos_ += rel; } | |||
void moveTo(Vec2 pos) { pos_ = pos; } | |||
void friction(Vec2 coef = Vec2(400, 50)); | |||
void gravity(Vec2 g = Vec2(0, 20)); | |||
void outline(Win &win); | |||
void update(WorldPlane &plane, float dt); | |||
void updateWithoutCollision(float dt); | |||
Vec2 force_ = { 0, 0 }; | |||
Vec2 vel_ = { 0, 0 }; | |||
bool on_ground_ = false; | |||
Vec2 size_; | |||
float mass_; | |||
Vec2 pos_; | |||
float bounciness_ = 0; | |||
float mushyness_ = 2; | |||
private: | |||
void collideX(WorldPlane &plane); | |||
void collideY(WorldPlane &plane); | |||
}; | |||
} | |||
} |
@@ -80,7 +80,7 @@ void World::setWorldGen(const std::string &gen) { | |||
} | |||
void World::spawnPlayer() { | |||
player_ = &planes_[current_plane_].spawnPlayer(); | |||
player_ = planes_[current_plane_].spawnPlayer(); | |||
} | |||
void World::setCurrentPlane(WorldPlane &plane) { | |||
@@ -131,7 +131,7 @@ Tile &World::getTile(const std::string &name) { | |||
} | |||
void World::draw(Win &win) { | |||
auto bounds = *player_->getBounds(); | |||
auto bounds = player_->getBody().getBounds(); | |||
win.cam_ = bounds.pos - (win.getSize() / 2) + (bounds.size / 2); | |||
planes_[current_plane_].draw(win); | |||
} | |||
@@ -145,7 +145,7 @@ void World::tick(float dt) { | |||
for (auto &plane: planes_) | |||
plane.tick(dt); | |||
auto bounds = *player_->getBounds(); | |||
auto bounds = player_->getBody().getBounds(); | |||
chunk_renderer_.tick( | |||
planes_[current_plane_], | |||
ChunkPos((int)bounds.pos.x / CHUNK_WIDTH, (int)bounds.pos.y / CHUNK_HEIGHT)); |
@@ -31,20 +31,23 @@ Context WorldPlane::getContext() { | |||
return { .game = *world_->game_, .world = *world_, .plane = *this, .resources = world_->resources_ }; | |||
} | |||
Entity &WorldPlane::spawnEntity(const std::string &name, const SRF ¶ms) { | |||
Entity *WorldPlane::spawnEntity(const std::string &name, const SRF ¶ms) { | |||
if (world_->ents_.find(name) == world_->ents_.end()) { | |||
panic << "Tried to spawn a non-existant entity " << name << "!"; | |||
abort(); | |||
} | |||
Entity *ent = world_->ents_[name]->create(getContext(), params); | |||
if (auto bounds = ent->getBounds(); bounds) { | |||
ent->move({ 0.5f - bounds->size.x / 2, 0 }); | |||
if (auto has_body = dynamic_cast<BodyTrait::HasBody *>(ent); has_body) { | |||
BodyTrait::Body &body = has_body->getBody(); | |||
BodyTrait::Bounds bounds = body.getBounds(); | |||
body.move({ 0.5f - bounds.size.x / 2, 0 }); | |||
} | |||
spawn_list_.push_back(std::unique_ptr<Entity>(ent)); | |||
info << "Spawned " << name << ". SRF: " << params; | |||
return *ent; | |||
return ent; | |||
} | |||
void WorldPlane::despawnEntity(Entity &ent) { | |||
@@ -101,7 +104,7 @@ Tile &WorldPlane::getTile(TilePos pos) { | |||
return world_->getTileByID(getTileID(pos)); | |||
} | |||
Entity &WorldPlane::spawnPlayer() { | |||
BodyTrait::HasBody *WorldPlane::spawnPlayer() { | |||
return gen_->spawnPlayer(*this); | |||
} | |||
@@ -127,7 +130,7 @@ void WorldPlane::breakBlock(TilePos pos) { | |||
} | |||
void WorldPlane::draw(Win &win) { | |||
auto pbounds = *world_->player_->getBounds(); | |||
auto pbounds = world_->player_->getBody().getBounds(); | |||
ChunkPos pcpos = ChunkPos( | |||
(int)floor(pbounds.pos.x / CHUNK_WIDTH), | |||
(int)floor(pbounds.pos.y / CHUNK_HEIGHT)); |
@@ -1,4 +1,4 @@ | |||
#include "Body.h" | |||
#include "traits/BodyTrait.h" | |||
#include <math.h> | |||
#include <array> | |||
@@ -8,18 +8,19 @@ | |||
#include "Win.h" | |||
namespace Swan { | |||
namespace BodyTrait { | |||
static float epsilon = 0.0001; | |||
void Body::friction(Vec2 coef) { | |||
void PhysicsBody::friction(Vec2 coef) { | |||
force_ += -vel_ * coef; | |||
} | |||
void Body::gravity(Vec2 g) { | |||
void PhysicsBody::gravity(Vec2 g) { | |||
force_ += g * mass_; | |||
} | |||
void Body::collideX(WorldPlane &plane) { | |||
void PhysicsBody::collideX(WorldPlane &plane) { | |||
auto bounds = getBounds(); | |||
bool collided = false; | |||
@@ -50,7 +51,7 @@ void Body::collideX(WorldPlane &plane) { | |||
} | |||
} | |||
void Body::collideY(WorldPlane &plane) { | |||
void PhysicsBody::collideY(WorldPlane &plane) { | |||
auto bounds = getBounds(); | |||
bool collided = false; | |||
on_ground_ = false; | |||
@@ -83,11 +84,11 @@ void Body::collideY(WorldPlane &plane) { | |||
} | |||
} | |||
void Body::outline(Win &win) { | |||
void PhysicsBody::outline(Win &win) { | |||
win.drawRect(pos_, size_); | |||
} | |||
void Body::update(WorldPlane &plane, float dt) { | |||
void PhysicsBody::update(WorldPlane &plane, float dt) { | |||
vel_ += (force_ / mass_) * dt; | |||
force_ = { 0, 0 }; | |||
@@ -97,10 +98,11 @@ void Body::update(WorldPlane &plane, float dt) { | |||
collideY(plane); | |||
} | |||
void Body::updateWithoutCollision(float dt) { | |||
void PhysicsBody::updateWithoutCollision(float dt) { | |||
vel_ += (force_ / mass_) * dt; | |||
pos_ += vel_ * dt; | |||
force_ = { 0, 0 }; | |||
} | |||
} | |||
} |