@@ -10,9 +10,9 @@ ItemStackEntity::ItemStackEntity( | |||
static std::uniform_real_distribution vy(-2.3f, -1.2f); | |||
item_ = &ctx.world.getItem(item); | |||
body_.pos_ = pos; | |||
body_.pos_.y += 0.5 - body_.size_.y / 2; | |||
body_.vel_ += Swan::Vec2{ vx(ctx.world.random_), vy(ctx.world.random_) }; | |||
body_.pos = pos; | |||
body_.pos.y += 0.5 - body_.size.y / 2; | |||
physics_.vel += Swan::Vec2{ vx(ctx.world.random_), vy(ctx.world.random_) }; | |||
} | |||
ItemStackEntity::ItemStackEntity(const Swan::Context &ctx, const PackObject &obj): | |||
@@ -26,10 +26,14 @@ void ItemStackEntity::draw(const Swan::Context &ctx, Swan::Win &win) { | |||
SDL_Texture *tex = item_->image_.texture_.get(); | |||
Swan::TexColorMod darken(tex, 220, 220, 220); | |||
win.showTexture(body_.pos_, tex, &rect, | |||
win.showTexture(body_.pos, tex, &rect, | |||
{ .hscale = 0.5, .vscale = 0.5 }); | |||
} | |||
void ItemStackEntity::update(const Swan::Context &ctx, float dt) { | |||
physics(ctx, dt, { .mass = MASS, .bounciness = 0.6 }); | |||
} | |||
void ItemStackEntity::tick(const Swan::Context &ctx, float dt) { | |||
despawn_timer_ -= dt; | |||
if (despawn_timer_ <= 0) | |||
@@ -37,13 +41,13 @@ void ItemStackEntity::tick(const Swan::Context &ctx, float dt) { | |||
} | |||
void ItemStackEntity::deserialize(const Swan::Context &ctx, const PackObject &obj) { | |||
body_.pos_ = obj.at("pos").as<Swan::Vec2>(); | |||
body_.pos = obj.at("pos").as<Swan::Vec2>(); | |||
item_ = &ctx.world.getItem(obj.at("item").as<std::string>()); | |||
} | |||
Swan::Entity::PackObject ItemStackEntity::serialize(const Swan::Context &ctx, msgpack::zone &zone) { | |||
return { | |||
{ "pos", msgpack::object(body_.pos_, zone) }, | |||
{ "pos", msgpack::object(body_.pos, zone) }, | |||
{ "tile", msgpack::object(item_->name_, zone) }, | |||
}; | |||
} |
@@ -8,6 +8,7 @@ public: | |||
ItemStackEntity(const Swan::Context &ctx, const PackObject &obj); | |||
void draw(const Swan::Context &ctx, Swan::Win &win) override; | |||
void update(const Swan::Context &ctx, float dt) override; | |||
void tick(const Swan::Context &ctx, float dt) override; | |||
void deserialize(const Swan::Context &ctx, const PackObject &obj) override; | |||
PackObject serialize(const Swan::Context &ctx, msgpack::zone &zone) override; | |||
@@ -16,10 +17,9 @@ private: | |||
static constexpr float MASS = 80; | |||
static constexpr Swan::Vec2 SIZE = Swan::Vec2(0.5, 0.5); | |||
static constexpr float DESPAWN_TIME = 5 * 60; | |||
static constexpr float BOUNCINESS = 0.6; | |||
ItemStackEntity(): PhysicsEntity(SIZE, MASS) { | |||
PhysicsEntity::body_.bounciness_ = 0.6; | |||
} | |||
ItemStackEntity(): PhysicsEntity(SIZE) {} | |||
float despawn_timer_ = DESPAWN_TIME; | |||
Swan::Item *item_ = NULL; |
@@ -6,7 +6,7 @@ | |||
PlayerEntity::PlayerEntity(const Swan::Context &ctx, Swan::Vec2 pos): | |||
PlayerEntity(ctx) { | |||
body_.pos_ = pos; | |||
body_.pos = pos; | |||
} | |||
PlayerEntity::PlayerEntity(const Swan::Context &ctx, const PackObject &obj): | |||
@@ -16,7 +16,7 @@ PlayerEntity::PlayerEntity(const Swan::Context &ctx, const PackObject &obj): | |||
void PlayerEntity::draw(const Swan::Context &ctx, Swan::Win &win) { | |||
body_.outline(win); | |||
anims_[(int)state_].draw(body_.pos_ - Swan::Vec2(0.2, 0.1), win); | |||
anims_[(int)state_].draw(body_.pos - Swan::Vec2(0.2, 0.1), win); | |||
} | |||
void PlayerEntity::update(const Swan::Context &ctx, float dt) { | |||
@@ -33,13 +33,13 @@ void PlayerEntity::update(const Swan::Context &ctx, float dt) { | |||
// Move left | |||
if (ctx.game.isKeyPressed(SDL_SCANCODE_A) || ctx.game.isKeyPressed(SDL_SCANCODE_LEFT)) { | |||
body_.force_ += Swan::Vec2(-MOVE_FORCE, 0); | |||
physics_.force += Swan::Vec2(-MOVE_FORCE, 0); | |||
state_ = State::RUNNING_L; | |||
} | |||
// Move right | |||
if (ctx.game.isKeyPressed(SDL_SCANCODE_D) || ctx.game.isKeyPressed(SDL_SCANCODE_RIGHT)) { | |||
body_.force_ += Swan::Vec2(MOVE_FORCE, 0); | |||
physics_.force += Swan::Vec2(MOVE_FORCE, 0); | |||
if (state_ == State::RUNNING_L) | |||
state_ = State::IDLE; | |||
else | |||
@@ -49,25 +49,25 @@ void PlayerEntity::update(const Swan::Context &ctx, float dt) { | |||
bool jump_pressed = ctx.game.isKeyPressed(SDL_SCANCODE_SPACE); | |||
// Jump | |||
if (body_.on_ground_ && jump_pressed && jump_timer_.periodic(0.5)) { | |||
body_.vel_.y = -JUMP_VEL; | |||
if (physics_.on_ground && jump_pressed && jump_timer_.periodic(0.5)) { | |||
physics_.vel.y = -JUMP_VEL; | |||
} | |||
// Fall down faster than we went up | |||
if (!body_.on_ground_ && (!jump_pressed || body_.vel_.y > 0)) | |||
body_.force_ += Swan::Vec2(0, DOWN_FORCE); | |||
if (!physics_.on_ground && (!jump_pressed || physics_.vel.y > 0)) | |||
physics_.force += Swan::Vec2(0, DOWN_FORCE); | |||
if (state_ != oldState) | |||
anims_[(int)state_].reset(); | |||
anims_[(int)state_].tick(dt); | |||
PhysicsEntity::update(ctx, dt); | |||
physics(ctx, dt, { .mass = MASS }); | |||
} | |||
void PlayerEntity::tick(const Swan::Context &ctx, float dt) { | |||
for (ItemStackEntity *ent: ctx.plane.getEntsOfType<ItemStackEntity>()) { | |||
float squared_dist = | |||
(getBody().getBounds().bottomMid() - ent->getBody().getBounds().center()) | |||
(body_.bottomMid() - ent->get(Swan::BodyTrait::Tag{}).center()) | |||
.squareLength(); | |||
if (squared_dist < 0.5 * 0.5) { |
@@ -25,7 +25,7 @@ private: | |||
static constexpr Swan::Vec2 SIZE = Swan::Vec2(0.6, 1.9); | |||
PlayerEntity(const Swan::Context &ctx): | |||
PhysicsEntity(SIZE, MASS), inventory_(INVENTORY_SIZE), | |||
PhysicsEntity(SIZE), inventory_(INVENTORY_SIZE), | |||
anims_{ | |||
Swan::Animation(ctx.resources.getImage("core/entity/player-still"), 0.8), | |||
Swan::Animation( |
@@ -1,5 +1,6 @@ | |||
add_library(libswan SHARED | |||
src/traits/BodyTrait.cc | |||
src/traits/PhysicsTrait.cc | |||
src/Animation.cc | |||
src/Chunk.cc | |||
src/Clock.cc |
@@ -7,6 +7,7 @@ | |||
#include "common.h" | |||
#include "log.h" | |||
#include "traits/BodyTrait.h" | |||
#include "traits/PhysicsTrait.h" | |||
namespace Swan { | |||
@@ -44,20 +45,24 @@ public: | |||
size_t generation_; | |||
}; | |||
class PhysicsEntity: public Entity, public BodyTrait::HasBody { | |||
class PhysicsEntity: public Entity, public BodyTrait, public PhysicsTrait { | |||
public: | |||
PhysicsEntity(Vec2 size, float mass): | |||
body_(size, mass) {} | |||
PhysicsEntity(Vec2 size): body_({ .size = size }) {} | |||
virtual BodyTrait::Body &getBody() override { return body_; } | |||
BodyTrait::Body &get(BodyTrait::Tag) override { return body_; } | |||
PhysicsTrait::Physics &get(PhysicsTrait::Tag) override { return physics_; } | |||
virtual void update(const Context &ctx, float dt) override { | |||
body_.standardForces(); | |||
body_.update(ctx, dt); | |||
void physics( | |||
const Context &ctx, float dt, | |||
const PhysicsTrait::PhysicsProps &props) { | |||
physics_.standardForces(props.mass); | |||
physics_.update(ctx, dt, body_, props); | |||
} | |||
protected: | |||
BodyTrait::PhysicsBody body_; | |||
BodyTrait::Body body_; | |||
PhysicsTrait::Physics physics_; | |||
}; | |||
} |
@@ -59,7 +59,7 @@ public: | |||
std::unordered_map<std::string, WorldGen::Factory> worldgen_factories_; | |||
std::vector<EntityCollection::Factory> ent_coll_factories_; | |||
BodyTrait::HasBody *player_; | |||
BodyTrait::Body *player_; | |||
Game *game_; | |||
std::mt19937 random_; |
@@ -1,99 +1,39 @@ | |||
#pragma once | |||
#include "../common.h" | |||
#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; | |||
float left() { return pos.x; } | |||
float right() { return pos.x + size.x; } | |||
float midX() { return pos.x + size.x / 2; } | |||
float top() { return pos.y; } | |||
float bottom() { return pos.y + size.y; } | |||
float midY() { return pos.y + size.y / 2; } | |||
Vec2 topLeft() { return { left(), top() }; } | |||
Vec2 midLeft() { return { left(), midY() }; } | |||
Vec2 bottomLeft() { return { left(), bottom() }; } | |||
Vec2 topMid() { return { midX(), top() }; } | |||
Vec2 center() { return { midX(), midY() }; } | |||
Vec2 bottomMid() { return { midX(), bottom() }; } | |||
Vec2 topRight() { return { right(), top() }; } | |||
Vec2 midRight() { return { right(), midY() }; } | |||
Vec2 bottomRight() { return { right(), bottom() }; } | |||
}; | |||
class Body { | |||
public: | |||
virtual ~Body() = default; | |||
virtual Bounds getBounds() = 0; | |||
virtual void move(Vec2 rel) = 0; | |||
virtual void moveTo(Vec2 pos) = 0; | |||
}; | |||
// PhysicsBody is a 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) override { pos_ += rel; } | |||
void moveTo(Vec2 pos) override { pos_ = pos; } | |||
void friction(Vec2 coef = Vec2(400, 50)); | |||
void gravity(Vec2 g = Vec2(0, 20)); | |||
void standardForces() { friction(); gravity(); } | |||
void outline(Win &win); | |||
void update(const Swan::Context &ctx, 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); | |||
struct BodyTrait { | |||
struct Body; | |||
struct Tag {}; | |||
virtual Body &get(Tag) = 0; | |||
struct Body { | |||
Vec2 pos{}; | |||
Vec2 size{}; | |||
float left() { return pos.x; } | |||
float right() { return pos.x + size.x; } | |||
float midX() { return pos.x + size.x / 2; } | |||
float top() { return pos.y; } | |||
float bottom() { return pos.y + size.y; } | |||
float midY() { return pos.y + size.y / 2; } | |||
Vec2 topLeft() { return { left(), top() }; } | |||
Vec2 midLeft() { return { left(), midY() }; } | |||
Vec2 bottomLeft() { return { left(), bottom() }; } | |||
Vec2 topMid() { return { midX(), top() }; } | |||
Vec2 center() { return { midX(), midY() }; } | |||
Vec2 bottomMid() { return { midX(), bottom() }; } | |||
Vec2 topRight() { return { right(), top() }; } | |||
Vec2 midRight() { return { right(), midY() }; } | |||
Vec2 bottomRight() { return { right(), bottom() }; } | |||
void outline(Win &win); | |||
}; | |||
}; | |||
// StaticBody is a BodyTrait::Body which just has a static | |||
// position and size. | |||
class StaticBody: public Body { | |||
public: | |||
StaticBody(Vec2 size, Vec2 pos): | |||
size_(size), pos_(pos) {} | |||
BodyTrait::Bounds getBounds() override { return BodyTrait::Bounds{ pos_, size_ }; } | |||
void move(Vec2 rel) override { pos_ += rel; } | |||
void moveTo(Vec2 pos) override { pos_ = pos; } | |||
Vec2 size_; | |||
Vec2 pos_; | |||
}; | |||
} | |||
} |
@@ -0,0 +1,47 @@ | |||
#pragma once | |||
#include "../traits/BodyTrait.h" | |||
#include "../Vector2.h" | |||
#include "../common.h" | |||
namespace Swan { | |||
struct PhysicsTrait { | |||
struct Physics; | |||
struct Tag {}; | |||
virtual Physics &get(Tag) = 0; | |||
struct PhysicsProps { | |||
float mass; | |||
float bounciness = 0; | |||
float mushyness = 2; | |||
}; | |||
struct Physics { | |||
Vec2 vel{}; | |||
Vec2 force{}; | |||
bool on_ground = 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 update( | |||
const Swan::Context &ctx, float dt, | |||
BodyTrait::Body &body, const PhysicsProps &props); | |||
}; | |||
}; | |||
/* | |||
* Physics | |||
*/ | |||
inline void PhysicsTrait::Physics::friction(Vec2 coef) { | |||
force += -vel * coef; | |||
} | |||
inline void PhysicsTrait::Physics::gravity(float mass, Vec2 g) { | |||
force += g * mass; | |||
} | |||
} |
@@ -83,8 +83,8 @@ void World::setWorldGen(std::string gen) { | |||
} | |||
void World::spawnPlayer() { | |||
player_ = dynamic_cast<BodyTrait::HasBody *>( | |||
planes_[current_plane_].spawnPlayer().get()); | |||
player_ = &((dynamic_cast<BodyTrait *>( | |||
planes_[current_plane_].spawnPlayer().get()))->get(BodyTrait::Tag{})); | |||
} | |||
void World::setCurrentPlane(WorldPlane &plane) { | |||
@@ -142,8 +142,7 @@ SDL_Color World::backgroundColor() { | |||
void World::draw(Win &win) { | |||
ZoneScopedN("World draw"); | |||
auto bounds = player_->getBody().getBounds(); | |||
win.cam_ = bounds.pos - (win.getSize() / 2) + (bounds.size / 2); | |||
win.cam_ = player_->pos - (win.getSize() / 2) + (player_->size / 2); | |||
planes_[current_plane_].draw(win); | |||
} | |||
@@ -158,10 +157,9 @@ void World::tick(float dt) { | |||
for (auto &plane: planes_) | |||
plane.tick(dt); | |||
auto bounds = player_->getBody().getBounds(); | |||
chunk_renderer_.tick( | |||
planes_[current_plane_], | |||
ChunkPos((int)bounds.pos.x / CHUNK_WIDTH, (int)bounds.pos.y / CHUNK_HEIGHT)); | |||
ChunkPos((int)player_->pos.x / CHUNK_WIDTH, (int)player_->pos.y / CHUNK_HEIGHT)); | |||
} | |||
} |
@@ -163,19 +163,19 @@ void WorldPlane::breakTile(TilePos pos) { | |||
} | |||
SDL_Color WorldPlane::backgroundColor() { | |||
return gen_->backgroundColor(world_->player_->getBody().getBounds().pos); | |||
return gen_->backgroundColor(world_->player_->pos); | |||
} | |||
void WorldPlane::draw(Win &win) { | |||
ZoneScopedN("WorldPlane draw"); | |||
auto ctx = getContext(); | |||
auto pbounds = world_->player_->getBody().getBounds(); | |||
auto &pbody = *(world_->player_); | |||
gen_->drawBackground(ctx, win, pbounds.pos); | |||
gen_->drawBackground(ctx, win, pbody.pos); | |||
ChunkPos pcpos = ChunkPos( | |||
(int)floor(pbounds.pos.x / CHUNK_WIDTH), | |||
(int)floor(pbounds.pos.y / CHUNK_HEIGHT)); | |||
(int)floor(pbody.pos.x / CHUNK_WIDTH), | |||
(int)floor(pbody.pos.y / CHUNK_HEIGHT)); | |||
// Just init one chunk per frame | |||
if (chunk_init_list_.size() > 0) { |
@@ -1,125 +1,11 @@ | |||
#include "traits/BodyTrait.h" | |||
#include <math.h> | |||
#include <array> | |||
#include <algorithm> | |||
#include "WorldPlane.h" | |||
#include "Win.h" | |||
namespace Swan { | |||
namespace BodyTrait { | |||
static float epsilon = 0.001; | |||
void PhysicsBody::friction(Vec2 coef) { | |||
force_ += -vel_ * coef; | |||
} | |||
void PhysicsBody::gravity(Vec2 g) { | |||
force_ += g * mass_; | |||
} | |||
void PhysicsBody::collideX(WorldPlane &plane) { | |||
auto bounds = getBounds(); | |||
bool collided = false; | |||
for (int y = (int)floor(bounds.top() + epsilon); y <= (int)floor(bounds.bottom() - epsilon); ++y) { | |||
int lx = (int)floor(bounds.left() + epsilon); | |||
Tile &left = plane.getTile({ lx, y }); | |||
if (left.is_solid_) { | |||
bounds.pos.x = (float)lx + 1.0; | |||
collided = true; | |||
break; | |||
} | |||
int rx = (int)floor(bounds.right() - epsilon); | |||
Tile &right = plane.getTile({ rx, y }); | |||
if (right.is_solid_) { | |||
bounds.pos.x = (float)rx - bounds.size.x; | |||
collided = true; | |||
break; | |||
} | |||
} | |||
if (collided) { | |||
pos_.x = bounds.pos.x; | |||
vel_.x *= -bounciness_; | |||
if (abs(vel_.x) < mushyness_) | |||
vel_.x = 0; | |||
} | |||
} | |||
void PhysicsBody::collideY(WorldPlane &plane) { | |||
auto bounds = getBounds(); | |||
bool collided = false; | |||
on_ground_ = false; | |||
for (int x = (int)floor(bounds.left() + epsilon); x <= (int)floor(bounds.right() - epsilon); ++x) { | |||
int ty = (int)floor(bounds.top() + epsilon); | |||
Tile &top = plane.getTile({ x, ty }); | |||
if (top.is_solid_) { | |||
bounds.pos.y = (float)ty + 1.0; | |||
collided = true; | |||
break; | |||
} | |||
int by = (int)floor(bounds.bottom() - epsilon); | |||
Tile &bottom = plane.getTile({ x, by }); | |||
if (bottom.is_solid_) { | |||
bounds.pos.y = (float)by - bounds.size.y; | |||
collided = true; | |||
on_ground_ = true; | |||
break; | |||
} | |||
} | |||
if (collided) { | |||
pos_.y = bounds.pos.y; | |||
vel_.y *= -bounciness_; | |||
if (abs(vel_.y) < mushyness_) | |||
vel_.y = 0; | |||
} | |||
void BodyTrait::Body::outline(Win &win) { | |||
win.drawRect(pos, size); | |||
} | |||
void PhysicsBody::outline(Win &win) { | |||
win.drawRect(pos_, size_); | |||
} | |||
void PhysicsBody::update(const Swan::Context &ctx, float dt) { | |||
vel_ += (force_ / mass_) * dt; | |||
force_ = { 0, 0 }; | |||
Vec2 dist = vel_ * dt; | |||
Vec2 dir = dist.sign(); | |||
Vec2 step = dir * 0.4; | |||
// Move in increments of at most 'step', on the X axis | |||
while (abs(dist.x) > abs(step.x)) { | |||
pos_.x += step.x; | |||
collideX(ctx.plane); | |||
dist.x -= step.x; | |||
} | |||
pos_.x += dist.x; | |||
collideX(ctx.plane); | |||
// Move in increments of at most 'step', on the Y axis | |||
while (abs(dist.y) > abs(step.y)) { | |||
pos_.y += step.y; | |||
collideY(ctx.plane); | |||
dist.y -= step.y; | |||
} | |||
pos_.y += dist.y; | |||
collideY(ctx.plane); | |||
} | |||
void PhysicsBody::updateWithoutCollision(float dt) { | |||
vel_ += (force_ / mass_) * dt; | |||
pos_ += vel_ * dt; | |||
force_ = { 0, 0 }; | |||
} | |||
} | |||
} |
@@ -0,0 +1,101 @@ | |||
#include "traits/PhysicsTrait.h" | |||
#include "WorldPlane.h" | |||
#include "Win.h" | |||
namespace Swan { | |||
static float epsilon = 0.001; | |||
static void collideX( | |||
PhysicsTrait::Physics &phys, BodyTrait::Body &body, | |||
WorldPlane &plane, const PhysicsTrait::PhysicsProps &props) { | |||
bool collided = false; | |||
for (int y = (int)floor(body.top() + epsilon); y <= (int)floor(body.bottom() - epsilon); ++y) { | |||
int lx = (int)floor(body.left() + epsilon); | |||
Tile &left = plane.getTile({ lx, y }); | |||
if (left.is_solid_) { | |||
body.pos.x = (float)lx + 1.0; | |||
collided = true; | |||
break; | |||
} | |||
int rx = (int)floor(body.right() - epsilon); | |||
Tile &right = plane.getTile({ rx, y }); | |||
if (right.is_solid_) { | |||
body.pos.x = (float)rx - body.size.x; | |||
collided = true; | |||
break; | |||
} | |||
} | |||
if (collided) { | |||
phys.vel.x *= -props.bounciness; | |||
if (abs(phys.vel.x) < props.mushyness) | |||
phys.vel.x = 0; | |||
} | |||
} | |||
static void collideY( | |||
PhysicsTrait::Physics &phys, BodyTrait::Body &body, | |||
WorldPlane &plane, const PhysicsTrait::PhysicsProps &props) { | |||
bool collided = false; | |||
phys.on_ground = false; | |||
for (int x = (int)floor(body.left() + epsilon); x <= (int)floor(body.right() - epsilon); ++x) { | |||
int ty = (int)floor(body.top() + epsilon); | |||
Tile &top = plane.getTile({ x, ty }); | |||
if (top.is_solid_) { | |||
body.pos.y = (float)ty + 1.0; | |||
collided = true; | |||
break; | |||
} | |||
int by = (int)floor(body.bottom() - epsilon); | |||
Tile &bottom = plane.getTile({ x, by }); | |||
if (bottom.is_solid_) { | |||
body.pos.y = (float)by - body.size.y; | |||
collided = true; | |||
phys.on_ground = true; | |||
break; | |||
} | |||
} | |||
if (collided) { | |||
phys.vel.y *= -props.bounciness; | |||
if (abs(phys.vel.y) < props.mushyness) | |||
phys.vel.y = 0; | |||
} | |||
} | |||
void PhysicsTrait::Physics::update( | |||
const Swan::Context &ctx, float dt, | |||
BodyTrait::Body &body, const PhysicsProps &props) { | |||
vel += (force / props.mass) * dt; | |||
force = { 0, 0 }; | |||
Vec2 dist = vel * dt; | |||
Vec2 dir = dist.sign(); | |||
Vec2 step = dir * 0.4; | |||
// Move in increments of at most 'step', on the X axis | |||
while (abs(dist.x) > abs(step.x)) { | |||
body.pos.x += step.x; | |||
collideX(*this, body, ctx.plane, props); | |||
dist.x -= step.x; | |||
} | |||
body.pos.x += dist.x; | |||
collideX(*this, body, ctx.plane, props); | |||
// Move in increments of at most 'step', on the Y axis | |||
while (abs(dist.y) > abs(step.y)) { | |||
body.pos.y += step.y; | |||
collideY(*this, body, ctx.plane, props); | |||
dist.y -= step.y; | |||
} | |||
body.pos.y += dist.y; | |||
collideY(*this, body, ctx.plane, props); | |||
} | |||
} |