Gdc09 Minigames

45
Mini Games Lessons From Rebuilding Classic Games in C++ and Joe Linhoff Eugene Jarvis Darren Torpey

description

 

Transcript of Gdc09 Minigames

Page 1: Gdc09 Minigames

Mini GamesLessons From Rebuilding Classic Games in C++ and OpenGL

Joe LinhoffEugene JarvisDarren Torpey

Page 2: Gdc09 Minigames

MiniGamesRebuilding Three Classic

Joe LinhoffEugene JarvisDarren Torpey

Page 3: Gdc09 Minigames

DePaul University

BS Game Development since 2004 programming production and design

MS Game Development Animation, Computer Science, Software

Engineering, Digital Cinema Outstanding Faculty

Eugene Jarvis (Game Designer In Residence) Alexander Seropian (Halo, future GDIR) William Muehl, Ed Keenan, Patrick Curry, Alan

Turner

Page 4: Gdc09 Minigames

Workshop Target

This is a discussion on the teaching of game development and will focus on the use of mini-games to teach game programming and game

design.

There will be no art.

Page 5: Gdc09 Minigames

Modern Game Design

1) Simulate Everything 2) The most realistic shit ever 3) goto 1;

Page 6: Gdc09 Minigames

Running A Game Dev Class

Page 7: Gdc09 Minigames

Infrastructure

Tools students and instructors use same tool set

Directory Structure bad paths kill projects

Server what kind of support you need

Communication Channels define them

Page 8: Gdc09 Minigames

Infrastructure

Tools MSVS C++ Express Edition TortoiseSVN (Subversion) IM (Skype)

Directory Structure explained in other slides

Server Subversion Wiki

Communication Channels (manage or drown) avoid email to students: SVN wiki from students: SVN Skype

Page 9: Gdc09 Minigames

Setup

Setup is critical Too many variables for students to do this Setup includes directory structure Must give working starter kits

SSID: "joshua weinberg mac bookpro 17" www.joeco.com/qe.htm

Page 10: Gdc09 Minigames

Setup

DirectX runtime Google and install lastest runtime from Microsoft's

site -- needed for sound and input MSVS C/C++ Express Edition

Page 11: Gdc09 Minigames

Version Control(highly recommended)

Distribution you setup the

directory structure you populate the files

Help students commit files

and can IM you for real-time help

Collection commit their work time stamped

TortoiseSVN easy to use works well SVN command line

tool for scripting free

Problems too much committed too little committed

Page 12: Gdc09 Minigames

Directory Structure

dev -- development root can exist anywhere class1 student1 student2 class2 student1 student2 projects gdc09 <-- $(SolutionDir) art mini -- code files for mini-games qeStartup.c m_minipong.cc mini.vcproj mini.vcproj.user <-- user properties default game.sln bin -- shared bin files qeblue.dll freeglut.dll inc -- shared headers for qe and freeglut qe.h qec.h qefn.h GL/glut.h GL/freeglut.h ... lib -- shared lib qeblue.lib freeglut.lib

Page 13: Gdc09 Minigames

MSVC Properties: paths

Set in all Configurations

Debugging Working Directory: $(SolutionDir) Environment: path=$(SolutionDir)../../bin;%path%C/C++ General Additional Include Directories: $(SolutionDir)../../incLinker General Additional Library Directories: $(SolutionDir)../../lib Input Additional Dependencies: qeblue.dll

set in project properties instead of Project and Solution Options

inherited properties may also provide good solution

Page 14: Gdc09 Minigames

mini.vcproj.user

this is the 'short' version of the user file mini.vcproj.D630.Joe.user is long version (includes

machine and user name) used if long version isn't found all modifications are saved to the long version confusing and not useful to commit the long

version since it only works on one machine lesson1: make changes and commit short

version lesson2: always test on a different system

Page 15: Gdc09 Minigames

Hello World

Page 16: Gdc09 Minigames

Building Hello World

should be able to download, launch the solution file, build, and run

Page 17: Gdc09 Minigames

config.h

one project build one program a time

// config.h#ifndef CONFIG_H#define CONFIG_H

// build one at a time#define BUILD_HELLO 1 // hello world#define BUILD_MINIPONG 0 // pong#define BUILD_MINIMISSILE 0 // missile command#define BUILD_MINIROBO 0 // robotron

#endif // ndef CONFIG_H

// Copyright (C) 2007-2009 Joe Linhoff, All Rights Reserved// m_hello.c#include "config.h" // include the config file first#if BUILD_HELLO // compile this app#include "qe.h" // engine include file

// qeMain()int qeMain(int argc,chr *argv[]){ qePrintf("%s / %s / %s\n",__FILE__,glGetString(GL_VERSION),qeVersion());

qePrintf("Hello World\n");

// turn control over to the engine until the user closes the program qeForever();

return 0;} // qeMain()

#endif // compile this app// EOF

Page 18: Gdc09 Minigames

QE

lightweight academic game engine written in C, supports C++ OpenGL see reference

Page 19: Gdc09 Minigames

Pong, 1972

Page 20: Gdc09 Minigames

Teaching Game Development Starting Student Projects

Research and brainstorm Create "1000 Features" list Choose coordinates Draw screenshot and world map Start very small iterations

limit scope of iteration to one sitting get something running in first five minutes bias work in beginning toward visual changes, then

input, core mechanic keep it working, always be improving

Start with programmer art Write clean code, bracket resources Refrain from refactoring until you can't stand it Always plan for the future but code for today

Page 21: Gdc09 Minigames

Game Development

Process workflow

Design what are you trying to do

Development tools and language build an exe

Game development techniques solutions to the problem space

Page 22: Gdc09 Minigames

1000 Features (handout)unique value 0..1000

possible feature for your game -- focus on what you see, hear, and how to get it on the screen

Page 23: Gdc09 Minigames

000ZY Coordinates

Right handed coordinate system Root for all models is (0,0,0) Z is forward Y is up All translation, rotation, scale match Maya

i.e. given TRS, build matrix such that object draws like it does in Maya

Choose units one unit is one foot

Page 24: Gdc09 Minigames

Camerassoftware metaphor

// JFL 03 Oct 08class Camera : public qe {public: chr name[16]; // name float fovyHalfRad; // in radians float nearClip; // near clipping plane float farClip; // far clipping plane float winWidth; // in pixels float winHeight; // in pixels float winWDivH; // window aspect ratio float nearHeight; // height at near plane float mat12[12]; // camera matrix int draw(); // draw-step function Camera(chr *name); // constructor}; // class Camera

// setup -- happens once in mini-pongthis->nearClip = 1;this->farClip = 500;this->fovyHalfRad = 0.5*((63*PI)/180.0);this->nearHeight = this->nearClip * MathTanf(this->fovyHalfRad);

// camera matrix -- from world space into camera spaceSET3(pos,0,CAMERA_Y,0); // position of cameraSET3(at,0,0,0); // where camera is looking atSET3(up,0,0,-1); // the camera's up directionqeCamLookAtM12f(this->mat12,pos,at,up); // camera mat

// draw -- set every frame before you drawif(qeGetWindowSize(&this->winWidth,&this->winHeight)<0) bret(-2); // jump to function exitthis->winWDivH=this->winWidth/this->winHeight;

// set the PROJECTION matrix (the camera lens)glMatrixMode(GL_PROJECTION);glLoadIdentity();float yy = this->nearHeight;float xx=this->nearHeight*this->winWDivH;glFrustum(-xx,xx,-yy,yy,this->nearClip,this->farClip); // MODELVIEW (position and orientation of the camera)glMatrixMode(GL_MODELVIEW);glLoadIdentity();qeGLM12f(this->mat12); // set matrix

Page 25: Gdc09 Minigames

OpenGL 4x4 Matrices (M16)

#define VecTransformM16(_d_,_v_,_m_) \ // d=dstvec v=srcvec m=mat16 (_d_)[0]=(_v_)[0]*(_m_)[M16_11]+(_v_)[1]*(_m_)[M16_21] \ +(_v_)[2]*(_m_)[M16_31]+(_m_)[M16_X], \ (_d_)[1]=(_v_)[0]*(_m_)[M16_12]+(_v_)[1]*(_m_)[M16_22] \ +(_v_)[2]*(_m_)[M16_32]+(_m_)[M16_Y], \ (_d_)[2]=(_v_)[0]*(_m_)[M16_13]+(_v_)[1]*(_m_)[M16_23] \ +(_v_)[2]*(_m_)[M16_33]+(_m_)[M16_Z]

#define VecRotM16(_d_,_v_,_m_) \ (_d_)[0]=(_v_)[0]*(_m_)[M16_11]+(_v_)[1]*(_m_)[M16_21] \ +(_v_)[2]*(_m_)[M16_31], \ (_d_)[1]=(_v_)[0]*(_m_)[M16_12]+(_v_)[1]*(_m_)[M16_22] \ +(_v_)[2]*(_m_)[M16_32], \ (_d_)[2]=(_v_)[0]*(_m_)[M16_13]+(_v_)[1]*(_m_)[M16_23] \ +(_v_)[2]*(_m_)[M16_33]

float mat[16]; glGetFloatv(GL_MODELVIEW_MATRIX,mat);

Page 26: Gdc09 Minigames

QE 3x4 matrices (M12)non-standard: XYZ and 3x3 rotation matrix

#define VecTransformM12(_d_,_v_,_m_) \ (_d_)[0]=(_v_)[0]*(_m_)[M12_11]+(_v_)[1]*(_m_)[M12_21] \ +(_v_)[2]*(_m_)[M12_31]+(_m_)[M12_X], \ (_d_)[1]=(_v_)[0]*(_m_)[M12_12]+(_v_)[1]*(_m_)[M12_22] \ +(_v_)[2]*(_m_)[M12_32]+(_m_)[M12_Y], \ (_d_)[2]=(_v_)[0]*(_m_)[M12_13]+(_v_)[1]*(_m_)[M12_23] \ +(_v_)[2]*(_m_)[M12_33]+(_m_)[M12_Z]

#define VecRotM12(_d_,_v_,_m_) \ (_d_)[0]=(_v_)[0]*(_m_)[M12_11]+(_v_)[1]*(_m_)[M12_21] \ +(_v_)[2]*(_m_)[M12_31], \ (_d_)[1]=(_v_)[0]*(_m_)[M12_12]+(_v_)[1]*(_m_)[M12_22] \ +(_v_)[2]*(_m_)[M12_32], \ (_d_)[2]=(_v_)[0]*(_m_)[M12_13]+(_v_)[1]*(_m_)[M12_23] \ +(_v_)[2]*(_m_)[M12_33]

Page 27: Gdc09 Minigames

Velocities

variable frame rates float qeTimeFrame()

returns seconds since engine start / restart

keep track of the time since the last update

use Euler integration

// JFL 25 Jan 09class Ball : public qe {public: chr name[16]; // name float timeOfLastUpdate; // in seconds float xyz[3]; // current float vel[3]; // velocity Ball(chr *name); // constructor int update(); // update function int draw(); // draw function}; // class Ball

// update, move the ballfloat t;

// find time since last updatet=this->timeOfLastUpdate;this->timeOfLastUpdate=qeTimeFrame();t=this->timeOfLastUpdate-t; // delta

// xyz += vel*tthis->xyz[0]+=this->vel[0]*t;this->xyz[1]+=this->vel[1]*t;this->xyz[2]+=this->vel[2]*t;

Page 28: Gdc09 Minigames

Collisions

simplifications move, then collide

non-moving objects don't worry about

resolution order run through once

guarantee after detection, move

objects out of that collision (may be in another -- too bad)

end up in valid world position

no movement after collision resolution

Page 29: Gdc09 Minigames

Collisions ball v world

if over right or left score point, re-serve

if over top or bottom set to top or bottom reflect (flip z vel)

paddle v world make sure player

stays on the court ball v paddles

test against near edge of paddle set to near edge bounce (flip x vel) add English (later)

improvements preserve distance

when colliding don't just set to

collision edge reflect at collision point

does order matter? theoretically unlikely

fast balls could run through the

paddle depends on paddle

size and ball speed really need to handle

moving collisions

Page 30: Gdc09 Minigames

Game ControllerUse Singleton Pattern

manage the game loop with one Game instance

good chance to use the Singleton pattern

Game *Game::instance=0; // initialize Singleton

// JFL 13 Aug 08Game::Game(chr *name) : qeUpdateBase(name,0,GAMEID_GAME){ // constructor this->name = qeObjName(this->_oShared); // get name} // Game::Game()

// JFL 16 Aug 08void Game::InstanceDelete(){ if(Game::instance) Game::instance->objRemove(); // request obj removal } // GameInstanceDelete()

// JFL 16 Aug 08Game* Game::InstanceNew(){ if(!Game::instance) Game::instance = new Game("game1"); return Game::instance;} // Game::InstanceNew()

// JFL 16 Aug 08Game* Game::InstanceGet(){ return Game::instance;} // Game::InstanceGet()

// JFL 03 Oct 08class Game : public qeUpdateBase { // game controller record chr *name; // points to system name static Game *instance; // singleton Game(chr *name); // constructorpublic: static Game* InstanceNew(); static Game* InstanceGet(); static void InstanceDelete();

}; // class Game

Page 31: Gdc09 Minigames

qeUpdateBase base class

engine base class provides virtual

update() draw() final()

adds to list of engine objects

all objs derived from qeUpdateBase update() functions

called before any of the draw() functions

Page 32: Gdc09 Minigames

qe base class

derive from qe for simple objects

no overhead runs through engine's

memory system keeps count to keep

you honest zeros memory on

allocation

Page 33: Gdc09 Minigames

Game Superstructurevisualization

Page 34: Gdc09 Minigames

Button Countsuns qeInpButton(uns inpb); // QEINPBUTTON_

by default the keys are mapped as buttons

every up and down transition, the engine adds a value to that count

single button count value gives state and history

if odd ==> down if(b&1) /* down */;

store count, come back later and find how many transitions good for coins

Page 35: Gdc09 Minigames

Joysticksfloat qeInpJoyAxisf(uns joy,uns axis); // use QEJOYAXIS_

uns qeInpJoyButton(uns joy,uns button); // use QEJOYBUTTON_

joysticks start at 0 OK to test even if stick

is not present the axis is defined qeInpJoyAxisf()

returns values -1..1 mind the DEADZONE

Page 36: Gdc09 Minigames

Draw simple filled rectangle

glColor3f(1,1,1); glPolygonMode(GL_FRONT,GL_FILL); // draw filled polygons glBegin(GL_QUADS); // draw quads counter-clockwise from camera's view glVertex3f(-1,0,-3); glVertex3f(-1,0,3); glVertex3f(2,0,3); glVertex3f(2,0,-3); glEnd();

Page 37: Gdc09 Minigames

Loading and Playing Sounds

capture sounds low-res, mono for

effects wav files register play

// setup sound "bump" on channel 1if((r=qeSndNew("bump",M_SNDNEW_CH_1,0,"art/sounds/pongbump.wav"))<0) BRK();

// trigger the soundqeSndPlay("bump");

Page 38: Gdc09 Minigames

qePrintf()qeLogf()

printf-like function calls to qePrintf() get

added to log file qelog.txt

add to log file directly with qeLogf()

Page 39: Gdc09 Minigames

BRK()

normal asserts() kill the game -- this can be bad

code with BRK() to continue running

the "break" goes away when outside the debugger

Page 40: Gdc09 Minigames

Bracket Resources

bullet-proof allocation and freeing of resources memory file-handles etc

usually two ways to kill normal object life program abort

good solution initialization

guaranteed to run clear all fields

body finalization

guaranteed to run can be triggered when

body finishes normally or w/abort

Page 41: Gdc09 Minigames

Missile Command, 1980

Page 42: Gdc09 Minigames

Strings 'chr' in qebase.h defines an 8 bit character for

internal programming use guarantees & principles

sizes are always byte sizes of whole buffers zero termination guaranteed if dstsize>0 pointer-terminated and zero-terminated strings

much faster, safer pointer-terminator always option, pass 0

must be zero-terminated sz* functions defined qebase.h int szcpy(chr *dst,int dstsize,chr *ss,chr *sx);

ss is string start, sx is pointer-terminator or 0 int szfmt(chr *dst,int dstsize,chr *fmt,...);

printf-like fmt

Page 43: Gdc09 Minigames

LLNode

Simple doubly linked list node

Type field t specifies game-specific type

Type field is zero for list head

// linked listtypedef struct _llnode { struct _llnode *next; struct _llnode *prev; int t; // type: listhead=0, others=non-zero} LLNode;

// JFL 23 Aug 06// JFL 20 Mar 08; re-worked from DLvoid LLMakeHead(LLNode *h){ h->next=h->prev=h; h->t=0;} // LLMakeHead()

// JFL 20 Mar 08; re-worked from DL// JFL 18 May 08; link to selfvoid LLMakeNode(LLNode *n,int t){ n->next=n->prev=n; n->t=t;} // LLMakeNode()

// JFL 23 Aug 06// JFL 20 Mar 08; re-worked from DLvoid LLLinkAfter(LLNode *h,LLNode *n){ n->next=h->next; n->next->prev=n; n->prev=h; h->next=n;} // LLLinkAfter()

// JFL 05 May 06// JFL 20 Mar 08; re-worked from DLvoid LLLinkBefore(LLNode *h,LLNode *n){ n->prev=h->prev; n->prev->next=n; n->next=h; h->prev=n;} // LLLinkBefore()

// JFL 05 May 06// JFL 20 Mar 08; re-worked from DLvoid LLUnlink(LLNode *n){ n->prev->next=n->next; n->next->prev=n->prev; n->next=n->prev=n; // multiple unlinks OK} // LLUnlink()

Page 44: Gdc09 Minigames

Robotron, 1982

Page 45: Gdc09 Minigames