Skip to content

Game Programming Concepts

Ivan Perez edited this page Oct 6, 2015 · 34 revisions

In the first chapters we used low-level libraries to create multimedia and interact with hardware.

In the following chapters we are going to explore higher-level concepts of game programming: patterns and solutions applied to frequently in game programming.

Many ideas presented here come from imperative game programming and you can find more about them in standard literature. Others will be motivated by trying to address problems from a purely functional perspective.

The big picture

At the beginning, games needs to set up the video configuration, load graphics and audio, render some loading screen, present a menu to configure settings and games, load levels, communicate with other players and the server, unless there is no server, in which case AI should control other players.

Games need to produce a pleasing visual and auditory effect, simulating realistic physics and with perfect synchronisation between images and sounds, wrapping you in a cloud that protects you from your daily problems, unless your mum calls you, in which case it must let you pause the game, or even save it and resume it later.

You can play games using different kinds of inputs (mouse, keyboard) on any device (console, PC, mobile), and they are expected to work seamlessly and perform efficiently, without draining your device's battery and letting you download the latest season of Breaking Bad in the background. Your games will be featured on online listings open to comments, ratings and discussions, and for every supporter and lover you will get two demanding teenagers with very low tolerance for failure who will rate your app -10 because it did not have use their 3000 USD graphics card newest extension for particle effects.

As you read the above, you will probably understand that game development is, in part, just art, that game success has a component of luck, and that the complexity of the problem, the expectations and the level of testing and robustness required are very high. And if this is your reaction, honestly, I don't blame you:

To attack this problem we need to divide it into subproblems and address each one independently. In some cases the solution will be a library that we can import from every project. In other cases, it will be a template that we need to integrate in our code and adapt. Finally, some solutions will not be coded as templates, but rather as patterns or guidelines, and used by many existing modules and definitions in our code. In general we will provide a pattern that captures the core idea and a default implementation that works well in many cases.

We are going to divide the problems above in the following sections. Note that the classification does not necessarily indicate how we classify the solutions (for instance, a solution could use a temporal abstraction to drive rendering).

  • [Architectural patterns](Architectural Patterns) for increased abstraction, scalability and/or performance.

    Synchronous and asynchronous game loops, state machines, time transformations and pausing, Functional Reactive Programming.

  • Multimedia, end points and IO.

    Visual IO (rendering, animations, z-axis, 2.5 and 3D, scrolling, parallax scrolling, cameras, on-screen Heads-Up Displays, asset management), Audio (background music, effects, audio synchronization), Network and AI players.

  • Physics.

    Physics and collisions, potential lacks and performance demands of different algorithms.

  • Robustness.

    Error handling, testing, debugging, collecting player data, performance analysis.

  • Usability.

    Saving or interrupting the game, Preferences, Reconfigurable input devices.

End points and IO

Interactive cameras and views

A common pattern in interactive applications is that the same entity that consumes or presents output also produces input. This may obviously true for players: they are the ultimate consumers and producers. With this abstraction in mind AI-controlled players can also been as pairs of consumer/producer: they take the game state, "show" it (to an intelligent agent/function), and produce a set of actions pertaining to some of the players.

In the game programming literature, this abstaction is known as a view. Other names for it are reactive value 1.

Consuming the output and producing a new input may not be synchronous actions. Network players, for instance, can be abstracted as views: the game state (or a game update) is sent via the network, and input actions are transmited back to the server. The player may be receiving updates every few miliseconds (if latency is low) while only firing a few times per second, max.

Using views also helps abstract from polling vs callbacks, rendering asynchronously, having multiple cameras for different players, and even using widget systems.

Example of a view in a monadic game. Example of views in Arrowized FRP. Example of views in Keera Hails.

Cameras

Games often present scenes that do not fit on the screen. Mario Bros. is such a game. Counter strike is such a game. Any racing game is also of this kind.

In arcade 2D-based games, one can easily simulate this effect by moving all other elements (oponents, background, etc), when the player "moves" forward. The player moving forward, then, is just an illusion. But, as your logic and physics become more complex, and you add more than one player, this workaround becomes harder to implement.

While elements are shown in screen coordinates, the internal processing function should work with game, or world coordinates.

What's actually going on in these games is that you have a perspective, a point of view, a camera pointed to the game world that only shows you a part of it, from a specific angle. What's more is that camera is a portal also for the input: what looks like middle of the screen in screen coordinates may not represent the center of the world.

It's easy to see that, given a function f that transforms game world coordinates into screen coordinates, we have:

gameForUser   = capScene screenSize $ transformState f gameState
inputFromUser = transformInput f<sup>-1</sup> screenInput

IN 3D... Game Engine Architecture

In 2D... Whatever

PLACE FOR ANOTHER EXAMPLE

HUDs, toolbars and overlaid visuals

Heads-on displays are a general name for those information panels shown on top of the game with additional information.

PLACE FOR AN IMAGE

What's interesting about them is that:

  • They can be enabled or disabled.
  • They may be shown or not depending on the game state.
  • They may be interactive (handle input apart from presenting output).

The last point is perhaps the most crucial one: while it is easy to display something in one area of the screen, we also need to:

  • Transform screen coordinates into coordinates local for the displayed elements.
  • Translate raw input events into more meaningful event descriptions.

For example, given an input event (eg. mouse click at position (x,y)), we need to determine wether it lies on the game area or a panel, and then translate the screen coordinates into local coordinates for that element. If it's the game area, all we need is to apply the inverse camera function. If the panel, we may just need to rebase them based on the position of the panel on the screen.

The general transformation is as follows:

PLACE FOR THE MATRIX

What we are describing here is true both for HUDs and any other permanent or temporary on-screen element that does not use the game camera as the main game area.

PLACE FOR AN EXAMPLE

Note that, after the transformation of the event coordinates, we still need to transform the low-level input event (click, etc.) into an declarative depiction of what happened (fire).

You can see this intermediate layer as a simple widget system, and may even consider creating an abstraction for containers and alignments that facilitates adapting to different screen sizes and screen rotations during gameplay. I recommend that you keep it as simple as you can, and as abstract as you can.

PLACE FOR AN EXAMPLE OF CONTAINERS

PLACE FOR AN EXAMPLE OF ALIGNMENT

Backgrounds, scrolling and parallax.

As we just saw in the chapter about cameras, many games present a portal to a world larger than it fits on the screen. Backgrounds can lighten an otherwise dull screen, but what really changes game appearance are moving backgrounds and a perception of depth.

First, we will explore backgrounds without depth (static and moving). Then we will explore backgrounds with depth (parallax). In the next section we will explore depth in a more general way (even in 2D games, often termed 2.5 as opposed to full 3D).

Static backgrounds

Implementing static backgrounds could not be more trivial. A static, uninteractive background can be presented both as an adhoc layer in the render (see first example) or integrated as one more visual element. What's important in the second case is that, unlike other visual elements, a static background is not affected by the game camera, but it is affected by transformations that have to do with laying different elements out on the screen.

A PICTURE IS WORTH A THOUSAND WORDS

PLACE FOR AN EXAMPLE

Moving backgrounds: a very large, but limited, world

In some cases, the game world is just slightly larger than the screen, but still limited in size. The background is therefore also larger than the screen, but finite. Presenting this kind of world is relatively simple, and it only requires that we crop part of it to the size of the screen. We can generalise this approach easily by using transformation/camera matrices applied to background coordinates.

What's important in this case is to make sure that players can never move out of the world boundaries, or there will be screen areas with no background.

PLACE FOR AN EXAMPLE

Moving backgrounds: unlimited worlds

Some games gave very large or even unlimited world sizes. In such cases, backgrounds tend to be designed so that each side matches the opposite perfectly, like in a rolling paper.

PLACE FOR AN ANIMATION

This was a common trick in animation, and you can see it often in older TV series:

PLACE FOR AN ANIMATION

There are several ways of implementing this. One way is to crop the background in two, and present one part and then the other:

PLACE FOR AN EXAMPLE

Depending on the underlying framework, you may get away without cropping: you can also paint the world twice, and then paint the rest of the scene relative to its position with respect to the background.

While I personally tend to favour the first approach, whether cropping or painting twice is performance-wise pretty much depends on the platform and the underlying graphics layer (some do not let you paint out of screen area, others easily facilitate rebasing the scene relative to a background).

Parallax:

Games can achieve a more appealing sense of perception by adding depth. Even if the action takes place in 2D, a common effect is to add several background elements moving at different speeds as characters move along the world (so as to make it look like some elements, the ones moving faster, are closer than others, moving slower).

PLACE FOR AN IMAGE

While this may seem like a relatively new trick because of its common presence on the web nowadays, there are old games around there that used this effect already:

PLACE FOR AN IMAGE

Implementing parallax, so as long as the background layers are all presented behind all the game action, is just as trivial as presenting one background, but having one camera transformation matrix for each background.

PLACE FOR AN EXAMPLE

Depth

2.5 dimensions

Even 2D games can achieve a sense of depth by introducing layers. Layers can be presented without any modification to make them look closer, or with a camera transformation.

PLACE FOR TWO IMAGES

Implementing these kinds of transformations is relatively trivial. First, your game elements need to have a third dimension. Unlike the x and y dimensions, which may have fine precision approximating the continuous, the z dimension can easily be a integer if all you want is to layer your scene. Different layers can then be presented to users one by one.

Layering your scene is actually a form of 3D with an integer z coordinate, and as such it introduces some of the casuistics of 3D:

  • If I click on the game area, which element of which layer am I trying to interact with?

  • If interactive layers are presented using parallax effects, how do I adapt the input?

  • If interactive layers are presented using parallax effects, how does that affect the physics?

TO BE COMPLETED

3D

TO BE COMPLETED. Readers will mainly be refered to books and other material.

Animations

Animations can be extremely appealing for players. Animations can be achieved either continuous transformation, or, in the case of sprite-based graphics, by a mapping from continuous time to discrete time.

Sprite-based animations

Transitions

Handling input during transitions

Physics and collisions

Like with most areas of game programming, you could devote tons of books only to simulating physics and collisions. Some games do not have a physics engine at all (board games), but even the simplest arcade games perform basic physics simulations in some way or another.

PLACE FOR AN IMAGE

References

  1. Keera Hails http://github.com/keerastudios/keera-hails
Clone this wiki locally