Der Weg zum eigenen Browsergame - Die Karte
Den Bezug zur Spielwelt stellen viele Spieler ausschließlich über die Karte her. Es ist immer schön zu wissen wer der Nachbar ist, welches Dorf sich als nächstes zu erobern lohnt und wie groß die Bedrohung durch den umliegenden Feind ist.
Grundlagen
Eine Karte besteht aus einzelnen Feldern, die durch ein 2 Dimensionales Koordinatenpaar eindeutig identifiziert werden.
So beginnt die Karte oben links mit dem Koordinatenpaar x=0 und y=0, oder kürzer (0|0). Unten rechts befindet sich also das größte Koordinatenpaar mit (MAP_WIDTH | MAP_HEIGHT), wobei MAP_WIDTH und MAP_HEIGHT für die Ausmaße der Karte stehen.
Eine erste Karte
Um die gesamte Karte darzustellen, müssen wir also nur MAP_WIDTH x MAP_HEIGHT Felder von 0 bis MAP_WIDTH-1 für die Breite, bzw. von 0 bis MAP_HEIGHT-1 für die Höhe erzeugen. Je nach Feldgröße (in Pixeln) würde die Karte recht viel Platz beanspruchen.
Folgendes kleines Codebeispiel erzeugt eine sehr einfache 25x25 Felder große Karte. Jedes Feld ist 50x30 Pixel groß.
define(MAP_WIDTH, 25); define(MAP_HEIGHT, 25); echo '<div id="mymap">'; for($y=0; $y < MAP_HEIGHT; $y++) { for($x=0; $x < MAP_WIDTH; $x++) { echo '<div style="float: left; width: 49px; height: 29px; margin-right: 1px; margin-bottom: 1px; background-color: #cccccc; text-align: center;">('.$x.'|'.$y.')</div>'; }; echo '<div style="clear:both;"></div>'; }; echo '</div>';
Das Skript kann, so wie es ist, kopiert und direkt ausgeführt werden.
Viel kann man mit einer solchen Karte zwar noch nicht anstellen, es soll aber erst mal als kleiner Anreiz dienen uns ein wenig mehr mit der Materie zu beschäftigen. Da geht auf jeden Fall noch mehr.
Die Karten-Klasse
Zur besseren Wiederverwendbarkeit, bauen wir das obere Codebeispiel in eine Klasse ein.
class MyMap { private $map_width; // Kartenbreite private $map_height; // Kartenhöhe private $field_width_px; // Breite eines Feldes in Pixel private $field_height_px; // Höhe eines Feldes in Pixel public function setSize($width, $height) { $this->map_width = intval($width); $this->map_height = intval($height); } public function setFieldSize($width_px, $height_px) { $this->field_width_px = intval($width_px); $this->field_height_px = intval($height_px); } public function getHtml() { $code = '<div id="mymap">'; for($y=0; $y < $this->map_height; $y++) { for($x=0; $x < $this->map_width; $x++) { $code .= '<div style="float: left; width: '.($this->field_width_px-1).'px; height: '.($this->field_height_px-1).'px; margin-right: 1px; margin-bottom: 1px; background-color: #009933; text-align: center;">('.$x.'|'.$y.')</div>'; }; $code .= '<div style="clear:both;"></div>'; }; $code .= '</div>'; return $code; } public function show() { echo $this->getHtml(); } };
Das selbe Ergebnis wie oben erhalten wir jetzt durch folgenden Code.
$map = new MyMap(); $map->setSize(25, 25); $map->setFieldSize(50, 30); $map->show();
Die Kartenfelder
Ein fundamentaler Bestandteil einer Karte sind die Felder. Hierüber bezieht der Spieler die Informationen die er braucht um sich orientieren zu können.
So sollte eine Karte nicht nur aus einer Hintergrundfarbe und ein paar darauf befindlichen Objekten bestehen, sondern durch eine individuelle Optik Wiedererkennungswerte schaffen. Denn nur so finden sich die Spieler zurecht und müssen sich nicht, an einen Faden gebunden, durch das Felderlabyrinth tasten.
Mit den folgenden Routinen können wir der Karte Felder hinzufügen und ihr somit das besondere Flair verschaffen.
... private $fields; // Kartenfelder public function setFields($fields) { $this->fields = $fields; } public function setField($x, $y, $field) { if (($x < 0) || ($y < 0) || ($x >= $this->map_width) || ($y >= $this->map_height)) return false; $this->fields[$x][$y] = $field; } public function getField($x, $y) { if (@isset($this->fields[$x][$y])) return $this->fields[$x][$y]; else return false; } ...
Damit die Felder auch angezeigt werden müssen wir die Methode getHtml() anpassen.
... public function getHtml() { $code = '<div id="mymap">'; for($y=0; $y < $this->map_height; $y++) { for($x=0; $x < $this->map_width; $x++) { $field = $this->getField($x, $y); if ($field) { $color = $field['color']; $caption = $field['caption']; } else { $color = '#009933'; $caption = ''; }; $code .= '<div style="float: left; width: '.($this->field_width_px-1).'px; height: '.($this->field_height_px-1).'px; margin-right: 1px; margin-bottom: 1px; background-color: '.$color.'; text-align: center;" title=" '.$caption.' ">('.$x.'|'.$y.')</div>'; }; $code .= '<div style="clear:both;"></div>'; }; $code .= '</div>'; return $code; } ...
Mit den neuen Feldern ergibt sich folgender Code für die Darstellung der Karte.
$map = new MyMap(); $map->setSize(25, 25); $map->setFieldSize(50, 30); $map->setField(18, 12, array("color"=>'#006699', "caption"=>'Wasser') ); $map->setField(10, 10, array("color"=>'#CCCCCC', "caption"=>'Berge') ); $map->show();
Das Kartenfenster (Window)
Natürlich wollen wir nicht immer die gesamte Karte sehen. Das wäre im höchsten Maße unübersichtlich. Wir betrachten also nur einen kleineren Teil durch ein Fenster mit einer festen Größe. Dieses Fenster zeigt also, ausgehend von der Fensterposition, alle Felder an die innerhalb der Fenstermaße liegen.
Die Klasse ergänzen wir also um folgende Attribute und Methoden.
.. private $window_width; // Fensterbreite private $window_height; // Fensterhöhe private $window_topleft_x; // X-Koordinate oben/links private $window_topleft_y; // Y-Koordinate oben/links public function setWindowSize($width, $height) { $this->window_width = intval($width); $this->window_height = intval($height); } public function setWindowPosition($x, $y) { if ($x < 0) $x = 0; if ($y < 0) $y = 0; if ($x+$this->window_width > $this->map_width) $x = $this->map_width - $this->window_width; if ($y+$this->window_height > $this->map_height) $y = $this->map_height - $this->window_height; $this->window_topleft_x = intval($x); $this->window_topleft_y = intval($y); } public function getWindowHtml() { $code = '<div id="mymapwindow">'; $window_bottomright_x = ($this->window_topleft_x + ($this->window_width-1) ); $window_bottomright_y = ($this->window_topleft_y + ($this->window_height-1) ); for($y=$this->window_topleft_y; $y <= $window_bottomright_y; $y++) { for($x=$this->window_topleft_x; $x <= $window_bottomright_x; $x++) { $field = $this->getField($x, $y); if ($field) { $color = $field['color']; $caption = $field['caption']; } else { $color = '#009933'; $caption = ''; }; $code .= '<div style="float: left; width: '.($this->field_width_px-1).'px; height: '.($this->field_height_px-1).'px; margin-right: 1px; margin-bottom: 1px; background-color: '.$color.'; text-align: center;" title=" '.$caption.' ">('.$x.'|'.$y.')</div>'; }; $code .= '<div style="clear:both;"></div>'; }; $code .= '</div>'; return $code; } public function showWindow() { echo $this->getWindowHtml(); } ..
In der Methode setWindowPosition() setzen wir die Koordinaten (oben/links) an denen das Fenster beginnt. In der selben Methode werden zuvor die Koordinaten auf ihre Richtigkeit geprüft. Das Fenster muss immer innerhalb der Karte liegen, andernfalls würden nicht existierende Felder angezeigt werden. Die Ausgabe des Fensters erfolgt mit der Methode showWindow(). Sie ähnelt sehr der Methode show(), mit dem Unterschied, dass hier die Schleifen nicht von 0 bis MAP_WIDTH bzw. 0 bis MAP_HEIGHT laufen, sondern nur über einer Zwischenmenge. Also von WINDOW_TOPLEFT_X bis WINDOW_TOPRIGHT_X, bzw. von WINDOW_TOPLEFT_Y bis WINDOW_TOPRIGHT_Y.
Unser Code ändert sich also folgendermaßen.
$map = new MyMap(); $map->setSize(25, 25); $map->setFieldSize(50, 30); $map->setField(18, 12, array("color"=>'#006699', "caption"=>'Wasser') ); $map->setField(10, 10, array("color"=>'#CCCCCC', "caption"=>'Berge') ); $map->setWindowSize(9, 9); // Das Sichtfenster soll 9x9 Felder groß sein $map->setWindowPosition(3, 10); // Position oben/links des Fensters $map->showWindow(); // Ausgabe des Sichtfensters
Die aktuelle Position auf der Karte
Dörfer oder andere Objekte liegen ja bekanntermaßen auf einem Feld in der Karte. Möchte man sich das Umfeld eines solchen Objekts betrachten, sollte das Sichtfenster um diesen Punkt herum liegen. Fügen wir unserer Klasse also noch folgendes hinzu.
.. private $x; // X-Koordinate der aktuellen Position private $y; // Y-Koordinate der aktuellen Position public function setPosition($x, $y) { if ($x < 0) $x = 0; if ($y < 0) $y = 0; if ($x >= $this->map_width) $x = $this->map_width - 1; if ($y >= $this->map_height) $y = $this->map_height - 1; $this->x = $x; $this->y = $y; $this->setWindowPosition($x - round($this->window_width / 2), $y - round($this->window_height / 2)); } ..
Auch in dieser Methode werden die Koordinaten wieder auf ihre Richtigkeit geprüft und ggf. korrigiert. Eine Feld auszuwählen, dass außerhalb der Karte liegt, würde auch keinen Sinn machen.
Am Ende wird die setWindowPosition()-Methode aufgerufen. Da wir unsere aktuelle Position im Fenster zentriert haben möchten, übergeben wir hier die Positions-Koordinaten, abzüglich der halben Fenstergröße.
Mit den folgenden Zeilen lässt sich also das an einer bestimmten Position zentrierte Sichtfenster einer große Karte darstellen.
$map = new MyMap(); $map->setSize(25, 25); $map->setFieldSize(50, 30); $map->setField(18, 12, array("color"=>'#006699', "caption"=>'Wasser') ); $map->setField(10, 10, array("color"=>'#CCCCCC', "caption"=>'Berge') ); $map->setWindowSize(9, 9); // Das Sichtfenster soll 9x9 Felder groß sein $map->setPosition(16, 7); // Aktuelle Position (im Fenster zentriert) $map->showWindow(); // Ausgabe des Sichtfensters
Der Feinschliff
Wir haben jetzt eine rudimentäre Klasse mit viel potential. Allerdings fehlt es hier natürlich noch an so manchem.
Die Karte ist mit ihren zwei definierten Feldern auch noch etwas mager ausgestattet. Natürlich könnte man in diesem Falle bei einer 25x25 Karte alle Felder von Hand definieren, allerdings ist das bei größeren Karten kein Spaß mehr.
Eine einfache Möglichkeit, eine Zufallskarte zu erzeugen, ist folgende.
$map = new MyMap(); $map->setSize(25, 25); $map->setFieldSize(50, 30); $map->setWindowSize(9, 9); $map->setPosition(16, 7); function generateRandomMap($map_width, $map_height) { $fields = array(); $possible_field_types = array( 0=>array("color"=>'#009933', "caption"=>'Wiese'), 1=>array("color"=>'#006699', "caption"=>'Wasser'), 2=>array("color"=>'#CCCCCC', "caption"=>'Berge'), ); for($y=0; $y < $map_height; $y++) { for($x=0; $x < $map_width; $x++) { $fields[$x][$y] = $possible_field_types[rand(0, 2)]; }; }; file_put_contents('map-fields-data.php', '<'.'?php $map_fields = '.var_export($fields, true).' ?'.'>'); return $fields; }; if (!is_file('map-fields-data.php')) generateRandomMap(25, 25); include_once 'map-fields-data.php'; $map->setFields($map_fields); $map->showWindow();
Wenn die Datei map-fields-data.php nicht existiert, wird eine zufällige Karte generiert und in dieser Datei als gültiger PHP-Quellcode abgespeichert. Ist sie bereits vorhanden wird sie per include in das Skript eingebunden.
Die ganze Klasse MyMap
class MyMap { private $map_width; // Kartenbreite private $map_height; // Kartenhöhe private $field_width_px; // Breite eines Feldes in Pixel private $field_height_px; // Höhe eines Feldes in Pixel private $window_width; // Fensterbreite private $window_height; // Fensterhöhe private $window_topleft_x; // X-Koordinate oben/links private $window_topleft_y; // Y-Koordinate oben/links private $fields; // Kartenfelder private $x; // X-Koordinate der aktuellen Position private $y; // Y-Koordinate der aktuellen Position public function setFields($fields) { $this->fields = $fields; } public function setField($x, $y, $field) { if (($x < 0) || ($y < 0) || ($x >= $this->map_width) || ($y >= $this->map_height)) return false; $this->fields[$x][$y] = $field; } public function getField($x, $y) { if (@isset($this->fields[$x][$y])) return $this->fields[$x][$y]; else return false; } public function setSize($width, $height) { $this->map_width = intval($width); $this->map_height = intval($height); } public function setFieldSize($width_px, $height_px) { $this->field_width_px = intval($width_px); $this->field_height_px = intval($height_px); } public function setPosition($x, $y) { if ($x < 0) $x = 0; if ($y < 0) $y = 0; if ($x >= $this->map_width) $x = $this->map_width - 1; if ($y >= $this->map_height) $y = $this->map_height - 1; $this->x = $x; $this->y = $y; $this->setWindowPosition($x - ($this->window_width >> 1), $y - ($this->window_height >> 1)); } public function setWindowSize($width, $height) { $this->window_width = intval($width); $this->window_height = intval($height); } public function setWindowPosition($x, $y) { if ($x < 0) $x = 0; if ($y < 0) $y = 0; if ($x+$this->window_width > $this->map_width) $x = $this->map_width - $this->window_width; if ($y+$this->window_height > $this->map_height) $y = $this->map_height - $this->window_height; $this->window_topleft_x = intval($x); $this->window_topleft_y = intval($y); } public function getWindowHtml() { $code = '<div id="mymapwindow">'; $window_bottomright_x = ($this->window_topleft_x + ($this->window_width-1) ); $window_bottomright_y = ($this->window_topleft_y + ($this->window_height-1) ); for($y=$this->window_topleft_y; $y <= $window_bottomright_y; $y++) { for($x=$this->window_topleft_x; $x <= $window_bottomright_x; $x++) { $field = $this->getField($x, $y); if ($field) { $color = $field['color']; $caption = $field['caption']; } else { $color = '#009933'; $caption = ''; }; $code .= '<div style="float: left; width: '.($this->field_width_px-1).'px; height: '.($this->field_height_px-1).'px; margin-right: 1px; margin-bottom: 1px; background-color: '.$color.'; text-align: center;" title=" '.$caption.' ">('.$x.'|'.$y.')</div>'; }; $code .= '<div style="clear:both;"></div>'; }; $code .= '</div>'; return $code; } public function showWindow() { echo $this->getWindowHtml(); } public function getHtml() { $code = '<div id="mymap">'; for($y=0; $y < $this->map_height; $y++) { for($x=0; $x < $this->map_width; $x++) { $field = $this->getField($x, $y); if ($field) { $color = $field['color']; $caption = $field['caption']; } else { $color = '#009933'; $caption = ''; }; $code .= '<div style="float: left; width: '.($this->field_width_px-1).'px; height: '.($this->field_height_px-1).'px; margin-right: 1px; margin-bottom: 1px; background-color: '.$color.'; text-align: center;" title=" '.$caption.' ">('.$x.'|'.$y.')</div>'; }; $code .= '<div style="clear:both;"></div>'; }; $code .= '</div>'; return $code; } public function show() { echo $this->getHtml(); } };
Schlusswort
Wir haben also jetzt eine Klasse mit der man ganz ordentliche Karten erstellen kann.
Jetzt liegt es an jedem selbst sich diese Klasse so zurecht zu biegen wie er sie für sein Spiel braucht. Spielt ein wenig damit herum und versucht mal die Felder aus einer Datenbank zu laden. Das wäre dann auch der üblichere weg :)
Hier das Tutorial zum Thema Datenbank:
Free Aqua Zoo - Aquarium Simulation
![]()
Free Aqua Zoo - die Aquarium Simulation
Pflege und züchte deine eigenen Fische und richte dein Aquarium ein.
Weiterlesen...Goodgame Poker Browsergame
![]()
Das Poker Browsergame
Poker bzw. Texas Hold'em zocken im Browserspiel von Goodgame.
Weiterlesen...Grepolis
![]()
Gepolis - Browsergame im antiken Griechenland
Spiele im antike Griechenland und gründe deine Polis
Weiterlesen...Der Weg zum eigenen Browsergame - Ressourcenproduktion

Der Weg zum eigenen Browsergame
Thema: Ressourcenproduktion
Weiterlesen...Der Weg zum eigenen Browsergame - Die Karte

Der Weg zum eigenen Browsergame
Thema: Die Karte
Weiterlesen...








