The Highway

We are trying to build a simulator for a chunk of the highway through downtown Austin.

Note

This is actually easy. put tons of cars on the road, and never move them. The real highway through Austin is also known as the world’s biggest parking lot. it stretches from San Antonio to North of Dallas! YMMV!

As we have been learning, we need to break down our problem into a set of classes, each responsible for one part of our problem. This entire project was inspired by the PoolBall project, where we have a bunch of balls sitting on a table, moving around and bouncing off of each other and the table edges.

If we turn the PoolTable into the actual highway, and turn PoolBalls into cars, we are almost there. However, we really do not want our cars to bounce off of each other, except by accident. Our new simulation will need to address how accidents happen and what to do whaen they do happen.

Highway Class

Let’s start off by building a class that will model the highway:

include/Highway.h
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#pragma once

#include "Vehicle.h"
#include "Random.h"

class Highway {
    public:
        int lanes;      // number of lanes to display
        int lWidth;     // width of a lane in pixels
        int length;     // length of highway section
        int speed;      // speed limit in pixels/sec
        int safe;       // safe passing distance
        double sScale;   // used to somtrol simulation speed
        double xScale;   // distance scale
        int xRoad;
        int yRoad;
        int rampSpeed;  // controls on ramp injection speed

        Highway();      // default contsructor
        void drawLanes( void );
        void setPosition( int x, int y );
        void setScaling( double speed, double length );

        // traffic setup
        static const int MAX_CARS = 20;
        Vehicle cars[MAX_CARS];

        Random sim_rand;

        // vehicle management
        void trafficSetup( int safe );
        void initVehicle( int c );
        void setRampSpeed( int speed );
        bool checkSafe( int c, int lane );
        void changeLanes( int c, int speed );
        void checkCollisions( void);
        void drawVehicle( void );
        void move( void );
        void inject( int time );
        void retire( int car );
};

Warning

In this version, everything is public. This is a bad idea, and you should decide what to make public, and what to make private. Those decisions may cause you to add additional methods to let users get at the private data.

Highway Attributes

When you start out designing a class, you begin by thinking about physical things from the world where the problem came from!

In our case, we are dealing with a physical highway, which has some number of lanes, each of which is so wide, and the total highway is some length. The simulation we re going to set up will divide that total length into a set of segments to make displaying a long highway easier to do on our skinny screen.

A number of the attributes you see here are there to allow us to think in terms of physical units of measure (miles, feet) and map those units into our simulators world (pixels, etc).

Highway Methods

Besides the obvious constructor, we define a bunch of methods that will help us manage all of those cars we will be adding, and making them move. Notice the method that will “draw” the highway. That routine will need to draw a complete screen, with all cars in their “current” position”, every time we call it.

Note

Actually, we will never call that method. Our “draeScene function, part of the graphics engine, will do that calling.

Highway Traffic

This class is responsible for managing all the traffic we will see on the screen. We need a way to add new cars who enter the highway, “retire” cars that leave the highway, and make those cars do something fun!

For this starting class, we are setting up an array of cars, which is really a bad approach. Given that you have a nice Linked-List class around (you do, don’t you?) It would be better to use that to set up our collection of cars. Then we are not constrained by some predefined maximum size.

Adding Cars

As a starting point for this simulation, we need to add new cars to the highway entrance. Those cars appear at random times in each lane, and are a random distance apart, going a random speed. Yikes, that is a lot of randomness to deal with.

Right, but we have a nice random number generator to help out. We just need to use it wisely.

When we create new cars for the simulation, we will use the random number generator to initialize attributes for those cars (something we will see in a bit). However, you cannot just accept those random values. You need ot confirm that what you have makes “sense”. One car should not land on top of another car, and a car should not be going 30 MPH faster thn another car directly in front of it. You do not want collisions to happen right away!

All of this logic must be included in the code that places a new car in the simulation.

Retiring Cars

When a car exits the simulation, we do not need that car again. In an array based design, we can use that index to set up a new car that will enter at the beginning of the highway. In a linked list implementation, we “reuse” the old data node, and reset the attributes so it is a new car.

Collision Avoidance

The real heart of this project is deciding how vehicles behave. We will store behavior attributes in each vehicle object, but it will be the highway class that makes all of the action happen

Your challenge is to come up with a set of behaviors that make your simulator act like a real highway.

Let’s see:

  • Some drivers go fast
  • Some drivers go slow
  • Some drivers want to be in the “fast lane”
  • Some drivers want to stay in their lane.

Some Drivers are willing to “tailgate”

  • Some drivers want a half mile between them and the car ahead.
  • Some drivers change lanes “instantly
  • Some drivers change lanes slowly

Finally, every driver reacts to things based on a reaction time. If they are too slow, they may run into something and cause an accident.

Then what do we do?

(My solution: make turn them back into poolballs, and let them bounce off of each other and the barriers on the sides of the road!

Vehicle Class

Now, let’s consider a class to manage a single car:

include/Vehicle.h
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#pragma once

class Vehicle {
    public:
        int size;       // how big should this vehicle be
        int xPos;       // screen position in pixels
        int yPos;       
        int xSpeed;     // current speed
        int ySpeed;

        int lane;
        int preferred_lane;
        bool active;
        int color;

        Vehicle();
        void setPosition( int x, int y );
        void setSpeed( int xv, int yv );

        void move( void );
};

Nothing much here. This is much like the class we set up for the PoolBall problem. In this design, we probably intend to draw our cars as small circles on the screen, just like a tiny poolball. If you want to make a car into a rectangle, you need a length and width, and if you want a truck, you might have attributes for the front truck part, and another set for the trailer.

Of course, modeling collisions if your vehicles are rectangles is going to be harder to figure out, but that is something you may want to consider.

Moving Forward

You have a basic structure to move forward, all you need to do is add the code toget things set up, then turn the simulation loose. Have some fun with this, it can become addicting!

As your design progresses, you may find the need to add attributes to these classes, and methods as well. Those decisions are usually made after you try something, and decide you can make things “better”. That is what programming is all about.