[Home] [Puzzles & Projects] [Delphi Techniques] [Math topics] [Library] [Utilities]
Here's another physical world simulation program that represents a simple gravity driven cart that knows how to accelerate under the influence of gravity and has some rolling friction that will cause it to coast to a stop eventually.
Background & Techniques
This program is a test-bed for for a future Roller Coaster program. The idea is to end up with a TCart object that behaves realistically as it rolls down a track at various angles (up and down), with various levels of gravity, mass, friction.
I'm still developing the code, but thought that this version contains enough interesting concepts to make it worth posting. Let me assure you that, even though the cart behaves pretty well now, I've sent it flying many directions at many speeds while debugging the code. Fun!
Like the Bouncing Ball program, we need to allow for gravity pulling down on a object. Unlike bouncing ball, the cart is constrained by the track so most of the force is probably spent just pushing against the track and only the leftover force is available to move the cart. Let's use theta to represent the angle of the track to the horizon. By convention we'll use positive values for track descending to the right, and negative values for ascending to the right. Then the force due to gravity acting straight down is divided into two components: one pushing at right angles against the track, mass*gravity*cos(theta) and one acting parallel to the track and available to move the cart, mass*gravity*sin(theta). There is some drag trying to keep the cart from accelerating, specifically rolling friction caused by friction in the wheels and axels and the slight deformation of the track as the wheels roll over it. There is also drag due to the cart pushing the air out of the way as it moves, we'll ignore that for now. The opposing force due to rolling friction is proportional to the weight pushing against the track and the coefficient of rolling friction (friction). So opposing force = friction*mass*gravity*cos(theta). The cart will be accelerated, according the Mr. Newton, by an amount directly proportional to the net force applied and inversely proportional to the mass, a=(aiding force-opposing force)/mass. Note that as long as mass is not 0, it simply cancels out, i.e. things with more mass do get pulled to earth harder, but it takes more force to get heavy things moving.
The TRamp class
TRamp is pretty minimal - just enough to draw a few lines for a track. I'm assuming that the final roller coaster track will be drawn with a bunch of short line segments. The interesting routine is GetAngle, called when the cart is to be moved. It finds the line segment on the ramp representing the current cart position. GetAngle scans forward or backward, depending on which direction the cart is moving until a segment is found encompassing the given Xval value. Future loops in the track will cause multiple line segments containing a particular Xval, so I take a StartAt parameter to begin the search. When the segment is found, the Yval value corresponding to Xval is found by interpolation and passed back to the caller.
The TCart class
TCart has scaling properties Locscale and TimeScale which I haven't' worried about yet - the idea eventually is to make the user interface in real world units (feet & pounds, or meters & kilograms). The Timescale property will allow the action to be speeded up - a thrilling ride that takes a minute in real time probably wouldn't look very thrilling if it ran for a minute on the screen.
Procedure Steptime does the move calculations, incrementing time by Timestep seconds each time it's called. Xval is incremented by velocity*Timestep, then TRamp.GetAngle is called to get the track angle and YVal for this piece of track. Acceleration for this angle is calculated as described above. The "opposing force" part is not quite straightforward - it's direction is determined by the direction of motion, independent of the ramp angle. I ended up defining a "sign" function and multiplying the opposing force by sign(velocity) to make sure that it always acted to slow the cart.
The DrawCart procedure also may be of interest to beginners. It uses the routines from the Rotate Square program to define a rectangle then rotate and translate it to its final location. The wheels are imperfectly located on hills for two reasons - 1) the TCanvas.ellipse procedure used to draw them needs 4 corners of a square to define each circle and 2) I was too lazy to write the code define, rotate, and translate each wheel's rectangle - seems like overkill somehow.
DrawCart also uses a "sprite" technique to draw the cart. The idea is to capture the piece of the background image where the cart will be drawn before drawing the cart. When it's time to draw the cart again, we'll restore the background (erasing the old cart image), then capture a new piece of the background image for the new cart location. The bitmap, Savebg, is defined to hold the background image. Saverect is a TRect record holding the coordinates of the area to be saved and restored.
Running/Exploring the Program
Suggestions for Further Explorations
Copyright © 2000-2017, Gary Darby All rights reserved.