Spieleentwicklung mit JavaScript - PlayFieldControl-Klasse
(Unterschied zwischen Versionen)
(Die Seite wurde neu angelegt: „= PlayFieldControl-Klasse = Der nächste naheliegende Schritt besteht darin, das EventHandling in eine Klasse zu packen, die für die Steuerung des Spielfelds zus…“) |
(→PlayFieldControl-Klasse) |
||
(Der Versionsvergleich bezieht 3 dazwischenliegende Versionen mit ein.) | |||
Zeile 1: | Zeile 1: | ||
= PlayFieldControl-Klasse = | = PlayFieldControl-Klasse = | ||
+ | |||
Der nächste naheliegende Schritt besteht darin, das EventHandling in eine Klasse zu packen, die für die Steuerung des Spielfelds zuständig ist. Vorerst soll es genügen, die Karte mit der Maus verschieben zu können. | Der nächste naheliegende Schritt besteht darin, das EventHandling in eine Klasse zu packen, die für die Steuerung des Spielfelds zuständig ist. Vorerst soll es genügen, die Karte mit der Maus verschieben zu können. | ||
Zeile 6: | Zeile 7: | ||
Beispiel: | Beispiel: | ||
<pre> | <pre> | ||
- | var div = document.getElementById( | + | function EventHandler( div_id ) |
- | div.addEventListener('mousedown', OnMouseDown, false); | + | { |
+ | var div = document.getElementById( div_id ); | ||
+ | div.addEventListener( 'mousedown', this.OnMouseDown, false ); | ||
+ | } | ||
- | + | EventHandler.prototype.OnMouseDown = function( e ) | |
{ | { | ||
alert( this ); | alert( this ); | ||
} | } | ||
+ | |||
+ | var eh; | ||
+ | function init() | ||
+ | { | ||
+ | //... | ||
+ | eh = new EventHandler( "board_div" ); | ||
+ | //... | ||
+ | } | ||
+ | </pre> | ||
+ | Bei einem Klick erscheint diese Messagebox: | ||
+ | |||
+ | [[Datei:Eventalert.png]] | ||
+ | |||
+ | Das heißt, über this kann auf die Elemente des HTMLDivElements zugegriffen werden, für das der EventHandler installiert wurde, aber nicht auf das Objekt, dessen Methoden aufgerufen werden. | ||
+ | |||
+ | Wie erhält man in der Eventhandler-Methode nun Zugriff auf das Objekt? | ||
+ | |||
+ | Mit einem Trick! In einer statischen Variable kann man eine Referenz auf eine Instanz der Eventhandler-Klasse ableben und dann in der Eventhandler-Funktion darauf zugreifen. Der Haken dabei ist, dass es insgesamt nur eine Instanz gleichzeitig geben kann. Das sollte für unsere Zwecke aber ausreichend sein. | ||
+ | |||
+ | Der Eventhandler wird also wie folgt erweitert: | ||
+ | <pre> | ||
+ | function EventHandler( div_id ) | ||
+ | { | ||
+ | EventHandler.instance = this; | ||
+ | this.info = "That's it!"; | ||
+ | var div = document.getElementById( div_id ); | ||
+ | div.addEventListener( 'mousedown', this.OnMouseDown, false ); | ||
+ | } | ||
+ | |||
+ | EventHandler.prototype.OnMouseDown = function( e ) | ||
+ | { | ||
+ | var me = EventHandler.instance; | ||
+ | alert( me.info ); | ||
+ | } | ||
+ | |||
+ | var eh; | ||
+ | function init() | ||
+ | { | ||
+ | //... | ||
+ | eh = new EventHandler( "board_div" ); | ||
+ | //... | ||
+ | } | ||
+ | </pre> | ||
+ | Und siehe da: | ||
+ | |||
+ | [[Datei:Thatsitalert.png]] | ||
+ | |||
+ | Mit diesem hart erarbeiteten know how kann nun die PlayFieldControl-Klasse implementiert werden. Die Klasse sollte in eine Datei namens PlayFieldControl.js ausgelagert werden. | ||
+ | |||
+ | <pre> | ||
+ | function PlayFieldControl( div_id, pf, button ) | ||
+ | { | ||
+ | this.pf = pf; | ||
+ | this.dragx = -1; | ||
+ | this.dragy = -1; | ||
+ | this.button = button; | ||
+ | PlayFieldControl.instance = this; | ||
+ | |||
+ | var div = document.getElementById( div_id ); | ||
+ | div.addEventListener('mousedown', this.OnMouseDown, false); | ||
+ | div.addEventListener('mousemove', this.OnMouseMove, false); | ||
+ | div.addEventListener('mouseup', this.OnMouseUp, false); | ||
+ | } | ||
+ | |||
+ | PlayFieldControl.prototype.OnMouseDown = function( e, fromMove ) | ||
+ | { | ||
+ | var me = PlayFieldControl.instance; | ||
+ | if( (e.which == me.button || fromMove) ) | ||
+ | { | ||
+ | me.dragx = e.pageX; | ||
+ | me.dragy = e.pageY; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | PlayFieldControl.prototype.OnMouseMove = function ( e ) | ||
+ | { | ||
+ | var me = PlayFieldControl.instance; | ||
+ | if( me.dragx > 0 && me.dragy > 0 ) | ||
+ | { | ||
+ | me.OnMouseUp( e, true ); | ||
+ | me.OnMouseDown( e, true ); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | PlayFieldControl.prototype.OnMouseUp = function( e, fromMove ) | ||
+ | { | ||
+ | var me = PlayFieldControl.instance; | ||
+ | if( (e.which == me.button || fromMove) && me.dragx > 0 && me.dragy > 0 ) | ||
+ | { | ||
+ | me.pf.move( me.dragx - e.pageX, me.dragy - e.pageY ); | ||
+ | me.dragx = -1; | ||
+ | me.dragy = -1; | ||
+ | } | ||
+ | } | ||
+ | </pre> | ||
+ | |||
+ | Dank dieser beiden Klassen schrumpft der Code des Programms auf ein paar Programmzeilen: | ||
+ | <pre> | ||
+ | <html> | ||
+ | <head> | ||
+ | <meta http-equiv="content-type" content="text/html;charset=UTF-8"> | ||
+ | <title>Sample</title> | ||
+ | <style type="text/css"> | ||
+ | body | ||
+ | { | ||
+ | margin: 0px; | ||
+ | padding: 0px; | ||
+ | } | ||
+ | .hidden | ||
+ | { | ||
+ | visibility: hidden; | ||
+ | } | ||
+ | .frame | ||
+ | { | ||
+ | border:1px black solid; | ||
+ | } | ||
+ | .board | ||
+ | { | ||
+ | position: absolute; | ||
+ | left: 10px; | ||
+ | top: 10px; | ||
+ | } | ||
+ | .debug | ||
+ | { | ||
+ | position: absolute; | ||
+ | left: 10px; | ||
+ | top: 400px; | ||
+ | } | ||
+ | </style> | ||
+ | <script type="text/javascript" src="PlayField.js"></script> | ||
+ | <script type="text/javascript" src="PlayFieldControl.js"></script> | ||
+ | <script type="text/javascript"> | ||
+ | var level = new Array( | ||
+ | //... Level Daten ... | ||
+ | ); | ||
+ | |||
+ | var pf; | ||
+ | var pfctrl; | ||
+ | |||
+ | function init() | ||
+ | { | ||
+ | pf = new PlayField( "board", "tileset", 5, 1, level ); | ||
+ | pf.moveTo( 0, 0 ); | ||
+ | |||
+ | pfctrl = new PlayFieldControl( "board_div", pf, 1 ); | ||
+ | } | ||
+ | </script> | ||
+ | </head> | ||
+ | <body onLoad="init();"> | ||
+ | <div class="board frame" id="board_div"> | ||
+ | <canvas id="board" width="460" height="340">Dieser Browser ist nicht geeignet.</canvas> | ||
+ | </div> | ||
+ | <img id="tileset" src="img/tileset.png" class="hidden"> | ||
+ | <canvas id="tile0" class="hidden" width="30" height="30"></canvas> | ||
+ | <canvas id="tile1" class="hidden" width="30" height="30"></canvas> | ||
+ | <canvas id="tile2" class="hidden" width="30" height="30"></canvas> | ||
+ | <canvas id="tile3" class="hidden" width="30" height="30"></canvas> | ||
+ | <canvas id="tile4" class="hidden" width="30" height="30"></canvas> | ||
+ | <form name="f" class="debug"> | ||
+ | <textarea name="t" cols=80 rows=10></textarea> | ||
+ | </form> | ||
+ | </body> | ||
+ | </html> | ||
</pre> | </pre> |
Aktuelle Version vom 14:01, 3. Sep. 2010
PlayFieldControl-Klasse
Der nächste naheliegende Schritt besteht darin, das EventHandling in eine Klasse zu packen, die für die Steuerung des Spielfelds zuständig ist. Vorerst soll es genügen, die Karte mit der Maus verschieben zu können.
Hier ergibt sich allerdings ein Problem: Da die Methode addEventListener eine Funktion erwartet, geht der Context zum Objekt, dessen Methoden aufgerufen werden sollen verloren. Die Handlerfunktionen werden zwar aufgerufen, aber über this wird nicht auf den Inhalt des EventHandler-Objekts zugegriffen, sondern auf die Inhalte desjenigen DOM-Objekts, an die die EventHandler gebunden sind.
Beispiel:
function EventHandler( div_id ) { var div = document.getElementById( div_id ); div.addEventListener( 'mousedown', this.OnMouseDown, false ); } EventHandler.prototype.OnMouseDown = function( e ) { alert( this ); } var eh; function init() { //... eh = new EventHandler( "board_div" ); //... }
Bei einem Klick erscheint diese Messagebox:
Das heißt, über this kann auf die Elemente des HTMLDivElements zugegriffen werden, für das der EventHandler installiert wurde, aber nicht auf das Objekt, dessen Methoden aufgerufen werden.
Wie erhält man in der Eventhandler-Methode nun Zugriff auf das Objekt?
Mit einem Trick! In einer statischen Variable kann man eine Referenz auf eine Instanz der Eventhandler-Klasse ableben und dann in der Eventhandler-Funktion darauf zugreifen. Der Haken dabei ist, dass es insgesamt nur eine Instanz gleichzeitig geben kann. Das sollte für unsere Zwecke aber ausreichend sein.
Der Eventhandler wird also wie folgt erweitert:
function EventHandler( div_id ) { EventHandler.instance = this; this.info = "That's it!"; var div = document.getElementById( div_id ); div.addEventListener( 'mousedown', this.OnMouseDown, false ); } EventHandler.prototype.OnMouseDown = function( e ) { var me = EventHandler.instance; alert( me.info ); } var eh; function init() { //... eh = new EventHandler( "board_div" ); //... }
Und siehe da:
Mit diesem hart erarbeiteten know how kann nun die PlayFieldControl-Klasse implementiert werden. Die Klasse sollte in eine Datei namens PlayFieldControl.js ausgelagert werden.
function PlayFieldControl( div_id, pf, button ) { this.pf = pf; this.dragx = -1; this.dragy = -1; this.button = button; PlayFieldControl.instance = this; var div = document.getElementById( div_id ); div.addEventListener('mousedown', this.OnMouseDown, false); div.addEventListener('mousemove', this.OnMouseMove, false); div.addEventListener('mouseup', this.OnMouseUp, false); } PlayFieldControl.prototype.OnMouseDown = function( e, fromMove ) { var me = PlayFieldControl.instance; if( (e.which == me.button || fromMove) ) { me.dragx = e.pageX; me.dragy = e.pageY; } } PlayFieldControl.prototype.OnMouseMove = function ( e ) { var me = PlayFieldControl.instance; if( me.dragx > 0 && me.dragy > 0 ) { me.OnMouseUp( e, true ); me.OnMouseDown( e, true ); } } PlayFieldControl.prototype.OnMouseUp = function( e, fromMove ) { var me = PlayFieldControl.instance; if( (e.which == me.button || fromMove) && me.dragx > 0 && me.dragy > 0 ) { me.pf.move( me.dragx - e.pageX, me.dragy - e.pageY ); me.dragx = -1; me.dragy = -1; } }
Dank dieser beiden Klassen schrumpft der Code des Programms auf ein paar Programmzeilen:
<html> <head> <meta http-equiv="content-type" content="text/html;charset=UTF-8"> <title>Sample</title> <style type="text/css"> body { margin: 0px; padding: 0px; } .hidden { visibility: hidden; } .frame { border:1px black solid; } .board { position: absolute; left: 10px; top: 10px; } .debug { position: absolute; left: 10px; top: 400px; } </style> <script type="text/javascript" src="PlayField.js"></script> <script type="text/javascript" src="PlayFieldControl.js"></script> <script type="text/javascript"> var level = new Array( //... Level Daten ... ); var pf; var pfctrl; function init() { pf = new PlayField( "board", "tileset", 5, 1, level ); pf.moveTo( 0, 0 ); pfctrl = new PlayFieldControl( "board_div", pf, 1 ); } </script> </head> <body onLoad="init();"> <div class="board frame" id="board_div"> <canvas id="board" width="460" height="340">Dieser Browser ist nicht geeignet.</canvas> </div> <img id="tileset" src="img/tileset.png" class="hidden"> <canvas id="tile0" class="hidden" width="30" height="30"></canvas> <canvas id="tile1" class="hidden" width="30" height="30"></canvas> <canvas id="tile2" class="hidden" width="30" height="30"></canvas> <canvas id="tile3" class="hidden" width="30" height="30"></canvas> <canvas id="tile4" class="hidden" width="30" height="30"></canvas> <form name="f" class="debug"> <textarea name="t" cols=80 rows=10></textarea> </form> </body> </html>