Browse Source

much more reliable collisions

opengl-renderer-broken
Martin Dørum 4 years ago
parent
commit
41acf5762e

+ 7
- 5
core.mod/src/entities/EntItemStack.cc View File

@@ -4,12 +4,15 @@

EntItemStack::EntItemStack(const Swan::Context &ctx, const Swan::SRF &params):
PhysicsEntity(SIZE, MASS) {
PhysicsEntity::body_.bounciness_ = 0.6;

readSRF(ctx, params);

static std::uniform_real_distribution dis(-0.2f, 0.2f);
static std::uniform_real_distribution vx(-2.3f, 2.3f);
static std::uniform_real_distribution vy(-2.3f, -1.2f);

body_.pos_ += Swan::Vec2{ dis(ctx.world.random_), dis(ctx.world.random_) };
body_.pos_.y += 0.5 - body_.size_.y / 2;
body_.vel_ += Swan::Vec2{ vx(ctx.world.random_), vy(ctx.world.random_) };
}

void EntItemStack::draw(const Swan::Context &ctx, Swan::Win &win) {
@@ -19,9 +22,8 @@ void EntItemStack::draw(const Swan::Context &ctx, Swan::Win &win) {

void EntItemStack::tick(const Swan::Context &ctx, float dt) {
despawn_timer_ -= dt;
if (despawn_timer_ <= 0) {
ctx.plane.despawnEntity(*this);
}
if (despawn_timer_ <= 0)
ctx.plane.despawnEntity(*this);
}

void EntItemStack::readSRF(const Swan::Context &ctx, const Swan::SRF &srf) {

+ 1
- 1
core.mod/src/entities/EntPlayer.h View File

@@ -20,7 +20,7 @@ public:

private:
static constexpr float FORCE = 3000;
static constexpr float JUMP_FORCE = 10;
static constexpr float JUMP_FORCE = 11;
static constexpr float MASS = 80;
static constexpr Swan::Vec2 SIZE = Swan::Vec2(0.6, 1.9);


+ 9
- 3
libswan/include/swan/Body.h View File

@@ -16,19 +16,25 @@ public:

void friction(Vec2 coef = Vec2(400, 50));
void gravity(Vec2 g = Vec2(0, 20));
void collide(WorldPlane &plane);

void outline(Win &win);
void update(float dt);
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_;
bool on_ground_ = false;
float bounciness_ = 0;
float mushyness_ = 2;

private:
void collideX(WorldPlane &plane);
void collideY(WorldPlane &plane);
};

}

+ 5
- 0
libswan/include/swan/BoundingBox.h View File

@@ -7,6 +7,11 @@ 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; }
};

}

+ 1
- 2
libswan/include/swan/Entity.h View File

@@ -47,8 +47,7 @@ public:
virtual void update(const Context &ctx, float dt) override {
body_.friction();
body_.gravity();
body_.update(dt);
body_.collide(ctx.plane);
body_.update(ctx.plane, dt);
}

virtual void move(const Vec2 &rel) override { body_.pos_ += rel; }

+ 67
- 41
libswan/src/Body.cc View File

@@ -1,12 +1,16 @@
#include "Body.h"

#include <math.h>
#include <array>
#include <algorithm>

#include "WorldPlane.h"
#include "Win.h"

namespace Swan {

static float epsilon = 0.0001;

void Body::friction(Vec2 coef) {
force_ += -vel_ * coef;
}
@@ -15,55 +19,67 @@ void Body::gravity(Vec2 g) {
force_ += g * mass_;
}

void Body::collide(WorldPlane &plane) {
int startx, endx, y;

// This collission code is horrible and in dire need of some more abstractions.
// I will fix later, ok? This works for now while working on more interesting things.

// Collide with sides
startx = (int)floor(pos_.x);
endx = (int)floor(pos_.x + size_.x);
y = (int)ceil(pos_.y + size_.y - 1.3);
for (int x = startx; x <= endx; ++x) {
for (int ry = y - 1; ry <= y; ++ry) {
Tile &wall = plane.getTile(TilePos(x, ry));
if (x == startx && vel_.x < 0 && wall.is_solid) {
vel_.x = 0;
pos_.x = startx + 1.001;
startx = (int)floor(pos_.x);
} else if (x == endx && vel_.x > 0 && wall.is_solid) {
vel_.x = 0;
pos_.x = (float)endx - size_.x - 0.001;
endx = (int)floor(pos_.x + size_.x);
}
//plane.debugBox(TilePos(x, ry));
void Body::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;
}
}

// Collide with top
y = (int)ceil(pos_.y - 1);
for (int x = startx; x <= endx; ++x) {
Tile &roof = plane.getTile(TilePos(x, y));
if (roof.is_solid && vel_.y < 0) {
pos_.y = y + 1;
vel_.y = 0;
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;
}
}

//plane.debugBox(TilePos(x, y));
if (collided) {
pos_.x = bounds.pos.x;

vel_.x *= -bounciness_;
if (abs(vel_.x) < mushyness_)
vel_.x = 0;
}
}

// Collide with floor
void Body::collideY(WorldPlane &plane) {
auto bounds = getBounds();
bool collided = false;
on_ground_ = false;
y = (int)ceil(pos_.y + size_.y - 1);
for (int x = startx; x <= endx; ++x) {
Tile &ground = plane.getTile(TilePos(x, y));
if (ground.is_solid && vel_.y > 0) {
pos_.y = (float)y - size_.y;
vel_.y = 0;

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 &right = plane.getTile({ x, by });
if (right.is_solid) {
bounds.pos.y = (float)by - bounds.size.y;
collided = true;
on_ground_ = true;
break;
}
//plane.debugBox(TilePos(x, y));
}

if (collided) {
pos_.y = bounds.pos.y;

vel_.y *= -bounciness_;
if (abs(vel_.y) < mushyness_)
vel_.y = 0;
}
}

@@ -76,7 +92,17 @@ void Body::outline(Win &win) {
win.draw(rect);
}

void Body::update(float dt) {
void Body::update(WorldPlane &plane, float dt) {
vel_ += (force_ / mass_) * dt;
force_ = { 0, 0 };

pos_.x += vel_.x * dt;
collideX(plane);
pos_.y += vel_.y * dt;
collideY(plane);
}

void Body::updateWithoutCollision(float dt) {
vel_ += (force_ / mass_) * dt;
pos_ += vel_ * dt;
force_ = { 0, 0 };

Loading…
Cancel
Save