#include <swan/swan.h> | #include <swan/swan.h> | ||||
class ItemStackEntity: public Swan::PhysicsEntity { | |||||
class ItemStackEntity final: public Swan::PhysicsEntity { | |||||
public: | public: | ||||
ItemStackEntity(const Swan::Context &ctx, Swan::Vec2 pos, const std::string &item); | ItemStackEntity(const Swan::Context &ctx, Swan::Vec2 pos, const std::string &item); | ||||
ItemStackEntity(const Swan::Context &ctx, const PackObject &obj); | ItemStackEntity(const Swan::Context &ctx, const PackObject &obj); |
#include <swan/swan.h> | #include <swan/swan.h> | ||||
#include <array> | #include <array> | ||||
class PlayerEntity: public Swan::PhysicsEntity, public Swan::InventoryTrait { | |||||
class PlayerEntity final: public Swan::PhysicsEntity, public Swan::InventoryTrait { | |||||
public: | public: | ||||
PlayerEntity(const Swan::Context &ctx, Swan::Vec2 pos); | PlayerEntity(const Swan::Context &ctx, Swan::Vec2 pos); | ||||
PlayerEntity(const Swan::Context &ctx, const PackObject &obj); | PlayerEntity(const Swan::Context &ctx, const PackObject &obj); | ||||
Swan::TilePos lightTile_; | Swan::TilePos lightTile_; | ||||
bool placedLight_ = false; | bool placedLight_ = false; | ||||
BasicInventory inventory_{INVENTORY_SIZE}; | |||||
Swan::BasicInventory inventory_{INVENTORY_SIZE}; | |||||
}; | }; |
Entity() = default; | Entity() = default; | ||||
Entity(Entity &&) = default; | Entity(Entity &&) = default; | ||||
virtual ~Entity() = default; | |||||
Entity &operator=(Entity &&) = default; | Entity &operator=(Entity &&) = default; | ||||
void despawn(const Swan::Context &ctx); | void despawn(const Swan::Context &ctx); | ||||
virtual ~Entity() = default; | |||||
virtual void draw(const Context &ctx, Cygnet::Renderer &rnd) {} | virtual void draw(const Context &ctx, Cygnet::Renderer &rnd) {} | ||||
virtual void update(const Context &ctx, float dt) {} | virtual void update(const Context &ctx, float dt) {} | ||||
virtual void tick(const Context &ctx, float dt) {} | virtual void tick(const Context &ctx, float dt) {} | ||||
void physics( | void physics( | ||||
const Context &ctx, float dt, | const Context &ctx, float dt, | ||||
const PhysicsTrait::PhysicsProps &props) { | |||||
const BasicPhysics::Props &props) { | |||||
physics_.standardForces(props.mass); | physics_.standardForces(props.mass); | ||||
physics_.update(ctx, dt, body_, props); | physics_.update(ctx, dt, body_, props); | ||||
protected: | protected: | ||||
BodyTrait::Body body_; | BodyTrait::Body body_; | ||||
PhysicsTrait::Physics physics_; | |||||
BasicPhysics physics_; | |||||
}; | }; | ||||
} | } |
class EventEmitterInterface { | class EventEmitterInterface { | ||||
public: | public: | ||||
virtual void unsubscribe(size_t id) = 0; | virtual void unsubscribe(size_t id) = 0; | ||||
protected: | |||||
~EventEmitterInterface() = default; | |||||
}; | }; | ||||
class EventListener: NonCopyable { | class EventListener: NonCopyable { | ||||
}; | }; | ||||
template<typename... Evt> | template<typename... Evt> | ||||
class EventEmitter: public EventEmitterInterface { | |||||
class EventEmitter final: public EventEmitterInterface { | |||||
public: | public: | ||||
using Callback = std::function<void(Evt...)>; | using Callback = std::function<void(Evt...)>; | ||||
class LightCallback { | class LightCallback { | ||||
public: | public: | ||||
virtual ~LightCallback() = default; | |||||
virtual void onLightChunkUpdated(const LightChunk &chunk, ChunkPos pos) = 0; | virtual void onLightChunkUpdated(const LightChunk &chunk, ChunkPos pos) = 0; | ||||
}; | }; | ||||
namespace Swan { | namespace Swan { | ||||
struct BodyTrait { | struct BodyTrait { | ||||
struct Body; | |||||
struct Tag {}; | struct Tag {}; | ||||
virtual Body &get(Tag) = 0; | |||||
struct Body { | |||||
struct Body final { | |||||
Vec2 pos{}; | Vec2 pos{}; | ||||
Vec2 size{}; | Vec2 size{}; | ||||
Vec2 topRight() { return { right(), top() }; } | Vec2 topRight() { return { right(), top() }; } | ||||
Vec2 midRight() { return { right(), midY() }; } | Vec2 midRight() { return { right(), midY() }; } | ||||
Vec2 bottomRight() { return { right(), bottom() }; } | Vec2 bottomRight() { return { right(), bottom() }; } | ||||
//void outline(Win &win); TODO | |||||
}; | }; | ||||
virtual ~BodyTrait() = default; | |||||
virtual Body &get(Tag) = 0; | |||||
}; | }; | ||||
} | } |
namespace Swan { | namespace Swan { | ||||
struct InventoryTrait { | struct InventoryTrait { | ||||
struct Inventory; | |||||
struct Tag {}; | struct Tag {}; | ||||
virtual Inventory &get(Tag) = 0; | |||||
struct Inventory { | struct Inventory { | ||||
virtual ~Inventory() = default; | virtual ~Inventory() = default; | ||||
ItemStack insert(ItemStack stack) { return insert(0, stack); } | ItemStack insert(ItemStack stack) { return insert(0, stack); } | ||||
}; | }; | ||||
struct BasicInventory: Inventory { | |||||
BasicInventory(int size): content(size) {} | |||||
virtual ~InventoryTrait() = default; | |||||
virtual Inventory &get(Tag) = 0; | |||||
}; | |||||
struct BasicInventory final: InventoryTrait::Inventory { | |||||
BasicInventory(int size): content(size) {} | |||||
std::vector<ItemStack> content; | |||||
std::vector<ItemStack> content; | |||||
int size() override { return content.size(); } | |||||
ItemStack get(int slot) override; | |||||
ItemStack set(int slot, ItemStack stack) override; | |||||
ItemStack insert(int slot, ItemStack stack) override; | |||||
}; | |||||
int size() override { return content.size(); } | |||||
ItemStack get(int slot) override; | |||||
ItemStack set(int slot, ItemStack stack) override; | |||||
ItemStack insert(int slot, ItemStack stack) override; | |||||
}; | }; | ||||
} | } |
namespace Swan { | namespace Swan { | ||||
struct PhysicsTrait { | struct PhysicsTrait { | ||||
struct Physics; | |||||
struct Tag {}; | struct Tag {}; | ||||
struct Physics { | |||||
virtual ~Physics() = default; | |||||
virtual void applyForce(Vec2 force) = 0; | |||||
virtual void addVelocity(Vec2 vel) = 0; | |||||
virtual Vec2 getVelocity() = 0; | |||||
}; | |||||
virtual ~PhysicsTrait() = default; | |||||
virtual Physics &get(Tag) = 0; | virtual Physics &get(Tag) = 0; | ||||
}; | |||||
struct PhysicsProps { | |||||
struct BasicPhysics final: public PhysicsTrait::Physics { | |||||
struct Props { | |||||
float mass; | float mass; | ||||
float bounciness = 0; | float bounciness = 0; | ||||
float mushyness = 2; | float mushyness = 2; | ||||
}; | }; | ||||
struct Physics { | |||||
Vec2 vel{}; | |||||
Vec2 force{}; | |||||
bool onGround = false; | |||||
Vec2 vel{}; | |||||
Vec2 force{}; | |||||
bool onGround = false; | |||||
void friction(Vec2 coef = Vec2(400, 50)); | |||||
void gravity(float mass, Vec2 g = Vec2(0, 20)); | |||||
void standardForces(float mass) { friction(); gravity(mass); } | |||||
void friction(Vec2 coef = Vec2(400, 50)); | |||||
void gravity(float mass, Vec2 g = Vec2(0, 20)); | |||||
void standardForces(float mass) { friction(); gravity(mass); } | |||||
void update( | |||||
const Swan::Context &ctx, float dt, | |||||
BodyTrait::Body &body, const PhysicsProps &props); | |||||
}; | |||||
void applyForce(Vec2 f) override; | |||||
void addVelocity(Vec2 v) override; | |||||
Vec2 getVelocity() override { return vel; } | |||||
void update( | |||||
const Swan::Context &ctx, float dt, | |||||
BodyTrait::Body &body, const Props &props); | |||||
}; | }; | ||||
/* | /* | ||||
* Physics | |||||
* BasicPhysics | |||||
*/ | */ | ||||
inline void PhysicsTrait::Physics::friction(Vec2 coef) { | |||||
inline void BasicPhysics::friction(Vec2 coef) { | |||||
force += -vel * coef; | force += -vel * coef; | ||||
} | } | ||||
inline void PhysicsTrait::Physics::gravity(float mass, Vec2 g) { | |||||
inline void BasicPhysics::gravity(float mass, Vec2 g) { | |||||
force += g * mass; | force += g * mass; | ||||
} | } | ||||
inline void BasicPhysics::applyForce(Vec2 f) { | |||||
force += f; | |||||
} | |||||
inline void BasicPhysics::addVelocity(Vec2 v) { | |||||
vel += v; | |||||
} | |||||
} | } |
include_directories: 'include', | include_directories: 'include', | ||||
dependencies: libswan_deps, | dependencies: libswan_deps, | ||||
link_with: library('swan', | link_with: library('swan', | ||||
'src/traits/BodyTrait.cc', | |||||
'src/traits/InventoryTrait.cc', | 'src/traits/InventoryTrait.cc', | ||||
'src/traits/PhysicsTrait.cc', | 'src/traits/PhysicsTrait.cc', | ||||
'src/Animation.cc', | 'src/Animation.cc', |
#include "traits/BodyTrait.h" | |||||
namespace Swan { | |||||
/* | |||||
void BodyTrait::Body::outline(Win &win) { | |||||
win.drawRect(pos, size); | |||||
} TODO */ | |||||
} |
namespace Swan { | namespace Swan { | ||||
ItemStack InventoryTrait::BasicInventory::get(int slot) { | |||||
ItemStack BasicInventory::get(int slot) { | |||||
if (slot >= (ssize_t)content.size()) | if (slot >= (ssize_t)content.size()) | ||||
return ItemStack{}; | return ItemStack{}; | ||||
return content[slot]; | return content[slot]; | ||||
} | } | ||||
ItemStack InventoryTrait::BasicInventory::set(int slot, ItemStack stack) { | |||||
ItemStack BasicInventory::set(int slot, ItemStack stack) { | |||||
if (slot >= (ssize_t)content.size()) | if (slot >= (ssize_t)content.size()) | ||||
return stack; | return stack; | ||||
return st; | return st; | ||||
} | } | ||||
ItemStack InventoryTrait::BasicInventory::insert(int slot, ItemStack stack) { | |||||
ItemStack BasicInventory::insert(int slot, ItemStack stack) { | |||||
for (int i = 0; !stack.empty() && i < (ssize_t)content.size(); ++i) | for (int i = 0; !stack.empty() && i < (ssize_t)content.size(); ++i) | ||||
stack = content[i].insert(stack); | stack = content[i].insert(stack); | ||||
return stack; | return stack; |
static float epsilon = 0.05; | static float epsilon = 0.05; | ||||
static void collideX( | static void collideX( | ||||
PhysicsTrait::Physics &phys, BodyTrait::Body &body, | |||||
WorldPlane &plane, const PhysicsTrait::PhysicsProps &props) { | |||||
BasicPhysics &phys, BodyTrait::Body &body, | |||||
WorldPlane &plane, const BasicPhysics::Props &props) { | |||||
bool collided = false; | bool collided = false; | ||||
for (int y = (int)floor(body.top() + epsilon); y <= (int)floor(body.bottom() - epsilon); ++y) { | for (int y = (int)floor(body.top() + epsilon); y <= (int)floor(body.bottom() - epsilon); ++y) { | ||||
} | } | ||||
static void collideY( | static void collideY( | ||||
PhysicsTrait::Physics &phys, BodyTrait::Body &body, | |||||
WorldPlane &plane, const PhysicsTrait::PhysicsProps &props) { | |||||
BasicPhysics &phys, BodyTrait::Body &body, | |||||
WorldPlane &plane, const BasicPhysics::Props &props) { | |||||
bool collided = false; | bool collided = false; | ||||
phys.onGround = false; | phys.onGround = false; | ||||
} | } | ||||
} | } | ||||
void PhysicsTrait::Physics::update( | |||||
void BasicPhysics::update( | |||||
const Swan::Context &ctx, float dt, | const Swan::Context &ctx, float dt, | ||||
BodyTrait::Body &body, const PhysicsProps &props) { | |||||
BodyTrait::Body &body, const BasicPhysics::Props &props) { | |||||
vel += (force / props.mass) * dt; | vel += (force / props.mass) * dt; | ||||
force = { 0, 0 }; | force = { 0, 0 }; | ||||