From ac17021d80e865a0f02e0d243aad0e568c18bc84 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 6 Mar 2010 16:50:44 +0000 Subject: [PATCH] First attempt at uphill/downhill physics --- include/IRollingStock.hpp | 2 +- include/ITrackSegment.hpp | 14 +++++++++++++- src/CrossoverTrack.cpp | 1 + src/CurvedTrack.cpp | 1 + src/Engine.cpp | 32 ++++++++++++++++++++++---------- src/Points.cpp | 1 + src/SlopeTrack.cpp | 14 +++++++++++++- src/StraightTrack.cpp | 1 + src/Train.cpp | 9 +++++---- src/Waggon.cpp | 4 ++-- 10 files changed, 60 insertions(+), 19 deletions(-) diff --git a/include/IRollingStock.hpp b/include/IRollingStock.hpp index dc2f437..a76bd57 100644 --- a/include/IRollingStock.hpp +++ b/include/IRollingStock.hpp @@ -27,7 +27,7 @@ struct IRollingStock { virtual ~IRollingStock() {} // Update speed, fuel, etc. - virtual void update(int aDelta) = 0; + virtual void update(int delta, float gradient) = 0; // Display the model virtual void render() const = 0; diff --git a/include/ITrackSegment.hpp b/include/ITrackSegment.hpp index 73a9bb8..b799e79 100644 --- a/include/ITrackSegment.hpp +++ b/include/ITrackSegment.hpp @@ -42,6 +42,9 @@ namespace track { struct TravelToken; typedef function TransformFunc; + typedef function GradientFunc; + + inline float flatGradientFunc(const TravelToken& t, float d) { return 0.0f; } // Sums up all the information required to travel along a piece // of track @@ -57,15 +60,24 @@ namespace track { // assumes that it is initially placed at the origin TransformFunc transformer; + // A function that returns the gradient at any point + GradientFunc gradientf; + // Number of possible exits from this track segment given the direction // we are travelling in int numExits; - // Wrapper for the above + // Wrappers for the above functions + void transform(double aDelta) const { transformer(*this, aDelta); } + + float gradient(float delta) const + { + return gradientf(*this, delta); + } }; } diff --git a/src/CrossoverTrack.cpp b/src/CrossoverTrack.cpp index aa4fc4b..1938daa 100644 --- a/src/CrossoverTrack.cpp +++ b/src/CrossoverTrack.cpp @@ -125,6 +125,7 @@ CrossoverTrack::getTravelToken(track::Position aPosition, aDirection, aPosition, bind(&CrossoverTrack::transform, this, _1, _2), + track::flatGradientFunc, 1 }; return tok; diff --git a/src/CurvedTrack.cpp b/src/CurvedTrack.cpp index 5e23bb1..3ad0979 100644 --- a/src/CurvedTrack.cpp +++ b/src/CurvedTrack.cpp @@ -104,6 +104,7 @@ CurvedTrack::getTravelToken(track::Position aPosition, aDirection, aPosition, bind(&CurvedTrack::transform, this, _1, _2), + track::flatGradientFunc, 1 }; return tok; diff --git a/src/Engine.cpp b/src/Engine.cpp index 3c76ac7..10550a5 100644 --- a/src/Engine.cpp +++ b/src/Engine.cpp @@ -64,7 +64,7 @@ public: // IRollingStock interface void render() const; - void update(int aDelta); + void update(int delta, float gradient); double speed() const { return mySpeed; } IControllerPtr controller() { return shared_from_this(); } @@ -84,6 +84,7 @@ private: double tractiveEffort() const; double resistance() const; double brakeForce() const; + double gravity(float gradient) const; IModelPtr model; @@ -168,6 +169,13 @@ double Engine::resistance() const return sign * (a + b*absSpeed + c*absSpeed*absSpeed); } +// Calculate the resistance due to gravity on a slope +double Engine::gravity(float gradient) const +{ + const double g = 9.78; + return -g * gradient; +} + // Calculate the magnitude of the braking force double Engine::brakeForce() const { @@ -187,7 +195,7 @@ double Engine::brakeForce() const } // Compute the next state of the engine -void Engine::update(int aDelta) +void Engine::update(int delta, float gradient) { // Update the pressure of the boiler // The fire temperature is delayed and then used to increase it @@ -197,27 +205,31 @@ void Engine::update(int aDelta) const double P = tractiveEffort(); const double Q = resistance(); const double B = isBrakeOn ? brakeForce() : 0.0; + const double G = gravity(gradient); // The applied tractive effort is controlled by the throttle const double netP = P * static_cast(myThrottle) / 10.0; - const double deltaSeconds = aDelta / 1000.0f; - const double a = ((netP - Q - B) / myMass) * deltaSeconds; + const double deltaSeconds = delta / 1000.0f; + const double a = ((netP - Q - B - G) / myMass) * deltaSeconds; // mySpeed = max(mySpeed + a, 0.0); mySpeed += a; - if (abs(mySpeed) < STOP_SPEED && myThrottle == 0) { + if (abs(mySpeed) < STOP_SPEED && myThrottle == 0 && isBrakeOn) { mySpeed = 0.0; haveStopped = true; } else haveStopped = false; - - // debug() << "P=" << netP << ", Q=" << Q - // << ", B=" << B - // << ", a=" << a << ", v=" << mySpeed - // << " (delta=" << aDelta << ")"; + +#if 1 + debug() << "P=" << netP << ", Q=" << Q + << ", B=" << B + << ", G=" << G + << ", a=" << a << ", v=" << mySpeed + << " (delta=" << delta << " grad=" << gradient << ")"; +#endif } // User interface to the engine diff --git a/src/Points.cpp b/src/Points.cpp index 41234e5..b41c54b 100644 --- a/src/Points.cpp +++ b/src/Points.cpp @@ -260,6 +260,7 @@ track::TravelToken Points::getTravelToken(track::Position position, direction, position, bind(&Points::transform, this, _1, _2), + track::flatGradientFunc, nExits }; diff --git a/src/SlopeTrack.cpp b/src/SlopeTrack.cpp index d875720..8617eb6 100644 --- a/src/SlopeTrack.cpp +++ b/src/SlopeTrack.cpp @@ -58,6 +58,7 @@ public: private: void ensureValidDirection(const track::Direction& dir) const; void transform(const track::TravelToken& token, double delta) const; + float gradient(const track::TravelToken& token, float delta) const; Point origin; float height; @@ -192,14 +193,25 @@ track::TravelToken SlopeTrack::getTravelToken(track::Position pos, dir, pos, bind(&SlopeTrack::transform, this, _1, _2), + bind(&SlopeTrack::gradient, this, _1, _2), 1 }; return tok; } +float SlopeTrack::gradient(const track::TravelToken& token, float delta) const +{ + assert(delta < length && delta >= 0.0f); + + if (token.direction == -axis) + delta = length - delta; + + return curve.deriv(delta).y; +} + void SlopeTrack::transform(const track::TravelToken& token, double delta) const { - assert(delta < length); + assert(delta < length && delta >= 0.0f); #if 0 debug() << "f(0)=" << curve(0.0f) diff --git a/src/StraightTrack.cpp b/src/StraightTrack.cpp index ec9acf6..a8d5e40 100644 --- a/src/StraightTrack.cpp +++ b/src/StraightTrack.cpp @@ -97,6 +97,7 @@ StraightTrack::getTravelToken(track::Position aPosition, aDirection, aPosition, bind(&StraightTrack::transform, this, _1, _2), + track::flatGradientFunc, 1 }; return tok; diff --git a/src/Train.cpp b/src/Train.cpp index 12c8ff7..93b39e8 100644 --- a/src/Train.cpp +++ b/src/Train.cpp @@ -276,27 +276,28 @@ void Train::updateSmokePosition(int aDelta) smokeTrail->setDelay(baseDelay - (throttle * 15)); } -void Train::update(int aDelta) +void Train::update(int delta) { int oldSpeedSign = engine().vehicle->speed() >= 0.0 ? 1 : 0; for (list::iterator it = parts.begin(); it != parts.end(); ++it) - (*it).vehicle->update(aDelta); + (*it).vehicle->update(delta, + (*it).travelToken.gradient((*it).segmentDelta)); int newSpeedSign = engine().vehicle->speed() >= 0.0 ? 1 : 0; if (oldSpeedSign != newSpeedSign) flipLeader(); - updateSmokePosition(aDelta); + updateSmokePosition(delta); // How many metres does a tile correspond to? const double M_PER_UNIT = 5.0; const Vector oldPos = partPosition(engine()); - const double deltaSeconds = static_cast(aDelta) / 1000.0f; + const double deltaSeconds = static_cast(delta) / 1000.0f; move(engine().vehicle->speed() * deltaSeconds / M_PER_UNIT); velocityVector = partPosition(engine()) - oldPos; diff --git a/src/Waggon.cpp b/src/Waggon.cpp index 52b117c..c56d5cd 100644 --- a/src/Waggon.cpp +++ b/src/Waggon.cpp @@ -33,7 +33,7 @@ public: ~Waggon() {} // IRollingStock interface - void update(int aDelta); + void update(int delta, float gradient); void render() const; IControllerPtr controller(); double speed() const { return 0.0; } @@ -65,7 +65,7 @@ void Waggon::text(const string& localName, const string& aString) model = loadModel(resource, aString, MODEL_SCALE); } -void Waggon::update(int aDelta) +void Waggon::update(int delta, float gradient) { } -- 2.39.2