USC GamePipe Game Engine AI

Scripting, Physics, Animation, and more

The USC GamePipe Game Engine, GGE, is a generic game engine created from the past work of many dedicated USC graduates. Numerous student groups build games, demos, and prototypes from the GGE. Modules such as UI, to Physics, to Rendering have been integrated into making a robust engine. One component though has always been severely lacking from the GGE, Artificial Intelligence.

In the past, two different teams have attempted to create a robust generalized AI system in the GamePipe Game Engine, which have only lead to multiple failures.

My implementation of the GGE AI was successful not just through long nights of coding, but through working very closely with each and every group responsible for the different systems within the GGE.

Platforms such as Havok, Ogre, OpenSteer, and Lua were all leveraged to allow for a flexible and robust AI system.

the Creation

in the wild

running

crowding

deserting

visual Debugging with Havok

the Documentation

Because documentation comes first!

Online C++ Doxygen

the Tech

Libraries

» Ogre Render

» Ogre Animation

» Havok Physics

» Havok Animation

» OpenSteer

» Lua

StarCraft NeuroEvolution Unit AI

evolving the past, one generation at a time

NeuroEvolution, or better yet Real Time NeuroEvolution of Augmenting Topologies(rtNEAT) uses generic algorithms and selective breeding to both train and shape neural networks into their optimal configuration. The original C++ rtNEAT algorithm was developed at the University of Texas, at Austin by Dr. Kenneth Stanley.

My experiment in rtNEAT ported the C++ centered algorithm into a Java implementation and implemented both C++ and Java algorithms into StarCraft for performance and feasibility testing.

AIIDE 2010 Tournament maps

the battlegrounds

The 2010 AI and Interactive Digital Entertainment Conference hosted an AI StarCraft competition which pitted various StarCraft bots against one another in numerous setups. I used the Tier 1 tournament maps against the built in StarCraft computer to both train and test rtNEAT.


the Creation

in the wild

the Documentation

Because documentation comes first!

Online JavaDocs

the Tech/Hacks

Libraries

» BWAPI – Brood War Application Programing Interface

» BWTA – Brood War Terrain Analyzer

» BWAPI-Proxy – BWAPI Java Socket Proxy

» C++ rtNEAT – Real Time NeuroEvolution of Augmenting Topologies

» Java rtNEAT – Java Real Time NeuroEvolution of Augmenting Topologies

Utilities

» ChaosLauncher by MasterofChaos

» BWAPI Injector

» Resolution Hack Loader by hellinsect

» W-MODE

OpenSource! System Information Monitor

Forget about what you thought is possible, and embrace Change

System Information Monitor was born with the idea of breaking free from platforms and installers. 4 weeks and a lot of hacking later, we have success.

the Prototype

click to launch the prototype


the Product

the Tech

Features

» Monitors System Information

» Supports Windows, Linux, Unix, Solaris

» No Install, Launch from the browser

» 26 Different Skins

» Open Source

APIs Utilized

» Hyperic Sigar

» JFreeChart

» Swing Application Framework

» Substance

» Swing

Other boring info

The guts of System Monitor lay in concurrency. At any point in time System Monitor is utilizing a thread pool in order to poll information from the operating system. Each of these sources respond at very diferrent rates so the thread pool keeps things flowing in at a near constant rate.

sharing is Caring

the Glorious Code

Because documentation comes first!

Online JavaDocs

Snatch it!

System Information Monitor

Just a taste

// only a snippet to protect the eyes

    @Override
    public void update() {
        final int currentCpu = this.cpu;

        Runnable updateData = new Runnable() {

            public void run() {
                chart.setNotify(false);

                LinkedList<LinkedList<Double>> cpuHistory = cpuProcess.getCpuHistory();
                LinkedList<Double> cpu;

                counter = counter.add(BigInteger.ONE);

                if (dataset.getColumnCount() > 0) {
                    dataset.removeColumn(0);
                }

                if (currentCpu == -1) {
                    // Number of CPUs
                    for (int i = 0; i < cpuHistory.size(); i++) {
                        cpu = cpuHistory.get(i);
                        dataset.addValue((Number) cpu.getFirst(), i, counter);
                    }
                } else {
                    if (currentCpu < cpuHistory.size()) {
                        cpu = cpuHistory.get(currentCpu);
                        dataset.addValue((Number) cpu.getFirst(), currentCpu, counter);
                    }
                }

                chart.setNotify(true);
                chart.fireChartChanged();
            }
        };
        SwingUtilities.invokeLater(updateData);
    }

    /**
     * Moves all the data from the CpuProcess to the dataset.  This operation
     * will do a complete replace on the dataset information.
     */
    private void moveData() {
        final int currentCpu = this.cpu;

        Runnable updateData = new Runnable() {

            public void run() {
                chart.setNotify(false);
                dataset.clear();

                LinkedList<LinkedList<Double>> cpuHistory = cpuProcess.getCpuHistory();
                LinkedList<Double> cpu;

                if (currentCpu == -1) {
                    // Number of CPUs
                    for (int i = 0; i < cpuHistory.size(); i++) {
                        cpu = cpuHistory.get(i);

                        BigInteger beforeCount = counter;

                        // Number of datapoints
                        for (int j = 0; j < cpu.size(); counter = counter.add(BigInteger.ONE), j++) {
                            dataset.addValue((Number) cpu.get(j), i, counter);
                        }

                        counter = beforeCount;
                    }
                } else {
                    cpu = cpuHistory.get(currentCpu);

                    BigInteger beforeCount = counter;

                    // Number of datapoints
                    for (int j = 0; j < cpu.size(); counter = counter.add(BigInteger.ONE), j++) {
                        dataset.addValue((Number) cpu.get(j), currentCpu, counter);
                    }

                    counter = beforeCount;
                }

                counter = counter.add(BigInteger.valueOf(cpuHistory.get(0).size()));

                chart.setNotify(true);
                chart.fireChartChanged();
            }
        };
        SwingUtilities.invokeLater(updateData);
    }
}

PHASE – 10 Weeks, Start to Finish

a 3d Engine, a 3d World, a 3d Game, everything from scratch

the Concept


the Creation

in the wild

the Ups and Downs

5 things that went right

» Implemented all game mechanics

» Created a node based graphics engine

» Create a configuration manager

» Extremely motivated developers

» Early specialization of developers

5 things that went wrong

» Lua integration

» Learning curve for design patterns

» Not focusing on cohesion

» Not testing builds on other machines

» Destructors were put off till the end of development

5 things that should have changed

» More focus on gameplay

» Utilize Lua more

» Focus on learning openGL

» Learn advanced Visual Studio practices

» Stress documentation

TDD for the win – AES Encryption

Because documentation > testing && testing > coding

Don’t worry, I got it Covered


and I’ll tell you exactly how too.


better yet, I’ll show you.

AES_java

// only a snippet because I care about your eyes
// but click here for the uncensored code

  /**
   * Applies S-Box substitution to each byte of a state matrix.
   *
   * @param s
   *          A state matrix having Nb columns and 4 rows.
   * @return s, after S-box substitution is applied to each byte.
   */
  protected int[][] subBytes(int[][] s) {
    for (int i = 0; i < 4; i++) {
      for (int j = 0; j < Nb; j++) {
        s[i][j] = subWord(s[i][j]) & 0xFF;
      }
    }
    return s;
  }

  /**
   * Applies S-box substitution to each byte of a 4-byte word.
   *
   * @param w
   *          A 4-byte word.
   * @return w, after S-box substitution is applied to each byte.
   */
  protected static int subWord(int w) {
    int subWord = 0;
    for (int i = 24; i >= 0; i -= 8) {
      int in = w << i >>> 24;
      subWord |= sBox[in] << (24 - i);
    }
    return subWord;
  }

  /**
   * Multiplies x times a polynomial b(x) in GF(2^8) modulo the irreducible
   * polynomial m(x) = x^8+x^4+x^3+x+1. (i.e. m(x) = 0x11b).
   *
   * @param b
   *          A polynomial b(x) = b7x^7+b6x^6+b5x^5+b4x^4+b3x^3+b2x^2+b1x+b0 in
   *          GF(2^8).
   * @return xb(x) mod x8+x4+x3+x+1.
   */
  protected static int xtime(int b) {
    if ((b & 0x80) == 0)
      return b << 1;
    return (b << 1) ^ 0x11b;
  }
}