JavaScript v praxi: Sokoban (5. přednáška)
Sokoban... Cíl Přesunout krabice tak, aby každá krabice byla na žlutém poli. Pravidla 1. Panáček se může pohybovat nahoru, dolů, doprava, doleva 2. Panáček může posunout krabicí ve směru pohybu, pokud je v tomto směru za krabicí volné místo.
Sokoban: Návrh Budeme potřebovat: Objekt reprezentující mapu Objekt reprezentující stav hry (hru) Funkci, která vykreslí mapu/aktuální stav Funkci, která bude upravovat stav v závislosti na uživatelském vstupu
Mapa 1 var level = { 2 0:[ W, W, W, W, W, W, W, W, W, W, 0 ], 3 1:[ W, 0, 0, X, X, X, X, 0, 0, W, 0 ], 4 2:[ W, 0, B, X, B,X, X, B,X, 0, 0, W, W ], 5 3:[ W, W, B, W, W, W, W, W, 0, 0, W ], 6 4:[ W, 0, 0, 0, 0, B, 0, 0, 0, 0, W ], 7 5:[ W, 0, 0, B, 0, B, 0, B, 0, S, W ], 8 6:[ W, 0, 0, W, W, W, W, W, W, W, W ], 9 7:[ W, W, W, W, 0, 0, 0, 0, 0, 0, O ], 10 } W stěna, 0 nic, X žluté políčko, B krabice, S panáček
Stav Hry Budeme chtít: uměl načíst mapu uměl vykreslit mapu 1 function game () { 2 this. loadmap = function ( mapa ) {... }; 3 this. drawplan = function ( htmlelement ) {... }; 4 this. moveleft = function () {... }; 5 this. moveright = function () {... }; 6 this. moveup = function () {... }; 7 this. movedown = function () {... }; 8 }
Kreslení Idea Zvolíme si nějaký div element (herní plán) do kterého budeme kreslit Každé prvek na mapě (krabice, stěna,...) bude odpovídat nějakému div elementu, který bude potomkem herního plánu. Umístění na plán zajistíme pomocí position:absolute; a css-vlastností top, left. O grafiku se bude starat css. <div id= HerniPlan style= position:relative; > <div class= stena style= position:absolute;top:0px; left:0px;width=10px;height=10px ></div> <div class= stena style= position:absolute;top:0px; left:10px;width=10px;height=10px ></div> <div class= stena style= position:absolute;top:10px; left:0px;width=10px;height=10px ></div> <div class= krabice style= position:absolute;top:10px; left:10px;width=10px;height=10px ></div> </div>
Intermezzo: Scripting the DOM Jak se v JavaScriptu pracuje s html prvky stránky (objekt document) getelementbyid( id ) getelementsbyclassname( css_class ) createelement( tagname ) Html prvky (které získáme pomocí předcházejích funkcí) jsou také objekty, mají různé vlastnosti (a metody): appendchild( element ) removechild( element ) children innerhtml id, classname, style onclick,...
Stav Hry: herní prvky stav si budeme udržovat jako seznam jednotlivých prvků (divů) na herním plánu u každého prvku si budeme pamatovat jeho pozici a jeho typ (W,0,X,B,S) 1 function prvek ( typ ) = { 2 this. typ = typ ; 3 this. div = document. createelement (" div "); 4 this. div. style. width =10+ px ; 5 this. div. style. height =10+ px ; 6 this. setxy = function (x, y) { 7 this.x = x; this.y = y; 8 this. style. top = this.y *10+ px ; 9 this. style. left = this.x *10+ px ; 10 } 11 this. placeonboard = function ( element ) { 12 element. appendchild ( this. div ); }; 13 this. removefromboard = function ( element ) { 14 element. removechild ( this. div ) ;}; 15 }
Stav Hry: načtení mapy 1 this. loadmap = function ( map ) { 2 this. herniprvky = []; 3 this. height = 0; 4 this. length = len ( map [0]) ; 5 this. panacek = null ; 6 for ( y in map ) { 7 this. height ++; 8 for (x in map [y] ) { 9 prvky = map [y][x]. split (, ); 10 for ( i in prvky ) { 11 var p = new prvek ( prvky [ i] ); 12 p. setxy ( parseint (x), parseint (y)); 13 this. herniprvky. push (p); 14 if ( prvky [i] == S ) { 15 this. panacek = p; 16 } 17 } 18 } 19 } 20 }
Stav Hry: kreslení 1 this. drawplan = function ( herniplan_ div ) { 2 for ( i in this. herniprvky ) { 3 this. herniprvky [i]. placeonboard ( herniplan_div ); 4 } 5 }
Stav Hry: moveleft 1 this. moveleft = function () { 2 // Nesmime vylezt z mapy 3 if ( this. panacek. x == 0) return false ; 4 var sousedi = this. prvkyatxy ( this. panacek.x -1, 5 this. panacek.y); 6 // Nesmime projit zdi 7 if ( this. contains ( sousedi, W ) ) return false ; 8 9 // Krabici muzeme posunout pouze, pokud je misto 10 if ( this. contains ( sousedi, B ) ) { 11 // Ani krabici nesmime vysunout z mapy 12 if ( this. panacek. x == 1 ) return false ; 13 ns= this. prvkyatxy ( this. panacek.x -2, this. panacek.y) 14 if ( this. contains (ns, W ) 15 this. contains (ns, B )) return false ; 16 krabice = this. gettype ( sousedi, B ); 17 krabice. setxy ( this. panacek.x -2, this. panacek.y); 18 } 19 // Posuneme panacka 20 this. panacek. setxy ( this. panacek.x -1, this. panacek.y); 21 }
Sta Hry: co chybí? funkce contains(list, typ) která vrátí true, pokud seznam list herních prvků obsahuje prvek typu typ funkce gettype(list,typ) herní prvek typu typ která vrátí ze seznamu list funkce, která si pamatuje, kolik tahů už bylo provedeno (skóre) funkce, která si udržuje přehled o tom, kolik krabic ještě chybí přesunout
Interakce s uživatelem vlastnosti jednotlivých prvků (onclick, onblur, onfocus,...) vlastnosti objektu document (onkeypress, onkeydown, onkeyup) metody objektu window (settimeout( "javascript code", msec ), setinterval, clearinterval)
Stav Hry: ošetření uživatelského vstupu 1 this. keyuphandler = function () { 2 var me = this ; 3 return function ( e ) { 4 if ( me. keysenabled ) return false ; 5 e = window. event e; 6 switch (e. keycode ) { 7 case 37: 8 me. moveleft (); break ; 9 case 38: 10 me. moveup (); break ; 11 case 39: 12 me. moveright (); break ; 13 case 40: 14 me. movedown (); break ; 15 default : 16 return true ; 17 } 18 return false ; 19 } 20 }
Dáme to dohromady 1 function startgame () { 2 var level = {... }; 3 var g = new game (); 4 g. loadmap ( level ); 5 herniplandiv = document. getelementbyid ( HerniPlan ); 6 g. drawplan ( herniplandiv ); 7 window. onkeyup = g. keyuphandler (); 8 } 9 10 window. onload = startgame ;