gdc09 minigames
DESCRIPTION
TRANSCRIPT
![Page 1: Gdc09 Minigames](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/1.jpg)
Mini GamesLessons From Rebuilding Classic Games in C++ and OpenGL
Joe LinhoffEugene JarvisDarren Torpey
![Page 2: Gdc09 Minigames](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/2.jpg)
MiniGamesRebuilding Three Classic
Joe LinhoffEugene JarvisDarren Torpey
![Page 3: Gdc09 Minigames](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/3.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/4.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/5.jpg)
Modern Game Design
1) Simulate Everything 2) The most realistic shit ever 3) goto 1;
![Page 6: Gdc09 Minigames](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/6.jpg)
Running A Game Dev Class
![Page 7: Gdc09 Minigames](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/7.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/8.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/9.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/10.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/11.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/12.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/13.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/14.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/15.jpg)
Hello World
![Page 16: Gdc09 Minigames](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/16.jpg)
Building Hello World
should be able to download, launch the solution file, build, and run
![Page 17: Gdc09 Minigames](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/17.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/18.jpg)
QE
lightweight academic game engine written in C, supports C++ OpenGL see reference
![Page 19: Gdc09 Minigames](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/19.jpg)
Pong, 1972
![Page 20: Gdc09 Minigames](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/20.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/21.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/22.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/23.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/24.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/25.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/26.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/27.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/28.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/29.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/30.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/31.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/32.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/33.jpg)
Game Superstructurevisualization
![Page 34: Gdc09 Minigames](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/34.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/35.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/36.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/37.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/38.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/39.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/40.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/41.jpg)
Missile Command, 1980
![Page 42: Gdc09 Minigames](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/42.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/43.jpg)
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](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/44.jpg)
Robotron, 1982
![Page 45: Gdc09 Minigames](https://reader033.vdocument.in/reader033/viewer/2022051612/54c0ac404a79595c658b45fe/html5/thumbnails/45.jpg)