Click here to Skip to main content
Click here to Skip to main content

A Simple Racing Cars (Tokens) Game App

, 30 Sep 2013 CPOL
Rate this:
Please Sign up or sign in to vote.
Using Thread and Java Swing components


Based on an assignment 'Racing Tokens', instead of using a Timer, I used Thread to race tokens (cars) around rounded rectangular tracks. Each token runs on its own thread. Each token can be any appropriate Java Swing shape (circle, triangle, or square).

Syntax to run: java Program [laps, tokens]

With laps (range from 1 to 3) and tokens (range from 2 to 4) are optional. Default 1 lap and 4 token. Tracks are dynamic sizing.

The plan of attack

Implement MVC model, I came up with three packages:

  • model: includes these classes: Token, Race, and RaceBuilder
  • view: includes these classes: RaceFrame, RacePanel, and ControlPanel
  • controller: includes RaceRunnable class

The class is the entry to run the program.

The details 

Token class

Start with class. It contains all the data associated with an actual token: name, radius (for a circle), color, position coordinates X and Y, distance and distance-right (down, left, up) it has run, track width and height, velocity,...

Velocity (pixels per second) is randomly calculated.

Among the setter and getter methods, the most essential ones are the methods to move (right, down, left, and up) associated with the draw methods based on its position.

public void moveToken() {
if (this.distanceRight <= this.trackWidth) {
    // move right, if this token has reached to far right, then move down
    this.shouldMoveRight = true;

} else if (this.distanceDown <= this.trackHeight) {
    // move down, if this token has reached the bottom, then move left
    this.shouldMoveDown = true;

} else if (this.distanceLeft <= this.trackWidth) {
        // code
} else if (this.distanceUp <= this.trackHeight) {
    // code


The method for the token to move it to the left is:

private void moveLeft(int miliseconds) {
    double pixels = 0.001D * velocity * miliseconds;
    this.distanceLeft += pixels;
    this.distance += pixels;

    this.distanceUp = 0;

and at the same time, draw its circle:

private void drawLeft(Graphics g) {
            this.initialPosition.x + (int) Math.round(this.distanceRight)
                    - (int) Math.round(this.distanceLeft),
            this.initialPosition.y + (int) Math.round(this.distanceDown),
            DIAMETER, DIAMETER);

(*) One important note of this Token class is that it implements the Runnable interface. So it is a task to be run in a thread.

Race class 

To store a list of Tokens, along with how many laps to run, the total distance to run for each token. The two key methods here is: (1) determine if all tokens are still running:

public boolean areAllTokensRunning() {
    for (Token token : tokens) {
        if ((this.distance + Token.RADIUS) > token.getDistance()) {
            return true;

    return false;

and (2) determines the winner:

public Token isWinner() {
    for (Token token : tokens) {
        if (this.distance <= token.getDistance()) {
            return token;

    return null;

The GUI classes

The main frame class, RaceFrame is to be the main container to display the app. It includes the RacePanel and ControlPanel GUI.

The RacePanel is to hold the Race (which contains a numbers of Tokens) and rounded rectangle tracks. Its size (width and height) determine the distance to run.

The ControlPanel includes the buttons (Start/Stop/Resume, increase/decrease speed), the label to declare the winner. These buttons listen to the user's activities and act accordingly.

The Controller

The RaceRunnable class, just needs to pass the parameters and fire the token's run() method to start thread for each token, through a 'chain of command' RaceFrame, RacePanel, and RacetoToken.

RaceRunnable itself is a task and to be run in the event dispatch thread:

public void run() {
    while (raceRunning && race.areAllTokensRunning()) {
        int track = 2 * (racePanel.getWidth() + racePanel.getHeight());
        race.setDistance(track * race.getLaps() - 480);

        race.updateTokenPositions(1, racePanel.getWidth() - 120,
                racePanel.getHeight() - 120); 
                  // 120 pixels margin from the right and top border

        SwingUtilities.invokeLater(new Runnable() {
            public void run() {

                if (race.isWinner() != null) {
                    raceRunning = false;

        try {
        } catch (InterruptedException e) {


  • This program needs a better way to choose the 'right' time to turn 'curly' at the track corner.
  • Also, it has not set up a 'fair game' and determined 'reasonably' which token wins.
  • The move and draw token methods are lengthy and should be re-written.
  • ...


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Lộc Nguyễn
Software Developer
United States United States
currentJob = new ComputerScientist("ND-1550", "02/04", "SPAWAR SSC PAC");
while (live) {
try {
} catch (Exception ex) {
Follow on   Google+   LinkedIn

Comments and Discussions

QuestionWhat is the main purpose of article? PinmemberNghia Do30-Sep-13 13:52 
AnswerRe: What is the main purpose of article? PinmemberLộc Nguyễn30-Sep-13 15:18 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.150327.1 | Last Updated 30 Sep 2013
Article Copyright 2013 by Lộc Nguyễn
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid