Tag Archive for 'Game Development'

AJAX Tiles Game

I started programming life by writing an AI for a simple game called RoboWar (back when it was a shareware game on Macintosh, in the pre-OS X days). Make sure you click the “Edit” buttons at the bottom of that page to view the kind of code I had to deal with. I then moved on to HyperTalk and, when I finally got my hands on a PC, started a ten-year spree in C++.

Recently, I started toying with a similar idea: to create a game where people could write an AI that would play for them, with simple and easily modeled rules, and a really easy way to share your creations with your programmer friends (because just adding your AI to a long list of other AIs is kind of boring and not very social).

So, I wrote a simple game in JavaScript. You feed it one URL for each player, and the game connects to that URL and asks for the next move. So, your AI is one URL, which makes it easy to share. Not to mention that you can probably write that AI in any language you wish, provided it can respond to HTTP requests and read JSON arrays of characters, and you can resort to a lot of fancy stuff (cloud computing, learning from experience, genetic algorithms) that would otherwise not be available in a game like RoboWar. The game board is readily available for you to observe while the game is played. It looks like this:

The rules to the game are fairly simple: pick white tiles to paint them with your color, pick tiles you already own to nuke them (blows up that tile and the four adjacent tiles as well), and connect a large group of tiles you own to a small group of tiles your opponent owns to conquer them. The player with the most tiles when the board is covered, wins. Play it here. I’ve already programmed four different AIs:

  • http://tiles.nicollet.net/ai/?random plays randomly.
  • http://tiles.nicollet.net/ai/?expand creates one single group of tiles and expands it as fast as possible.
  • http://tiles.nicollet.net/ai/?fearful nukes its own tiles when they might become connected to enemy tiles.
  • http://tiles.nicollet.net/ai/?contain attempts to contain the enemy in a prison of nuked tiles.

None of these are particularly good, and a human player can certainly beat them quite easily, but they’re a good challenge for your own AI. If you wish to participate without starting from scratch, you can fork the sample AI on GitHub to create your own (it’s PHP code). Also, the GitHub README contains all the technical details about what data your AI URL receives and what data it should respond with. And, if you’re curious, the game rules are cleanly described in the JavaScript source code.

I’m looking forward to hearing from you. Please share your AIs in the comments below, if you please: I’m really interested in what you might come up with.

Shogun – Rise of the Renegade

The good folks at int13 have released a preview of their latest video game, Shogun – Rise of the Renegade:

It looks absolutely great—can’t wait to get my hands on it (I might even buy a smartphone so I can play it). It should be available next month on iPhone and Samsung Wave, shortly followed by an Android release.

Shogun was meant to be the follow-up project to Darklaga (the video game I developed with int13 back in 2004), but I had to leave the team without being able to start working on it seriously. It’s good to see that they managed to get the project out of the closet to develop and release it five years after its inception.

Plus, that’s a little bit of my own legacy right there— the “Shogun” part of the name was my idea!

More details available on the (french) int13.net website.

Shoot’em up Game Design

To understand how to make a game difficult, you have to understand how the player reacts to obstacles. In shoot’em up games, difficulty comes from the following causes:

  • Reflex-based obstacles require good hand-eye coordination and the ability to react in a split second. Examples are very fast shots or speeding suicide bombers.
  • Tactics-based obstacles require more concentration, because they are crafted in such a way that blind reflexes will not work. Examples are player position during intricate boss attacks, or choosing the order in which to kill the enemies.
  • Strategy-based obstacles usually involve the choice of weapons, or the use of smart bombs.

The common denominator to all these obstacles is the one and only player resource: concentration time. A given player can only concentrate on a fixed amount of entities and concepts in a given time duration.

An isolated entity (a ship, a bullet), no matter how dangerous, should never require large amounts of skill to overcome, because this is simply not fun for the player: acquiring the required skill can only happen when fighting that entity, which means the player will fail a large amount of times. However, the interaction of several entities creates another kind of difficulty: since the player can only handle a limited amount of entities at a given time, player skill will come from the ability to decide which entites are worth concentrating on, and which are not. Difficulty will then come from interesting ways in which entites can be made to interact in order to surprise or puzzle the player.

Clustering

The human brain has several innate abilities that allow it to handle large amounts of entites. The most important of these is clustering: if several entities are similar enough in their aspect and (simple) behavior, then the brain will be able to handle all of them at the same time as if there was only one. This has several implications on the difficulty of several situations:

  • Shots that move in the same direction are easier to manage than shots fired in random directions.
  • Shots that come from the same point are easier to manage than shots fired from several different points.
  • Enemies that are far away from each other cannot be easily concentrated on.
  • Differences in movement speed, as well as complex non-linear movement, increase the difficulty of managing entitites. However, if all entitites move exactly the same way (even if it is complex), then the effect is lessened a great deal.
  • Colour-coding helps isolate movements. By having all shots that move in a given direction have a certain colour, the player will dodge them with less difficulty.

In a shoot’em up game I worked on, Darklaga, these effects were obvious as different kinds of shots were used. In the high-difficulty modes, enemies used both a slow-moving shot type and a fast-moving one. The slow-moving type was initially used to spin a web, through which the player had to navigate. Because the fast-moving shots were almost the same color as the slow-moving ones, the player had many difficulties spotting them because he was concentrated on navigating through the web.

Delayed threats

The next step is the introduction of delayed threats. Indeed, right now all techniques only serve to increase the difficulty of dodging enemy fire, which is an immediate threat. Once an enemy shot is fired, the only solution is to dodge it. However, if a type of enemy is known for firing dangerous pellets, then that enemy is a delayed threat: if it is killed before it fires, then the game becomes easier. As such, destroying delayed threats is a top priority for the player (second only to the necessity to avoid immediate threats). Here are several pointers related to delayed threats:

  • Delayed threats fall into two categories: diversion and sneaking. The former must attract the concentration of the player onto itself to divert him from immediate threats. The latter will attempt to stay unseen in order to unleash an immediate threat of its own.
  • Diversion threats rely on attracting the player’s attention, and to do this they use several properties of the human brain. They blink/are animated/have a distinct color, they appear in a clear area where nothing else can block the view, and are usually quite big. Average differences in movement speed are not noticed (but different movement directions are). The reverse is true for sneaking threats.
  • A delayed threat need not be an enemy. A wave of shots that moves towards the player is an immediate threat. Now, hide among these shots a similar-looking shot that moves in the same direction (so it will not stand out of the crowd), but at a smaller speed (so natural clustering will ignore it), and you have an unseen sneaking threat going straight for the player if he did not spot it fast enough to move away. This technique was used for the Blazing Star final boss, by the way.
  • A delayed threat need not even be hostile! By setting free a valuable power-up at the right time (and having that power-up ‘leave’ the screen after a short time), the player faces the ‘danger’ of not picking up that item. This is a very interesting diversion system.
  • Delayed threats that must be destroyed (essentially enemies) are stronger when the weapon of the player does not have a wide spray or auto-aiming. The harder it is to aim at a threat, the more difficult it will be to counter it.

What would be examples of this? Darklaga featured “warping” enemies which appeared somewhere on the screen, waited a short moment, and unleashed a vicious attack at the player. It was very important to destroy these enemies as soon as possible (and they were weak), or they would transform the playing field into hell in space. Another such “delayed” feature was the introduction of kamikaze enemies. These would slowly move down the screen vertically, stop, and suddenly move horizontally to ram the player’s ship from its undefended sides. These enemies were mainly introduced to rebalance the otherwise unbalanced vertical laser (a very powerful weapon that ripped through enemies, but which required one to move fast enough to kill the kamikaze before it rushed in).

More diversions

There are even more ways to apply the constatation that the player can only concentrate on so many things at a given time:

  • Darklaga had a special class of enemy that rotated around the player. The enemy would usually do almost nothing (it did not shoot very often either), but it was safe from any attacks until its giratory movement placed it in front of the player’s ship (at which point it died). However, a rotating enemy ship is enough to attract the player’s attention, and divert it from more important concerns. Not having those enemies be completely inoffensive also helped keep a portion of the player’s attention on them.
  • The player naturally concentrates on his or her target. This can be used to your advantage in several ways. The most obvious is to have the player keep its eyes on an enemy a few milliseconds after its death. Idea: a way to do this is to have a little slot machine appear where the enemy was (which can roll out an instant bonus for the player).
  • Another is to notice that players watch the enemy until it dies (and not until they fire the final shot that would kill it): if the lethal blow is not different from normal shots, the player will wait until it reaches the enemy. Idea: have the player weapon fire “targeted” missiles at the enemy, with missiles being slower and more powerful as time passes; the lethal missile will be very slow. It works even best with a flamethrower, since missiles can be counted.
  • Have threats appear as much more dangerous than they really are. Darklaga featured horizontal walls of enemies. If the player kept firing constantly, they would die whether or not the player was paying attention at them. However, even though it served no purpose, most testers kept their eyes on the enemy wall until it was destroyed, and were hit by enemy fire in the process.
  • Teleporting enemies can be made to teleport behind the player when he isn’t looking (because his attention was diverted by something else). And the time spent on dispatching them can be put to use by other delayed threats coming from the other way.

Published Articles

I have recently contributed two articles to two game development books.

These are:

Both are in the gamedev.net collection.

Adobe Flash 10 : 3D in your browser

A short while ago, Adobe set loose the newest version of the Flash player, along with the development SDK.

Among the advertised benefits of this new player, there is the ability to use native support for drawing three-dimensional objects. Nothing on the scale of Papervision3D, though: the programming interface is extremely limited in its scope and, although a great step from what Flash supported natively in earlier versions, it’s still a long way from what desktop 3D programmers have grown accustomed to. We can only hope for existing engine developers (or new teams) to harness the low-level primitives of Flash Player 10 into high-level drawing primitives.

Graphics Processing Units

I suspect that many readers, especially those with a Flash/Flex background, are not familiar with the modern graphics pipeline found in the hardware of most reasonably recent computers, so a quick primer on the subject could be helpful.

The CPU in a typical computer is a general-purpose piece of hardware: it can handle 3D as well as it can handle spreadsheets or web browsing. This led to the creation of a new class of software which was specifically designed to perform computations related to 3D: it could only do these computations, but it did them darn fast. So, video games and CAO programs started delegating some processing to this hardware, which slowly evolved over time into our modern GPU hardware.

Early on, the GPU could only handle elementary functions such as projecting 3D triangles on a 2D screen, but quickly gained new features, such as mapping textures on triangles or handling lights (this is what the TnL revolution was: Texture and Lighting the availability of Transform and Lighting in hardware), and more recently the ability to apply an arbitrary amount of operations independently to every pixel drawn on the screen. Today’s GPUs are massive beasts, able to handle thousands of pixels in parallel where a CPU could only handle one or two.

CPU and GPU architectures How does it work?

The CPU collects or creates the data that should be displayed. This is generally composed of 3D data (triangles that are to be drawn) and 2D data (textures to be mapped onto triangles). Most of the time, these are sent to the GPU during an initialization step and stored in the GPU memory. Sometimes, new data is computed at runtime and is sent asynchronously (that is, the GPU receives the new data while drawing the old data, so that no time is wasted).

Once the required data is present on the GPU, the CPU sends rendering instructions. These instructions are usually quite small (“Draw object #3 at position (x,y,z) using textures #5 and #7″) but result in massive amounts of work (Object #3 contains thousands of triangles and fills millions of pixels on the screen) so that the majority of data transfers happen between the GPU local memory and the GPU local processor using high-speed connections on the video card.

The result is that the CPU can send a few dozen cheap rendering instructions, then handle whatever it needs to handle (gathering user input, performing physics simulations, handling the network connections), while the the GPU toils away at running the provided instructions on thousands of polygons and millions of pixels with amazing performance.

A common techique to improve performance is batching. Once the multiprocessors start working on a new instruction, they work fast, but starting a new task takes some time. As such, drawing 600 polygons in one instruction is significantly slower than drawing 300 polygons twice with two instructions. Batching consists in grouping as many polygons as possible in a single batch that can be drawn with a single instruction, and is the backbone of performance improvement.

The exact details of what happens on the GPU has changed over time, with the addition of textures, lighting, instancing, bump-mapping, arbitrary pixel shaders and vertex shaders, 64-bit numbers, integer support, the unified shader model of DirectX 10, and a whole lot of other esoteric names for esoteric features. The core processes delegated to the GPU, however, have not really changed:

  • Vertex operations involve gathering 3D data from various sources (usually, local memory that has been initialized with data from the CPU) and then transforming it according to certain sets of rules, so that it ends up as a 2D shape projected onto the screen.Various additional operations at this stage involve:
    • Lighting: for every point of the 3D shape, the illumination is computed and stored.
    • Instancing: creating many copies of a single piece of 3D data, such as soldiers in an army or trees in a forest.
    • Tessellation: transforming non-polygonal curved surfaces into polygons.
  • Pixel operations involve filling the projected 3D data with on-screen pixels, using predefined rules for deciding what the color will be or whether the pixel is to be drawn.A large number of additional operations at this stage can be performed:
    • Blending: instead of replacing existing color on the screen, a mix is computed to achieve transparency or illumination effects.
    • Textures: data for every pixel is collected from one or more textures.
    • Lighting: using the illumination stored in the 3D shape, as well as other sources (normal maps, bump maps) illumination is computed for every pixel.
    • Depth: if the pixel being drawn is behind the pixel present at the same location on the screen, it’s not drawn.
    • Stencils: using a screen-sized boolean texture, rendering can be limited to only certain areas.

The result of these operations can be displayed or kept in an off-screen buffer for use as a source of 2D data later on.

Two steps in GPU processing

Back to Flash Player 10

Flash Player 10 allows the programmer to control the pixel operations level. That is, the programmer provides the 2D data and the Shapes, and the Flash player performs the required pixel operations and outputs the resulting pixels to a Graphics object. The function to perform this is the raw Graphics.drawTriangles(), or the combination of Graphics.drawGraphicsData() and the GraphicsTrianglePath class.

I see two problems with this:

There is no Depth Buffering

This is the biggest problem, in my opinion: drawing projected data does not handle the depth of pixels at all, which makes it impossible to tell whether a certain triangle stands in front of another. As a consequence, the Graphics.drawTriangles() function assumes that the triangles it is asked to draw are ordered from the furthest to the nearest using the Painter’s Algorithm. Since triangles have no reason to be in the correct order to begin with, the programmer is forced to sort triangles by hand. This has two obvious performance-related consequences:

  • No caching of the polygon data on the GPU is possible: since the order of polygons might change from one frame to the next, the CPU-GPU transfer lines are used to send the polygon data every frame, which decreases performance.Even worse, general batching is impossible: if polygons from two batches are interleaved, then the batches must be split to respect the order of the polygons. This means that instead of sending 600-polygon batches to the GPU like a video game would, the Flash Player will be sending a whole lot of 2-polygon or 4-polygon batches instead.

    Of course, smart programmers might still achieve batching as a custom trick in specific situations, but common rendering techniques which automatically achieve high amounts of batching tend to rely on depth buffering to work, and as such might not be carried over as easily.

  • Instead of being done on the GPU (often in a highly optimized fashion), sorting has to happen on the CPU. Polygon-based sorting is either incorrect (sorting polygon centers might result in overlap problems with polygons that are not facing the eye), or complex (using a BSP tree to determine optimal rendering order). Not to mention the problem of overlapping or crossing polygons in the Painter’s Algorithm which can only be solved by slicing the inconvenient polygons beforehand.

Vertex operations remain on the CPU

In order to know where to render things, one needs to project 3D shapes onto a 2D screen. This task is traditionally performed by the GPU in classic desktop applications, but has to be done on the CPU in Flash 10. This is usually done by constructing a view-and-projection matrix, and then using Matrix3D.transformVector() to transform vectors individually, then manually extracting the x and y coordinates of the resulting vectors and plugging them in an array that is compatible with Graphics.drawTriangles().

Resist the temptation of using Matrix3D.transformVectors() to transform an array of vectors in one shot: while this may result in higher performance, it is not equivalent: if your matrix incorporates projection (which is required for projecting 3D shapes on 2D screens) that projection will not be applied, only the affine transform will be. Besides, you will still have to manually extract the x and y coordinates.

My choice was to use Matrix3D.transformVectors() to apply the entire affine transform, then applying the projection manually using arithmetic operators:

matrix.transformVectors(triangles, transformed); 

for (var i : int = 0; i < vertices; ++i)
{
    var z : Number = transformed[3*i+2];
    projected[2*i]   = ((transformed[3*i] / z) + 1) * width;
    projected[2*i+1] = ((transformed[3*i+1] / z) + 1) * height;
}

This choice was dictated by another fun fact: unlike OpenGL or Direct3D, there is no simple and obvious way of creating a projection matrix in Flash 10. In fact, when I tried to use Matrix3D.rawData to create a projection matrix from its mathematical definition, the program complained that the matrix was not invertible (which is often the point of a projection matrix).

A step forward

Reading my above disappointments, it would be easy to conclude that Flash Player 10 is a worthless technology with only marginal improvements over previous versions and limited lip service to the ressurection of browser-based 3D. This is not the case, and there are massive benefits to Flash Player 10. Even if there is still no batching or GPU-based geometry transforming, and even if the user has to sort polygons by hand, there is a high-performance way to map a texture using texture coordinates, which should definitely improve the performance of several existing 3D engines from the Flash Player 9 era within a matter of weeks. An active engine undergoing continued development efforts, such as Papervision3D, should be able to integrate the new features quite easily.

Besides, Flash 10 is not aimed at rivaling high-end 3D video games (or at least, I hope it wasn’t) but rather to apply simple 3D effects to DisplayObjects, thereby leveraging existing 2D codebases in a fresh new direction. And this, it does quite well: sorting works quite simply (as long as you have no overlaps), transforming is handled internally using matrices, and so on.

Still, a better interface could have been chosen to support general 3D. I could understand that depth buffering cannot work on every possible piece of phone hardware, but sacrificing what is a de facto standard on desktop and laptop computers seems strange. The same goes for vertex and index buffers (sent to the GPU). These can be trivially emulated in software, yet provide tremendous performance benefits by lowering the transfers from CPU to GPU.

In conclusion, don’t expect to write the next Crysis or Half-Life 2 using Flash Player 10, but the technology should be able to equal older 3D game graphics without too much difficulty (Crash Bandicoot, The Sims, Ragnarok Online, Second Life) and enhancing the aspect of existing Flex applications with 3D effects should be a breeze.

Game Development Tutorial

Creating video games is not easy, but few things are easy: cooking for ten, writing a book or running ten miles are quite difficult as well. The difference is that with games, people don’t know how to start. To cook for ten people, you know it’s going to involve shopping for ingredients, using a kitchen to boil, simmer, roast and prepare them, and serve them. Writing a book involves typing on your keyboard until you’ve written all the hundreds of pages you wanted to write. Running ten miles involves getting your shoes on and going outside.

But how does one start creating a video game? How does the initial idea of a video game translate to an actual program you can run? This step isn’t the hardest of all steps in game development (far from it) but it deters a lot of otherwise well-motivated wannabes.

As a former game developer (I was the lead programmer for Darklaga : Cannonball Symphony) I will try to answer a few of these questions on the technical side. To this end, I have written a short video game which you can find here, which happens to be a reimplementation of Pong (one of the earliest video games). In this article, I will discuss video game development using that game as an illustration.

How Game Development Works

So, how does a video game get created? It usually follows the same set of steps:

  • A team of designers has a basic idea for a game. it designs most of the high-level details of the game: the look and feel, the various elements and their behavior, win and loss conditions, player controls, and so on.
  • A team of artists creates the graphics and sounds for the game, using their favorite editors and tools and recording studios, according to the designer’s vision.
  • A team of programmers writes the program itself, describing how, where and when the graphics should appear and the sounds should be played, and how the player’s input affects this, according to the designer’s vision.
  • Testers play the game, provide input to the designers, who alter the design to please the testers. The cycle repeats until the testers are happy or money runs out.
  • A publisher takes the game, packages it, sends it to retail stores and advertises it.

Of course, all of this could be done by a single person (Pong), or it could be done by an independent team of five (Darklaga), or it could be done by a professional experienced studio backed by a strong publisher (Red Alert 3).

In an ideal world, you would be able to pitch in an idea, and people would take that idea, create a game from it, publish it and give you a share of the money. This rarely happens in the real world, because games take time to be developed, there’s limited manpower to go around, and so those few idea-pitcher positions are already taken by people with vast amounts of experience and connections in the business. Tom Sloper has a few quite interesting articles about getting your game done, which you can read here.

So, if you have a great game idea, but neither connections nor experience in the business, you’re basically stuck with either giving up or doing it yourself. This will involve either convincing a programmer to work for you, or doing the programming yourself. If you want to try programming, read on.

Programming Games

Video games are computer programs: contraptions designed and written by programmers to make the computer behave in a certain way. Since programmers tend not to be happy with available tools, they often invent new ways of programming computers, which means there are many ways of creating a video game. For instance, the Pong game I wrote for this article is written using a programming language called Javascript (or ECMAScript, depending on whom you ask). The part of the program responsible for making the ball bounce on the screen edges looks like this:

if (this.ball.y + ball.h > field.h)
  { this.ball.vy = - ball.s } 

if (this.ball.y - ball.h < - field.h)
  { this.ball.vy = ball.s }

Different programming languages look different. Sometimes, differences are small, so an equivalent program in the C++ programming language would look like:

if (this -> ball.y + ball::h > field::h)
  { this -> ball.vy = - ball::s } 

if (this -> ball.y - ball::h < - field::h)
  { this -> ball.vy = ball::s }

These two are fairly similar, because both C++ and Javascript belong to the same family of languages (called the C family) and therefore share a lot of features and constructs. By contrast, Objective Caml is a programming language of the ML family, and has a quite different take on things:

method verticalBounce =
  if y -. Const.ball_h < -. Const.field_h then
    {< vy = Const.ball_s >}
  else if y + Const.ball_h > Const.field_h then
    {< vy = -. Const.ball_s >}
  else
    self

Different languages have different capabilities. I chose Javascript because it allows running the game in a browser with no downloading or applets. One could choose the ActionScript language to run a video game in a Flash or Flex applet, or the Java language for running a video game in a Java applet, both within a browser. Developing for Windows or the XBox could involve using the C#, F# or VisualBasic.Net languages. Developing for the PC and most consoles can also happen in the C++ and C languages, as well as one of the many BASIC language variants and many others as well. Writing the central server program for multiplayer games could involve the ErLang or Stackless Python programming languages for performance reasons. Writing a video game for a pocket calculator would involve using the assembly language for that calculator. Every programmer know several languages, and chooses whichever best fits the problem he is solving.

Code is written for humans to read and only incidentally. for computers to execute.
- Donald Knuth

All languages have a thing in common: they’re human-readable text which the computer does not understand, and as such they necessitate a translation phase where the program, written in a programming language, is transformed into a sequence of machine instructions that the computer can execute. This translation sometimes happens before running the program (done by another program called a compiler), and sometimes it happens while running the program (done by another program called an interpreter). Some languages, such as C++, tend to be always compiled, while other languages, such as JavaScript, tend to be always interpreted, and many programs are half-compiled and half-interpreted.

Almost everyone has a Javascript interpreter on their computer: Internet Explorer, Firefox and Safari all bundle one, because web pages tend to use Javascript to make their content dynamic and interact with the user. Because of this, all you need to start programming is a text editor (such as Notepad) to edit javascript files and a web browser (such as Internet Explorer) to view the result. I prefer to use improved tools (the Crimson Editor, Firefox and the Firebug plug-in) because they help me write programs faster.

If I have seen further it is only by standing on the shoulders of Giants.
- Isaac Newton

A very important aspect of programming (and computer usage in general) is the use of existing tools for accomplishing common tasks. Programmers who regularly solve the same problems eventually write down code to solve these problems, once and for all, and then store that code in code libraries. Sometimes, a library is useful enough that it deserves to be published and used by many other programmers worldwide. For instance, my Pong game needs to move green things around on the screen, which is a fairly common task that is already done by the jQuery Javascript library. In general, when a programmer has a difficult task to solve, he usually searches for an existing solution on the web before rolling out his own.

A Programming Primer

This article is not going to teach you how to program. That would require more space and time than I have here. What it can do, however, is teach a few basic elements of programming in Javascript, which you may also find useful in other languages.

The simplest way of executing Javascript is to write it as part of a web page. For instance:

<html>
  <head>
    <title></title>
    <script type="text/javascript">
<![CDATA[
   { write your javascript code here }
]]>
    </script>
  </head>
  <body></body>
</html>

Save this text with the “html” file extension, and start writing Javascript. Open the file in a browser to test it (depending on your security settings, you might have to enable scripts for this to work). Again, I strongly advise you to use the CrimsonEditor/Firefox/Firebug triad for working with Javascript.

Statements, Variables, Values

Javascript is an imperative language: it describes sequences of operations to be performed by the computer. Individual operations are called statements. For instance, the sentence $(document).text(“Hello”) is an operation which replaces the content of the document with the text “Hello”. You can chain several statements together by separating them with semicolons: the statements are then executed in order, left-to-right and top-to-bottom. One very useful statement is the “alert” statement, which creates a message box containing some text:

alert("This is my message")

If you’re using Firebug, you have access to the superior “console.debug” option, which is not as nasty as a message box and allows you to output things more complex than text:

console.debug("This is my message")

Programs manipulate values: these can be numbers, lists of other values, pieces of text, parts of a web page, or even parts of a program. The most elementary operation to be performed with a value is to store it in a variable: this is useful so that values are kept around when you’re not using them. A variable is just a name which is associated with a value: you can retrieve that value at any time by writing the variable’s name, and you can change the value of a variably any time you wish.

Creating a variable uses the “var” keyword, which is reserved for that purpose:

var zero = 0

This statement creates a variable, called zero, and associates it with the number 0. You can use a variable anywhere you would use its value:

var message = "This is my message" ;
alert(message)

This displays “This is my message” in a message box. You can also change the value of a variable after you’ve created it. That operation is called an assignment:

var message = "This is my message" ;
alert(message) ;
message = "On second thought, it isn't" ;
alert(message)

This displays “This is my message” followed by “On second thought, it isn’t”. The first value assigned to the variable is lost, replaced by the second value assigned to the variable.

You can manipulate values in many fashions. For instance, you can have arithmetic operations (+a, -a, a + b, a – b, a / b are fairly obvious, a * b is multiplication, and a % b is the remainder of dividing a by b), comparisons (a == b for equality, a != b for inequality, a < b, a > b, a <= b and a >= b), and logical connectors (a && b : and, a || b: or, !a : not).

Blocks, Functions

I have mentioned earlier that you can manipulate parts of a program. The easiest way of doing so (although somewhat limited) is to use blocks and control structures. A block is zero, one or more statements between curly braces, for instance { a ; b }. A control structure is a special statement which is followed by a block, and executes that block under special circumstances. For example, a conditional statement only executes its associated block if a certain condition is true:

if (age < 13)
{ alert("You are not allowed to view this website")  }

Control statements give you control over which statements are executed in certain situations. They are invaluable for expressing complex behavior in your programs. A typical extension of the conditional statement is to also specify something to be done when the condition is not verified:

if (name == "John") { alert("Hello, John!") }
else                { alert("Who are you?") }

By now, you have probably noticed that I position my blocks and statements around randomly. This is indeed the case: Javascript doesn’t care about the position of your statements and blocks. Just like in English, you can write your sentences every way you wish as long as you don’t split or swap your words.

Another typical control statement is the loop. It executes its associated block repeatedly as long as its condition is true. So, displaying a countdown from 10 to 0 would look like this:

var i = 10 ;
while (i != 0)
{ alert(i) ; i = i - 1 }

The loop displays the number, then substracts one from it, until the number is no longer different from zero.

The improved version of a block is a function: a function is, for all purposes, a block that can be manipulated as a value. This means that you can assign it to variables, keep it around, and execute it when you want it to. You create a function from a block by using the “function()” keyword in front of that block. You then call functions (which executes the corresponding block) by appending two parentheses after the variable name:

var scare = function() { alert("Boo!") }; 

if (surprise)
{ scare() ; alert("Sorry for scaring you!") }
else
{ alert("I'm going to scare you!") ; scare() }

Functions serve several purposed in a program. Their primary purpose is to eliminate repeated code: if you have code which is repeated in several places, turn that code into a function and call the function wherever you need without having to rewrite the code. This even works if you have code that is not identical, but still similar enough:

var i = 1 ;
var total = 0 ;
while (i <= 10) { total = total + i }
alert(total) ; 

i = 1 ;
total = 0;
while (i <= 20) { total = total + i }
alert(total)

These two pieces of code compute the sum of numbers between 1 and 10, and between 1 and 20. The only difference here is the number 10 (or 20). It is then possible to make this number a parameter of a function: when a function has a parameter, a value for that parameter has to be provided when the function is called. The parameter then becomes a variable associated to that value. In this case:

var sum = function(max)
{ var i = 1 ;
  var total = 0 ;
  while (i <= max) { total = total + i }
  alert(total) }; 

sum(10) ;
sum(20)

A function may have several parameters. If that is the case, then the parameter values must be provided in the same order. Parameters enhance the ability of functions to eliminate repetitive code.

The secondary use of functions is to serve in special situations where one needs to represent a block. For instance, the setTimeout() operation registers a function to be executed after a specified duration. So, for instance:

alert("First message") ;
setTimeout(function(){ alert("Third message") }, 3000) ;
alert("Second message")

This displays “First message”. When that message box is closed, it registers “Third message” to be displayed after 3 seconds (3000 milliseconds) and immediately displays “Second message”. Another example is jQuery’s “when document is loaded” operation, $():

$(function(){ alert("Document has finished loading") });

Note that you can define functions and assign them to a new variable in a single action using an alternative simplified syntax:

function sum(max)
{ var i = 1 ;
  var total = 0 ;
  while (i <= max) { total = total + i }
  alert(total) }

Objects, Classes

One other feature of Javascript is the ability to combine several values into one. For example, it’s interesting to store together in a single variable the horizontal and vertical positions of the ball in a Pong game, yet still be able to access them independently. In Javascript, an object is an aggregation of several values: these values are members of the object, and they are given names which allows the program to access them:

var obj = { x : 10, y : 20 } ;
alert (obj.x) ;
alert (obj.y) ;
obj.x = 30 ;
alert (obj.x)

This code creates an object with members x (equals 10) and y (equals 20). It then displays the value of member x, then the value of member y. Then, it changes the value of member x, and displays it again. The result is 10, 20, 30.

When it becomes useful to create many objects along the same pattern, as well as define functions which can operate on these objects, Javascript allows you to define classes of objects. A class is a template which allows the creation of objects which have function members that operate on the object. A class is a template used for the creation of objects. For instance:

function number(x)
{ this.x = x } 

number.prototype.increase = function() { this.x = this.x + 1 } ; 

number.prototype.show = function() { alert(this.x) } ; 

var n = new number(10) ;
n.show() ;
n.increase() ;
n.show()

This example introduces several new concepts, which are all necessary to understand classes:

  • The ‘prototype’ keyword indicates that the ‘number’ function is in fact a class, and defines two functions, ‘increase’ and ‘show’, as being members of all objects of class ‘number’.
  • The ‘new’ keyword creates a new object of the ‘number’ class. That is, it creates an empty object, then adds every function inside the class prototype to that object. Then, it calls the function ‘number’ itself, with the provided parameter values.
  • The ‘this’ keyword acts as a variable. Whenever a member of an object is called,’this’ becomes equal to that object, so that any operations applied to ‘this’ will be applied to the object. When the ‘number’ function is called because of the ‘new’ keyword, ‘this’ becomes equal to the newly created object.

In detail, what the example above does is:

  • Define a function called ‘number’.
  • Decide that ‘number’ is in fact a class, and define member functions ‘increase’ and ‘show’.
  • Create a new instance of ‘number’ : this creates an object, adds the ‘increase’ and ‘show’ functions to it, sets ‘this’ to that object, and calls ‘number’.
  • When ‘number’ is called, it creates a new member ‘x’ and sets it to 10. So, the new object has a member ‘x’ equal to 10.
  • The program calls the ‘show’ function. This sets ‘this’ to the object, and the function reads the ‘x’ member of that object (which equals 10) and displays it.
  • The program calls the ‘increase’ function. This sets ‘this’ to the object, and the function adds one to the ‘x’ member of that object (so it now equals 11).
  • The program calls the ‘show’ function. This sets ‘this’ to the object, and the function reads the ‘x’ member of that object (which is now 11) and displays it.

Note that the value of ‘this’ is restored after a member function returns.

But I Can’t Remember All This!

Of course, you can’t. This kind of stuff takes time and patience to remember. So, take your time and read it a few times. If you don’t understand something, try it out to see for yourself what happens. If you really don’t get it, ask around. I’m willing to answer questions if you ask them in comments to this entry, and you can always ask questions around the good folks at gamedev.net anytime. After a few weeks of practice, you’ll be able to do most of this on your own.

Game Design

Before you jump right into coding (and drawing your assets, if applicable) you need to have a fairly complete and detailed description of the game you intend to develop. Otherwise, like a mason without a plan, the house you build is unlikely to ever be finished, and will crash to the ground in strong wind if it is.

The basic requirements for a pong game are as follows:

  • The Pong game contains a square ball and two rectangular paddles.
  • The ball moves at a certain speed along both horizontal and vertical axis.
  • When it hits the top or bottom of the screen, the vertical velocity is reversed.
  • When it hits the left or right edges of the screen, the horizontal velocity is reversed and the ball is moved to the center (horizontally). The player on the other side gains a point.
  • When it hits a paddle, the horizontal velocity is reversed.
  • Paddles are vertical, and there is one on each side of the screen.
  • They move up and down at a fixed speed.
  • When they hit the top or bottom edges of the screen, they stop moving.
  • They move slightly slower than the ball (so that “follow the ball” is not a winning strategy).
  • The player controls the left paddle, an AI controls the right paddle.

Writing the program

The game is a large piece of functionality. However, programming only allows us to express small bits of functionality. So, we will have to split up the program in smaller pieces before we can create it.

One common way of splitting things is the MVC architecture. MVC stands for Model/View/Controller, which can be explained like this:

  • The Model describes everything that happens behind the scenes. It doesn’t care about how the game will be displayed on the screen, or how the input from the player will be received. What it cares about is where the ball is, where the paddles are, how the ball should bounce when it hits something, and when scores should increase. This will be an entire object containing all the data required to describe the game, along with functions that compute the movement of the paddles and ball over time.
  • The View describes how the game should be displayed. It doesn’t really care why the ball and paddles move a certain way: all it cares about is where the ball and paddles are, and which way they are moving. It gets this information from the model, and displays it in one way or another.
  • The Controller is what makes the game interactive: it reads user input in one way or another, generates AI strategies, and enters all that data into the model. Once the model has computed the new positions and scores, it asks the view to draw it, then starts again.

Applying MVC splits the program in three parts that are much cleaner and, therefore, potentially easier to create. It’s usually considered a good first step when designing a program.

The Model

Since the view depends on the model, and the controller depends on both the view and the model, the first thing to be implemented is usually the model: it’s independent of anything else, and so it can be written on its own.

First, there is data to be stored that will change a lot over time:

  • The position of the ball, as the ball’s velocity.
  • The vertical position of each paddle, and its vertical velocity.
  • The score of each player.

Then, there’s also data that will not change:

  • The default horizontal and vertical speed of the ball.
  • The horizontal position and default vertical speed of the paddles.
  • The dimensions of the field, ball and paddles.

We can store these constants in objects that will never be changed:

var field    = { w: 320, h: 240 };
var paddle   = { x: 300, w:   2, h:  30, s: 76 };
var ball     = { w:   5, h:   5, s: 120 };

The changing data itself should be stored in a model object, which should store the different categories of model data in sub-objects:

function model()
{ var s = ball.s;
  this.left   = {  pos: 0,   vel: 0 };
  this.right  = {  pos: 0,   vel: 0 };
  this.ball   = {    x: 0,     y: 0,
                    vx: s,    vy: s };
  this.scores = { left: 0, right: 0 }
}

Before going on, let’s discuss a bit all these definitions. Obviously, this code creates a model class with data for left and right paddles, a ball, and scores. Constants are also defined to describe the dimensions of the field, paddles and ball, as well as the default speeds of the ball and paddles. This can be inferred fairly easily from the code if you know JavaScript. The unanswered question is, what do those numbers represent?

  • Since the play field is symmetric, I have chosen coordinates (0,0) to represent the center of the field. This way, the top and bottom edges are at -field.h and field.h respectively (which means the total height of the field is, in fact, 480 pixels and not 240 pixels), the left and right edges are at -field.w and field.w (total width of 640 pixels). In general, the width and height are actually half-widths and half-heights, and the position of an object is in fact the position of its center.
  • Speeds are expressed in pixels per second. This means that the ball traverses the field vertically in 2 seconds and horizontally in 2.6 seconds, and the paddles traverse the field vertically in a bit more than 3 seconds (all of this is computed without taking the dimensions of the elements into account).
  • The scores are points. You add one point to the winner’s score on each round.

Initially, everything is centered, and the ball moves to the bottom-right (and since it moves faster than the AI’s paddle, the AI always loses the first round, but that’s not really a problem because it lets the player get his bearings for nearly two seconds).

The most elementary thing that can happen to the model is be controlled: this makes the paddles move by changing their velocity. So, when a player presses a key, the velocity changes, and when the key is released the velocity resets to zero. The model doesn’t care about keys (that is the job of the controller), only about directions, so the movement functions have a direction parameter:

model.prototype.moveLeft = function(d)
{ this.left.vel  = d * paddle.s }; 

model.prototype.moveRight = function(d)
{ this.right.vel = d * paddle.s };

These functions are added to the model class and move the left and right paddle, at the appropriate speed, depending on the direction. Here, we assume that the direction parameter d will equal -1 for “up”, 0 for “don’t move” and 1 for “down”, and we’ll have to take care in the controller in order to guarantee that.

The other thing that the model does is make things move. In the computer world, movement is a quick succession of different images which give the illusion of movement (as with flipbooks). So, instead of working in a continuous motion, the model should skip ahead of time by a certain duration (known as the time step). Here, I’m going to choose a reasonable timestep: 10 milliseconds (that’s 100 steps per second):

var timestep = 0.01;

The update function is pretty heavy: it has to move the objects around (to match those 10 milliseconds) then determine if the ball should bounce, if the paddles should stop moving, and if the scores should increase. The entire function is:

model.prototype.update = function()
{
  var t = timestep; 

  this.left.pos  += t * this.left.vel;
  this.right.pos += t * this.right.vel;
  this.ball.x    += t * this.ball.vx;
  this.ball.y    += t * this.ball.vy; 

  var clip = function(pad)
  { var pos = pad.pos;
    pos = Math.min(pos,field.h - paddle.h);
    pos = Math.max(pos,paddle.h - field.h);
    if (pos != pad.pos) pad.vel = 0;
    pad.pos = pos;
  }; 

  clip(this.left);
  clip(this.right); 

  if (this.ball.y + ball.h > field.h)
  { this.ball.vy = - ball.s } 

  if (this.ball.y - ball.h < - field.h)
  { this.ball.vy = ball.s } 

  if (this.ball.x - ball.h < - paddle.x + paddle.w &&
      this.ball.x + ball.h > - paddle.x - paddle.w &&
      this.ball.y + ball.h > this.left.pos - paddle.h &&
      this.ball.y - ball.h < this.left.pos + paddle.h )
  { this.ball.vx = ball.s } 

  if (this.ball.x - ball.h < paddle.x + paddle.w &&
      this.ball.x + ball.h > paddle.x - paddle.w &&
      this.ball.y + ball.h > this.right.pos - paddle.h &&
      this.ball.y - ball.h < this.right.pos + paddle.h)
  { this.ball.vx = - ball.s }  

  if (this.ball.x - ball.h < -field.w)
  { this.scores.right++;
    this.ball.x = 0;
    this.ball.vx = ball.s } 

  if (this.ball.x + ball.h > field.w)
  { this.scores.left++;
    this.ball.x = 0;
    this.ball.vx = - ball.s } 

};

Let’s go through it step-by-step:

  • First, it moves objects around. This is done by adding (+=) the moved distance (t * speed) to the position of objects. This computes the final position of objects after that step. The next steps then handle collisions.
  • The first collision test is handled by the “clip” function, which prevents the paddles from leaving the screen (it’s a function because there are two paddles, so I created it once and used it for both paddles). The basic rule is: clip the paddle to the screen and, if it went outside, set its speed to zero. Since the position of the paddle is the position of its center, I have to take the height of the paddle into account in order to avoid leaving the field.
  • The next two collision tests happen between the ball and the top and bottom edges of the field: if the ball went beyond these, the vertical speed is set so that the ball moves back into the field.
  • The next two collision tests happen between the ball and the paddles. It tests whether the ball-rectangle hits the paddle-rectangle by checking whether any of them intersect (collision detection is a topic in itself) and if they do, sets the horizontal speed to move back into the field.
  • The last two collision tests check if the ball leaves the field on either side. When this happens, the score of the corresponding player is increased (++), the ball is moved to the center (x=0) and its speed is reversed.

So, if we call the “update” function, it computes the state of the game after 10 milliseconds. If we do it often enough, we can get the game state in real time. Now, we have to display it.

The View

The view is the part of the program responsible for displaying things to the player. It reads data from the model, and somehow maps it to whatever display techniques the program has.

In this example, I’m using the jQuery library. It allows the program to resize and move around DIV elements of a web page (by default, a DIV element is a rectangle with a set position). So, the first step I will take is create the HTML page which will be manipulated by the view:

<html>
  <head><title>Pong</title>
  <script type="text/javascript" src="jquery.js"></script>
  <script type="text/javascript" src="pong.js"></script>
  <style>
#playfield {
  color           : black;
  background-color: black;
  border          : 0px none black;
  margin          : 0px;
  padding         : 0px;
  position        : absolute;
  top             : 0px;
  left            : 0px }
div {
  font-size       : 1px;
  color           : white;
  background-color: #33FF33;
  margin          : 0px;
  padding         : 0px;
  position        : absolute;
  top             : 0px;
  left            : 0px }
div.score {
  color           : #33FF33;
  background-color: transparent;
  width           : 640px;
  font-size       : 20px;
  font-family     : courier new }
  </style>
  </head>
  <body>
    <input id="playfield"/>
    <div><div id="paddle_left"/></div>
    <div><div id="paddle_right"/></div>
    <div><div class="score" style="text-align:left" id="score_left">0</div></div>
    <div><div class="score" style="text-align:right" id="score_right">0</div></div>
    <div><div id="ball"/></div>
  </body>
</html>

This creates several rectangles, with identifiers, and also determines their color and margin. Note that the playfield is an “input” (because we need to receive input from the player, so we use this object as a trick). Also, all “div” elements are within “div” elements, to prevent their relative positions from influencing each other (because several elements with an absolute position are within the same body).

Most of the above should be fairly obvious to you (if it isn’t you can peek at a few online courses: html and css).

A point of interest here is the fact that the HTML file includes our script (pong.js) as well as the jQuery script (jquery.js). You can download jQuery here.

what is interesting about jQuery is that it allows selecting the objects quite easily, and then telling them to do things such as moving. An extremely important function in the view is this:

var move = function(avatar,pos,spd,size)
{ var x = pos.x - size.w + field.w;
  var y = pos.y - size.h + field.h;
  avatar.stop()
    .css({left:x,top:y})
    .animate({left:x+10*spd.vx, top:y+10*spd.vy},10000,"linear");
};

This function has four parameters: the ‘avatar’ is a jQuery object representing one of the “div” elements above (the ball, a paddle etc), the ‘pos’ is the position (with x and y coordinates) where that object should be, ‘spd’ is the velocity (with vx and vy coordinates) with which the object moves, and ‘size’ is the dimensions (with w and h coordinates) of that object. The dimensions are required because the position of a jQuery object (with ‘absolute’ positioning, as we are using here) is expressed as an offset between the top-left corner of the screen and the top-left container of the object itself, whereas the position in the model is the offset between the center of the playing field and the center of the object. So, variables ‘x’ and ‘y’ are computed to represent the object’s position on the HTML page.

This function stops the current movement of the avatar with ‘stop()’ then sets the left and top coordinates with ‘css()’, and finally asks the object to move with ‘animate()’ by specifying the destination (which we compute by adding the distance traversed in ten seconds to the current position), the duration (10 seconds = 10000 milliseconds) and the animation style (“linear”, which means there are no accelerations and no brakes).

In short, this function should be called whenever the movement of an object changes: jQuery then takes care of animating the object until its movement changes again. This way, we don’t have to change the movement of objects every ten milliseconds.

However, this requires the view to store the previous value of movement, in order to determine when movement changes by comparing the new value and the old value (if they’re the same, no changes happened). So, the view object would look like this:

function view()
{ this.ball   = {   vx: null,    vy: null };
  this.scores = { left:    0, right:    0 };
  this.paddle = { left: null, right: null };
  this.avatar = { ball: $('div#ball'),
                  sc_l: $('div#score_left'),
                  sc_r: $('div#score_right'),
                  pa_l: $('div#paddle_left'),
                  pa_r: $('div#paddle_right'),
                  play: $('input#playfield') }; 

  this.avatar.ball.width(1.9*ball.w)  .height(1.9*ball.h);
  this.avatar.pa_l.width(1.9*paddle.w).height(1.9*paddle.h);
  this.avatar.pa_r.width(1.9*paddle.w).height(1.9*paddle.h);
  this.avatar.play.width(2*field.w)   .height(2*field.h);
}

This class does the following things:

  • It defines members “ball”, and “paddle” which contain the velocities (but not positions) of paddles and the ball. So, when velocities change, the view notices and asks jQuery to change the trajectories. It also defines the currently displayed score (so that, when these change, they are updated).
  • It defines the avatars: this is done by using the jQuery selector: $(‘div#paddle_left’) selects the DIV element with the identifier ‘paddle_left’ that we defined in the HTML page earlier.
  • It resizes the avatars based on the constants, with the functions ‘width()’ and ‘height()’. Note that the width and height of the ball and paddles are smaller than they should be: this is a common trick for games, since players are bound to notice some close misses and interpret them as “this shouldn’t have missed”, making the image of the paddles and ball smaller reduces near misses and keeps the players happier.

Next, the view object uses a ‘render()’ function to display things. This function will use the ‘move()’ function we defined earlier:

view.prototype.render = function(model)
{ var move = function(avatar,pos,spd,size)
  { var x = pos.x - size.w + field.w;
    var y = pos.y - size.h + field.h;
    avatar.stop()
      .css({left:x,top:y})
      .animate({left:x+10*spd.vx, top:y+10*spd.vy},10000,"linear");
  }; 

  if (this.ball.vx != model.ball.vx || this.ball.vy != model.ball.vy)
  { this.ball.vx = model.ball.vx;
    this.ball.vy = model.ball.vy;
    move(this.avatar.ball,model.ball,this.ball,ball) } 

  if (this.paddle.left != model.left.vel)
  { this.paddle.left = model.left.vel;
    move(this.avatar.pa_l,
         {x: -paddle.x, y:model.left.pos},
         {vx: 0, vy: this.paddle.left}, paddle) } 

  if (this.paddle.right != model.right.vel)
  { this.paddle.right = model.right.vel;
    move(this.avatar.pa_r,
         {x: paddle.x, y: model.right.pos},
         {vx: 0, vy: this.paddle.right}, paddle) } 

  if (this.scores.left != model.scores.left)
  { this.scores.left = model.scores.left;
    this.avatar.sc_l.html(model.scores.left) } 

  if (this.scores.right != model.scores.right)
  { this.scores.right = model.scores.right;
    this.avatar.sc_r.html(model.scores.right) }
}

The render function always checks whether the current value inside the model is different (!=) from the value stored in the view (this). When this is the case, the ‘move’ function is called to move the appropriate avatar in the appropriate fashion (or, in the case of scores, the inner text of the score avatar is changed using the ‘html()’ function from jQuery).

The Controller

The last piece of the game is the controller. It should gather information from the user, compute the AI’s response to ball movement, and measure how long has elapsed since the last time the view has been refreshed and update the model accordingly.

This time, the controller has no reason to be an object, because nobody will manipulate it (except, of course, itself). Instead, we can just define some values inside a function and use them to do the job:

var gameModel = new model();
var gameView  = new view();

As a first step in implementing the controller, we need to extract the keypresses from the user and write a function that applies them. This is done as follows:

  var keys  = { up: false, down: false }; 

  gameView.avatar.play.keydown(function(event){
    if (event.which == 38) keys.up = true;
    if (event.which == 40) keys.down = true;
    return false
  }); 

  gameView.avatar.play.keyup(function(event){
    if (event.which == 38) keys.up = false;
    if (event.which == 40) keys.down = false;
    return false
  });   

  var playerMoveLeft = function(model)
  { model.moveLeft((keys.up ? -1 : 0) + (keys.down ? 1 : 0)); }

The ‘keydown’ function provided by jQueryhas a single parameter, which is a function. That parameter will be called whenever an unpressed key is pressed when the playing field is selected. The same happens for ‘keyup’, which reacts when a pressed key is released. The functions check what the key was by looking at ‘event.which’: a value of 38 is the “up” arrow key while a value of 40 is the “down” arrow key (39 and 41 are the left and right arrow keys, respectively). The functions also use the statement ‘return false’: this notifies the playing field (which is originally a text field from a form) that the key press should be ignored, instead of adding the letter to the field.

What the functions do is set the value of keys.up and keys.down: the “playerMoveLeft” function then reads the value of the keys to determine which keys are currently pressed. The “a ? b : c” construct uses “b” if “a” is true, and “c” otherwise. So:

  • If the up key is pressed but the down key is not, the direction is -1 + 0 = -1
  • If the down key is pressed but the up key is not, the direction is 0 + 1 = 1
  • If neither key is pressed, the direction is 0 + 0 = 0
  • If both keys are pressed, the direction is -1 + 1 = 0

So, the code above correctly responds to player input whenever the ‘playerMoveLeft’ function is called.

Another step is to define a similar aiMoveRight function for computing the AI response. We want the AI do to something smart enough to be challenging. However, since the ball moves slowly from left to right, a perfect AI could simply compute where the ball will land and wait there: it would therefore never lose. This is a good thing for computer science, but a bad thing in game: a good game AI is not an AI that always wins, but an AI that loses in a challenging and fun manner.

The following code accomplishes this:

  var aiMoveRight = function(model)
  { var dir = 0;
    if (model.ball.vx > 0)
    { var dist = (paddle.x - model.ball.x);
      var target = model.ball.y + model.ball.vy * (dist / model.ball.vx);
      while (target > field.h-ball.h || target < ball.h-field.h)
      { if (target > 0) { target = 2*(field.h-ball.h) - target }
        else            { target = 2*(ball.h-field.h) - target }
      }            

      dir =
        (model.right.pos + paddle.h < target ?  1 : 0) +
        (model.right.pos - paddle.h > target ? -1 : 0)  

      var accuracy =
        field.h * Math.exp((model.scores.left - model.scores.right)/3); 

      if (dist > accuracy)
      { dir = -dir }
    } 

    model.moveRight(dir);
  }

The general structure of the code is reasonably easy to get: the code computes the direction in which the AI (right) paddle should move, then sets that direction on the last line. If the ball is not moving right (vx > 0) the AI paddle does not move (dir = 0). However, if the ball is indeed moving right, then the computation starts: the algorithm computes the distance between the ball and the paddle. From that, it computes the point where the ball should meet the paddle (and stores the vertical coordinate in the ‘target’ variable). Once the target is known, the direction is computed: if the paddle is below the target, it moves up, and if it’s above, it moves down. This is a perfect AI: it never loses because it always knows where the ball hits and moves there immediately. So, we dumb it down by adding accuracy: if the ball is further away from the paddle than a certain distance threshold (stored in the ‘accuracy’ variable) then the paddle does the opposite of what it should do (dir = -dir).

The two important questions here are: how is the target determined, and how is the accuracy determined?

The target is computed by determining where the ball would end up if there were no top or bottom edges: one simply calculates the horizontal distance and deduces from the horizontal and vertical speed ratio the vertical distance that it will go from its current position. Once this position is known, the code takes into account bounces: if the target is outside the top or bottom edges, then it will bounce, which means that the target position should be reflected around that edge. For the bottom edge, reflection is done with ‘target = 2*(field.h-ball.h) – target’ and for the top edge it’s done with ‘target = 2*(ball.h-field.h) – target’. The AI repeats this reflection process until the target is within the playing field.

The accuracy is computed by getting the exponential of the score difference (with a few modifiers, ‘field.h’ and ’3′, obtained through playtesting). The point of using an exponential is that, as the score difference increases (in favor of the player) the exponential increases substantially and so the accuracy also increases, and as the score difference increases (in favor of the AI) the exponential decreases substantially without going below zero. So, the point of the exponential is getting an accuracy that increases when the player is doing well, without going below zero.

As a result, the AI starts playing perfectly when the player has three more points than the AI.

The last thing the controller does is keep the model and view up to date. To do this, it computes the current time (in seconds, with decimals) and also remembers the last time it was updated. Then, if the last update is more than one timestep ago, it updates the model and increases the last-update-time by one timestep, and repeats this process until the model is up-to-date. Then, it renders the model.

  var time = function() { return +(new Date) / 1000 };
  var last = time(); 

  var act  = function()
  {
    playerMoveLeft(gameModel);
    aiMoveRight(gameModel); 

    var now = time();
    while (now > last)
    { gameModel.update();
      last += timestep } 

    gameView.render(gameModel);
    setTimeout(act,50);
  }

The time function uses a common trick: it creates a date object (which by default contains the current time), converts it to the number of milliseconds since a fixed point in time, and divides it by 1000. The ‘return’ statement means that when the function is called, it will be replaced by the returned value (var last = time();).

The ‘act()’ function applies input to the game model, then performs as many updates as necessaryand finally renders the model. Then, it asks Javascript to execute ‘act()’ again in 50 milliseconds (that’s 20 times per second).

The result is to wrap all of this in a single ‘controller()’ function and ask jQuery to execute the entire thing when the document has finished loading:

function controller()
{ var gameModel = new model();
  var gameView  = new view();
  var keys  = { up: false, down: false }; 

  gameView.avatar.play.keydown(function(event){
    if (event.which == 38) keys.up = true;
    if (event.which == 40) keys.down = true;
    return false
  }); 

  gameView.avatar.play.keyup(function(event){
    if (event.which == 38) keys.up = false;
    if (event.which == 40) keys.down = false;
    return false
  });   

  var playerMoveLeft = function(model)
  { model.moveLeft((keys.up ? -1 : 0) + (keys.down ? 1 : 0)); } 

  var aiMoveRight = function(model)
  { var dir = 0;
    if (model.ball.vx > 0)
    { var dist = (paddle.x - model.ball.x);
      var target = model.ball.y + model.ball.vy * (dist / model.ball.vx);
      while (target > field.h-ball.h || target < ball.h-field.h)
      { if (target > 0) { target = 2*(field.h-ball.h) - target }
        else            { target = 2*(ball.h-field.h) - target }
      }            

      dir =
        (model.right.pos + paddle.h < target ?  1 : 0) +
        (model.right.pos - paddle.h > target ? -1 : 0)  

      var accuracy =
        field.h * Math.exp((model.scores.left - model.scores.right)/3); 

      if (dist > accuracy)
      { dir = -dir }
    } 

    model.moveRight(dir);
  } 

  var time = function() { return +(new Date) / 1000 };
  var last = time(); 

  var act  = function()
  {
    playerMoveLeft(gameModel);
    aiMoveRight(gameModel); 

    var now = time();
    while (now > last)
    { gameModel.update();
      last += timestep } 

    gameView.render(gameModel);
    setTimeout(act,50);
  } 

  act();
} 

$(function(){new controller});

The Article

This game uses 200 lines of Javascript and 50 lines of quick-and-dirty HTML. It took me about three hours to develop. This article is the longest article so far on Nicollet.Net and took me an entire day to write. You can expect other video games and maybe even other tutorials in the future, in the same vein as this one. If you have questions, or if you have enjoyed this, make sure to add a comment below. Links to this tutorial from places where beginners ask a lot of questions are also most welcome.

Video Game Bricks

I don’t believe in game engines. I tend to consider software development as the process of using existing bricks together with glue code to obtain the expect result, whereas engines provide the final result with the holes to be filled in. This is not to say that game engines are useless—countless situations can benefit from them. However, my approach to game development has always been to rely on frameworks and collections of helper and utility classes, perhaps due to my beginnings as a DirectDraw programmer.

Objective Caml games do exist, even though they often lack the backing of a full video game studio. Whether used as a prototyping tool or to develop the final product, I think the functional approach can benefit video game development. To that end, I regularly develop small bricks that can be useful for game development. All of the source code presented here is my own work, placed in the public domain.

Vectors and Transforms

Bidimensional vectors with supporting elementary mathematical operators:

type vector = { x : float; y : float } 

val right : vector
val up : vector
val zero : vector 

val equal : vector -> vector -> bool 

val ( ++ ) : vector -> vector -> vector
val ( -- ) : vector -> vector -> vector
val ( *+ ) : float -> vector -> vector 

val sqlen : vector -> float
val len : vector -> float 

exception ZeroVector
val normalize : vector -> vector 

val dot : vector -> vector -> float

The operators behave as expected. Equality and normalization work with a fixed epsilon of 1e-6. The total memory usage for a vector is 20 bytes (16 for the coordinates, 4 for internal usage), and they are manipulated by reference. Intermediary operations on vectors tend to be inlined, and intermediary values are garbage-collected when present.

Bidimensional transforms and corresponding operations:

type transform 

val identity   : transform
val rotate     : transform -> float -> transform
val scale      : transform -> float -> transform
val translate  : transform -> Vector.vector -> transform 

type transform_description =
    {
      angle    : float;
      scale    : float;
      position : Vector.vector
    } 

val make       : transform_description -> transform
val describe   : transform -> transform_description 

val apply      : transform -> Vector.vector -> Vector.vector
val compose    : transform -> transform -> transform

This type represents similarities. The total memory usage is 36 bytes (32 for the coordinates, 4 for internal usage), and they are manipulated by reference.

Downloads: vector.ml vector.mli transform.ml transform.mli

Indexing

When using functional programming, the aliasing problem makes it impossible to have several data structures directly reference a certain value without having to update all data structures when that value changes. A solution to that problem is to store indirect references instead: the value is stored in a single data structure and bound to a key. The other data structures do not reference the value, but rather “whatever the key is bound to”. Meaning that changing the single data structure holding the value also implicitely updates the value for all other data structures.

An indexing data structure provides exactly that: a way of binding a value to a key and retrieving it with that key. If no backtracks happen, then the following implementation performs all relevant operations in amortized constant time.

type         'a t
type         handle
exception    UnboundHandle 

val empty  : int -> 'a t 

val add    : 'a -> 'a t -> 'a t * handle
val remove : handle -> 'a t -> 'a t
val get    : handle -> 'a t -> 'a 

val map    : ('a -> 'b) -> 'a t -> 'b t
val mapi   : (handle -> 'a -> 'b) -> 'a t -> 'b t
val iter   : ('a -> unit) -> 'a t -> unit
val iteri  : (handle -> 'a -> unit) -> 'a t -> unit
val fold   : (handle -> 'a -> 'b -> 'b) -> 'b -> 'a t -> 'b

Note that “UnboundHandle” is not necessarily raised. If it is, then you know what happened. However, attempting to access a removed handle is, in the general case, undefined, and may return another value.

You can also look for persistent arrays for generic data storage.

Downloads: assoc.ml assoc.mli

Segregation is Good

As a frequent reader of the gamedev.net game development forums, I often notice that most beginner and intermediate developers start designing the architecture of their game by deciding on a base class from which all game objects will inherit, and storing a list of these objects. The justifications given are usually that:

  • It’s Object Oriented.
  • Inheriting from a base class allows code reuse.

The most appealing advantage of the “base class everything inherits from” approach is that it provides the illusion of a solid design foundation (that is essential to the “getting things done” feeling that motivates many of us) without requiring a lot of thought. All that is to be done is to slap together a few functions into a base class (usually plagiarized from one of the many tutorials available on the web) and then start inheriting.

The Issues

The naive approach to the base class solution can be summarized as this:

interface BaseObject
{
  void render();
  void update();
}

In theory, this interface seems to do everything required: after all, every object will have to update its state, and every frame it shall render itself to the screen. In practice, however, this approach leads to two serious issues:

  • Not all objects are both updated and rendered. For instance, a script or a trigger cannot be rendered, but they still have to be regularly updated. The least that could be done here is to separate the rendering side of things from the update side.
  • Sometimes, updating requires access to other objects. This happens for instance when objects collide or when an AI looks for a target. However, interacting with other objects only happens through the base object interface, which provides no information about what the other object is. Even assuming that all objects have a collision hull as part of their public interface (which in itself also does not make any sense, since many objects do not collide with anything), determining that the other object in a collision is a friend or an enemy requires knowledge beyond any acceptable base interface.

While the former can easily be solved by using two base classes instead of one, the latter is much more problematic. It is usually solved through contraptions such as downcasting (which eliminates the benefits of the Liskov Substitution Principle) or the Visitor Design Pattern (which eliminates the benefits of the Open-Closed Principle in most modern static languages).

The benefits

But surely people wouldn’t be using base classes this way if there wasn’t a tangible benefit to using them, would they? Well-known games (including the original Half Life engine, which was mod-friendly enough to give birth to a vast number of mods) have used this approach through the ages.

Purty pictar of waterfall. There is a fundamental rule for interface implementation and class inheritance:

The finality of every interface and every inheritance relationship is to allow code to operate on different types of objects.

The sole benefit of using a base class for game objects is to store those objects in a single container and apply update and render functions over that container. Everything else in a typical game requires using a more specific type through visitation or downcasting.

When, then, is a single container useful? In the case of a game engine, a single container is useful because on the one hand, it’s preferable to have the engine handle the storage, lifetime and processing of game objects and on the other hand, designing a game engine to allow the addition of other containers (one for each type of object, for instance) is difficult.

As such, having everything inherit from a single type makes communications between the engine and the game much easier (only one type of object has to be carried through the interface), even though it might make the development of the actual game harder.

Of course, a container may allow multiple interfaces to exist: a container for renderable objects, a container for updated objects, a container for objects with collision detection, a container for objects with a physical model, a container for objects which are synchronized over the network and so on. However, the original problem remains: when two objects collide, the collision response depends on the exact type of the objects, which exists in game space but not in engine space. The engine is therefore by construction unable to provide the original most derived types back to the game, and so the game must retrieve them by other means (note that visitation is not possible, because it requires to encode the possible most derived types in the visitor, which itself is encoded in the interface of the visited object.

However, beginner and intermediate programmers don’t write engines (or at least, they shouldn’t, because the motive that drives studios to write engines is the necessity to distribute programming tasks across large teams with varying competence, and to keep the code for later projects), they write games. The source code of these games is worked on by only a small handful of programmers, usually only one, which allows a far greater level of control, especially for purposes of refactoring. As such, the necessity of having generic containers disappears, and the main benefit of a single base class with it.

Segregate types

My advice is pretty simple: strive to keep one list per type of object. In your average video game, you would have a list of projectiles flying around, a list of AI-controlled opponents, and a player-controlled character.

Do not let this approach hurt code reuse, however. If both the player character and the AI-controller opponents can take damage from walking in lava, you don’t want to write the damage assignment code twice. Instead, you can have both the AI-controller opponents and the player-controlled character implement the same interface with a single “takeDamage()” function, and apply the damage assignment code to both. You may even share the health/damage handling code between the player and the opponents by aggregating a “health” class, by inheriting from a “Character” class which manages health, or by applying a “WithHealth” mix-in:

class IDamageTaker
{ public: virtual void takeDamage(int); }; 

template <typename T>
class WithHealth : public IDamageTaker, public T
{
  int health;
public:
  void takeDamage(int d)       { health -= d; }
  void healDamage(int d)       { health += d; }
  bool alive()           const { return health > 0; }
}; 

class Vanilla
{ public: virtual ~Vanilla() {} }; 

class PlayerCharacter : public
  WithHealth<
  WithPosition<Vanilla> >
{ /* Player-related data here */ }; 

class AIOpponent : public
  WithHealth<
  WithPosition<
  WithTarget<Vanilla> > >
{ /* Opponent-related data here */ };

Now, the code for health management is not duplicated and the code for assigning damage is not duplicated. The only dupicated code is the traversal of the various lists (since instead of traversing a single list, now several lists must be traversed in order to reach all elements), and that code is not only very small, but also fairly easy to factor out (for instance, by implementing an iterator that traverses several containers in order).

On the other hand, because of the presence of several lists, there is no more need for determining whether a projectile has hit an opponent or the player: the type of the object is known simply because the currently processed list is also known.



1170 feed subscribers
(readers who polled a feed this week)