81
Game Programming I: Introduction UP ITTC Game Development Track Francis Joseph Viola-Fernando Seriña

Game Programming I - Introduction

Embed Size (px)

DESCRIPTION

Introductory lecture to Game Engines

Citation preview

Page 1: Game Programming I - Introduction

Game Programming I: Introduction

UP ITTC Game Development Track Francis Joseph Viola-Fernando Seriña

Page 2: Game Programming I - Introduction

Goals

Page 3: Game Programming I - Introduction

Objectives

Identify and implement the fundamental structure of all video games in C++

Identify and implement the different modules in a video game

Prerequisite: Computer Programming 3 (C++)

Page 4: Game Programming I - Introduction

As a Software

Video Games are fundamentally, software. Development of Video Games follow Software Engineering Practices and Methods.

Unlike Business applications, a Video Game should continue with or without User Input.

A major difference between Video Games and other software is that development teams include more than just programmers. They include artists, level designers, writers, etc. – similar to movie production.

Page 5: Game Programming I - Introduction

Video Games

Video Games always require a computer to receive player input, perform logic and return feedback to the player.

Thus, card games and board games are not considered Video Games (even if they have Video Game versions).

Page 6: Game Programming I - Introduction

Modules & Managers Elements of a Video Game

Page 7: Game Programming I - Introduction

Sample Modules

Game Logic

Input Audio

Video

Resources Data

Timer

Page 8: Game Programming I - Introduction

Sample Modules

A Video Game is comprised of different systems working together

Each system is further divided into subsystems. For example: Game Logic may consist of Physics and AI Graphics may include 2D and 3D Resources may handle images, meshes, audio sources, etc.

Each module may have a Manager that would handle all the subsystems and their interactions between other systems

Most of the modules correspond to specific hardware types

Page 9: Game Programming I - Introduction

Specialized Modules

There are devices which have specialized hardware for specific modules. For example: Physics Modules (Physics Processing Units)

Post Rendering Effects (Digital Signal Processor)

Network Module

Logging (Debugging)

Page 10: Game Programming I - Introduction

Game Manager

The Game Manager is the core of a Video Game. Ideally, it is the entry and exit point of the program. The game manager initializes the other modules in the game.

All objects in the scene that are either visible, has logic or both is managed by the Game Manager. These objects are commonly called game objects (which will be discussed later).

The Game Manager handles the Game Loop (to be discussed in the next chapter)

Page 11: Game Programming I - Introduction

Time Manager

The Time Manager (or Timer) keeps track of the amount of time between iterations of the game loop

Usually measured in milliseconds

Other information that the Timer may keep track of: Time elapsed since the Video Game started

Time elapsed between video output (to determine or control frames per second)

Page 12: Game Programming I - Introduction

Input Manager

The Input Manager (or simply Input) records the states of all available input devices to be used

Input devices may differ per platform as listed: For Desktop/Laptops; keyboard, joystick, mouse, webcam,

microphone, etc. For Consoles/Handhelds; game pad buttons, joystick, IR, device

orientation or motion, multi-touchscreen, camera, microphone, etc.

Other information the Input may record: Duration of an input state (ex: charging of a weapon) Events or Change of state of an input (ex: on press, on release) Order of consecutive events (ex: combo, double click)

Page 13: Game Programming I - Introduction

Output Manager

The Output Manager (or simply Output) handles feedback to the player

Output is usually split into Audio and Video subsystems

The Audio subsystem control the playing of music and sound effects

The Video subsystem manages the visual feedback to the player, which may be in 2D, 3D or both

Page 14: Game Programming I - Introduction

The Game Loop Fundamental Structure for all Video Games

Page 15: Game Programming I - Introduction

The Game Loop

Input

Update Output

Page 16: Game Programming I - Introduction

The Game Loop

As mentioned before, Video Games should continue processing whether the user has entered any input or not

Thus, we cannot use blocking input functions such as printf() or cin to receive input

Then, we update the logic of the game and return an output before we repeat the cycle

Each cycle in the game loop is called a frame, similar to the frames of a movie. After all, a video game is an interactive movie

Page 17: Game Programming I - Introduction

The Game Loop

bool isPlaying = true; if (!Init()) return -1; // Enter the game loop while (isPlaying) { Input(); Update(); Output(); } CleanUp();

Page 18: Game Programming I - Introduction

Init() and CleanUp()

Init() is used for initializing the video game, initializing the modules and loading resources

CleanUp() is used for releasing resources and shutting down the other modules

Note: The constructor and destructor may be used instead of Init() and

CleanUp()

These 2 functions are not part of the game loop

Presenter
Presentation Notes
Note (1) – I personally prefer to use Init() and CleanUp() over the constructor and deconstructor so that I can see them in a single function.
Page 19: Game Programming I - Introduction

Input()

Input() calls the Input Manager to recheck all the states from the input devices

Page 20: Game Programming I - Introduction

Update()

Update() contains the logic of the Video Game

Player’s objects react to Input

Collision Tests, Physics and AI are also executed in the Update

May not exactly be in the order as shown

Update Timer

Collision Tests and Reactions

React to Input

Update AI

Update Physics

Page 21: Game Programming I - Introduction

Output()

Output() gives the player feedback

Output devices differ per platform but they generally involve both Video and Audio

Rather than displaying directly to the screen, we put the output in a buffer

Clear Buffer

Objects Write to Buffer

Output Buffer

Page 22: Game Programming I - Introduction

Exiting the Game Loop

The Game Loop, and eventually the game itself, exits when the condition (isPlaying) becomes false

Page 23: Game Programming I - Introduction

Simple DirectMedia Layer C cross-platform multimedia library

Page 24: Game Programming I - Introduction

SDL

Cross-platform multimedia library to handle the following: Events (aka Input: keyboard, mouse, joystick)

Time

Output (audio, video)

Threads

SDL has a lot of extensions to make use of networking, different file formats and others

Official Website: http://www.libsdl.org/

Page 25: Game Programming I - Introduction

Installation

Download the latest developmental libraries for your OS at http://www.libsdl.org/download-1.2.php

The README included in the archives should be enough to install it

To use the headers and libraries, each project needs to edit their properties to include the headers and link the libraries properly

NOTE: Get the development libraries if available. They have devel in their

package names

This lecture uses SDL 1.2.14

Page 26: Game Programming I - Introduction

Setting up a project (Xcode 3)

After installing the SDL framework, Documentation and Project Templates as mentioned in the README

In the New Project wizard, select Application under User Templates and select SDL Application

Page 27: Game Programming I - Introduction

Setting up a project (Xcode 3)

Name the project SDL01

In the Groups & Files panel, rename main.c to main.cpp to allow C++

Also in Groups & Files, select Targets then double click on SDL01

Page 28: Game Programming I - Introduction

Setting up a project (Xcode 3)

Under the Build tab, change the Base SDK to Current Mac OS

Build and run to test if it works

The program is an empty window which exits on any key press

Page 29: Game Programming I - Introduction

Extensions

SDL only loads BMP (for images) and WAV (for audio)

However, we need compressed file formats to reduce application size

SDL_image allows loading of JPG , PNG and more

SDL_mixer allows loading of MP3 and more

Other SDL extensions that we may need in the future: SDL_net and SDL_ttf

Page 30: Game Programming I - Introduction

Working with SDL

Page 31: Game Programming I - Introduction

Objectives

Implement the Game Loop in C++ using SDL

Start from src/01/main.cpp

Build and run main.cpp. You will get an empty 640x480 window that exits when clicking the close button

Page 32: Game Programming I - Introduction

src/01/main.cpp explained

#include "SDL.h"

This directive loads all the functionality of SDL. Note: the exact path of the header may be different depending on your system

Page 33: Game Programming I - Introduction

src/01/main.cpp explained

// Global Variables bool isPlaying = true; SDL_Surface *screen = 0;

isPlaying is a flag to determine if the game is still running. This controls the game loop.

screen is the video surface which will be displayed on the screen. All other images are drawn unto screen.

Page 34: Game Programming I - Introduction

src/01/main.cpp explained

// Function prototypes bool Init(); void Input(); void Update(); void Output(); void CleanUp(); The said functions are used for modularization purposes.

Page 35: Game Programming I - Introduction

src/01/main.cpp explained

int main(int argc, char *argv[]) { if (!Init()) return -1; // Enter the game loop while (isPlaying) { Input(); Update(); Output(); } CleanUp(); return 0; }

Page 36: Game Programming I - Introduction

src/01/main.cpp explained – Init()

/* Initialize the SDL library */ if ( SDL_Init(SDL_INIT_EVERYTHING) < 0 ) { fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError()); return false; } SDL_Init() initializes the modules specified in the parameter. For now, we load everything. SDL_Init() should return 0 if no error has been found. Otherwise, it returns a value < 0. It is

highly advisable to check if SDL has indeed initialized and handle the case if it doesn’t. /* Set 640x480 video mode */ screen = SDL_SetVideoMode(640,480, 32, SDL_SWSURFACE); if (screen == NULL) { fprintf(stderr, "Couldn't set 640x480x32 video mode: %s\n", SDL_GetError()); SDL_Quit(); return false; } SDL_SetVideoMode() sets up the video surface and returns a pointer to the surface. The

parameters are width, height, bits per pixel and video flags.

Page 37: Game Programming I - Introduction

src/01/main.cpp explained – Input()

SDL_Event e; while (SDL_PollEvent(&e)) { switch (e.type) { case SDL_QUIT: // Pressing the close button // will quit the program isPlaying = false; break; } } This is the event handling portion of the game. Currently, we will

only handle the quit event (pressing the close button of the window).

Page 38: Game Programming I - Introduction

src/01/main.cpp explained – Output()

SDL_Flip(screen); In order to display output, we draw images unto the surface

screen and display screen unto the screen. Basically, screen acts as a buffer to be drawn on.

SDL_Flip() draws the buffer unto the screen. This should always be the last line of the Output() and eventually, the last part of the game loop

Page 39: Game Programming I - Introduction

src/01/main.cpp explained – CleanUp()

SDL_Quit(); When done with SDL, we call on SDL_Quit() to free up the

resources created by SDL_Init() and SDL_SetVideoMode(). Thus, we don’t need to manually free up screen, but other surfaces must be freed manually.

Page 40: Game Programming I - Introduction

Sprites SDL_Surface

Page 41: Game Programming I - Introduction

Sprites

Sprites are image resources that are displayed on screen

In SDL, a sprite is called a Surface. Anything that can be drawn or drawn unto is a surface.

For this lecture, we will assume that all sprites are located under images folder in the working directory

Double check the working directory of your project to know where to put the images

Page 42: Game Programming I - Introduction

Sprites

Copy the images folder from src/02/ to your working directory

Continuing from src/01/main.cpp…

Add the following global variable SDL_Surface *ship = 0;

Load image unto the sprite (Init()) ship = SDL_LoadBMP("images/ship.bmp"); if (!ship) { fprintf(stderr, "Error: %s", SDL_GetError()); }

Write sprite unto the screen (Output()) SDL_BlitSurface(ship, NULL, screen, NULL);

Free up sprite (CleanUp()) SDL_FreeSurface(ship);

Page 43: Game Programming I - Introduction

Build and Run

Build and run the program

You should see a ship with pink background unto a black screen

Page 44: Game Programming I - Introduction

SDL_LoadBMP()

SDL_LoadBMP() takes 1 parameter of type (char *) which denotes the path of the image to be loaded.

SDL_LoadBMP() allows us to load Windows Bitmap images into our program. Similar to SDL_SetVideoMode(), if loading fails, it returns a null pointer.

It is highly advisable to handle such cases by checking if the pointer exists.

http://www.libsdl.org/cgi/docwiki.cgi/SDL_LoadBMP

Page 45: Game Programming I - Introduction

SDL_BlitSurface()

The process of writing an image unto another is called blitting. We use SDL_BlitSurface() to draw one surface unto another.

The first parameter is the source surface while the third parameter is the destination surface.

The second parameter determines which part of the source surface will be copied unto the destination. Setting this to null will draw the whole source unto the destination.

The fourth parameter is the location in the destination surface where the source will be drawn on. Setting this to null will draw the source on the upper left corner.

http://www.libsdl.org/cgi/docwiki.cgi/SDL_BlitSurface

Page 46: Game Programming I - Introduction

SDL_FreeSurface()

SDL_FreeSurface() takes 1 parameter of type SDL_Surface*.

When a surface will no longer be used, it is preferred to free up the memory using SDL_FreeSurface(). Since the resource has been freed, it is common practice to set that pointer to 0. However, we didn’t do that because we’re expecting the program to end right after CleanUp().

http://www.libsdl.org/cgi/docwiki.cgi/SDL_FreeSurface

Page 47: Game Programming I - Introduction

Adding a Color Key

To set the pink of the surface to transparent, we call SDL_SetColorKey() after we successfully loaded the image

SDL_SetColorKey(ship, SDL_SRCCOLORKEY | SDL_RLEACCEL, SDL_MapRGB(ship->format, 255, 0, 255));

SDL_SetColorKey() takes 3 parameters – source surface, color key flags and a color

The color key flags can be OR’ed together to be set them together. SDL_SRCCOLORKEY indicates that the color specified will be transparent. SDL_RLEACCEL allows the color keyed surface to be drawn faster

The color is actually a 32 bit number that varies per operating machine. Thus, SDL_MapRGB() removes this dependency and generates that number for you using the format of the surface and the color value in red, green and blue.

http://www.libsdl.org/cgi/docwiki.cgi/SDL_SetColorKey

Page 48: Game Programming I - Introduction

Sprites

See src/02/main.cpp for any clarifications

See the SDL API for more information on the aforementioned functions

http://www.libsdl.org/cgi/docwiki.cgi/SDL_API

Page 49: Game Programming I - Introduction

React to Input

Page 50: Game Programming I - Introduction

Input

Though SDL allows us to keep track of many different types of events, we will only take note of the arrow keys for now.

We will keep track of the state of each key using a bool variable. True means the key is pressed, False means it’s released.

Create the following enum enum direction_t { UP = 0, DOWN, LEFT, RIGHT };

Add the following global variable bool keys[4];

Page 51: Game Programming I - Introduction

Input

Add the following cases inside the Input() case SDL_KEYDOWN: SetKey(e.key.keysym.sym, true); break; case SDL_KEYUP: SetKey(e.key.keysym.sym, false); break;

Page 52: Game Programming I - Introduction

Input

Add the following function. Don’t forget to add the prototype as well void SetKey (SDLKey key, bool val) { switch (key) { case SDLK_DOWN: keys[DOWN] = val; break; case SDLK_UP: keys[UP] = val; break; case SDLK_LEFT: keys[LEFT] = val; break; case SDLK_RIGHT: keys[RIGHT] = val; break; } }

Page 53: Game Programming I - Introduction

Update

We need to keep the location of the ship. Create the following global variables.

int shipX = 0; int shipY = 0;

To find out which keys are pressed, we simply check keys[] in the Update()

if (keys[RIGHT]) shipX++; else if (keys[LEFT]) shipX--; if (keys[DOWN]) shipY++; else if (keys[UP]) shipY--;

Page 54: Game Programming I - Introduction

Output

Since the coordinates of our ship have changed, we need to specify where to draw it.

Replace the previous call with SDL_BlitSurface() with the following in the Output()

SDL_Rect destRect; destRect.x = shipX; destRect.y = shipY; SDL_BlitSurface(ship, NULL, screen, &destRect);

Note that SDL_Rect is a struct pre-defined in SDL. It contains x, y, w and h. However, as a fourth parameter in SDL_BlitSurface(), only the x and y are used.

Page 55: Game Programming I - Introduction

Build and Run

Build and run the program

The ship should now be movable by pressing the arrow keys

Page 56: Game Programming I - Introduction

Surface Coordinates

You may have noticed in the code that pressing down increases the y-coordinate of the ship. This is so because in surface coordinates, the upper left corner denotes (0, 0) and +x goes to the right while +y goes down.

This convention is commonly used for Screen Coordinates (but this is NOT a standard)

Page 57: Game Programming I - Introduction

Ship Trails

You may have noticed that moving the ship around would leave a trail of its edges unto the background. This is because our screen buffer is drawn unto every frame and nothing is clearing it out.

One way to fix this is to clear the buffer using SDL_FillRect() and specify the desired color (not recommended)

The better solution is to draw a background every frame, making sure that the background is drawn first.

Page 58: Game Programming I - Introduction

React to Input

See src/03/main.cpp for any clarifications

Page 59: Game Programming I - Introduction

Timer

Page 60: Game Programming I - Introduction

Purpose

In our previous example, the coordinates of the ship change for every frame that the keys are pressed. This would be undesirable because our games could be played in different machines with different frame speeds.

If one computer runs with 60 fps and another running at 30 fps, the computer with 60 fps would move faster than the other.

Instead of being frame-rate dependent, we will include a timer which will calculate the time between frames so that motion will be time-dependent.

Page 61: Game Programming I - Introduction

Timer

Add the following global variables float timeSinceStart = 0; float dt = 0;

Add the following to the top portion of the Update() float newTime = SDL_GetTicks() * 0.001f; dt = newTime - timeSinceStart; timeSinceStart = newTime; Both values are in seconds. SDL_GetTicks() returns the

number of milliseconds since SDL_Init(). We are also keeping the time between frames (dt).

Page 62: Game Programming I - Introduction

Ship Speed

Since our motion will now be time-dependent, we need to set a speed (pixels/sec) as a global variable.

float shipSpeed = 400;

In the Update(), in/decrement shipX or shipY by (shipSpeed * dt);

Note: shipX and shipY should now be float as well.

Page 63: Game Programming I - Introduction

Build and Run

Build and run the program

Try changing the value of shipSpeed and see what happens.

See src/04/main.cpp for any clarifications

Page 64: Game Programming I - Introduction

Asteroids

Page 65: Game Programming I - Introduction

Asteroids

We will now add adversaries for our player.

The ship needs to dodge the asteroid. Colliding with the asteroid will cause the ship to spawn at the starting position.

The asteroid starts from the top of the screen, slowly moving downwards. Upon going past the bottom edge of the screen, the asteroid will reappear on top with a random x-coordinate.

Page 66: Game Programming I - Introduction

Random Number

Since we will need a random number generator, include the <ctime> library

#include <ctime>

At the end of the Init(), right before return true;

srand(time(NULL));

To use, simply call rand() and this will generate a random integer. Limit the values using modulo.

Page 67: Game Programming I - Introduction

Asteroid Properties

Create the following global variables SDL_Surface *asteroid = 0; float asteroidX = 0; float asteroidY = -128; // above the screen float asteroidSpeed = 200;

Page 68: Game Programming I - Introduction

Asteroid Sprite

Load the image (Init()) asteroid = SDL_LoadBMP("images/asteroid.bmp"); if (!asteroid) { fprintf(stderr, "Error: %s", SDL_GetError()); } SDL_SetColorKey(asteroid, SDL_SRCCOLORKEY | SDL_RLEACCEL, SDL_MapRGB(asteroid->format, 255, 0, 255));

As a practice, when coding the loading of a sprite, handle the

release of the resource immediately (CleanUp()) SDL_FreeSurface(asteroid);

Page 69: Game Programming I - Introduction

Asteroid Logic

Add the following after the ship’s movement in the Update() asteroidY += (asteroidSpeed * dt); if (asteroidY > 480) { asteroidY = -128; asteroidX = rand() % 512; } This moves the asteroid downward until it reaches the end

and spawns on top upon going beyond the bottom edge.

Page 70: Game Programming I - Introduction

Draw the Asteroid

Inside the Output() after drawing the ship; destRect.x = asteroidX; destRect.y = asteroidY; SDL_BlitSurface(asteroid, NULL, screen, &destRect);

Note that we’re recycling the same destRect used for the ship.

Page 71: Game Programming I - Introduction

Test

Before we go to collision detection and reaction, now would be a good time to test it.

Build and run the program

The asteroid should come from the top, moving downwards and respawning above the top edge of the screen.

It would be advisable to change the initial coordinates of the ship to somewhere in the middle of the screen.

Page 72: Game Programming I - Introduction

Circle – Circle Collision

For now, we will let our collision areas be a circle. Circle collisions are easy to understand

Two circles are colliding if the distance between their centers is less than the sum of their radii

Page 73: Game Programming I - Introduction

Circle – Circle Collision

Given the position both circles; (posAX, posAY) and (posBX, posBY), and their radius; radiusA and radiusB, we can compute for the distance as follows:

distanceSq = (posAX – posBX) * (posAX – posBX) + (posAY – posBY) * (posAY – posBY)

Rather than getting the square root, we leave them as squared values because the sqrt() function is really slow

If (radiusA + radiusB) * (radiusA + radiusB) > distanceSq, then the 2 circles intersect

Page 74: Game Programming I - Introduction

Asteroid – Ship Collision

Ship Collision Area Center: (shipX + 32, shipY + 32)

Radius: 16

Asteroid Collision Area Center: (asteroidX + 64, asteroidY + 64)

Radius: 48

Note that our collision areas aren’t perfect

Page 75: Game Programming I - Introduction

Asteroid – Ship Collision

After colliding, the ship will return to its starting position. if (AreCirclesIntersecting(shipX + 32, shipY + 32, 16, asteroidX + 64, asteroidY + 64, 48)) { shipX = 288; shipY = 416; }

Note that this is in the last part of the Update()

Page 76: Game Programming I - Introduction

Asteroids

Build and run your program.

Move the ship towards the asteroid and see what happens when they collide.

See src/05/main.cpp for any clarifications

Page 77: Game Programming I - Introduction

Congratulations!

Hooray to you for your first attempt at making video games!

Wasn’t that a piece of cake?

Sure, installation and set up was hell but when you got that first window up, it was pure bliss.

Page 78: Game Programming I - Introduction

Exercises

1. Limit the movement of the ship such that it cannot leave the boundaries of the stage

2. Put in 1 more asteroid and this one moves horizontally

3. Make the movement of the first asteroid to be alternating (moving down then up)

4. Add a boost for the ship (holding the space bar would double its speed)

Page 79: Game Programming I - Introduction

Limitations

Page 80: Game Programming I - Introduction

Realizations

1. Adding more game objects is a hassle to manage. Each game object will either be drawn (sprite, position, etc) or execute logic (react to input, collision, etc) or both.

2. Having a dynamic number of game objects during run time is currently not possible.

3. Resources are manually managed. (allocating, freeing, using)

4. The game loop is already constant. Changing the rules of the game doesn’t affect it.

5. Ideally, the modules are separate (Input and Timer)

6. How do we add a Title Screen and In-Game Menu?

7. How do we change levels?

8. Logging using fprintf() to stderr. What if I wanted to log to a file?

9. And so on…

Page 81: Game Programming I - Introduction

Frameworks a.k.a. Game Engines

A Framework is an integration of different technologies to remove the constant parts of a program and lessen the hassle of work not directly related to the purpose of the software.

For example The Game Loop

Resource Management

Game Object Management

Separation of Modules