Physical: A Physics-Based Game Creation Engine

Physical: A Physics-Based Game Creation System
by Alec Rivers


Introduction

Physical is a game creation system that encompasses the entire game design process from graphics routines to game world dynamics. It is built upon the foundation of an innovative 2D physics engine that drives all the interactions of the game world. Physical has incorporated functions for window creation, keyboard handling, graphics, and game flow. It also streamlines the object creation and management aspects of game design. Furthermore, the presence of the physics engine makes collision detection and object destruction a matter of course, and vastly simplifies the creation of interactive elements. The bottom line is, this tool makes it very easy to write games.

However, easy can have two meanings. Products such as Klik & Play simplify game design to a point at which novices can create games - hence making game creation "easy". Physical, however, is designed for intermediate to advanced programmers, and its primary focus is to make game creation a quick and streamlined process - "easy" in the sense of reduced programmer effort, not necessarily simplicity.

But don't let that scare you away. Physical is also easy to understand. Programmers using Physical should have a good grasp on object oriented programming, which is a cornerstone of Physical's construction, but even if they lack that a few hours with a C++ textbook will bring them up to speed. Eventually, my hope is that Physical will make game creation easy in both of the ways mentioned above.

Physics Engines and Game Creation

Physics engines are generally seen as luxury items in game design - nice ways to add special effects to a game, but generally just a graphics tool and not something central to a game. Game worlds are usually simulated using hard-coded motions and behaviors, and a physics engine is added on top to deal with special cases like falling boxes.

I feel that this should change. I believe that physics engines' rightful place is at the very core of a game system, not added on to the top for special effects. Previously, this was simply not possible, given the processing constraints of gamers' systems - physical simulation is an intensive task, and the more objects you simulate, the more processor speed you require. Now, however, at least in 2D, this approach is possible.

When a physics engine is at the base of a game, the entire way of thinking about game design changes. Everything in your game is part of the physical world: the target, the main character, vehicles, bullets. When you add a spaceship to a game, you are not just changing some logical construct, you are actually creating a physical object. When you design a level, you are not coding a program, you are crafting a world.

Beyond ideological concerns, however, this actually brings great advantages for the developer. Consider the case of designing a spaceship in a computer game. In a traditional computer game, this would involve creating a class Spaceship, giving it properties like rotation, speed, acceleration, health, etc., etc.. The programmer would then have to create many specialized functions for controlling the spaceship: what to do when the player accelerates, how to handle inertia, collision detection, and a million other factors.

Using Physical to Create Games

In Physical, it's an entirely different matter. To create a spaceship in Physical, one only has to consider what it really is: an object that moves. A programmer just has to create a physical object (first drawing the spaceship in a paint program, then loading the image into Physical's included object editor to make it into an actual physical object that can be simulated) and then give it a few properties. Using the object editor, the programmer can designate where he wants the engines to be, and then using Physical's simple programming framework he can create actuators at those points that apply forces in response to user input. Voila: a spaceship that accelerates, turns, lands, and even crashes with just a few lines of actual code.

A spaceship, first being edited in the object editor, then in action in a game

Unlike most programming libraries, Physical incorporates its own programming framework that systemizes and facilitates the design of game elements. This programming framework makes it a cinch to handle interactions with physical objects. Adding weapons, controls, and even AI can be accomplished in a matter of minutes. Physical also has over a dozen built in interaction objects, including engines, a basic gun, particle effects, muscles, and automatically expiring bullets. All of these objects are designed to be extended easily, so you can customize their functionality as you see fit.

Using these tools, a simple game can be written with just one or two hundred lines of code. With a good grasp of Physical's framework, you'll be able to write up arcade, action or puzzle games in days instead of months. To get you up to speed, I've written an overview of Physical's physics engine, object editor, and framework, as well as a basic tutorial that takes you through all the steps of making a simple game. I've also included an extensive Reference section that covers the implementation details of the core Physical engine and all of its built-in objects. I hope you enjoy working with Physical as much as I have enjoyed creating it.

Example Game

If you want to skip past all the talk and just try the physics engine out, you can go play the example game included with the tutorial: Physical Asteroids.


Overview of Physical

Physical, as it stands right now, has three major components.

  • A 2D physics engine
  • An object editor
  • A programming framework

This section is an overview of these components, and should give the reader enough familiarity with Physical to understand what it is and how it works. The specifics of programming with these tools are covered in the Reference section.


Physical's Physics Engine

Overview of Physical's Physics Engine

Before you try to understand anything else about Physical, you should understand its physics engine.

In a traditional physics engine, an object such as a box is treated as one discrete entity simulated using Newtonian mechanics. The laws of torque and inertia are hard-coded into the engine, and the object's movement is determined using formulas derived from them. This approach is known as rigid body physics, and it works well for many situations. You may have seen rigid body physics engines in some of the newer commercial games like Hitman 2 or in demos of Half Life 2. (If you haven't, I highly recommend a freeware game with the amusingly-translated title "Stair Dismount.") Simpler examples of this kind of engine have been in use for years in special cases like the cars in racing games.

A screenshot from a demo of a rigid body physics engine (not written by me)

However, rigid body physics engines severely limit the number of ways objects can be interacted with. For the most part, objects can only be moved around. They cannot be broken in two, crushed, stretched, or split. In a field such as computer gaming, where destruction and breakage form the majority of interactions with the game world, this is a serious shortcoming. Furthermore, rigid body physics engines are unable to simulate environments with complex or high numbers of interactions: water flowing over a mill wheel, for example, or flame eating at a building.

Physical's physics engine is based upon the work of Italian computer scientist Giovanni Tummarello. Tummarello's approach is an extension of what is known as a mass-spring system. In a mass-spring system, physical objects like a box are not whole entities in and of themselves, but are formed out of many smaller particles, referred to in the engine as atoms. (The word ‘atom’ is used to mean a small, indivisible unit of matter; atoms in the physics engine do not necessarily behave like atoms in the real world.) In an object, these atoms are connected to each other, usually in a lattice structure, by ‘links’. These links are essentially springs, and their behavior is governed by Hooke’s law. While each atom reacts only to very simple forces – such as link forces and bouncing off of walls – in systems with many linked atoms, higher level laws such as those described in Newtonian physics emerge. For example, while there is no specific equation in the engine that governs rotation, and while atoms themselves don't even have an orientation, a box made up of many linked atoms will rotate realistically when hit.

A mass-spring system in action

Tummarello extended this paradigm in two ways. First, he included an atom-based repulsion system that made every atom repel every other atom, simulating collisions.

A mass-spring system with atom repulsion

Secondly, he added the ability for links to break when extended beyond a breaking point. This was a critical step, because it meant that mass-spring systems could now do everything that was lacking from rigid body physics: objects could deform and break.

A mass-spring system with link breakage

All this talk of physics may be a bit much to take in all at once. The bottom line is this: at the core of Physical is a physics engine that can simulate just about anything you can throw at it. It can handle objects that bounce, roll, stretch, break, get sliced, get crushed, and everything in between, even simulating fluids with ease. It does have weaknesses - ironically, it is not very good at large, rigid objects, which were the easiest thing to simulate with rigid body physics - but its capability for destruction offers a wealth of new possibilities in terms of gameplay.


The Physical Object Editor

Overview of the Physical Object Editor

The Physical Object Editor

Objects in Physical's physics engines are made up of atoms and links, as described earlier. Polygons are stretched across those atoms and links to texture objects. Objects of this kind are of course not exactly industry standard, so a tool had to be created to help game designers create them. That tool is the Physical Object Editor.

Object creation using POE generally follows this path:

  1. First, an artist draws the object using image editing software, saving it as a TGA. (Even MS Paint will do, if you can convert its output into TGAs.)
  2. Then, either a programmer or the artist uses POE's "Auto Generate from Image" functionality to import the image. This creates an atom and link lattice based on the image, interpreting alpha levels of 0 as transparency in RGBA images and the color magenta as transparency in RGB images.
  3. The atom lattice automatically generated provides only a rough outline of the object, so the programmer must then manually tweak the atoms to provide a closer fit to the image.
  4. Finally, the properties of the atoms themselves are edited in the object editor. These properties include the masses of the atoms and the strength of the links. Atoms and links can also be assigned groups, which can be used in the code of the game to assign the atoms or links to various roles (engines, etc.).

The easiest way to understand the object editor is to look at an already created object. I suggest opening the spaceship from the Physical Asteroids demo game. To find out more about creating and editing your own objects, see the Reference section.


Physical's Programming Framework

Overview of Physical's Programming Framework

Physical's third, and in many ways most important, component is its programming framework. This is a system of data structures and interfaces that put all the abstract concepts of games and objects into a simple, easy to work with layout. Rather like the MFC classes for Windows programming, it consists of a number of pre-created base classes that provide core functionality and are designed to be extended. These base classes are linked together in a tight hierarchy that provide logical game structure and simple program flow.

A symbolic representation of the structure of a game built with Physical

The above diagram shows the structure of a game built with Physical. It shows the four basic classes in Physical: Game, System, Renderer, and Object.

Game:
A Game structure acts as a container for all the diverse elements of a Physical program. Physical defines a base class Game, which includes functionality common to all games: variables for holding key states, mouse position, and mouse button states; a quit() method; and a stepFunc() method that is typically called by the main program every frame and forms the basis for the game loop. A programmer would generally extend the base Game class for their own game (e.g., class SpaceGame : public Game). A Game also contains pointers to a generic System and Renderer.

System:
A System is the basis of all physics simulation. It contains lists of all the atoms and links in the world, and has an update() method that advances the physical simulation one time step. It is pretty much a black box that just "does the work". Its update() function is automatically called from Game's stepFunc(), so programmers will generally never have to deal with it explicitly.

Renderer:
A Renderer is the basis for all graphics in a game. The base class Renderer is just a stub, containing no functionality of its own: programmers must choose a preexisting extension of this or write their own for rendering. So far I have written one extension, GLRenderer, which is a fully functional OpenGL based renderer, but I may eventually add a DXRenderer or others. Again, the renderer is by and large a black box, being called automatically from the base class Game's stepFunc(). The only time a programmer will have to deal directly with it is in initializing the program window (choosing width, height, bytes per pixel, and so on).

Object:
The Object class essential to the game dynamics of any game programmed with Physical. Understanding it thoroughly is key to developing with Physical. Basically, an object is a way of organizing atoms and links in a game. Programmers must extend the base class Object to add functionality. The easiest way to explain this is with an example. Consider the spaceship example described in the introduction. After creating the physical object of the spaceship in POE, a programmer must then give it interactivity. This is done with an object. First, the programmer would extend the class Object to make a new class, Spaceship:

class Spaceship : public Object
{
};

The programmer would then add some sub-objects for the engines. In this case, I presume the existence of another extension of the Object class, Engine, with the method applyForce(float). (In reality, a class very much like this does exist, called Actuator or DActuator.)

class Spaceship : public Object
{
   Engine left_engine;
   Engine right_engine;
};

Next, the programmer would take advantage of one of Object's built in functions: stepFunc(). An Object's stepFunc() is called every game step.

class Spaceship : public Object
{
    Engine left_engine;
    Engine right_engine;

    void stepFunc()
    {
        if(keys[UP])
        {
            left_engine.applyForce(ENGINE_POWER);
            right_engine.applyForce(ENGINE_POWER);
        }
        if(keys[LEFT])
            right_engine.applyForce(ENGINE_POWER);
        if(keys[RIGHT])
            left_engine.applyForce(ENGINE_POWER);
    }
};

Now, this is a little bit pseudo code (the Spaceship class needs a constructor, access to the keyboard, and to designate which atoms belong in the engines) but the reality is not very far off, and it demonstrates how easy it really is to create new objects and interaction schemes in Physical. Through using Object's built in functions of stepFunc() and atomFunc(Atom *) (which is called every time an atom inside an object is updated) adding functionality is a snap.

A completed game using Physical would therefore consist of a new Game class and a bunch of new Objects. One of the great thing about Objects is that they are totally portable, and if I wanted to mix a tank from one game with a spaceship from another, I would have no trouble doing so. I have already in my demo game work created a number of potentially useful Objects (a grappling hook, to cite an example), and I can see a future in which many game developers working on independent products would slowly build up a huge library of Objects, to the point that entire new games could be easily created out of preexisting elements. (Can you imagine a system in which to create a war game, you just have to drop the Objects "Tank", "Plane", and "Soldier" into a common framework?)


Introduction

Tutorial

This tutorial will guide you through creating a simple Physical-based game. Steps covered are:

  • Setting up a Project
  • Creating a Game
  • Creating an Object
  • Extending Object
  • Finishing Touches

Included at the end is Physical Asteroids, an example game that builds upon the foundation written in the tutorial and showcases many of the elements of programming with Physical.

NOTE: You should read the Overview before beginning this tutorial.

NOTE: It's easiest to navigate this tutorial using the Previous and Next buttons on the toolbar.

NOTE: This tutorial assumes you are using Microsoft Visual C++ 6.0. For any other IDE or version of Visual C++, the general steps will be the same, but the exact procedures may vary. Use your judgment.

NOTE: This tutorial also assumes you are computer-literate. If you need help navigating around your computer and copying files, give up on this, turn off the "light box", and go play with some putty.


Physical: A Physics-Based Game Creation Engine - Help

Step 1: Setting Up a Project

Installing Physical

First thing's first. If you've only got this help file, you'll need to go download Physical:
http://people.cornell.edu/pages/arr33/physical/physical.zip

Once you've downloaded it, extract the zip file to some relatively central directory (e.g., c:\programming).

Creating an Empty Project

Now create a new project called "tutorial" in Visual C++. Select project type "Win32 Application" and give it its own directory (e.g. c:\programming\tutorial). Select "An empty project."

Copy the file main.cpp from your Physical directory to the directory of your project. main.cpp is just contains a default WinMain that should be sufficient for most Physical programs. (You can always modify it if you want to later.) If you have no idea what WinMain is, it really doesn't matter, just do what I say and you'll be fine. Now, go back to Visual C++, right-click "tutorial files" in the Workspace pane (on the left), click "Add Files to Project...", and then double-click main.cpp, which should be right there.

Now, click the Project menu and select Settings. Select "Win32 Release" from the "Settings For" dropdown menu. Click the Link tab. In the "Object/library modules" box, go to the very end and add "c:\programming\physical\physical.lib" (or wherever you put it). Now select "Win32 Debug" from the dropdown and do the same thing, but adding "c:\programming\physical\physd.lib". Now, select "All Configurations" from the dropdown. Click the C/C++ tab and select Preprocessor from the Category dropdown list. In the "Additional include directories" box, add "c:\programming\physical\include".

You've now set up a basic empty project. But it won't run yet, because you need to create your game. Go on to Step 2: Creating a Game.


Physical: A Physics-Based Game Creation Engine - Help

Step 2: Creating a Game

In this step, you will extend the base class Game, included with physical, to define your own game, Tutorial. If you don't know anything about inheritance, now is the time to learn.

Defining the Game

Click the File menu, and then New. Select "C++ Source File". Call it "tutorial.cpp". In this new blank file, type

//TUTORIAL.CPP

#include "tutorial.h"

Now create a new .h file (File, New, "C/C++ Header File") and call it "tutorial.h". The first thing you should do is put an #ifndef clause in there:

//TUTORIAL.H

#ifndef TUTORIAL_H
#define TUTORIAL_H

#endif

All this does is tell the compiler to only compile this file once. (It does this by checking if a variable TUTORIAL_H has been created and, if not, creating it.) Now it's time to actually write your new Game. Put this code between the #ifndef / #endif clauses.

...

#include <game.h>

struct Tutorial : public Game {
    Tutorial(HINSTANCE &hInstance)
};

...

Now we'll go define that constructor in tutorial.cpp. Note the extra #include.

//TUTORIAL.CPP

#include "tutorial.h"
#include <glrenderer.h>

Tutorial::Tutorial(HINSTANCE &hInstance) {
    system = new System(800, 600);
    renderer = new GLRenderer(this, system, hInstance);

    renderer->initializeGraphics("Tutorial Window", 800, 600);
}

To explain: you should already know that a Game contains functionality common to all games. It also has a pointer to a System and a Renderer. These are the key structures that handle physics and rendering. The base class Game defines knows by default to pass new physical elements off to the System and new graphical elements to the Renderer. A Game also updates both its system and its renderer automatically. The one thing a Game does not do automatically is actually create this system and renderer. This is because both class System and class Renderer are designed to be extended: for example, the Renderer is just an empty class; it takes a subclass such as GLRenderer, which uses OpenGL, to actually implement Renderer's functions. (A basic System does in fact implement all its functions, but nonetheless there is the possibility that it could be extended in the future.) As a result, the base class Game does not know what kind of System and Renderer the implemented game might want to use, so it just refers to them through pointers. It is up to the subclass of Game to initialize those pointers. (Note also that the system should be initialized before the renderer so that the renderer can be passed a valid pointer to the system it will be rendering.)

So, we have done exactly that, and initialized the System to create a world of size 800 x 600 pixels. We have also created a GLRenderer and initialized it with a pointer to this game (the this pointer. This was done so that the game's draw() function will be called. You don't have to worry about that now), a pointer to the system, and a copy of the hInstance, which a GLRenderer requires in order to create a window.

Note also that a call has been made to the renderer's intializeGraphics() function. In this case, we have told it to create a window with the caption "Tutorial Window" and the size 800 x 600 pixels. (This call is identical to calling the game's iintializeDisplay() function with the same parameters; it is called through the renderer to illustrate that it is the renderer that will actually be doing the graphics initialization.)

Updating main.cpp

We're almost there. Now we just have to go back to main.cpp and change a couple of things:

...

/******* CHANGE THIS *******/
#include "tutorial.h"
/******* CHANGE THIS *******/

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    MSG msg;
    int msgval = 0;

    freopen("debug.txt", "w", stderr);
    setbuf(stderr, NULL);

    /******* CHANGE THIS *******/
    Game *game = new Tutorial(hInstance);
    /******* CHANGE THIS *******/

...

Change the ???'s to the code in red. This just tells the main.cpp what kind of a game it's dealing with, and creates the (probably) sole instance of your newly-written Tutorial class.

Compile and run the project. You should see a window with a black background appear. Congratulations! You've created your first compiling project with Physical. Go on to Step 3.


Physical: A Physics-Based Game Creation Engine - Help

Step 3: Creating an Object

In Steps 1 & 2 we created a project and initialized an empty world. Now we want to put something in that world.

Drawing the Object

The first thing we have to do is design an object with the help of the Physical Object Editor. As you should have read in the overview, creating an object generally starts with drawing a picture of what we want the object to look like. However, in this case we'll use an image file I've included in this tutorial: Spaceship. Cclick that link and chose "Save" and then put it in the directory of your tutorial project.

Now, run the program "Physical Object Editor.exe" in your Physical directory. In the object editor, click "Auto Generate from Image". Navigate to and select spaceship.tga in your tutorial directory. Select "Square" as the generation method. You should see something like this:

First, save this. Click File -> Save and save it as "spaceship.pob" in your tutorial directory. Now, click "Links" in the right part of the window. (This will stop you from selecting links when you drag-select.) You can now select atoms by left-clicking and dragging in the main window. Once you have some atoms selected, you can move them using the arrow keys on your keyboard or you can delete them using the delete key. (You can also move them using the "Move" button, but that is not recommended as it moves in non-integral amounts.) You can also zoom in and out using the mouse wheel or the toolbar buttons.

The first phase of designing an object in the object editor is just "pruning" it. This means you should go around the edges of the image and move atoms to the edge of the image, deleting those that are really far out. Keep in mind that an object is displayed using polygons with atoms for vertices, so if you delete an atom you will remove the polygons it was a part of, and possibly remove part of the image you did not want to. There is no undo feature (yet), so save often.

At any rate, here's what your finished version should look like: (If it's not a perfect duplicate, it doesn't matter.)

Adding the Object

Now let's add that to your game world. Back in Visual C++, go into tutorial.cpp and add this code to the game's constructor:

...
    renderer->initializeGraphics("Tutorial Window", 800, 600);

    Object *o;
    o = new Object(this);
    o->load("spaceship.pob", 400, 300);
}
...

Here we're creating a new object and loading the spaceship.pob file. When constructing the Object we pass it a pointer to the game - every Object must have a pointer to its parent object. Notice also that we use a pointer to hold the object, and new to create it: this is important. If you try to create an object directly (e.g., Object o(this)), the object will be deleted after the constructor finishes, due to its scope. However, the atoms will remain, because they are created within Object.load() using new, and will keep a pointer to where their object was. They will try to dereference that and the game will crash.

Compile and run the program. You should see a spaceship appear in the middle of the screen and then fall to the bottom, exploding. (Wasn't that fun?) You've now added your first physical object to a game.

Well, clearly, the spaceship does not hold up very well under gravity. Nor should it! So let's go change the system's gravity. In tutorial.cpp, change the line

system = new System(800, 600);

to

system = new System(800, 600, 0.0);

This specifies a third parameter to the constructor, gravity. Previously, it was assuming its default value of -0.05, which is a pretty normal strength downwards gravity. Compile the program and run it again. The spaceship should just hang there near the middle of the screen.

We've designed our object and added it to our game, but so far it doesn't do much. We'll fix that in Step 4: Extending Object.


Physical: A Physics-Based Game Creation Engine - Help

Step 4: Extending Object

In this step, we'll extend Object to create a new class, Spaceship, much as we extended Game to create Tutorial. Their similarity is no coincidence: in fact, Game itself extends Object, so Tutorial is also an Object! Extending Object is one of the most important tasks in creating a game with Physical, and it will come up frequently. You'll find that it's a powerful tool and a useful paradigm for game creation.

Defining Spaceship

Up until now, all the programming you've done for this tutorial has been pure rote: it's just been the stuff you have to get out of the way before you can start your game. Now, however, we're about to add actual functionality and interactivity, and design a structure (Spaceship) that will be of real value, and may be something you will build upon or reuse in the future. You will get to make design decisions about what a Spaceship's capabilities are and how it functions. In short, now we come to the fun part.

Since you've extended an Object once before, we'll go through this quickly. Create new files spaceship.cpp and spaceship.h. Put this code into them:

//SPACESHIP.H

#ifndef SPACESHIP_H
#define SPACESHIP_H

#include <object.h>

struct Spaceship : public Object {

};

#endif

//SPACESHIP.CPP

#include "spaceship.h"

As you can see, this extension of Object does not add any functionality. There are two ways we could add functionality. One way is to overload one of Object's (and therefore Spaceship's as well) built in functions like stepFunc() or atomFunc(Atom *a) to do something - for example, in atomFunc(), we could have Spaceship add a random force to every atom. (As you may remember, atomFunc(Atom *a) is called once every frame for every atom inside the Object. When a .pob file is loaded using load(), the atoms it creates are automatically added to the object that does the loading.)

The other way is to add to Spaceship one or more already created sub-Objects that overload stepFunc or atomFunc themselves. This is what we're going to do.

Adding the Engines

Physical comes with many built in extensions of Object that add common functionality. In our case, we are interested in adding engines to the Spaceship. To create an engine using Physical's built in Objects, you need two things: an Actuator and a Direction. An Actuator is an extension of Object that applies a force to all of its atoms. A Direction specifies a direction, usually in terms of two or more atoms. (If we want our engines to fire forward we can't tell the actuator to add force in a constant direction, because as the ship turns around the direction "forward" changes. A Direction can specify "forward" in terms of two atoms, a front and a back, so that when the ship swivels about the direction changes too.)

So let's get down to it. Go into spaceship.h. #include <atomdir.h> and <dactuator.h>. Add member variables

DActuator *left_engine, *right_engine;
AtomDir *left_engine_dir, *right_engine_dir;
bool *accelerate, *turn_left, *turn_right;
float engine_power;

Write a new constructor, Spaceship(Object *parent, bool *accelerate, bool *turn_left, bool *turn_right, float engine_power). Now go into spaceship.cpp. Define the constructor like this:

//SPACESHIP.CPP

#include "spaceship.h"
Spaceship::Spaceship(Object *parent, bool *accelerate, bool *turn_left, bool *turn_right, float engine_power)
: Object(parent)
{
    this->accelerate = accelerate;
    this->turn_left = turn_left;
    this->turn_right = turn_right;
    this->engine_power = engine_power;

    left_engine_dir = new AtomDir();
    right_engine_dir = new AtomDir();

    left_engine = new
      DActuator(this, left_engine_dir);
right_engine = new
      DActuator(this, right_engine_dir);
}

This completes most of the framework of Spaceship, but we need to add two more functions before it will actually do anything useful. Go back to spaceship.h and define the functions void stepFunc() and Atom *addAtom(Atom *a). Go into spaceship.h, and define them as follows:

void Spaceship::stepFunc() {
    Object::stepFunc();

    if(*turn_right && !*turn_left) {
        left_engine->applyForce(engine_power);
    }
    else if(*turn_left && !*turn_right) {
        right_engine->applyForce(engine_power * 0.5f);
    }
    else if(*accelerate) {
        left_engine->applyForce(engine_power);
        right_engine->applyForce(engine_power);
    }
}

Atom *Spaceship::addAtom(Atom *a) {
    if(a->object) return a;         //check to avoid an infinite loop: ship adds atom to engine, engine adds atom to parent (the ship), repeats
    Object::addAtom(a);

    if(a->group == 1) {
        left_engine->addAtom(a);
        left_engine_dir->front = a;
    }
    if(a->group == 2) {
        left_engine->addAtom(a);
        left_engine_dir->back = a;
    }
    if(a->group == 3) {
        right_engine->addAtom(a);
        right_engine_dir->front = a;
    }
    if(a->group == 4) {
        right_engine->addAtom(a);
        right_engine_dir->back = a;
    }

    return a;
}

Here, stepFunc is a function that is called every frame (every System.update(), to be precise) and checks to see if the user is accelerating, turning left, or turning right, and tells the actuators to apply a corresponding force. addAtom is called for each atom when the object is being loaded from a .pob file, and assigns the directions' front and back atoms based on the atoms' groups (an atom's group is a property that can be defined in the object editor) as well as placing atoms in their respective engines (so that the actuator can apply forces to them).

Congratulations, you've written your first interactive object! The process we've just gone through is one you'll use for just about every interactive element in your games. All that remains is to update your game to take advantage of Spaceship's capabilties.

Updating Your Game

Go into tutorial.cpp. Change

Object *o;
o = new Object(this);

to

Spaceship *o;
o = new Spaceship(this, &keys[VK_UP], &keys[VK_LEFT], &keys[VK_RIGHT], 1.0);

and #include "spaceship.h" at the top. Now that that's all settled, open up spaceship.pob again with the object editor.

Here, we want to change the groups of 4 atoms to indicate the positions of the left and right engines. Drag select a single atom at the front of the left engine. Type "1" in the group box on the right and click "Update Properties." Select an atom at the back of the left engine and make its group 2. Do the same for the right engine, using 3 and 4 as group numbers. Your finished product should look like this: (Note the colors depicting group numbers)

Now, recompile your game, and take your new spaceship for a spin! Control it with the arrow keys.


Physical: A Physics-Based Game Creation Engine - Help

Step 5: Finishing Touches

So far, you've created the foundation for a game. In this step we'll apply some finishing touches to that foundation, and explore some more capabilities of Physical. Once this tutorial is complete, you'll have a good foundation with which to start a full-fledged game.

Adding Key Handling

Currently, the only way to close your program is to press the "X" on its window. This works fine for now, but what if you wanted to go full-screen? Let's let the user press Escape to quit. We do this by overloading Tutorial.keyDown(). Add the definition in tutorial.h, then define it as follows:

void Tutorial::keyDown(int key) {
    Game::keyDown(key);

    if(key == VK_ESCAPE)
        quit = true;
}

Remember, however, that keyDown is a function only of games, so you can't put that function in normal objects. If you want an object (such as a spaceship) to do something on a key press, the best way to do that is to pass it a pointer to a bool (the key) in the constructor, as we did with the arrow keys. This keeps abstraction to a maximum, allows you to remap keys or have multiple players, and has the added benefit of making AI handling very easy. For AI, you can create a structure - say, SpacePirate - which has a pointer to a Spaceship and a few member variables of type bool, then have the SpacePirate create its own ship with references to its bools. The SpacePirate can then decide what it wants to do in its stepFunc and then update its bools (corresponding to accelerating, turning left, etc.) accordingly.

Changing the Ship's Structure

As you've probably noticed, the spaceship as it is now is rather weak, and tends to shatter. There are a few things we can do about this. First, go into the Physical Object Editor and select all the atoms and links. Set their rigidities to 30, and their spring constants to 0.5. (Rigidity determines how many times per frame a link / atom force is calculated. Higher values not only increases rigidity on their own but also allow for higher spring constants. You can fiddle with the spring constants until they are as high as they can go without exploding.) Also change the lower break point to 0.4 and the upper break point to 2.0. Save the object and run the game again. The ship should be more stable. In my version of the tutorial game, I weakened the braces holding the engines to the ship and also changed the base class of Spaceship from Object to Material, to decrease the "frayed edge" effect when an object is damaged. (Read more about that at Material.)

Further Ideas

We've reached the end of the scope of this tutorial. You have learned by now the basic structures you'll need to manipulate in creating a game with Physical. If you want some more practice before creating your own game, or you want to try extending the game we've started here, try implementing some of these things:

  • Add a gun to the spaceship. This can be easily done with the DGun structure. You may need a MultiAtomDir if you want the gun to fire from the middle of the ship.
  • Add a second player. This should only take one or two lines of code.
  • Experiment with StaticObjects.
  • Add particle effects for the engines. This will require an understanding of atom levels.

I've written a game that demonstrates most of these suggestions, and more. It was written in around a week, but could have been done much quicker if I hadn't also been working on the engine at the same time. Here it is: SpaceGame. The source code is included, so feel free to poke around and figure out how I've done things.

I hope this tutorial has given you a taste of how easy it is to design games using Physical. Some of it may seem complicated or confusing at first, but after you've written a little more and gotten used to the basic structures of Physical it'll make more intuitive sense, and you'll be able to churn out new interactive elements in no time. Good luck programming!


Physical: A Physics-Based Game Creation Engine - Help

Example Game: Physical Asteroids

I've written a simple game that builds upon the foundation created in the tutorial and showcases many of the common elements of programming with Physical. It was originally intended to be an Asteroids clone, but ended up taking on a life of its own.

Installing the Game

Extract this to any directory and it will create a subfolder with the game. Just double click the .exe to play, or open the .dsw file to edit the code. (To get it to recompile, you may have to update the project settings as in Step 1 to correspond to your Physical directory.)

Gameplay

The green arrow points to the nearest asteroid, the red arrow back to Bob's Junkyard, your home base. Go get the asteroids and drag them back to Bob's. If you get them near enough to the entrance, the friendly workers at Bob's will latch on to them with their tractor beam and bring them in. Watch out, though, greed may get the best of them if you're in the crusher when an asteroid is being brought in. Once crushed, the little asteroid bits get sucked into the main processing plant. Eventually this will make you money.

NOTE: Bob's Junkyard is an extension of StaticObject. Static objects were not covered in the tutorial, but represent an important tool for handling unbreakable objects. Static objects are not physically simulated and are created straight from an image using the Tools... Create Static Object option in the Physical Object Editor.

Controls

Accelerate | Up arrow
Turn left | Left arrow
Turn right | Right arrow
Fire cannon | Left or right control
Fire grappling hook | Left or right shift
Quit | Q or Escape
Render faster (increase compframes) | Page up
Render smoother (decrease compframes) | Page down

System Requirements

A tolerably fast CPU, > 500 MHz
A 3D accelerator card with support for OpenGL (IMPORTANT! Otherwise it will look like a slide show)


Physical: A Physics-Based Game Creation Engine - Help

Reference

This is the main programmer's reference section for Physical. It is split into two sections:

Code:
The code and structures used in Physical. By far the larger section. Programmers looking to work with physical should at least browse this, studying the more essential structures and coming back to look up specifics when needed.

Tools:
This section covers the standalone design tools used in conjunction with Physical. As of yet, only one such tool, the Physical Object Editor, exists, but there may eventually be more.


Physical: A Physics-Based Game Creation Engine - Help

Tools

This section covers the standalone design tools used in conjunction with Physical. As of yet, only one such tool, the Physical Object Editor, exists, but there may eventually be more.


The Physical Object Editor

First, read the Overview of the Physical Object Editor.

Using the Physical Object Editor

Some specifics on using the Physical Object Editor:

  • The left mouse performs whatever action you have selected on the right panel. Usually this means clicking and dragging.
  • Click and drag the right mouse button to pan your view.
  • Roll the mouse wheel to zoom in and out. You can also use the toolbar buttons if you do not have a mouse wheel.
  • There are two ways to move atoms:
    • Select atoms, then select "Move" on the right panel, then click and drag the left mouse button. This moves atoms in non-integral amounts and is NOT RECOMMENDED.
    • Select atoms, then use the arrow keys on your keyboard to move the atoms one pixel (at normal zoom) up, down, left, or right. This is RECOMMENDED, as it will help you maintain symmetry.
  • Move Texture on Drag
    • From the Edit menu, you can select and deselect the option "Move Textures on Drag." This affects whether the textures are moved / deformed with the atoms when the atoms are moved or whether their position removes constant despite their component atoms moving (default).
  • The Select Button
    • Note that you can check the boxes for atoms, links, or both. This affects what objects are selected when you drag a selection box in the main window.
  • Levels
    • You can edit the levels of an atom by clicking Edit... Levels.

Creating an Object

Follow the approach given in the Overview.

Editing Properties

Edit properties of links or atoms by selecting atoms or links, changing the values in the properties pane, and then clicking Update Properties.

Atom Properties

Rigidity: Integer. Determines how many times an atom's repulsion forces are updated per system update. The higher this value, the smaller errors you will get in atom repulsions.
Mass: Float. Changes the atom's mass. Higher mass means it takes more force to move an atom.
Move Constant: Float [0,1]. This changes how much of the force applied to an atom will be converted into inertialess motion. Inertialess motion is a bit of a physics hack discussed in Atom.
Group: Integer. An atom's group is an integer used as a general tag that can be interpreted as an object wishes. Generally, it is used so that the uniform data output by the Physical Object Editor can be broken down into more useful groups and sub-groups during an object's load function - e.g., placing certain atoms in the engines of a ship, others in the body, etc.

Link Properties

Rigidity: Integer. Determines how many times per system update a links spring forces are calculated and applied. As with atom, the higher this number, the lower the error, but the longer the computation. Use 3 for jello-y objects, up to 30 for rigid ones.
Spring Constant: Float [0,1] The spring constant used in calculating the spring forces. Higher values can cause explosions due to the quantization of time (don't ask). However, you can generally get away with slightly higher values if you increase the rigidity.
Rest Length: Float. The length the spring tries to stay at. This actually cannot be edited right now: you can change the property, but the rest lengths are all set to the distances between the atoms at save time.
Lower Break Point: Float [0,1]. The lower bound on the stretching a spring can withstand before breaking. I.e., if the spring has a rest length of 10 and a lbp of .5, it will break if is compressed to a length of less than 5.
Upper Break Point: Float. Analog to the lower break point for maximum elongation.

Creating a Static Object

To create a static object (see StaticObject, RepulseField) first draw the object you want to make into a static object. Save it as an RGBA TGA image with alpha 0 for the background. Then, if you want the parts of the object that are solid to be different from what is drawn, create a separate masking image with alpha 0 for the parts that should not be solid. Click Tools... Create Solid Object and select the masking image. The Physical Object Editor then creates a RepulseField based on that image, with the vector offsets for non-solid pixels set to zero and the vectors of solid pixels being the offset to the closest non-solid pixel. (In other words, a RepulseField that pushes atoms inside the object to the oustide.) Then, in the save dialog, type in where you want to save the RepulseField (it will have the extension .prf). Finally, in your code, you can create a StaticObject using the original image as the texture and a the .prf file as the RepulseField.


Physical: A Physics-Based Game Creation Engine - Help

Code

This section contains an overview of the various structures used in physical. These structures are split into three categories:

Physics:
The structures in this section make up the underlying physics engine in Physical. The main structure in this section that programmers will have to deal with is System, but it is important to at least understand the others. It is unlikely that the programmer will want to change or extend any of this code, however.

Rendering:
The structures in this section make up Physical's rendering framework. The core structure is Renderer, which is intended to be extended to create rendering engines. One such rendering engine has already been provided, GLRenderer, but the programmer may wish to either extend GLRenderer or create a new Renderer (extending from Renderer) of their own.

Objects:
These structures are the highest level objects included in Physical, and of them, only the Object structure is actually required for Physical to function. Despite this, they are the structures most game programmers will probably deal the most with. All the structures are extensions of Object, either directly or indirectly, and serve to add functionality and interactivity to Physical. These structures are designed to implement some of the most common elements of a game written with Physical. They include things like guns, particle effects, and actuators. For the most part, programmers will maintain a separate folder of their own objects, specific to the game they are working on, and use a mix of those objects and the ones included in Physical.


Atom

PhysList

PhysList is a helper list structure, and does not fit into the three main categories. It is pretty crude and it is suggested that you use other structures for your own list-keeping, at least until this is cleaned up.


Physical: A Physics-Based Game Creation Engine - Help

Physics

The structures in this section make up the underlying physics engine in Physical. The main structure in this section that programmers will have to deal with is System, but it is important to at least understand the others. It is unlikely that the programmer will want to change or extend any of this code, however.


Atom

System

The System is the mastermind of the physics engine. It maintains lists of all the atoms and links in the world, as well as the physical constants (gravity, width of the world, height of the world). It calls the update() functions of all of the atoms and links from its own update().

struct System {
        float width;
        float height;
        float rcontainerw;
        float rcontainerh;
        float gravity;                     //typically negative

        bool frozen;                       //if set to true, the world does not update and nothing moves. Use this for pausing
        int highest_rigidity;

        unsigned int frame;                //the frame counts how many calls to update() have been made
        unsigned int tick;                 //the tick increases every time atoms are placed into containers

        PhysList<Atom> atoms;
        PhysList<Link> links;
        int numatoms;

        Container containers[CONTAINERW][CONTAINERH];    //containers subdivide the world into boxes of size (1/rcontainerw), (1/rcontainerh). Atoms are placed in these boxes during updates to make finding neighbors easier. See Container

        std::bitset<INTERACTTABLESIZE> interacttable;    //a table of size MAXATOMS x MAXATOMS. interacttable[i][j] is true if atoms i and j repel each other, false otherwise. Generally interacttable[i][j] is set to false when a link between a and j is created
        std::bitset<MAXATOMS> atom_indices;

        System(float width = 1000.0f, float height = 1000.0f, float gravity = -30.0f, float rcontainerw = 0.1f, float rcontainerh = 0.1f);
        void resize(int w, int h);
        Atom *addAtom(Atom *a);
        Link *addLink(Link *l);
        void removeAtom(Atom *a);
        void removeLink(Link *l);
        Link *findLink(Atom *a, Atom *b);
        void update();
        void clear();
};

void resize(int w, int h);
 Resizes the world. Atoms beyond the new edges are pulled into the world on their next update. Measurements in pixels.

Link *findLink(Atom *a, Atom *b);
 Returns the link between atoms a and b, if it exists.

void update();
 Updates the world. For each atom a, a.repel() is called a.rigidity times and a.update() is called once. For each link l, l.update() is called l.rigidity times.


Atom

The atom is the most basic unit of physical simulation in Physical. An atom is a simple particle with a position and velocity. Its acceleration is affected by the gravity of the System it is a part of and the links that connect it to other atoms (although those forces are applied in Link). Atoms also repel each other when they move closer than the average of their repulsion distances (generally 10 pixels).

Although the forces acting on a single atom are simple, a system of hundreds of atoms can display remarkably complex behaviors. For example, even though an atom does not have an orientation, structures constructed out of atoms and links rotate just as you would expect them too. Even loose atoms are good at simulating fluids, thanks to their repulsion forces.

Most of the time, atoms will be created by Object.load, and you will not have to deal with them. However, there may be cases where you want to create atoms on the fly, such as for a waterfall or bullets from a gun. You should also get a basic understanding of atoms just because they are so important to the physics of Physical.

struct Atom {
        float x, y;        //the position of the atom
        float ox, oy;      //the old position (last update) of the atom - used for inertia
        float fx, fy;      //the force being applied to the atom
        int rigidity;      //how many times per system update the repulse forces are calculated
        float rrigidity;   //reciprocal of rigidity
        Atom *next;        //used in containers to make atoms into linked lists
        int level;         //the level the atom exists on
        bool levels[MAXLEVELS]; //the levels the atom interacts with
        int index;         //index of atom - used only for saving / loading
        float mk;          //intertialess motion constant
        float rdist;       //distance at which atom repels other atoms
        int cx, cy;        //which container the atom is in
        bool draw;         //whether or not to draw the atom
        float mass;        //the atom's mass
        float rm;          //reciprocal of mass - this is what's actually used
        bool interpolate;  //atoms with interpolate set to true update their position rigidity times per update rather than once per update, for smoother movement. Set this to true for things like bullets that run the risk of jumping right through an object due to time steps
        float ix, iy;      //for interpolate only
        bool particle;     //something of a hack... don't interact, only other with it
        int group;         //for loading complex objects. May be removed, eventually... not sure
        int numlinks;      //number of links atom is attached to (used for determining draw)

        Object *object;    //object the atom belongs to - used for atomUpdate
        System *system;    //system the atom belongs to - used for bouncing off walls, gravity

        Atom(float x = 0.0f, float y = 0.0f, float mass = 1.0f, float ix = 0.0f, float iy = 0.0f, int level = 1, const bool levels[MAXLEVELS] = defaultlevels, float mk = 0.1f, int rigidity = 3, float rdist = 5.0f);
        ~Atom();
        void init();
        void repulse(Atom *b);
        virtual void addLink(Link *l);
        virtual void removeLink(Link *l);
        bool in(Object *o);
        void updateContainer();
        void repel();
        void update();
        void snap();
        void save(FILE *output); //DO NOT MAKE THIS VIRTUAL - or it will screw up loading and saving because of dynamic binding
        void load(FILE *input, float offx = 0.0f, float offy = 0.0f); //DO NOT MAKE THIS VIRTUAL - or it will screw up loading and saving because of dynamic binding
};

Atom(float x = 0.0f, float y = 0.0f, float mass = 1.0f, float ix = 0.0f, float iy = 0.0f, int level = 1, const bool levels[MAXLEVELS] = defaultlevels, float mk = 0.1f, int rigidity = 3, float rdist = 5.0f);
Creates an atom at position (x, y) with mass mass, inertia (ix, iy), on level level, interacting with levels levels, with an inertialess motion constant mk, with a rigidity of rigidity, and an atom repulsion distance of rdist.

void init();
Clears member variables to default states. Called automatically in constructor.

bool in(Object *o);
Returns true if the atom is in o, false otherwise. "In" is defined simply as the atom's object being o or any of o's parents.

void update();
Updates the atom's position based on gravity and inertia. Bounds the atom to the world and places it in a container. Calls the atom's object's atomFunc.

void snap();
Updates the atom's position based on forces applied. Bounds the atom to the world and places it in a container. Does not call atomFunc.

Levels

There is currently in place a rather inelegant but very useful system to make Physical from 2D into "2.5 D". That system is levels. In this system, every atom has a level and a list of bools determining what levels the atom interacts with. Two atoms a and b will only repel each other if a.levels[b.level] = true. By this method, you can create humans that can walk in front of buildings (in a side-scroller) or jet-exhaust that spawns inside the engine but does not rip it to shreds (as in my example game Physical Asteroids). Levels can be edited using the Physical Object Editor.


Atom

Link

The Link is the second most important physics structure, after Atom. A Link acts as a spring between two atoms, and springs are the basis of multi-atom structures. When two atoms are linked, they no longer repel each other, but the spring tries to maintain its rest length, and will apply forces on the atoms to do this. Springs break when they stretch below their lower break point (lbp) or above their upper break point (ubp). When a spring breaks, its atoms repel each other normally.

struct Link {
        Atom *a, *b;

        float rl;       //the rest length of the spring
        float lbp;      //the length below which the spring breaks
        float ubp;      //the length above which the spring breaks
        float k;        //the spring constant
        float mrat;     //ratio of inertialess motion
        bool draw;      //whether or not to draw the spring
        Object *object;
        int rigidity;
        bool being_deleted;
        int numpolys;   //number of polygons of which this spring is a side. Affects draw

        Link(Atom *a = NULL, Atom *b = NULL, float rl = -1.0f, float lbp = 0.8f, float ubp = 1.2f, float k = 0.20f, int rigidity = 3);
        ~Link();

        void init();
        bool in(Object *o);
        void update();
        virtual void addPoly(Poly *p);
        virtual void removePoly(Poly *p);

        void save(FILE *output); //DO NOT MAKE THIS VIRTUAL - or it will screw up loading and saving because of dynamic binding
        void load(FILE *input, PhysList<Atom> atoms, float offx = 0.0f, float offy = 0.0f); //DO NOT MAKE THIS VIRTUAL - or it will screw up loading and saving because of dynamic binding
};

bool in(Object *o);
Returns true if the link is in o, false otherwise. "In" is defined simply as the link's object being o or any of o's parents.

void update();
 Updates the spring, moving the atoms. Called automatically by System.update().


Atom

Container

A container is just an internal structure used for subdividing the physical world. The system creates a matrix of 10 pixel x 10 pixel containers, and drops atoms into the container for the area they are in. Then, when calculating repulsion forces (the force whereby two near by atoms repel each other) the atom only has to check atoms in neighboring boxes for distance, rather than iterating through all atoms in the world.

You, as a game designer, will never have to deal with containers.

struct  Container {
Atom  *first;
Atom  *last;
unsigned  int stamp;

Container();
void   add(Atom   *a, int
 tick);
};

If you're wondering what stamp is, it's just a record of what tick (see System) the container was updated, so the container does not have to empty itself each update.


Atom

RepulseField

A RepulseField is a matrix of vectors. Applied to an atom, a RepulseField moves the atom by the vector corresponding to the Atom's initial position. Think of it like a vector force field. RepulseFields are used to implement StaticObjects, but they can also be used to create other things, such as one-way passages, slippery slides, or forces like wind from a fan. The only difficulty with RepulseFields is creating an editing them: a tool exists to create static objects, but for the other possible applications no tool yet exists (although you could probably write one yourself without much difficulty).

struct   RepulseField {
int **xo;
int **yo;
int width;
int height;
int x;
int y;
int ax;
int ay;

RepulseField();
RepulseField(int
width, int  height);
RepulseField(const char
*fn, int   xp = 0, int
 yp = 0);
RepulseField(FILE *file, int
 xp = 0, int   yp = 0);
~RepulseField();
void  apply(Atom
*a);
void  save(const char
*fn);
void  save(FILE
*output);
void  load(const char
*fn);
void  load(FILE
*output);
};

void apply(Atom *a);
 Applies the RepulseField to a. It takes a's position and finds the corresponding vector, then adds that vector to a's position. Don't forget to call this function! You have to do it manually for every RepulseField. Put it in your game or object's atomFunc.


Physical: A Physics-Based Game Creation Engine - Help

Rendering

The structures in this section make up Physical's rendering framework. The core structure is Renderer, which is intended to be extended to create rendering engines. One such rendering engine has already been provided, GLRenderer, but the programmer may wish to either extend GLRenderer or create a new Renderer (extending from Renderer) of their own.


Atom

Renderer

This is the base class of all renderers in Physical. It is effectively an abstract class, as any game using only the base renderer will not even be able to create a window. The only reason it is not defined as abstract is so a game with no desire to display graphics (a benchmarking program, for example) can create an "empty renderer" that will provide enough functionality to keep the program from crashing when other functions try to interface with the renderer (for example, when reading in a new object that includes polygons).

NOTE: A game's renderer should be created after the system is created, so it can be passed a valid pointer to the system it will render.

struct Renderer  {
int
windoww;
int
windowh;

PhysList<Poly>
polys;

Game *game;
System
*system;

Renderer(Game
*game);
virtual void initializeGraphics(char
*title, float window_width, float window_height, int bpp,
bool fullscreen, bool resizable);
virtual void deactivateGraphics();
virtual void resize(int w, int h);
virtual void draw();
Poly
*addPoly(Poly  *p);
void removePoly(Poly
*p);
void removeLink(Link
*l);
};

Renderer(Game *game);
    Creates a new renderer with a pointer to the Game creating it. (A renderer must know about the game for two reasons: first, to have access to the atoms and links in the System so it can draw them, and secondly, so it can call the game's draw() function.)

virtual void initializeGraphics(char *title, float window_width, float window_height, int bpp, bool fullscreen, bool resizable);
    Like all the drawing functions, initializeGraphics is not implemented in the base renderer and is a stub function. In theory, it should initialize the graphics, presumably by creating a new window, with title title and the parameters given. resizable determines whether or not the edges of the window can be dragged to resize the window.

virtual void deactivateGraphics();
    Shuts down the renderer. Should be called in the destructor of your game.

virtual void resize(int w, int h);
    Resize the renderer and potentially the window.

virtual void draw();
    Draws all of the atoms, links, and polygons in the system and then calls the draw() function of the game. This is probably what you'd overload in an extension of an already feature-complete renderer (e.g. GLRenderer).

Poly *addPoly(Poly *p);         //returns p
void removePoly(Poly *p);
void removeLink(Link *l);
    Automatically called bookkeeping functions. The only one you might have to deal with is addPoly, if you want to create a new polygon between three atoms in the game. Typically, however, you would create a new object and draw the polygons manually in its draw() function.


Atom

GLRenderer

GLRenderer is, for the time being, the only fully-functional renderer included in Physical. It implements all of the functions of a basic Renderer using OpenGL.

struct GLRenderer : public Renderer {
        HINSTANCE hInstance;
        HWND hWnd;
        HGLRC hRC;
        HDC hDC;

        GLRenderer(Game *game, HINSTANCE &hInstance);
        virtual void initializeGraphics(char *title, float window_width, float window_height, int bpp, bool fullscreen, bool resizable);
        virtual void deactivateGraphics();
        virtual void resize(int w, int h);
        virtual void draw();
};

GLRenderer(Game *game, HINSTANCE &hInstance);
    Creates a new GLRenderer with a pointer to the Game creating it and an HINSTANCE, which is passed into the WinMain function of a windows program. (The HINSTANCE is required for the creation of the window.)

virtual void initializeGraphics(char *title, float window_width, float window_height, int bpp, bool fullscreen, bool resizable);
virtual void deactivateGraphics();
virtual void resize(int w, int h);
virtual void draw();
    Overloaded functions. They do what you'd expect. See Renderer.


Atom

Poly

The Poly class draws a textured triangle with vertices at three atoms' positions. By stretching many polygons across an entire object (as is done automatically in Physical Object Editor) one can texture an object and make it appear as more than just atoms and links.

struct Poly {
        Atom *a1, *a2, *a3;                          //pointers to the atoms at each vertex. Only used to assign the position pointers (next) on load
        double *x1, *x2, *x3, *y1, *y2, *y3;         //pointers to doubles that determine where the polygon is drawn. Generally point to the x,y coordinates of atoms
        float tx1, ty1, tx2, ty2, tx3, ty3;          //the texture coordinates - floats that determine the position on the texture each vertex is at, in pixels
        float rtx1, rty1, rtx2, rty2, rtx3, rty3;    //a conversion of the texture coordinates to floats from 0 to 1 with (0,0) being the origin and (1,1) being the upper-right corner
        Link *l1, *l2, *l3;                          //the links that make up the edges of the polygon. Determined in System::addPoly

        Object *object;
        Texture *texture;

        Poly();
        Poly(Atom *a, Atom *b, Atom *c);
        ~Poly();
        void init();                                //just initializes member variables. Only called internally.
        bool in(Object *o);
        void setTexCoords();

        void save(FILE *output); //DO NOT MAKE THIS VIRTUAL - or it will screw up loading and saving because of dynamic binding
        void load(FILE *input, PhysList<Atom> atoms, PhysList<Texture> textures, float offx = 0.0f, float offy = 0.0f); //DO NOT MAKE THIS VIRTUAL - or it will screw up loading and saving because of dynamic binding
};

Poly(Atom *a, Atom *b, Atom *c);
    Creates a new polygon with vertices at the atoms given.

~Poly();
    The polygon destructor. Calls the removePoly() functions of its constituent links and its parent object. This can result in a link becoming visible, if it is no longer the edge of any polygon.

bool in(Object *o);
Returns true if the poly is in o, false otherwise. "In" is defined simply as the poly's object being o or any of o's parents.

void setTexCoords();
    Converts the pixel texture coordinates (tx1, tx2, etc.) to the [0,1] floats (rtx1, rtx2, etc.). Call this after you've modified the pixel texture coordinates.

void load(FILE *input, PhysList<Atom> atoms, PhysList<Texture> textures, float offx = 0.0f, float offy = 0.0f);
    Worth mentioning because of its parameters: it must be passed lists of the atoms and textures read in during the loading of the current object, so it can correctly identify its own texture and atoms. Do NOT pass it in the global atom and texture lists, or it may mistake previously-existing atoms and textures for its own.


Atom

Texture

Holds a texture. Copied from nehe tutorials. If you want to edit a texture after it is loaded, you can do this using some obscure OpenGL functions. I may release a demo with this functionality.

struct Texture {
        GLubyte *imageData; // Image Data (Up To 32 Bits)
        int datasize;
        GLuint bpp; // Image Color Depth In Bits Per Pixel
        int bypp;
        GLuint width; // Image Width
        GLuint height; // Image Height
        int w;
        int h;
        GLuint texID; // Texture ID Used To Select A Texture
        GLuint type; // Image Type (GL_RGB, GL_RGBA)
        char filename[256];

        Texture();
        Texture(char *fn);
        void init();
        void init(char *fn);
        Color getPixel(int x, int y);
        void save(FILE *output);
        void load(FILE *input);
};

Texture(char *fn);
 The standard way to create a texture. Automatically loads the filename given, e.g.:
 t = new Texture("spaceship.tga").
Only loads TGAs, for now.

void save(FILE *output);
void load(FILE *input);
 NOT what you think - these functions do not actually save and load the image data. Rather, save just records the texture's filename, so that an object's textures can be saved and then loaded and initialized using that filename.


Atom

Color

Self-explanatory.

struct Color {
GLubyte r;
GLubyte g;
GLubyte b;
GLubyte a;

Color();
Color(int
r, int     g, int
 b);
Color(int
r, int   g, int
 b, int   a);
bool     operator ==(Color &c);
bool     operator !=(Color &c);
};


Physical: A Physics-Based Game Creation Engine - Help

Objects

These structures are the highest level objects included in Physical, and of them, only the Object structure is actually required for Physical to function. Despite this, they are the structures most game programmers will probably deal the most with. All the structures are extensions of Object, either directly or indirectly, and serve to add functionality and interactivity to Physical. These structures are designed to implement some of the most common elements of a game written with Physical. They include things like guns, particle effects, and actuators. For the most part, programmers will maintain a separate folder of their own objects, specific to the game they are working on, and use a mix of those objects and the ones included in Physical.


Atom

Object

Object is the single most important class for a programmer using Physical. It is a container for atoms and links, but it is more than that: it is the foundation of any animate object. Through its functions stepFunc and atomFunc, which are called once per game tick and once for every atom per game tick, respectively, an Object can exert forces upon its component atoms. As such, an Object can embody any kind of interactive or animate element, from an engine to a spaceship to a growing plant. Most of the game design that takes place in Physical will occur in the form of extending Object to add functionality like that. As such, understanding the Object class is thoroughly is key to developing with Physical. A primer on the subject can be found in the tutorial (specifically Step 4).

NOTE: As with all overloaded functions, you should always call the base class's function first: i.e., in Spaceship.stepFunc() you should first call Object::stepFunc().

struct Object {
        Object *parent;
        PhysList<Object> children;
        bool being_deleted;

        Object();
        Object(Object *parent);
        ~Object();
        virtual Atom *addAtom(Atom *a);
        virtual Link *addLink(Link *l);
        virtual Poly *addPoly(Poly *p);
        virtual Texture *addTexture(Texture *t);
        virtual StaticObject *addStaticObject(StaticObject *o);
        virtual void removeAtom(Atom *a);
        virtual void removeLink(Link *l);
        virtual void removePoly(Poly *p);
        virtual void removeObject(Object *o);
        void load(const char *fn, float offx = 0.0f, float offy = 0.0f); //DO NOT MAKE THIS VIRTUAL - or it will screw up loading and saving because of dynamic binding
        void load(FILE *input, float offx = 0.0f, float offy = 0.0f); //DO NOT MAKE THIS VIRTUAL - or it will screw up loading and saving because of dynamic binding
        virtual void stepFunc();
        virtual bool atomFunc(Atom *a);
        virtual void draw();
};

Object(Object *parent);
 This creates an Object. Every Object, except a Game, needs a parent. (The constructor without an Object should never be called. It's only used in Game's creator.) An Object relies on its parent for many, many things: whenever an atom is added, it is also passed to the object's parent to be added to that; whenever the atomFunc is called, the parent's atomFunc is called as well.

virtual Atom *addAtom(Atom *a);
virtual Link *addLink(Link *l);
virtual Poly *addPoly(Poly *p);
virtual Texture *addTexture(Texture *t);
virtual StaticObject *addStaticObject(StaticObject *o);
virtual void removeAtom(Atom *a);
virtual void removeLink(Link *l);
virtual void removePoly(Poly *p);
virtual void removeObject(Object *o);
 These functions are called whenever an atom, link, polygon, or texture is added or removed from an Object. (The StaticObject calls may be removed, don't count on them.) You can overload these functions in a variety of ways. The Roster object object overloads them to maintain a list of all atoms, links, polygons and textures in the object, for use later in various functions such as calculating the center of gravity or saving an object. You could also create an object that "stops working" after a certain number of atoms or links are removed.

virtual void stepFunc();
 An object's stepFunc is called before every system update. Here is where you would put code that activate engines based on key presses or check the status of a mouse pointer or makes AI decisions. Remember to call Object::stepFunc() so that the child objects can also be updated.

virtual bool atomFunc(Atom *a);
 An object's atomFunc is called once for every atom during each system update. Here you would put code that applies a force to all of the atoms, or takes some action dependent on the atom's state. atomFunc could be handled by simply iterating through all the atoms during an Object's stepFunc, but this was seen as a cleaner solution.

virtual void draw();
 Called during rendering. Make any special rendering calls you want to here. Note that this framework is a little shaky, as it cannot change dependent upon what kind of renderer you are using. I am still trying to find an architecture that allows that. As a result, this call may change or disappear in the future. For now, you'll just have to rewrite all your draw functions if you change renderer.


Atom

Game

This is the base class of every game made with Physical. A Game structure acts as a container for all the diverse elements of a Physical program. The base class Game includes functionality common to all games: variables for holding key states, mouse position, and mouse button states; a quit() method; and a stepFunc() method that is typically called by the main program every frame and forms the basis for the game loop. Extend the Game class to create your own game (e.g., class SpaceGame : public Game). A Game also contains pointers to a System and Renderer. When an atom, link, or poly is added to a game, Game passes that pointer off to the appropriate container (System or Renderer).

struct Game : public Object {
        bool keys[256];
        int mouse_x;
        int mouse_y;
        bool lmb;
        bool rmb;
        bool quit;                    //a bool checked every tick in main.cpp. If true, the program quits
        int compframes;               //the number of frames computed for every frame displayed. Usually 1, but on systems with poor graphics capabilities, higher values may be a good idea

        System *system;
        Renderer *renderer;
        PhysList<StaticObject> static_objects;

        Game(int compframes = 1);
        ~Game();
        void initializeDisplay(char *title, int screenWidth = 800, int screenHeight = 600, int bytesPerPixel = 16, bool fullScreen = false, bool resizable = false);
        void deactivateDisplay();
        virtual void keyDown(int key);
        virtual void keyUp(int key);
        virtual void mouseMove(int x, int y);
        virtual void lmbDown();
        virtual void lmbUp();
        virtual void rmbDown();
        virtual void rmbUp();
        Atom *addAtom(Atom *a);
        Link *addLink(Link *l);
        Poly *addPoly(Poly *p);
        Texture *addTexture(Texture *t);
        StaticObject *addStaticObject(StaticObject *o);
        void removeAtom(Atom *a);
        void removeLink(Link *l);
        void removePoly(Poly *p);
        virtual void stepFunc();
        virtual bool atomFunc(Atom *a);
};

void initializeDisplay(char *title, int screenWidth = 800, int screenHeight = 600, int bytesPerPixel = 16, bool fullScreen = false, bool resizable = false);
 Just calls the renderer's intializeGraphics()function with these parameters.

void deactivateDisplay();
 Again, just hands it to the renderer.

virtual void   keyDown(int
 key);
virtual void   keyUp(int
 key);
virtual void   mouseMove(int
 x, int   y);
virtual void   lmbDown();
virtual void   lmbUp();
virtual void   rmbDown();
virtual void   rmbUp();
Functions designed to be overloaded. Called when these events occur. They also update the various bools (the set of keys. lmb, rmb, etc.).

StaticObject *addStaticObject(StaticObject *o);
    A Game keeps track of all of the static objects in the world so that it can call their atomFunc() during its own atomFunc(). Ideally, there would be some sort of an infrastructure where an atom can belong both to a static object and to something else not a subclass of static object, but this is not the case.

virtual void stepFunc();
    The same stepFunc() as for any object, but particularly important in the case of a Game. This is the root stepFunc that is called every tick by main.cpp, and it is typcally where the central game loop would be.


Atom

StaticObject

A StaticObject is just a wrapper for a RepulseField that adds the ability to draw a correspondingly positioned texture. Using this, you can draw an object in a paint program, turn it into a RepulseField using POE, and then both draw and update it using a StaticObject. In short, you can make objects that atoms bounce off of but that do not bend or break like normal objects and are also much, much faster to update.

struct StaticObject : public Object {
        RepulseField *rf;
        Texture *tex;

        StaticObject(Object *parent, RepulseField *rf, Texture *tex);
        virtual bool atomFunc(Atom *a);
        virtual void draw();
};

virtual bool atomFunc(Atom *a);
 This must be called every atom update. It in turn calls the RepulseField's apply function. Ideally, there would be some sort of an infrastructure where an atom can belong both to a static object and to something else not a subclass of static object, but this is not the case. This is all handled automatically if the StaticObject is directly added to a Game. See Game.addStaticObject.


Atom

Material

Material extends Roster. In a Material, links that are not part of any polygon are destroyed. This stops broken objects from getting a tattered or frayed appearance, which often happens with simple Objects, and which does not look right for anything constructed out of a solid material like a spaceship.

struct Material : public Roster {
        Material(Object *parent);
        void removePoly(Poly *p);
};


Atom

Roster

A Roster is an extension of Object that keeps track of all the atoms, links, polygons, and textures added to it. As such, a Roster (or a subclass of Roster) is the only kind of Object that has a save function (because none of the others know what is in them). Because a Roster keeps track of its atoms, it can also do some special things like apply forces and rotational forces.

struct Roster : public Object {
        PhysList<Atom> atoms;
        PhysList<Link> links;
        PhysList<Poly> polys;
        PhysList<Texture> textures;
        float cx, cy;

        Roster(Object *parent);
        virtual Atom *addAtom(Atom *a);
        virtual Link *addLink(Link *l);
        virtual Poly *addPoly(Poly *p);
        virtual Texture *addTexture(Texture *t);
        virtual void removeAtom(Atom *a);
        virtual void removeLink(Link *l);
        virtual void removePoly(Poly *p);
        void estimateCenter();
        virtual void calculateCenter();
        void applyForce(float fx, float fy);
        void applyRotation(float speed);

        void save(const char *fn); //DO NOT MAKE THIS VIRTUAL - or it will screw up loading and saving because of dynamic binding
        void save(FILE *output); //DO NOT MAKE THIS VIRTUAL - or it will screw up loading and saving because of dynamic binding
};

void estimateCenter();
 Estimates the center by just setting cx and cy to the position of the first atom.

void calculateCenter();
 Sets cx and cy to the actual center of the object based on averaging the positions of all the atoms.


Atom

Actuator

An Actuator is a very simple actuator. It just applies a force (fx, fy) to every atom in the object.

struct Actuator : public Object {
        float fx, fy;

        Actuator(Object *parent);
        void applyForce(float forcex, float forcey);
        virtual void stepFunc();
        virtual bool atomFunc(Atom *a);
};

void applyForce(float forcex, float forcey);
 Applies the given force to all atoms. Only lasts one tick, so you have to reapply it each update. The idea is that you would do checks like

if(*accelerate)
    engine->applyForce(0.0f, 1.0f);


Atom

DActuator

A DActuator is an actuator that applies a force in a direction given by a Direction object. That way, you can have an engine that applies a force forward, where "forward" is defined by the relative positions of two atoms. (See Step 4 in the tutorial.) You apply forces based on magnitude - that is to say, applying a force of 3.0f will add a vector in the direction of the direction and with a magnitude 3 times as large as the direction's magnitude (dx, dy).

struct DActuator : public Object {
        float fx, fy;
        Direction *direction;

        DActuator(Object *parent, Direction *direction = NULL);
        virtual void applyForce(float force) ;
        virtual void stepFunc();
        virtual bool atomFunc(Atom *a);
};

void applyForce(float force);
 Applies the given force to all atoms. Only lasts one tick, so you have to reapply it each update. The idea is that you would do checks like

if(*accelerate)
    engine->applyForce(1.0f);


Atom

DGun

A DGun is a simple gun that fires single atoms based on a Direction.

struct DGun : struct Object {
        bool *trigger;              //when true, the gun fires
        float force;                //the force of the bullet being fired
        int life;                   //how long the bullet lives
        int cool_down;              //how long after firing the gun must wait to fire again
        int temp;                   //internally used to keep track of cooling down
        float offset;               //how far forward of the direction's position the bullet should appear
        float mass;                 //the mass of the bullet
        Direction *direction;

        DGun(Object *parent, bool *trigger = NULL, Direction *direction = NULL, float force = 0.0f, float offset = 1.0f, int cool_down = 10, int life = 50, float mass = 5.0f);
        virtual void stepFunc();
};


Atom

Direction

A Direction defines a point, an inertia, and a direction. Generally you would use this for making engines (see Step 4 in the tutorial) or guns or any other object that depends on a moving or shifting platform. Direction itself does nothing; functionality is written in in subclasses.

struct Direction {
        float dx, dy;
        float x, y;
        float ix, iy;

        virtual void calc();
};

virtual void calc();
 Calculates and updates all the member variables. Empty, of course, in this class.


Atom

AtomDir

An AtomDir is a simple implementation of Direction that creates a direction based on the relative positions of two atoms. The back atom is used to determine the position and inertia of the direction.

struct AtomDir : public Direction {
        Atom *front;
        Atom *back;

        AtomDir(Atom *front = NULL, Atom *back = NULL);
        virtual void calc();
};


Atom

MultiAtomDir

Like an AtomDir, but takes the average of a list of front atoms and the average of a list of back atoms for front and back positions. This is useful when you want to add a gun or an engine between two rows of atoms. The back atoms are used to determine direction position and inertia.

struct MultiAtomDir : public Direction {
        PhysList<Atom> front;
        PhysList<Atom> back;

        void addFront(Atom *a);
        void addBack(Atom *a);
        void calc();
};


Atom

MouseDir

A Direction that uses the relative positions of the mouse cursor and an Atom to determine a direction. The atom's position and inertia are used for the direction's position and inertia.

struct MouseDir : struct Direction {
        Atom *atom;
        float *mouse_x;
        float *mouse_y;

        MouseDir(Atom *atom, float *mouse_x, float *mouse_y);
        virtual void calc();
};


Atom

Particle

Extends LifeAtom to include drawing an image around the atom. Starts with rgba values of r, g, b, and a, and they decay or increase at a rate of (r,g,b,a)ch. By default, those values are set to good settings for fire / engine exhaust.

struct Particle : public LifeAtom {
        float r, g, b, a;              //initial r,g,b values
        float rch, gch, bch, ach;      //change values - how quickly they decay / increase
        int startlife;
        float rstartlife;              // 1.0 / startlife
        float size;
        float hsize;                   // 0.5 * size
        Texture *tex;                  //the particle image

        Particle(Object *parent, Atom *me, Texture *tex = NULL, int life = 50, float size = 20.0f, float r = 1.0f, float g = 1.0f, float b = 1.0f, float a = 1.0f, float rch = 0.0f, float gch = -2.0f, float bch = 0.0f, float ach = -1.0f);
        virtual void draw();
};


Atom

LifeAtom

A LifeAtom is a wrapper for an Atom that just deletes the Atom when a certain number of updates have elapsed. Used primarily for bullets and particles.

struct LifeAtom : public Object {
        Atom *me;
        int life;               //number of updates left before atom is deleted

        LifeAtom(Object *parent, Atom *me, int life);
        virtual void removeAtom(Atom *a);
        void stepFunc();
};