Sie sind auf Seite 1von 24

4/30/12

Game Engine & F ame o k in Ja a

yet another insignificant programming notes...

HOME

Java GAME Programming


Game Engine & FrameWork

Instead of writing games in an ad-hoc manner (which I did but found it grossly inefficient), I decided to put up a framework for programming games in Java. This is because many of the tasks involved in game programming are similar in many types of games. A framework not only helps in improving the productivity but also ensures high quality codes. Before presenting the entire framework, let's look at the individual pieces involved in game programming.

Custom Draw ing


Game programming requires custom drawing. For a Swing application, we extend a J a e (called G m C n a ) and Pnl aeavs override the p i t o p n n ( r p i s method to do custom drawing. (Older Java AWT appplications perform anCmoetGahc) custom drawing on j v . w . a v s which is discouraged for Swing applications.) The p i t o p n n ( method is aaatCna, anCmoet) not meant to be called directly, but called-back via the r p i t )method. The G a h c context supports rendering of ean( rpis text (d a S r n ( ), primitive shapes (d a X x ) f l X x ) and bitmap images (d a I a e ) For higher-quality rwtig) r w x ( , i l x ( ), r w m g ( ). graphics, we could use G a h c 2 (of the Java 2D API) instead of the legacy G a h c . The custom drawing panel is rpisD rpis usually designed as an inner class to the main game class, in order to directly access the private variables of the outer class - in particular, the game objects. The G m C n a is a key-event source, as well as listener (via a d e L s e e ( h s ). aeavs dKyitnrti) As source, it triggers K y v n upon key-pressed, key-released and key-typed. As a listener, it implements K y i t n r eEet eLsee interface and provides event handlers for key-pressed, key-released and key-typed. The main game class is derived from a J r m , as a typical Swing application. An instance of G m C n a called c n a is Fae aeavs avs instantiated and set as the content pane for the J r m . Fae The game logic is supported in these methods: g m I i ( : initialization codes. Run only once. aent) g m S a t ) to start or re-start the game. aetr(: g m S u d w ( : clean-up codes (e.g., write the high-score). Run once before the program terminates. aehton) g m U d t ( : to be called in the game loop for updating the position and state of the game objects, detecting aepae) collision and providing proper responses. g m D a ( r p i s D g d or g m D a ( r p i s g : render the graphics, to be called inside the aerwGahc2 2) aerwGahc ) p i t o p n n ( of the drawing J a e . anCmoet) Pnl g m K y r s e ( n k y o e , g m K y e e s d i t k y o e , and g m K y y e ( n k y o e : aeePesdit eCd) aeeRlae(n eCd) aeeTpdit eCd) K y v n handler for key-pressed, key-released and key-typed. eEet The structure (i.e., template) of the graphics part of the a Java game is as follows:
ipr jv.w.; mot aaat* ipr jv.w.vn.; mot aaateet* ipr jvxsig* mot aa.wn.; pbi casGmMi etnsJrm { ulc ls aean xed Fae / Dfn cntnsfrtegm / eie osat o h ae sai fnlitCNA_IT =80 ttc ia n AVSWDH 0; sai fnlitCNA_EGT=60 ttc ia n AVSHIH 0; / ... / ... / mi casfrtegm -asigapiain / an ls o h ae wn plcto

/ wdhadhih o tedaigcna / it n egt f h rwn avs

/ Dfn isac vralsfrtegm ojcs / eie ntne aibe o h ae bet / ... / ...
3.n .ed . g/home/ehch a/p og amming/ja a/J8d_Game_F ame o k.h ml 1/24

4/30/12

Game Engine & F ame o k in Ja a

/ ... / ... / Hnl frtecso daigpnl / ade o h utm rwn ae piaeGmCna cna; rvt aeavs avs / Cntutrt iiilz teU cmoet adgm ojcs / osrco o ntaie h I opnns n ae bet pbi GmMi( { ulc aean) / Iiilz tegm ojcs / ntaie h ae bet gmIi(; aent) / U cmoet / I opnns cna =nwGmCna(; avs e aeavs) cna.ePeerdienwDmninCNA_IT,CNA_EGT) avsstrfreSz(e ieso(AVSWDH AVSHIH); ti.eCnetaecna) hsstotnPn(avs; / OhrU cmoet sc a bto,soebad i ay / te I opnns uh s utn cr or, f n. / ... / ... ti.eDfutlsOeainEI_NCOE; hsstealCoeprto(XTO_LS) ti.ak) hspc(; ti.eTte"YGM"; hsstil(M AE) ti.eVsbetu) hsstiil(re; } / --- Altegm rltdcdshr --/ --- l h ae eae oe ee --/ Iiilz altegm ojcs rnol oc. / ntaie l h ae bet, u ny ne pbi vi gmIi( {... } ulc od aent) ... / Satadr-tr tegm. / tr n esat h ae pbi vi gmSat){... } ulc od aetr( ... / Sudw tegm,cenu cd ta rn ol oc. / hton h ae la p oe ht us ny ne pbi vi gmSudw( {... } ulc od aehton) ... / Oese o tegm. / n tp f h ae pbi vi gmUdt( {... } ulc od aepae) ... / Rfehtedslyatrec se. / ers h ipa fe ah tp / Ue(rpisg a agmn i yuaentuigJv 2. / s Gahc ) s ruet f o r o sn aa D pbi vi gmDa(rpisDgd {... } ulc od aerwGahc2 2) ... / Poesakypesdeet / rcs e-rse vn. pbi vi gmKyrse(n kyoe { ulc od aeePesdit eCd) sic (eCd){ wth kyoe cs Kyvn.KU: ae eEetV_P / ... / ... bek ra; cs Kyvn.KDW: ae eEetV_ON / ... / ... bek ra; cs Kyvn.KLF: ae eEetV_ET / ... / ... bek ra; cs Kyvn.KRGT ae eEetV_IH: / ... / ... bek ra; } } / Poesakyrlae eet / rcs e-eesd vn. pbi vi gmKyeesditkyoe {... } ulc od aeeRlae(n eCd) ... / Poesakytpdeet / rcs e-ye vn. pbi vi gmKyye(hrkyhr {... } ulc od aeeTpdca eCa) ... / Ohrmtos / te ehd / ... / ...
3.n .ed . g/home/ehch a/p og amming/ja a/J8d_Game_F ame o k.h ml 2/24

4/30/12

Game Engine & F ame o k in Ja a

/ Cso daigpnl witna a inrcas / utm rwn ae, rte s n ne ls. casGmCna etnsJae ipeet Kyitnr{ ls aeavs xed Pnl mlmns eLsee / Cntutr / osrco pbi GmCna( { ulc aeavs) stoual(re; / s ta cnrciekyeet eFcsbetu) / o ht a eev e-vns rqetou(; eusFcs) adeLsee(hs; dKyitnrti) } / Oerd pitopnn t d cso daig / vrie anCmoet o o utm rwn. / Cle bc b rpit) / ald ak y ean(. @vrie Oerd pbi vi pitopnn(rpisg { ulc od anCmoetGahc ) Gahc2 gd=(rpisDg / i uigJv 2 rpisD 2 Gahc2); / f sn aa D sprpitopnn(2) ue.anCmoetgd; / pitbcgon / an akrud stakrudClrBAK; eBcgon(oo.LC) / myuea iaefrbcgon / a s n mg o akrud / Da tegm ojcs / rw h ae bet gmDa(2) aerwgd; } / Kyvn hnlr / eEet ades @vrie Oerd pbi vi kyrse(eEete { ulc od ePesdKyvn ) gmKyrse(.eKyoe); aeePesdegteCd() } @vrie Oerd pbi vi kyeesdKyvn e { ulc od eRlae(eEet ) gmKyeesdegteCd() aeeRlae(.eKyoe); } @vrie Oerd pbi vi kyye(eEete { ulc od eTpdKyvn ) gmKyye(.eKyhr); aeeTpdegteCa() } } / mi / an pbi sai vi mi(tig]ag){ ulc ttc od anSrn[ rs / Ueteeetdsac tra t bidteU frtra-aey / s h vn ipth hed o ul h I o hedsft. Sigtlte.noeae(e Rnal( { wnUiiisivkLtrnw unbe) @vrie Oerd pbi vi rn){ ulc od u( nwGmMi(; e aean) } }; ) } }

The purpose of the template (and framework) is to guide you on where to place your programming codes. In other words, do not modify the "fixed" portion of the template, but concentrate on implementing your game logic. The above template implements only key listener. Some games may require mouse listener or mouse-motion listener. They can be added similar to key listener.

Init and Shutdow n - g m I i ( & g m S u d w ( aent) aehton)


The g m I i ( method is meant to be run once, to instantiate all the gaming objects, pre-load images and sound aent) effects, among others. In this framework, g m I i ( is called once in the constructor of the main application G m M i . aent) aean The g m S u d w ( is also meant to be run once, for clean-up operations such as writing out the high-score. aehton)

Starting the Game Pla - g m S a t ) aetr(


3.n .ed . g/home/ehch a/p og amming/ja a/J8d_Game_F ame o k.h ml 3/24

4/30/12

Game Engine & F ame o k in Ja a

Once all the game objects are in place (via g m I i ( ), we can start the game by running a game loop to repeat the aent) game steps. In a typical single-player game, the game loop executes at a fixed interval. It calculates the new position of all the game objects and move them into the new position. It then detects collision among the game objects and provides responses, renders a new frame and pushes it to the screen.

We shall use the method g m S a t )to start the play, or re-start after the the previous play. The g m S a t )runs aetr( aetr( the game-loop as follows:
/ Sat(n r-tr)tegm. / tr ad esat h ae pbi vi gmSat){ ulc od aetr( / Rgnrt tegm ojcsfranwgm / eeeae h ae bet o e ae ... ... / Gm lo / ae op wie(re { hl tu) / Udt tesaeadpsto o altegm ojcs / pae h tt n oiin f l h ae bet, / dtc cliin adpoiersoss / eet olsos n rvd epne. gmUdt(; aepae) / Rfehtedsly / ers h ipa. rpit) ean(; / Dlytmrt poietencsaydlyt me tetre rt. / ea ie o rvd h eesr ea o et h agt ae ... ... } }

Within the game loop, we invoke the g m U d t ( method to calculate the position of the game objects, update their aepae) states, detect collision and provide responses. The game loop is written as an infini e loop. We need to keep track of the a e of the game via b o e nvariables such ola as g m O e and g m P u e . (I will change it to an enumeration later.) We can then use these b o e nflags to control aevr aeasd ola the loop. For example,
/ Saeo tegm / tt f h ae boengmOe =fle ola aevr as; boengmPue =fle ola aeasd as; ... ... ... ... pbi vi gmSat){ ulc od aetr( / Rgnrt tegm ojcsfranwgm / eeeae h ae bet o e ae ... ... / Gm lo / ae op wie(re { hl tu)
3.n .ed . g/home/ehch a/p og amming/ja a/J8d_Game_F ame o k.h ml 4/24

4/30/12

Game Engine & F ame o k in Ja a

i (aevr bek / bektelo t fns tecretpa f gmOe) ra; / ra h op o iih h urn ly i (gmPue){ f !aeasd / Udt tesaeadpsto o altegm ojcs / pae h tt n oiin f l h ae bet, / dtc cliin adpoiersoss / eet olsos n rvd epne. gmUdt(; aepae) } / Rfehtedsly / ers h ipa rpit) ean(; / Dlytmrt poietencsaydlyt me tetre rt. / ea ie o rvd h eesr ea o et h agt ae ... ... } }

Controlling the Refresh (Update) Rate of the Game


The monitor refreshes at 50-100 Hz. There is pointless for your game to update your game faster than the monitor. For some action games, you may wish to intercept the video buffer and update the game at the same rate as the monitor. For others like tetris and snake games, you may wish to update at the same rate as the player's response, says 1-5 moves per second. Suppose that we wish to refresh the game at 5 moves per second. Each move takes 1000/5 = 200 milliseconds. The delay timer must provide (200 - time taken to run the earlier processes). This can be achieved as follows:
sai fnlitUDT_AE=4 / nme o gm udt prscn ttc ia n PAERT ; / ubr f ae pae e eod sai fnlln UDT_EID=10000L/UDT_AE / nnscns ttc ia og PAEPRO 00000 PAERT; / aoeod / Saeo tegm / tt f h ae boengmOe =fle ola aevr as; boengmPue =fle ola aeasd as; ... ... ... ... pbi vi gmSat){ ulc od aetr( ln bgnie tmTkn tmLf; og eiTm, ieae, ieet / Rgnrt tegm ojcsfranwgm / eeeae h ae bet o e ae ... ... / Gm lo / ae op wie(re { hl tu) bgnie=Sse.aoie) eiTm ytmnnTm(; i (aevr bek / bektelo t fns tecretpa f gmOe) ra; / ra h op o iih h urn ly i (gmPue){ f !aeasd / Udt tesaeadpsto o altegm ojcs / pae h tt n oiin f l h ae bet, / dtc cliin adpoiersoss / eet olsos n rvd epne. gmUdt(; aepae) } / Rfehtedsly / ers h ipa rpit) ean(; / Dlytmrt poietencsaydlyt me tetre rt / ea ie o rvd h eesr ea o et h agt ae tmTkn=Sse.aoie)-bgnie ieae ytmnnTm( eiTm; tmLf =(PAEPRO -tmTkn /1000 / i mlieod ieet UDT_EID ieae) 000; / n ilscns i (ieet 1)tmLf =1; / stamnmm f tmLf 0 ieet 0 / e iiu ty{ r / Poie tencsaydlyadas yed cnrls ta ohrtra cnd wr. / rvds h eesr ea n lo ils oto o ht te hed a o ok Tra.le(ieet; hedseptmLf) }cth(nerpeEcpine){} ac Itrutdxeto x } }

JDK 1.5 provides a new timer called S s e . a o i e ) for measuring the elapsed time, which is reportedly more ytmnnTm( precise than the legacy S s e . u r n T m M l i ( . ytmcretieils) The static method T r a . l e ( suspends the current thread, and wait for the specified milliseconds before hedsep) attempting to resume. This process serves two purposes. Firstly, it provides the necessary time delay needed to meet the target rate. Secondly, by suspending itself, another thread can resume and perform its task. In particular, the so-called e en di pa ch h ead, which is responsible for processing input events (such as mouse-clicked, key-pressed) and
3.n .ed . g/home/ehch a/p og amming/ja a/J8d_Game_F ame o k.h ml 5/24

4/30/12

Game Engine & F ame o k in Ja a

refreshing the display, cannot be a ed. Otherwise, the infamous n e pon i e display is frozen and the system does not response to any input event.

e -in e face resulted, that is, the

Game Thread
Next, we need to run the game loop in its own thread - let's call it the game thread. We use a dedicated thread to run our game loop to ensure responsive user-interface (as mentioned above). The game thread (called G m T r a ) is derived from the class T r a . It is written as an inner class. We override the aehed hed r n )method to program the running behavior of the thread. To start the play, we need to create a new instance of the u( G m T r a and invoke the s a t )method, which will call-back the r n )method to run the programmed behavior. aehed tr( u( There is, however, an issue here. We would like to start the play via the g m S a t )method. But we need to program aetr( the running behavior in the overridden r n ) To resolve this program, I break the game starting method into two parts: u(. g m S a t )which simply create and run a new G m T r a ; and g m L o ( , which is called by the r n )method aetr( aehed aeop) u( to run the game loop, as follows:
pbi casGmMi etnsJrm { / mi gm cas ulc ls aean xed Fae / an ae ls sai fnlitUDT_AE=4 ttc ia n PAERT ; / nme o gm udt prscn / ubr f ae pae e eod sai fnlln UDT_EID=10000L/UDT_AE / nnscns ttc ia og PAEPRO 00000 PAERT; / aoeod / Saeo tegm / tt f h ae boengmOe =fle ola aevr as; boengmPue =fle ola aeasd as; ... ... ... ... / T satadr-tr tegm. / o tr n esat h ae pbi vi gmSat){ ulc od aetr( / Cet anwtra / rae e hed Tra gmTra = nwTra( { hed aehed e hed) / Oerd rn)t poieternigbhvo o ti tra. / vrie u( o rvd h unn eair f hs hed @vrie Oerd pbi vi rn){ ulc od u( gmLo(; aeop) } } ; / Sattetra.sat)clsrn) wihi tr clsgmLo(. / tr h hed tr( al u(, hc n un al aeop) gmTra.tr(; aehedsat) } / Rntegm lo hr. / u h ae op ee piaevi gmLo( { rvt od aeop) / Rgnrt tegm ojcsfranwgm / eeeae h ae bet o e ae ... ... / Gm lo / ae op ln bgnie tmTkn tmLf; og eiTm, ieae, ieet wie(re { hl tu) bgnie=Sse.aoie) eiTm ytmnnTm(; i (aevr bek / bektelo t fns tecretpa f gmOe) ra; / ra h op o iih h urn ly i (gmPue){ f !aeasd / Udt tesaeadpsto o altegm ojcs / pae h tt n oiin f l h ae bet, / dtc cliin adpoiersoss / eet olsos n rvd epne. gmUdt(; aepae) } / Rfehtedsly / ers h ipa rpit) ean(; / Dlytmrt poietencsaydlyt me tetre rt / ea ie o rvd h eesr ea o et h agt ae tmTkn=Sse.aoie)-bgnie ieae ytmnnTm( eiTm; tmLf =(PAEPRO -tmTkn /1000 / i mlieod ieet UDT_EID ieae) 000; / n ilscns i (ieet<1)tmLf =1; / stamnmm f tmLf 0 ieet 0 / e iiu ty{ r / Poie tencsaydlyadas yed cnrls ta ohrtra cnd wr. / rvds h eesr ea n lo ils oto o ht te hed a o ok Tra.le(ieet; hedseptmLf) }cth(nerpeEcpine){} ac Itrutdxeto x
3.n .ed . g/home/ehch a/p og amming/ja a/J8d_Game_F ame o k.h ml 6/24

4/30/12

Game Engine & F ame o k in Ja a

} } }

Game States
Let's try to handle the game state in a more systematic way, instead of using boolean flags (such as g m O e and aevr g m P u e ). The state diagram for a typical game is as illustrated below: aeasd

We shall define a nested static enumeration to represent the game states in the G m M i class as follow: aean
pbi casGmMi etnsJrm ulc ls aean xed Fae / Eueainfrtesae o tegm. / nmrto o h tts f h ae sai eu Sae{ ttc nm tt IIILZD PAIG PUE,GMOE,DSRYD NTAIE, LYN, ASD AEVR ETOE } sai Saesae ttc tt tt; ... ... } / cretsaeo tegm / urn tt f h ae

The enumeration S a eand the instance variable s a eare declared as static, which can be accessed via the classname tt tt directly. For example, you can manipulate the s a e tt:
/ i GmMi cas / n aean ls sae=SaeGMOE; tt tt.AEVR ... ... sic (tt){ wth sae cs IIILZD ae NTAIE: ... ... bek ra; cs PAIG ae LYN: ... ... bek ra; cs PUE: ae ASD ... ... bek ra; cs GMOE: ae AEVR ... ... bek ra; cs DSRYD ae ETOE: ... ... bek ra; }

The Complete Jav a Game Framew ork


ipr jv.w.; mot aaat* ipr jv.w.vn.; mot aaateet*
3.n .ed . g/home/ehch a/p og amming/ja a/J8d_Game_F ame o k.h ml 7/24

4/30/12

Game Engine & F ame o k in Ja a

ipr jvxsig* mot aa.wn.; pbi casGmMi etnsJrm { ulc ls aean xed Fae / mi casfrtegm a aSigapiain / an ls o h ae s wn plcto

/ Dfn cntnsfrtegm / eie osat o h ae sai fnlitCNA_IT =80 ttc ia n AVSWDH 0; / wdhadhih o tegm sre / it n egt f h ae cen sai fnlitCNA_EGT=60 ttc ia n AVSHIH 0; sai fnlitUDT_AE=4 ttc ia n PAERT ; / nme o gm udt prscn / ubr f ae pae e eod sai fnlln UDT_EID=10000L/UDT_AE / nnscns ttc ia og PAEPRO 00000 PAERT; / aoeod / ... / ... / Eueainfrtesae o tegm. / nmrto o h tts f h ae sai eu Sae{ ttc nm tt IIILZD PAIG PUE,GMOE,DSRYD NTAIE, LYN, ASD AEVR ETOE } sai Saesae ttc tt tt; / cretsaeo tegm / urn tt f h ae / Dfn isac vralsfrtegm ojcs / eie ntne aibe o h ae bet / ... / ... / ... / ... / Hnl frtecso daigpnl / ade o h utm rwn ae piaeGmCna cna; rvt aeavs avs / Cntutrt iiilz teU cmoet adgm ojcs / osrco o ntaie h I opnns n ae bet pbi GmMi( { ulc aean) / Iiilz tegm ojcs / ntaie h ae bet gmIi(; aent) / U cmoet / I opnns cna =nwGmCna(; avs e aeavs) cna.ePeerdienwDmninCNA_IT,CNA_EGT) avsstrfreSz(e ieso(AVSWDH AVSHIH); ti.eCnetaecna) hsstotnPn(avs; / OhrU cmoet sc a bto,soebad i ay / te I opnns uh s utn cr or, f n. / ... / ... ti.eDfutlsOeainEI_NCOE; hsstealCoeprto(XTO_LS) ti.ak) hspc(; ti.eTte"YGM"; hsstil(M AE) ti.eVsbetu) hsstiil(re; } / Altegm rltdcdshr / l h ae eae oe ee / Iiilz altegm ojcs rnol oc i tecntutro temi cas / ntaie l h ae bet, u ny ne n h osrco f h an ls. pbi vi gmIi( { ulc od aent) / ... / ... sae=SaeIIILZD tt tt.NTAIE; } / Sudw tegm,cenu cd ta rn ol oc. / hton h ae la p oe ht us ny ne pbi vi gmSudw( { ulc od aehton) / ... / ... } / T satadr-tr tegm. / o tr n esat h ae pbi vi gmSat){ ulc od aetr( / Cet anwtra / rae e hed Tra gmTra = nwTra( { hed aehed e hed) / Oerd rn)t poieternigbhvo o ti tra. / vrie u( o rvd h unn eair f hs hed @vrie Oerd pbi vi rn){ ulc od u( gmLo(; aeop) } } ; / Sattetra.sat)clsrn) wihi tr clsgmLo(. / tr h hed tr( al u(, hc n un al aeop) gmTra.tr(; aehedsat)
3.n .ed . g/home/ehch a/p og amming/ja a/J8d_Game_F ame o k.h ml 8/24

4/30/12

Game Engine & F ame o k in Ja a

} / Rntegm lo hr. / u h ae op ee piaevi gmLo( { rvt od aeop) / Rgnrt tegm ojcsfranwgm / eeeae h ae bet o e ae / ... / ... sae=SaePAIG tt tt.LYN; / Gm lo / ae op ln bgnie tmTkn tmLf; og eiTm, ieae, ieet wie(re { hl tu) bgnie=Sse.aoie) eiTm ytmnnTm(; i (tt = SaeGMOE)bek / bektelo t fns tecretpa f sae = tt.AEVR ra; / ra h op o iih h urn ly i (tt = SaePAIG { f sae = tt.LYN) / Udt tesaeadpsto o altegm ojcs / pae h tt n oiin f l h ae bet, / dtc cliin adpoiersoss / eet olsos n rvd epne. gmUdt(; aepae) } / Rfehtedsly / ers h ipa rpit) ean(; / Dlytmrt poietencsaydlyt me tetre rt / ea ie o rvd h eesr ea o et h agt ae tmTkn=Sse.aoie)-bgnie ieae ytmnnTm( eiTm; tmLf =(PAEPRO -tmTkn /1000; / i mlieod ieet UDT_EID ieae) 000L / n ilscns i (ieet<1)tmLf =1; / stamnmm f tmLf 0 ieet 0 / e iiu ty{ r / Poie tencsaydlyadas yed cnrls ta ohrtra cnd wr. / rvds h eesr ea n lo ils oto o ht te hed a o ok Tra.le(ieet; hedseptmLf) }cth(nerpeEcpine){} ac Itrutdxeto x } } / Udt tesaeadpsto o altegm ojcs / pae h tt n oiin f l h ae bet, / dtc cliin adpoiersoss / eet olsos n rvd epne. pbi vi gmUdt( {... } ulc od aepae) ... / Rfehtedsly Cle bc varpit) wihivk tepitopnn(. / ers h ipa. ald ak i aan(, hc noe h anCmoet) piaevi gmDa(rpisDgd { rvt od aerwGahc2 2) sic (tt){ wth sae cs IIILZD ae NTAIE: / ... / ... bek ra; cs PAIG ae LYN: / ... / ... bek ra; cs PUE: ae ASD / ... / ... bek ra; cs GMOE: ae AEVR / ... / ... bek ra; } / ... / ... } / Poesakypesdeet Udt tecretsae / rcs e-rse vn. pae h urn tt. pbi vi gmKyrse(n kyoe { ulc od aeePesdit eCd) sic (eCd){ wth kyoe cs Kyvn.KU: ae eEetV_P / ... / ... bek ra; cs Kyvn.KDW: ae eEetV_ON / ... / ... bek ra; cs Kyvn.KLF: ae eEetV_ET / ... / ... bek ra; cs Kyvn.KRGT ae eEetV_IH: / ... / ...
3.n .ed . g/home/ehch a/p og amming/ja a/J8d_Game_F ame o k.h ml 9/24

4/30/12

Game Engine & F ame o k in Ja a

bek ra; } } / Poesakyrlae eet / rcs e-eesd vn. pbi vi gmKyeesditkyoe { } ulc od aeeRlae(n eCd) / Poesakytpdeet / rcs e-ye vn. pbi vi gmKyye(hrkyhr { } ulc od aeeTpdca eCa) / Ohrmtos / te ehd / ... / ... / Cso daigpnl witna a inrcas / utm rwn ae, rte s n ne ls. casGmCna etnsJae ipeet Kyitnr{ ls aeavs xed Pnl mlmns eLsee / Cntutr / osrco pbi GmCna( { ulc aeavs) stoual(re; / s ta cnrciekyeet eFcsbetu) / o ht a eev e-vns rqetou(; eusFcs) adeLsee(hs; dKyitnrti) } / Oerd pitopnn t d cso daig / vrie anCmoet o o utm rwn. / Cle bc b rpit) / ald ak y ean(. @vrie Oerd pbi vi pitopnn(rpisg { ulc od anCmoetGahc ) Gahc2 gd=(rpisDg rpisD 2 Gahc2); sprpitopnn(2) ue.anCmoetgd; / pitbcgon / an akrud stakrudClrBAK; / myuea iaefrbcgon eBcgon(oo.LC) / a s n mg o akrud / Da tegm ojcs / rw h ae bet gmDa(2) aerwgd; } / Kyvn hnlr / eEet ades @vrie Oerd pbi vi kyrse(eEete { ulc od ePesdKyvn ) gmKyrse(.eKyoe); aeePesdegteCd() } @vrie Oerd pbi vi kyeesdKyvn e { ulc od eRlae(eEet ) gmKyeesdegteCd() aeeRlae(.eKyoe); } @vrie Oerd pbi vi kyye(eEete { ulc od eTpdKyvn ) gmKyye(.eKyhr); aeeTpdegteCa() } } / mi / an pbi sai vi mi(tig]ag){ ulc ttc od anSrn[ rs / Ueteeetdsac tra t bidteU frtra-aey / s h vn ipth hed o ul h I o hedsft. Sigtlte.noeae(e Rnal( { wnUiiisivkLtrnw unbe) @vrie Oerd pbi vi rn){ ulc od u( nwGmMi(; e aean) } }; ) } }

Summar
You can use the above template by:
3.n .ed . g/home/ehch a/p og amming/ja a/J8d_Game_F ame o k.h ml 10/24

4/30/12

Game Engine & F ame o k in Ja a

Declare all the instance variables for game objects. Instantiate all the game objects in the method g m I i ( . aent) Program the g m U d t ( , for calculating the new position of the game objects, updating the states, detecting the aepae) collision and providing the responses. Program the g m D a ( , for display game objects and information after each game step. aerw) Handle the input event in g m K y r s e ( . Update the state of the game. aeePesd)

Case Stud 1: The Snake Game (Part I)


Let's design a simple snake game based on this framework. The snake move around the pit in search of food. It grows by one cell-length whenever it eats a piece of food. The snake dies when it try to eat itself, or moves outside the pit.

A S a eis made up of one or more horizontal or vertical S a e e m n s. A P tcontains one S a eand one piece of nk nkSget i nk F o . An enumeration called D r c i nis defined as a static nested class of S a efor the four moving directions: U , od ieto nk P D W , L F and R G T ON ET IH.

Game Actor Design


In general, a "moving" game actor should have these properties:
poetdboenaie rtce ola lv; poetddul x y rtce obe , ; poetddul sed rtce obe pe; poetddul drcin rtce obe ieto; poetddul rttoSed rtce obe oainpe; poetddul wdh hih; rtce obe it, egt / aieo da / lv r ed / (,y lcto o iscne / x ) oain f t etr / sedi pxl prgm-tp / pe n ies e aese / mvmn drcini dges / oeet ieto n ere / rttoa sedi dgesprgm-tp(pinl / oainl pe n ere e aese otoa) / wdhadhih o ti atr / it n egt f hs co

It should possess these operations:


/ Da isl / rw tef pbi vi da(rpisDgd {... } ulc od rwGahc2 2) ...
3.n .ed . g/home/ehch a/p og amming/ja a/J8d_Game_F ame o k.h ml 11/24

4/30/12

Game Engine & F ame o k in Ja a

/ Iiilz (rr-ntaie ti atra tesato tegm. / ntaie o eiiilz) hs co t h tr f h ae pbi vi rgnrt( {... } ulc od eeeae) ... / Frcliindtcin / o olso eeto pbi boenitret(hp sae {... } / itret wt tegvnsae ulc ola nescsSae hp) ... / nescs ih h ie hp pbi boencnan(hp sae {... } ulc ola otisSae hp) ... / cmltl ecoe tegvnsae / opeey nlss h ie hp pbi SaegtonsD){... } ulc hp eBud2( ... / rtrsabudn bx / eun onig o

For the snake game, we can simplify the design as the snake can move left/right/up/down, one cell at each update. The pit consists of cells (of R W by C L M S The coordinates are referenced to the cells' row and column numbers. OS O U N ).

Enum S a e D r c i n nk.ieto
We first decided to have an enum called D r c i n to represent the movement direction of the snake. We decided to ieto, place this enum as a static nested enum inside the S a eclass as follows: nk
pbi casSae{ ulc ls nk pbi sai eu Drcin{ ulc ttc nm ieto U,DW,LF,RGT P ON ET IH } ... ... ... ... }

Class S a e e m n nkSget
Next, we decided that a snake shall make up of horizontal and vertical segments. Each segment has its head at (h a X ed, h a Y a length, and a movement direction. Segment can grow (at the head) and shrink (at the tail) by one cell. It can e d ), draw itself. It has a method called c n a n ( n x i t y for collision detection. otisit , n )
ipr jv.w.rpis mot aaatGahc; /* * *Saeemn rpeet oehrzna o vria sgeto asae Te"ed o nkSget ersns n oiotl r etcl emn f nk. h ha" f *ti sgeti a (ed,haY.Tesgeti dansatn fo te"ed hs emn s t haX ed) h emn s rw trig rm h ha" *adpoedn "egh clsi "ieto" utli rahste"al. n rceig lnt" el n drcin, ni t ece h ti" * / pbi casSaeemn { ulc ls nkSget piaeithaX haY rvt n ed, ed; / Tepsto o teha o ti sget / h oiin f h ed f hs emn piaeitlnt; rvt n egh / lnt o ti sget / egh f hs emn piaeSaeDrcindrcin rvt nk.ieto ieto; / drcino ti sget / ieto f hs emn / Cntutanwsaesgeta gvn(ed,haY,lnt addrcin / osrc e nk emn t ie haX ed) egh n ieto. pbi Saeemn(n haX ithaY itlnt,SaeDrcindrcin { ulc nkSgetit ed, n ed, n egh nk.ieto ieto) ti.ed =haX hshaX ed; ti.ed =haY hshaY ed; ti.ieto =drcin hsdrcin ieto; ti.egh=lnt; hslnt egh } / Go b adn oecl t teha o ti sget / rw y dig n el o h ed f hs emn. pbi vi go( { ulc od rw) lnt+; egh+ / ne t ajs tehaXadhaY / ed o dut h ed n ed sic (ieto){ wth drcin cs LF: haX- bek ae ET ed-; ra; cs RGT haX+ bek ae IH: ed+; ra; cs U: ae P haY- bek ed-; ra; cs DW: haY+ bek ae ON ed+; ra; } } / Srn b rmvn oecl fo teti o ti sget / hik y eoig n el rm h al f hs emn. pbi vi srn( { ulc od hik) lnt-; / n cag i haXadhaYnee egh/ o hne n ed n ed edd }
3.n .ed . g/home/ehch a/p og amming/ja a/J8d_Game_F ame o k.h ml 12/24

4/30/12

Game Engine & F ame o k in Ja a

/ Gttelnt,i cls o ti sget / e h egh n el, f hs emn. pbi itgtegh){rtr lnt;} ulc n eLnt( eun egh / GtteXcodnt o tecl ta cnan teha o ti saesget / e h oriae f h el ht otis h ed f hs nk emn. pbi itgted( {rtr haX } ulc n eHaX) eun ed; / GtteYcodnt o tecl ta cnan teha o ti saesget / e h oriae f h el ht otis h ed f hs nk emn. pbi itgted( {rtr haY } ulc n eHaY) eun ed; / GtteXcodnt o tecl ta cnan teti o ti saesget / e h oriae f h el ht otis h al f hs nk emn. piaeitgtal( { rvt n eTiX) i (ieto = SaeDrcinLF){ f drcin = nk.ieto.ET rtr haX+lnt -1 eun ed egh ; }es i (ieto = SaeDrcinRGT { le f drcin = nk.ieto.IH) rtr haX-lnt +1 eun ed egh ; }es { le rtr haX eun ed; } } / GtteYcodnt o tecl ta cnan teti o ti saesget / e h oriae f h el ht otis h al f hs nk emn. piaeitgtal( { rvt n eTiY) i (ieto = SaeDrcinDW){ f drcin = nk.ieto.ON rtr haY-lnt +1 eun ed egh ; }es i (ieto = SaeDrcinU){ le f drcin = nk.ieto.P rtr haY+lnt -1 eun ed egh ; }es { le rtr haY eun ed; } } / Rtrstu i tesaesgetcnan tegvncl.Ue frcliindtcin / eun re f h nk emn otis h ie el sd o olso eeto. pbi boencnan(n x ity { ulc ola otisit , n ) sic (ieto){ wth drcin cs LF: rtr (y= ti.ed)& (x =ti.ed)& ( < gtal()) ae ET eun ( = hshaY & ( hshaX & x = eTiX)); cs RGT rtr (y= ti.ed)& (x< ti.ed)& ( =gtal()) ae IH: eun ( = hshaY & ( = hshaX & x eTiX)); cs U: ae P rtr (x= ti.ed)& (y =ti.ed)& ( < gtal()) eun ( = hshaX & ( hshaY & y = eTiY)); cs DW: rtr (x= ti.ed)& (y< ti.ed)& ( =gtal()) ae ON eun ( = hshaX & ( = hshaY & y eTiY)); } rtr fle eun as; } / Da ti sget / rw hs emn. pbi vi da(rpisg { ulc od rwGahc ) itx=haX n ed; ity=haY n ed; sic (ieto){ wth drcin cs LF: ae ET fr(n i=0 i<lnt;i+ { o it ; egh +) gfl3Rc( *GmMi.ELSZ,y*GmMi.ELSZ, .ilDetx aeanCL_IE aeanCL_IE GmMi.ELSZ -1 GmMi.ELSZ -1 tu) aeanCL_IE , aeanCL_IE , re; x+ +; } bek ra; cs RGT ae IH: fr(n i=0 i<lnt;i+ { o it ; egh +) gfl3Rc( *GmMi.ELSZ,y*GmMi.ELSZ, .ilDetx aeanCL_IE aeanCL_IE GmMi.ELSZ -1 GmMi.ELSZ -1 tu) aeanCL_IE , aeanCL_IE , re; x-; } bek ra; cs U: ae P fr(n i=0 i<lnt;i+ { o it ; egh +) gfl3Rc( *GmMi.ELSZ,y*GmMi.ELSZ, .ilDetx aeanCL_IE aeanCL_IE GmMi.ELSZ -1 GmMi.ELSZ -1 tu) aeanCL_IE , aeanCL_IE , re; y+ +;
3.n .ed . g/home/ehch a/p og amming/ja a/J8d_Game_F ame o k.h ml 13/24

4/30/12

Game Engine & F ame o k in Ja a

} bek ra; cs DW: ae ON fr(n i=0 i<lnt;i+ { o it ; egh +) gfl3Rc( *GmMi.ELSZ,y*GmMi.ELSZ, .ilDetx aeanCL_IE aeanCL_IE GmMi.ELSZ -1 GmMi.ELSZ -1 tu) aeanCL_IE , aeanCL_IE , re; y-; } bek ra; } } / Frdbgig / o eugn. @vrie Oerd pbi Srn tSrn( { ulc tig otig) rtr "eda ( +haX+""+haY+""+"t ( +gtal( +"" eun Ha t " ed , ed ) o " eTiX) , +gtal( +""+" lnt i "+gtegh)+" dri "+drcin eTiY) ) , egh s eLnt( , i s ieto; } }

Class S a e nk
Next, the S a eclass is designed to maintain a list of S a e e m n s nk nkSget.
ipr jv.w.; mot aaat* ipr jv.tl* mot aaui.; /* * *ASaei md u o oeo mr Saeemn.TefrtSaeemn i te nk s ae p f n r oe nkSget h is nkSget s h *"ed o tesae Tels Saeemn i te"al o tesae A te ha" f h nk. h at nkSget s h ti" f h nk. s h *saemvs i ad oecl t teha adte rmvsoefo teti.I nk oe, t ds n el o h ed n hn eoe n rm h al f *tesaeet apeeo fo,teha ad oecl btteti wl nt h nk as ic f od h ed ds n el u h al il o *srn. hik * / pbi casSae{ ulc ls nk pbi sai eu Drcin{ ulc ttc nm ieto U,DW,LF,RGT P ON ET IH } piaeClrclr=ClrBAK rvt oo oo oo.LC; / clrfrti saebd / oo o hs nk oy piaeClrclred=ClrGEN / clrfrte"ed rvt oo ooHa oo.RE; / oo o h ha" piaeSaeDrcindrcin rvt nk.ieto ieto; / tecretdrcino tesaesha / h urn ieto f h nk' ed / Tesaesget ta frstesae / h nk emns ht om h nk piaeLs<nkSget saeemns=nwAryitSaeemn (; rvt itSaeemn nkSget e raLs<nkSget ) piaeboendrpaeedn; / Pnigudt fradrcincag? rvt ola iUdtPnig / edn pae o ieto hne piaeRno rno =nwRno(; / frrnol rgnrtn asae rvt adm adm e adm) / o admy eeeaig nk / Rgnrt tesae / eeeae h nk. pbi vi rgnrt( { ulc od eeeae) saeemnscer) nkSget.la(; / Rnol gnrt asaeisd tept / admy eeae nk nie h i. itlnt =2; n egh 0 ithaX=rno.etn(aeanCLMS-lnt *2 +lnt; n ed admnxItGmMi.OUN egh ) egh ithaY=rno.etn(aeanRW -lnt *2 +lnt; n ed admnxItGmMi.OS egh ) egh drcin=SaeDrcinvle([admnxItSaeDrcinvle(.egh] ieto nk.ieto.aus)rno.etn(nk.ieto.aus)lnt); saeemnsadnwSaeemn(ed,haY lnt,drcin) nkSget.d(e nkSgethaX ed, egh ieto); drpaeedn =fle iUdtPnig as; } / Cag tedrcino tesae btn 10dge tr alwd / hne h ieto f h nk, u o 8 ere un loe. pbi vi stieto(nk.ieto nwi){ ulc od eDrcinSaeDrcin eDr / Inr i teei adrcincag pnigadn 10dge tr / goe f hr s ieto hne edn n o 8 ere un i (drpaeedn & (eDr! drcin f !iUdtPnig & nwi = ieto) & (nwi = SaeDrcinU & drcin! SaeDrcinDW) & (eDr = nk.ieto.P & ieto = nk.ieto.ON | (eDr= SaeDrcinDW & drcin! SaeDrcinU) | nwi = nk.ieto.ON & ieto = nk.ieto.P
3.n .ed . g/home/ehch a/p og amming/ja a/J8d_Game_F ame o k.h ml 14/24

4/30/12

Game Engine & F ame o k in Ja a

| (eDr= SaeDrcinLF & drcin! SaeDrcinRGT | nwi = nk.ieto.ET & ieto = nk.ieto.IH) | (eDr= SaeDrcinRGT& drcin! SaeDrcinLF)){ | nwi = nk.ieto.IH & ieto = nk.ieto.ET) Saeemn haSget=saeemnsgt0; / gtteha sget nkSget edemn nkSget.e() / e h ed emn itx=haSgetgted(; n edemn.eHaX) ity=haSgetgted(; n edemn.eHaY) / adanwsgetwt zr lnt a tenwha sget / d e emn ih eo egh s h e ed emn saeemnsad0 nwSaeemn(,y 0 nwi); nkSget.d(, e nkSgetx , , eDr) drcin=nwi; ieto eDr drpaeedn =tu;/ wl b cerdatrudtd iUdtPnig re / il e lae fe pae } } / Mv tesaeb oese.Tesae"ed sgetgosb oecl.Ters o te / oe h nk y n tp h nk ha" emn rw y n el h et f h / sget rmi ucagd Te"al sgetwl ltrb srn i cliindtce. / emns ean nhne. h ti" emn il ae e hik f olso eetd pbi vi udt( { ulc od pae) Saeemn haSget nkSget edemn; haSget=saeemnsgt0; / "ed sget edemn nkSget.e() / ha" emn haSgetgo(; edemn.rw) drpaeedn =fle iUdtPnig as; / cnpoestekyiptaan / a rcs h e nu gi } / Ntetnafo ie.Srn teti b oecl. / o ae od tm hik h al y n el pbi vi srn( { ulc od hik) Saeemn tiSget nkSget alemn; tiSget=saeemnsgtsaeemnssz( -1; alemn nkSget.e(nkSget.ie) ) tiSgetsrn(; alemn.hik) i (alemn.eLnt( = 0 { f tiSgetgtegh) = ) saeemnsrmv(alemn) nkSget.eoetiSget; } } / GtteXcodnt o tecl ta cnan teha o ti saesget / e h oriae f h el ht otis h ed f hs nk emn. pbi itgted( { ulc n eHaX) rtr saeemnsgt0.eHaX) eun nkSget.e()gted(; } / GtteYcodnt o tecl ta cnan teha o ti saesget / e h oriae f h el ht otis h ed f hs nk emn. pbi itgted( { ulc n eHaY) rtr saeemnsgt0.eHaY) eun nkSget.e()gted(; } / Rtrstelnt o ti saeb adn u altesget. / eun h egh f hs nk y dig p l h emns pbi itgtegh){ ulc n eLnt( itlnt =0 n egh ; fr(nkSgetsget:saeemns { o Saeemn emn nkSget) lnt + sgetgtegh) egh = emn.eLnt(; } rtr lnt; eun egh } / Rtrstu i tesaecnan tegvn(,y cl.Ue i cliindtcin / eun re f h nk otis h ie x ) el sd n olso eeto pbi boencnan(n x ity { ulc ola otisit , n ) fr(n i=0 i<saeemnssz(;i+ { o it ; nkSget.ie) +) Saeemn sget=saeemnsgti; nkSget emn nkSget.e() i (emn.otisx y){ f sgetcnan(, ) rtr tu; eun re } } rtr fle eun as; } / Rtrstu i tesaeet isl / eun re f h nk as tef pbi boenettef){ ulc ola aIsl( ithaX=gted(; n ed eHaX) ithaY=gted(; n ed eHaY) / etisl i te(ed,haY ht isbd sget(t owrs / a tef f h haX ed) is t oy emn 4h nad) fr(n i=3 i<saeemnssz(;i+ { o it ; nkSget.ie) +) Saeemn sget=saeemnsgti; nkSget emn nkSget.e()
3.n .ed . g/home/ehch a/p og amming/ja a/J8d_Game_F ame o k.h ml 15/24

4/30/12

Game Engine & F ame o k in Ja a

i (emn.otishaX haY){ f sgetcnan(ed, ed) rtr tu; eun re } } rtr fle eun as; } / Da isl. / rw tef pbi vi da(rpisg { ulc od rwGahc ) gstoo(oo) .eClrclr; fr(n i=0 i<saeemnssz(;i+ { o it ; nkSget.ie) +) saeemnsgti.rwg; / da altesget nkSget.e()da() / rw l h emns } i (nkSget.ie) 0 { f saeemnssz( ) gstoo(ooHa) .eClrclred; gfl3Rc(eHaX)*GmMi.ELSZ,gted( .ilDetgted( aeanCL_IE eHaY) *GmMi.ELSZ,GmMi.ELSZ -1 aeanCL_IE aeanCL_IE , GmMi.ELSZ -1 tu) aeanCL_IE , re; } } / Frdbgig / o eugn. @vrie Oerd pbi Srn tSrn( { ulc tig otig) SrnBfe s =nwSrnBfe(; tigufr b e tigufr) s.ped"*nk* Drcini "+drcin+"n) bapn(*Sae* ieto s ieto \"; itcut=1 n on ; fr(nkSgetsget:saeemns { o Saeemn emn nkSget) s.ped" Sget"+cut+" "; bapn( emn on : ) cut+ on+; s.pedsget; bapn(emn) s.ped'n) bapn(\'; } rtr s.otig) eun btSrn(; } }

In order to process only the first key input, and ignore the rest until the first key is processed, a flag called d r p a e e d n is used, which will be set whenever a change of direction input is received. This stops further changes, iUdtPnig until the snake is updated.

[PENDING] more explanation

Class F o od
Next, the Food class, which is rather straight forward.
3.n .ed . g/home/ehch a/p og amming/ja a/J8d_Game_F ame o k.h ml 16/24

4/30/12

Game Engine & F ame o k in Ja a

ipr jv.w.; mot aaat* ipr jv.tl* mot aaui.; /* * *Fo i afo ie ta tesaecnet I i pae rnol i tept od s od tm ht h nk a a. t s lcd admy n h i. * / pbi casFo { ulc ls od piaeitx y rvt n , ; / cretfo lcto (,y i cls / urn od oain x ) n el piaeClrclr=ClrBU; / clrfrdsly rvt oo oo oo.LE / oo o ipa piaeRno rn =nwRno(;/ Frrnol paigtefo rvt adm ad e adm) / o admy lcn h od / Dfutcntutr / eal osrco. pbi Fo( { ulc od) / paeotietept s ta i wl ntb "ipae" / lc usd h i, o ht t il o e dslyd. x=-; 1 y=-; 1 } / Rgnrt afo ie.Rnol paeisd tept(lgtyofteeg) / eeeae od tm admy lc nie h i sihl f h de. pbi vi rgnrt( { ulc od eeeae) x=rn.etn(aeanCLMS-4 +2 adnxItGmMi.OUN ) ; y=rn.etn(aeanRW -4 +2 adnxItGmMi.OS ) ; } / Rtrstexcodnt o tecl ta cnan ti fo ie. / eun h oriae f h el ht otis hs od tm pbi itgt( {rtr x } ulc n eX) eun ; / Rtrsteycodnt o tecl ta cnan ti fo ie. / eun h oriae f h el ht otis hs od tm pbi itgt( {rtr y } ulc n eY) eun ; / Da isl. / rw tef pbi vi da(rpisg { ulc od rwGahc ) gstoo(oo) .eClrclr; gfl3Rc( *GmMi.ELSZ,y*GmMi.ELSZ, .ilDetx aeanCL_IE aeanCL_IE GmMi.ELSZ,GmMi.ELSZ,tu) aeanCL_IE aeanCL_IE re; } }

Class G m M i aean
Finally, it is the main class G m M i , based on the framework. aean
ipr jv.w.; mot aaat* ipr jv.w.vn.; mot aaateet* ipr jvxsig* mot aa.wn.; pbi casGmMi etnsJrm { ulc ls aean xed Fae / mi casfrtegm a aSigapiain / an ls o h ae s wn plcto

/ Dfn cntnsfrtegm / eie osat o h ae sai fnlitRW =5; ttc ia n OS 0 / nme o rw (ncls / ubr f os i el) sai fnlitCLMS=5; / nme o clms(ncls ttc ia n OUN 0 / ubr f oun i el) sai fnlitCL_IE=1;/ Sz o acl (npxl) ttc ia n ELSZ 2 / ie f el i ies sai fnlitCNA_IT =CLMS*CL_IE / wdhadhih o tegm sre ttc ia n AVSWDH OUN ELSZ; / it n egt f h ae cen sai fnlitCNA_EGT=RW *CL_IE ttc ia n AVSHIH OS ELSZ; sai fnlitUDT_AE=3 ttc ia n PAERT ; / nme o gm udt prscn / ubr f ae pae e eod sai fnlln UDT_EID=10000L/UDT_AE / nnscns ttc ia og PAEPRO 00000 PAERT; / aoeod piaefnlClrCLRPT=ClrLGTGA; rvt ia oo OO_I oo.IH_RY / Eueainfrtesae o tegm. / nmrto o h tts f h ae sai eu Sae{ ttc nm tt IIILZD PAIG PUE,GMOE,DSRYD NTAIE, LYN, ASD AEVR ETOE } sai Saesae ttc tt tt; / cretsaeo tegm / urn tt f h ae / Dfn isac vralsfrtegm ojcs / eie ntne aibe o h ae bet piaeFo fo; rvt od od
3.n .ed . g/home/ehch a/p og amming/ja a/J8d_Game_F ame o k.h ml 17/24

4/30/12

Game Engine & F ame o k in Ja a

piaeSaesae rvt nk nk; / Hnl frtecso daigpnl / ade o h utm rwn ae piaeGmCna pt rvt aeavs i; / Cntutrt iiilz teU cmoet adgm ojcs / osrco o ntaie h I opnns n ae bet pbi GmMi( { ulc aean) / Iiilz tegm ojcs / ntaie h ae bet gmIi(; aent) / U cmoet / I opnns pt=nwGmCna(; i e aeavs) ptstrfreSz(e DmninCNA_IT,CNA_EGT) i.ePeerdienw ieso(AVSWDH AVSHIH); ti.eCnetaept; hsstotnPn(i) ti.eDfutlsOeainEI_NCOE; hsstealCoeprto(XTO_LS) ti.ak) hspc(; ti.eTte"NK GM"; hsstil(SAE AE) ti.eVsbetu) hsstiil(re; / Sattegm. / tr h ae gmSat) aetr(; } / --- Altegm rltdcdshr --/ --- l h ae eae oe ee --/ Iiilz altegm ojcs rnol oc i tecntutro temi cas / ntaie l h ae bet, u ny ne n h osrco f h an ls. pbi vi gmIi( { ulc od aent) / Alct anwsaeadafo ie,d ntrgnrt. / loae e nk n od tm o o eeeae sae=nwSae) nk e nk(; fo =nwFo(; od e od) sae=SaeIIILZD tt tt.NTAIE; } / Sudw tegm,cenu cd ta rn ol oc. / hton h ae la p oe ht us ny ne pbi vi gmSudw( {} ulc od aehton) / T satadr-tr tegm. / o tr n esat h ae pbi vi gmSat){ ulc od aetr( / Cet anwtra / rae e hed Tra gmTra = nwTra( { hed aehed e hed) / Oerd rn)t poieternigbhvo o ti tra. / vrie u( o rvd h unn eair f hs hed @vrie Oerd pbi vi rn){ ulc od u( gmLo(; aeop) } } ; / Sattetra.sat)clsrn) wihi tr clsgmLo(. / tr h hed tr( al u(, hc n un al aeop) gmTra.tr(; aehedsat) } / Rntegm lo hr. / u h ae op ee piaevi gmLo( { rvt od aeop) / Rgnrt adrsttegm ojcsfranwgm / eeeae n ee h ae bet o e ae i (tt = SaeIIILZD| sae= SaeGMOE){ f sae = tt.NTAIE | tt = tt.AEVR / Gnrt anwsaeadafo ie / eeae e nk n od tm saergnrt(; nk.eeeae) itx y n , ; d { o fo.eeeae) odrgnrt(; x=fo.eX) odgt(; y=fo.eY) odgt(; }wie(nk.otisx y) / rgnrt i fo pae udrtesae hl saecnan(, ); / eeeae f od lcd ne h nk sae=SaePAIG tt tt.LYN; } / Gm lo / ae op ln bgnie tmTkn tmLf; og eiTm, ieae, ieet wie(re { hl tu)
3.n .ed . g/home/ehch a/p og amming/ja a/J8d_Game_F ame o k.h ml 18/24

4/30/12

Game Engine & F ame o k in Ja a

bgnie=Sse.aoie) eiTm ytmnnTm(; i (tt = SaeGMOE)bek / bektelo t fns tecretpa f sae = tt.AEVR ra; / ra h op o iih h urn ly i (tt = SaePAIG { f sae = tt.LYN) / Udt tesaeadpsto o altegm ojcs / pae h tt n oiin f l h ae bet, / dtc cliin adpoiersoss / eet olsos n rvd epne. gmUdt(; aepae) } / Rfehtedsly / ers h ipa rpit) ean(; / Dlytmrt poietencsaydlyt me tetre rt / ea ie o rvd h eesr ea o et h agt ae tmTkn=Sse.aoie)-bgnie ieae ytmnnTm( eiTm; tmLf =(PAEPRO -tmTkn /1000 / i mlieod ieet UDT_EID ieae) 000; / n ilscns i (ieet<1)tmLf =1; / stamnmm f tmLf 0 ieet 0 / e iiu ty{ r / Poie tencsaydlyadas yed cnrls ta ohrtra cnd wr. / rvds h eesr ea n lo ils oto o ht te hed a o ok Tra.le(ieet; hedseptmLf) }cth(nerpeEcpine){} ac Itrutdxeto x } } / Udt tesaeadpsto o altegm ojcs / pae h tt n oiin f l h ae bet, / dtc cliin adpoiersoss / eet olsos n rvd epne. pbi vi gmUdt( { ulc od aepae) saeudt(; nk.pae) poesolso(; rcsCliin) } / Cliindtcinadrsos / olso eeto n epne pbi vi poesolso( { ulc od rcsCliin) / ceki ti saeet tefo ie / hc f hs nk as h od tm ithaX=saegted(; n ed nk.eHaX) ithaY=saegted(; n ed nk.eHaY) i (ed = fo.eX)& haY= fo.eY) { f haX = odgt( & ed = odgt() / fo etn rgnrt oe / od ae, eeeae n itx y n , ; d { o fo.eeeae) odrgnrt(; x=fo.eX) odgt(; y=fo.eY) odgt(; }wie(nk.otisx y) hl saecnan(, ); }es { le / ntetn srn teti / o ae, hik h al saesrn(; nk.hik) } / Ceki tesaemvsoto bud / hc f h nk oe u f ons i (ptcnan(ed,haY){ f !i.otishaX ed) sae=SaeGMOE; tt tt.AEVR rtr; eun } / Ceki tesaeet isl / hc f h nk as tef i (nk.otishaX haY){ f saecnan(ed, ed) sae=SaeGMOE; tt tt.AEVR rtr; eun } } / Rfehtedsly Cle bc varpit) wihivk tepitopnn(. / ers h ipa. ald ak i aan(, hc noe h anCmoet) piaevi gmDa(rpisg { rvt od aerwGahc ) sic (tt){ wth sae cs PAIG ae LYN: / da gm ojcs / rw ae bet saeda() nk.rwg; fo.rwg; odda() / gm if / ae no gstotnwFn(Dao" Fn.LI,1); .eFn(e ot"ilg, otPAN 4)
3.n .ed . g/home/ehch a/p og amming/ja a/J8d_Game_F ame o k.h ml 19/24

4/30/12

Game Engine & F ame o k in Ja a

gstoo(oo.LC) .eClrClrBAK; gdaSrn(Sae ( +saegted( +""+saegted( +"" 5 2) .rwtig"nk: " nk.eHaX) , nk.eHaY) ), , 5; bek ra; cs GMOE: ae AEVR gstotnwFn(Vraa,Fn.OD 3); .eFn(e ot"edn" otBL, 0) gstoo(oo.E) .eClrClrRD; gdaSrn(GM OE!,20 CNA_EGT/2; .rwtig"AE VR" 0, AVSHIH ) bek ra; } } / Poesakypesdeet Udt tecretsae / rcs e-rse vn. pae h urn tt. pbi vi gmKyrse(n kyoe { ulc od aeePesdit eCd) sic (eCd){ wth kyoe cs Kyvn.KU: ae eEetV_P saestieto(nk.ieto.P; nk.eDrcinSaeDrcinU) bek ra; cs Kyvn.KDW: ae eEetV_ON saestieto(nk.ieto.ON; nk.eDrcinSaeDrcinDW) bek ra; cs Kyvn.KLF: ae eEetV_ET saestieto(nk.ieto.ET; nk.eDrcinSaeDrcinLF) bek ra; cs Kyvn.KRGT ae eEetV_IH: saestieto(nk.ieto.IH) nk.eDrcinSaeDrcinRGT; bek ra; } } / Cso daigpnl witna a inrcas / utm rwn ae, rte s n ne ls. casGmCna etnsJae ipeet Kyitnr{ ls aeavs xed Pnl mlmns eLsee / Cntutr / osrco pbi GmCna( { ulc aeavs) stoual(re; / s ta cnrciekyeet eFcsbetu) / o ht a eev e-vns rqetou(; eusFcs) adeLsee(hs; dKyitnrti) } / Oerd pitopnn t d cso daig / vrie anCmoet o o utm rwn. / Cle bc b rpit) / ald ak y ean(. @vrie Oerd pbi vi pitopnn(rpisg { ulc od anCmoetGahc ) sprpitopnn() ue.anCmoetg; / pitbcgon / an akrud stakrudCLRPT; / myuea iaefrbcgon eBcgon(OO_I) / a s n mg o akrud / Da tegm ojcs / rw h ae bet gmDa() aerwg; } / Kyvn hnlr / eEet ades @vrie Oerd pbi vi kyrse(eEete { ulc od ePesdKyvn ) gmKyrse(.eKyoe); aeePesdegteCd() } @vrie Oerd pbi vi kyeesdKyvn e {} ulc od eRlae(eEet ) @vrie Oerd pbi vi kyye(eEete {} ulc od eTpdKyvn ) / Ceki ti ptcnan tegvn(,y,frcliindtcin / hc f hs i otis h ie x ) o olso eeto pbi boencnan(n x ity { ulc ola otisit , n ) i (x<0 | ( =RW) { f ( ) | x OS) rtr fle eun as; } i (y<0 | ( =CLMS){ f ( ) | y OUN) rtr fle eun as;
3.n .ed . g/home/ehch a/p og amming/ja a/J8d_Game_F ame o k.h ml 20/24

4/30/12

Game Engine & F ame o k in Ja a

} rtr tu; eun re } } / mi / an pbi sai vi mi(tig]ag){ ulc ttc od anSrn[ rs / Ueteeetdsac tra t bidteU frtra-aey / s h vn ipth hed o ul h I o hedsft. Sigtlte.noeae(e Rnal( { wnUiiisivkLtrnw unbe) @vrie Oerd pbi vi rn){ ulc od u( nwGmMi(; e aean) } }; ) } }

An instance of G m C n a called p tis used. A method c n a n ( , y is added in the G m C n a for collision aeavs i otisx ) aeavs detection. [PENDING]

Collision Detection & Response


The hardest thing to decide is where (which class) to place the collision detection and responses codes. Should they be separated? How to add in these codes and yet the actors are still well encapsulated? If other words, one actor should not know the existence of the other actors. I recommend that: Separate the detection and response codes. The game loop shall carry out these steps: All sprites move to the next position (i.e., move one step). Check for collision in these new positions, and update the state of the sprites. Based on the new state, perform collision response. Repeat the loop. For simple game, you may combine detection (in step 2) and response (in step 3) together. But take note that all the actors should move into the next position before carry out the collision detection. The collision detection and responses code should be kept in the main game class, instead of within the actor. To support this, the main class must be able to retrieve certain information from the actor. Hence, it is proposed that each of the actor should have the following methods. The main class can use these methods of the two sprites to detect collision between them. (What to return? Shape and Rectangle2D?)
pbi boenitret(hp sae {... } / itret wt tegvnsae ulc ola nescsSae hp) ... / nescs ih h ie hp pbi boencnan(hp sae {... } ulc ola otisSae hp) ... / cmltl ecoe tegvnsae / opeey nlss h ie hp pbi SaegtonsD){... } ulc hp eBud2( ... / rtrsabudn bx / eun onig o frec pi o atr,atr.hcCliinatr) o ah ar f cos co1cekolso(co2. frec atr rsosUoCliin) o ah co, epnepnolso(.

Actor shall maintain its own state, via an associated enumeration called S a e tt. [TODO] Shall I move, check collision, and unmove if not collided; or check move, move (no unmove)?

Snake Game - Part II


Let zest up the snake game by adding a control panel, score board, and sound effects.

Control Panel

3.n .ed . g/home/ehch a/p og amming/ja a/J8d_Game_F ame o k.h ml

21/24

4/30/12

Game Engine & F ame o k in Ja a

pbi casGmMi etnsJrm { ulc ls aean xed Fae ... ... ... ... / Hnl frtecso daigpnladU cmoet. / ade o h utm rwn ae n I opnns piaeGmCna pt rvt aeavs i; piaeCnrlae cnrl rvt otoPnl oto; piaeJae llcr; rvt Lbl bSoe / Cntutrt iiilz teU cmoet adgm ojcs / osrco o ntaie h I opnns n ae bet pbi GmMi( { ulc aean) / Iiilz tegm ojcs / ntaie h ae bet gmIi(; aent) / U cmoet / I opnns Cnanrc =ti.eCnetae) otie p hsgtotnPn(; c.eLyu(e BreLyu() pstaotnw odraot); pt=nwGmCna(; i e aeavs) / daigpnl / rwn ae ptstrfreSz(e DmninCNA_IT,CNA_EGT) i.ePeerdienw ieso(AVSWDH AVSHIH); c.d(i) padpt; c.d(i,BreLyu.ETR; padpt odraotCNE) cnrl=nwCnrlae(; / cnrlpnl oto e otoPnl) / oto ae c.d(oto,BreLyu.OT) padcnrl odraotSUH; ti.eDfutlsOeainEI_NCOE; hsstealCoeprto(XTO_LS) ti.ak) hspc(; ti.eTte"NK GM"; hsstil(SAE AE) ti.eVsbetu) hsstiil(re; } / Gm CnrlPnlwt Sat So,PueadMt btos dsge a a inrcas / ae oto ae ih tr, tp as n ue utn, eind s n ne ls. casCnrlae etnsJae { ls otoPnl xed Pnl piaeJutnbntrPue rvt Bto tSatas; piaeJutnbntp rvt Bto tSo; piaeJutnbnue rvt Bto tMt; piaeIaecnioSat=nwIaecngtls(.eRsuc(mdapabc-tr.n","TR"; rvt mgIo cntr e mgIo(eCas)gteore"ei-lyaksatpg) SAT) piaeIaecnioPue=nwIaecngtls(.eRsuc(mdapabc-as.n","AS"; rvt mgIo cnas e mgIo(eCas)gteore"ei-lyakpuepg) PUE) piaeIaecnioSo =nwIaecngtls(.eRsuc(mdapabc-tppg) "TP) rvt mgIo cntp e mgIo(eCas)gteore"ei-lyakso.n", SO"; piaeIaecnioSud=nwIaecngtls(.eRsuc(adovlm-ihpg) "ON O"; rvt mgIo cnon e mgIo(eCas)gteore"ui-ouehg.n", SUD N) piaeIaecnioMtd=nwIaecngtls(.eRsuc(adovlm-ue.n","UE"; rvt mgIo cnue e mgIo(eCas)gteore"ui-ouemtdpg) MTD) pbi Cnrlae( { ulc otoPnl) ti.eLyu(e FoLyu(lwaotCNE,1,1); hsstaotnw lwaotFoLyu.ETR 0 0) bntrPue=nwJutnioSat; tSatas e Bto(cntr) bntrPuestnbe(re; tSatas.eEaldtu) adbntrPue; d(tSatas) bntp=nwJutnioSo) tSo e Bto(cntp; bntpstnbe(as) tSo.eEaldfle; adbntp; d(tSo) bnue=nwJutnioMtd; tMt e Bto(cnue) bnuestnbe(re; tMt.eEaldtu) adbnue; d(tMt) llcr =nwJae( bSoe e Lbl" Soe "+soe; cr: cr) adllcr) d(bSoe; bntrPueadcinitnrnwAtoLsee( { tSatas.dAtoLsee(e cinitnr) pbi vi atoPromdAtoEete { ulc od cinefre(cinvn ) sic (tt){ wth sae cs IIILZD ae NTAIE: cs GMOE: ae AEVR bntrPuestcnioPue; tSatas.eIo(cnas) gmSat) aetr(; bek ra; cs PAIG ae LYN: sae=SaePUE; tt tt.ASD bntrPuestcnioSat; tSatas.eIo(cntr)
3.n .ed . g/home/ehch a/p og amming/ja a/J8d_Game_F ame o k.h ml 22/24

4/30/12

Game Engine & F ame o k in Ja a

bek ra; cs PUE: ae ASD sae=SaePAIG tt tt.LYN; bntrPuestcnioPue; tSatas.eIo(cnas) bek ra; } bntpstnbe(re; tSo.eEaldtu) ptrqetou(; i.eusFcs) } }; ) bntpadcinitnrnwAtoLsee( { tSo.dAtoLsee(e cinitnr) pbi vi atoPromdAtoEete { ulc od cinefre(cinvn ) sae=SaeGMOE; tt tt.AEVR bntrPuestcnioSat; tSatas.eIo(cntr) bntrPuestnbe(re; tSatas.eEaldtu) bntpstnbe(as) tSo.eEaldfle; } }; ) bnueadcinitnrnwAtoLsee( { tMt.dAtoLsee(e cinitnr) pbi vi atoPromdAtoEete { ulc od cinefre(cinvn ) i (onEfc.oue= SudfetVlm.UE { f Sudfetvlm = onEfc.oueMT) Sudfetvlm =SudfetVlm.O; onEfc.oue onEfc.oueLW bnuestcnioSud; tMt.eIo(cnon) ptrqetou(; i.eusFcs) }es { le Sudfetvlm =SudfetVlm.UE onEfc.oue onEfc.oueMT; bnuestcnioMtd; tMt.eIo(cnue) ptrqetou(; i.eusFcs) } } }; ) } / Rstcnrlfranwgm / ee oto o e ae pbi vi rst){ ulc od ee( bntrPuestcnioSat; tSatas.eIo(cntr) bntrPuestnbe(re; tSatas.eEaldtu) bntpstnbe(as) tSo.eEaldfle; } } }

The control panel is derived from J a e and is designed as an inner class, just like the drawing panel. Pnl There are four J u t n inside the panel. Instead of text-label buttons, image-icons are used. The icons are Bto downloaded from the open-source "Tango desktop project @ http://tango.freedesktop.org". For the "mute" button, two image-icons are required (mute and volume-on). You need to enable/disable the button accordingly, and transfer the focus to the drawing panel, after a button is pushed.

Pla ing Sound Effect


Include the S u d f e t enum, descried in the earlier chapter. Define the names of the sound effects and their onEfc associated wave file. You can then play the sound effect in the game logic.
pbi eu Sudfet{ ulc nm onEfc DE"i.a", I(dewv) / gm oe / ae vr ET"afo.a";/ eta fo ie A(etodwv) / a n od tm ... ... ... ... }

Tw o Snakes
3.n .ed . g/home/ehch a/p og amming/ja a/J8d_Game_F ame o k.h ml 23/24

4/30/12

Game Engine & F ame o k in Ja a

Try: Each snake shall maintain its own set of keys for UP, DOWN, LEFT and RIGHT turn, and other attributes such as color. The snake cannot climb over another. If one snake's movement is blocked by another, it halts, until its direction is changed via a proper key input. Each snake has a "heart" (3rd cells from its head). It will be killed if it is hit at its heart.

REFERENCES & RESOURCES


Source codes of the "Sun Java Wireless Toolkit (WTK) 2.5 Demo: Worm Game". Jonathan S. Harbour, "Beginning Java 5 Game Programming": Good introductory book with sufficient technical details to get you started. Nice coverage on 2D vector graphics and bitmap including sprite animation. Easy to read and can be finished in a few days. However, the games are written in applet. No coverage of 3D technologies such as JOGL, JOAL and Java 3D. Also does not take full advantage of Java 5, in particular enumeration for keeping game and sprite states. No coverage on full-screen API, and performance for advanced game. Dustin Clingman, Shawn Kendall and Syrus Mesdaghi, "Practical Java Game Programming": filled with more advanced technical details. Topics such as IO operations and performance are applicable even for non-gaming applications. Much harder to read. Cover 2D and 3D (JOGL, JOAL, Java 3D).

Latest version tested: JDK 1.6 Last modified: September 4, 2008


Feedback, comments, corrections, and errata can be sent to Chua Hock-Chuan (ehchua@ntu.edu.sg) HOME

3.n .ed . g/home/ehch a/p og amming/ja a/J8d_Game_F ame o k.h ml

24/24