void physics_step(DB& db, double timeStep) { using std::get; using components::Velocity; using components::BoundingBox; using components::Solid; using components::NoCollide; using Ginseng::Not; auto gravity = 1500.0; auto bb_vels = db.query<BoundingBox, Velocity, Not<NoCollide>>(); auto bbs = db.query<BoundingBox, Not<NoCollide>>(); for (auto ent : db.query<CollisionData>()) { db.eraseComponent(get<1>(ent).id()); } for (auto ent_v : bb_vels) { Velocity &v_vel = get<2>(ent_v).data(); v_vel.acc.y += gravity; for (auto& p : v_vel.timed_accs) { double t = std::min(p.second,timeStep); p.second -= t; v_vel.acc += p.first * float(t/timeStep); } v_vel.timed_accs.erase(std::remove_if(v_vel.timed_accs.begin(), v_vel.timed_accs.end(), [](auto& p){return p.second<=0;}), v_vel.timed_accs.end()); } auto do_axis = [&](auto get_axis) { for (auto ent_v : bb_vels) //search entities with velocities { EntID v_eid = get<0>(ent_v); BoundingBox &v_bb = get<1>(ent_v).data(); Velocity &v_vel = get<2>(ent_v).data(); get_axis(v_vel.vel) += get_axis(v_vel.acc) * timeStep; get_axis(v_bb.rect) += get_axis(v_vel.vel) * timeStep + 0.5 * get_axis(v_vel.acc) * timeStep * timeStep; auto v_coll_info = v_eid.get<CollisionData>(); if (!v_coll_info) { db.makeComponent(v_eid, CollisionData{}); v_coll_info = v_eid.get<CollisionData>(); } for (auto ent_bb : bbs) //search entities with bounding boxes { EntID bb_eid = get<0>(ent_bb); BoundingBox &bb = get<1>(ent_bb).data(); if (v_eid == bb_eid) continue; sf::FloatRect isect; sf::FloatRect bbsmall (bb.rect.left, bb.rect.top, bb.rect.width-0.5, bb.rect.height-0.5); if (v_bb.rect.intersects(bbsmall, isect)) { if (bb_eid.get<Solid>()) { if (get_axis(v_bb.rect) < get_axis(bb.rect)) { get_axis(v_bb.rect) -= get_axis.len(isect); } else { get_axis(v_bb.rect) += get_axis.len(isect); } get_axis(v_vel.vel) = 0; get_axis.other(v_vel.vel) -= float(get_axis.other(v_vel.vel)*5*timeStep); //friction } auto bb_coll_info = bb_eid.get<CollisionData>(); if (!bb_coll_info) { db.makeComponent(bb_eid, CollisionData{}); bb_coll_info = bb_eid.get<CollisionData>(); } auto hitdirs = get_axis.hitdirs(v_bb.rect, bb.rect); v_coll_info.data().hits.push_back(CollisionData::Hit{bb_eid,hitdirs.first}); bb_coll_info.data().hits.push_back(CollisionData::Hit{v_eid,hitdirs.second}); } } get_axis(v_vel.acc) = 0; } }; do_axis(GetX{}); do_axis(GetY{}); }