// // Path.cpp // OSXGLEssentials // // Created by Joshua Moerman on 10/03/14. // // #include "Path.h" #include #include // A default thingy which makes implementing it easier. A subclass only have to // provide new points, which will be connected (So this is not suitable for // e.g. jumps or circles) struct DefaultBuilder : PathBuilder { // number of vertices in one chunk static constexpr auto chainLength = 8; DefaultBuilder(b2World & world_, b2Vec2 startingPoint) : world(world_) , previous(startingPoint) , current(startingPoint) { fixture.friction = 2.0; } void buildUpTo(float x) override { b2BodyDef groundBodyDef; groundBodyDef.position = {0.0f, -10.0f}; while(current.x < x){ auto oldPreviousPoint = previous; b2Vec2 chainPositions[chainLength]; chainPositions[0] = current; for(int i = 1; i < chainLength; ++i){ chainPositions[i] = next; previous = current; current = next; // we always generate one more, for the b2 ghost vertices generate_next(); } b2ChainShape chain; chain.CreateChain(chainPositions, chainLength); chain.SetPrevVertex(oldPreviousPoint); chain.SetNextVertex(next); fixture.shape = &chain; auto groundBody = world.CreateBody(&groundBodyDef); groundBody->CreateFixture(&fixture); } } virtual void generate_next() = 0; protected: std::mt19937 generator{0}; std::uniform_real_distribution distribution{-1.0, 1.0}; b2World & world; b2Vec2 previous; b2Vec2 current; b2Vec2 next; b2FixtureDef fixture; }; // Creates random terrain, roughness comes with time struct RandomBuilder : DefaultBuilder { RandomBuilder(b2World & world_, b2Vec2 startingPoint) : DefaultBuilder(world_, startingPoint) { generate_next(); } virtual void generate_next() override { auto t = current.x; float m = std::sqrt(0.001f*t + 1) - 1; if(t <= 0) m = 0; float slope = m * distribution(generator); auto rot = b2Rot(slope); next = b2Mul(rot, {10, 0}) + current; } }; // A flat road struct FlatBuilder : DefaultBuilder { FlatBuilder(b2World & world_, b2Vec2 startingPoint) : DefaultBuilder(world_, startingPoint) { generate_next(); } virtual void generate_next() override { b2Vec2 newPiece = {10, 0}; next = newPiece + current; } }; Path::Path(b2World & world_) : world(world_) , impl(new RandomBuilder(world, {-20, 0})) {} void Path::buildUpTo(float x){ impl->buildUpTo(x); }