Bug time trials (Vehicle Simulation)

[Home]   [Puzzles & Projects]    [Delphi Techniques]   [Math topics]   [Library]   [Utilities]

 

Search

Search WWW

Search DelphiForFun.org

As of October, 2016, Embarcadero is offering a free release of Delphi (Delphi 10.1 Berlin Starter Edition ).     There are a few restrictions, but it is a welcome step toward making more programmers aware of the joys of Delphi.  They do say "Offer may be withdrawn at any time", so don't delay if you want to check it out.  Please use the feedback link to let me know if the link stops working.

 

Support DFF - Shop

 If you shop at Amazon anyway,  consider using this link. We receive a few cents from each purchase.   Thanks.

 

Support DFF - Donate

 If you benefit from the website,  in terms of knowledge, entertainment value, or something otherwise useful, consider making a donation via PayPal  to help defray the costs.  (No PayPal account necessary to donate via credit card.)  Transaction is secure.

Contact

Feedback:  Send an e-mail with your comments about this program (or anything else).

Search DelphiForFun.org only

 

 

 

Problem Description

Program implements a  "bug" which  can be "driven" using arrow keys around a circular track with a number of gates.   The objective is to navigate the course in the minimum time and/or distance.  .
 

Background & Techniques

The program evolved from a prototype vehicle simulation program written at the request of a viewer.  I had added a second overlapping circle to the original circular vehicle in order to investigate "pointing" the vehicle in the direction of travel.   The result looked like a bug, so I decided to make an obstacle course to practice driving the thing.  Bug Time Trials is the result.

The bug is most easily controlled by using arrow keys.  Up and down arrows control speed; left and  right arrows control the turning angle. 

bullet "Up" increases positive velocities (bug moving forward) or reduces negative velocities (bug moving backwards) .
bullet "Down" decreases positive velocities or increases negative velocities.  
bullet  "Right" increases the angle at which the bug is turning in a clockwise direction, up to 90  (as if the bug were an automobile rotating about it's rear wheels with it's front wheels turned 90 to the right.)   . 
bullet "Left" increases the angle of turning in the counterclockwise direction. 
bullet If the number keypad is used, the "5" key (in the middle of the 4 arrow keys) can be used to reset the turn angle back to zero and improves maneuverability at higher speeds.   For keyboards without a keypad, the "Z" key  can be pressed with same "stop turning" effect.

After you click the Start button, the required course blinks a few times then the clock starts.  The clock stops when the bug touches the finish line after passing through the four 4 gates positioned at 9, 12, 3, and 6 o'clock positions. 

Non-programmers are welcome to read on, but may want to skip to the bottom of this page to download executable version of the program.

Programmer Notes

The three parts of the program that were the most challenging (and the most fun) were figuring how to control the vehicle, collision detection,  and rescaling when  the form is resized.    

Vehicle control: 

The "bug" is built from two overlapping circles (TShape controls) with the head 1/2  the size of the body and positioned so that 2/3 of the head is exposed in whatever direction the bug is pointing at the moment.  Bug movement is controlled by a loop that runs about 100 times per second.  "Sleep(10)" pauses 10 milliseconds at the start of each pass through the loop. .   An "OnKeyDown" exit sets the appropriate  increment to +1 or - 1 and "OnKeyUp"  resets the increment back to 0.  So while the key is depressed, the speed or angle is being changed at the rate of about 100 steps per second.  Since the range of changes is  -100 to +100 pixels per second for velocity and -90 degrees to +90 degrees for turn angle,  it takes about 1 second to from 0 to either of the extremes.

The geometry to calculate the angle to turn each time through the loop is a bit tricky and  needs a diagram to do it justice.  The calculation code is:

  dtheta:=-sin(DegToRad(anglebar.position))*dd/radius; 

I'm not good at diagrams so here it is in words.  If you really need it and get stuck, use feedback to send me a note and I'll spend more time on it. 

Using the distance traveled by the bug is a good estimate of the arc length when the vehicle is turning and for small turning angles.  The idea is that the front of the vehicle moves at an angle controlled by the turning angle relative to the angle of the vehicle (or bug). While that is going on the rear of the vehicle (or tail of the bug) is moving approximately up the line toward where the nose was when the move started.    If we draw the triangle N1,N2,T where N1 is the starting position of the bug's nose, N2 is the ending position of the nose and T is the Tail position of the bug at the end of the move, then

  • N1N2 is the arc of length "dd", the distance traveled during the current time interval, 

  • radius = line TN2, the length of the bug,

  • angle TN1N2 is anglebar.position (the angle of the wheels, call it alpha for brevity) and

  • angle N1TN2 is the desired "dtheta" change in theta, the heading of the bug. 

By the law of sines from trigonometry, sin(alpha)/radius = sin(dtheta)/dd or sin(dtheta) = sin(alpha)*dd/radius.   Since dtheta is a very small angle,  dtheta and sin(dtheta) are nearly equal so we can use dtheta = sin(alpha)*dd/radius. The minus sign in the equation above reflects the fact that right turns are negative angles but are represented in the anglebar slider as positive values.

Collision detection

is considerably simpler; it just takes more code than one might think before they have done it once.  After position change of the bug has been calculated, we'll check the distance of the body and of the head  to each of the things it might collide with (the 10 "gate posts" and the edges o0f the form in this case.  The gate posts and the bug and head and body are all circular Tshapes and are copied to a "Shapes" array at FormCreate time.   Thus lets us use a loop to check for collisions.  When found, I decided to just beep and reverse the direction of the bug.  Oh, and,  as I found out the hard way,   we also  undo the position change calculations made.

Resizing

Another area that has lots of steps, none very complex.  The OnResize exit is called after the dimensions have been changed.  I save the dimensions before the resize and calculate  scale factors for the change in the x and y directions at resize time.  The smaller one is used to ensure that the course still fits the form after scaling.  Then again the Shapes   array is used to calculate new top, left, width, and height values for the bug, and the gate posts. Then we also do some juggling of the label and countdown timer positions. 

Other stuff

  •  There are lines calculated across each of the gates (only the finish line is drawn).  As the bug moves we check off each gate passed through  so the driver cannot cheat by skipping a gate and so we can tell when the bug reaches the finish line.
  • Our countdown timer class is used to display the run time.     
  • The UGeometry unit  provides the "LinesIntersect" function  used here to determine when the bug crosses through a gate.   UGeometry is contained in our DFF library zip file (DFFLIBV04 or later) which must be downloaded one time if you plan to recompile the program. 

I've been doing this for more than 40 years and it still is  mildly surprising how many actual operations are involved in a seemingly simple project such as this one.    About 500 lines worth in this case.   Addendum

Addendum

May 24, 2014:  It's been a number of years since I looked at this program but conversations with a viewer about robot control recently led me to refresh this to Version 2.  The main change is allowing the "bug" to be resized smaller to make passing through the gates a little easier.  However the default full size bug now has less gate clearance. 

My new best times are 19 seconds for the the "Easy" level, high 20's for the "Harder level, and low  30's for the "Expert" level.  The bug now reverses slowly in a straight line after a gate collision instead of reversing at the collision vehicle speed and turn angle.  Hitting a gate post is still guaranteed to add several seconds to your lap time!    The best technique I've found uses the arrow keys with right hand for bug control and the "Z" key with the right hand to straighten out and zip through the gates when the bug is lined up.        

Running/Exploring the Program 

Suggestions for Further Explorations

bullet Add flexible obstacle course support by saving and loading course description  files.
bullet Save "high scores" feature. 
bullet Use average speed through the course as a third  performance measure. 

 

Original Date: September 28, 2006 

Modified: February 18, 2016

 

  [Feedback]   [Newsletters (subscribe/view)] [About me]
Copyright 2000-2017, Gary Darby    All rights reserved.