PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Wie funktioniert eine Game_Map



Cornix
13.01.2010, 20:54
Guten Abend, die letzten Tage habe ich damit verbracht langsam zu verstehen wie all die vielen vorgefertigten Scripte des RMXP genau funktionieren. Dabei war ich soweit auch recht erfolgreich bis ich auf die Game_Map gestoßen bin.
In meinem Vorgehen zum Verständniss des ganzen versuche ich gerne das Script selbst nach zu schreiben, natürlich nicht 1 zu 1 übernommen.
Allerdings scheint die Game_Map eine besonders harte Nuss zu sein, zumindest für mich. Viele mir vollkommen unverständliche Befehle treten dabei auf, allen voran der Passability Check.

Zeilen wie:

bit = (1 << (d / 2 - 1)) & 0x0foder:

elsif @passages[event.tile_id] & 0x0f == 0x0fsind für mein Verständniss sprichwörtlich wie eine Faust ins Gesicht.

Mein bisheriger Fortschritt war es schoneinmal zu verstehen, dass es sich bei den @passages um eine 2 Tabelle handeln soll welche werte von 0 - 524 in Ausgaben wie 0, 15, 8 oder 64 umwandelt.

Was nun allerdings was genau bedeuten soll oder inwiefern ich diese Daten benutzen kann um die Begehbarkeit eines Tiles heraus zu finden entzieht sich jedoch völlig meiner Erkenntniss.

Bin für jede Form von Aufklärung dankbar.
Cornix.

The_Burrito
14.01.2010, 00:30
Diese Befehle überprüfen einzelne Bits.
Zahlen die mit 0x beginnen werden von Ruby als Hexadezimalzahlen interpretiert.
0x0F wäre demnach 16 was einem Bitmuster von 00001111 entspricht in einem Byte entspricht.
Der & Operator ist ein "bitweises und" was so viel bedeutet wie er geht jedes Bit von seinem ersten Operanden durch und vergleicht es mit dem Bit an der selben Stelle des zweiten Operanden, und liefert nur dann eine 1 an jener Stelle im Ergebnis wenn bei beiden Operanden dort eine 1 war.

Beispiele:


00001111 & 11110000 = 00000000
11111111 & 00000001 = 00000001
10101010 & 11110000 = 10100000


Der << Operator verschiebt in seinem 1. Operanden (sofern es sich um eine Zahl handelt) alle Bits um eine Anzahl an Bits nach links wie der 2. Operand angibt, und füllt von rechts mit 0en auf.

Beispiele:


00000001 << 3 = 00001000
00001111 << 4 = 11110000


Solche Operationen auf Bitebene werden normalerweise dann verwendet wenn man in einer einzigen Variable mehrere Wahr/Falsch Zustände Speichern möchte. Man kann sich das so vorstellen, dass jedes Bit in einem Byte quasi einen Switch darstellt der bei 0 auf OFF und bei 1 auf ON ist.
Um das jetzt auf die Begehrbarkeit von Tiles anzuwenden könnte es in etwa wie folgt aussehen:


8 7 6 5 4 3 2 1
+-+-+-+-+-+-+-+-+
|.|.|.|.|N|E|W|S|
+-+-+-+-+-+-+-+-+
N = Passierbar Norden?
E = Passierbar Osten?
W = Passierbar Westen?
S = Passierbar Süden?

Welches Bit jetzt tatsächlich mit welcher Richtung übereinstimmt weiß ich jetzt nicht auswendig, aber so in ungefähr könnte es aussehen. Gehen wir aber einmal davon aus, dass es so aussieht, so wäre ein Tile im Norden passierbar wenn im 4. Bit eine 1 steht, usw.

Die Abfrage


@passages[event.tile_id] & 0x0f == 0x0f

ist also die Abfrage ob ein Tile in alle Richtungen begehbar ist.
Wie vorher erwähnt ist 0x0f die hexadezimale schreibweise von 16 also Binär 00001111. Diese schreibweise hat den Vorteil, dass man immer 4 binäre Ziffern (also jeweils 4 Bits eines Bytes) mit einer Hexadezimalziffer darstellen kann.



0 = 0000
1 = 0001
2 = 0010
3 = 0011
4 = 0100
5 = 0101
6 = 0110
7 = 0111
8 = 1000
9 = 1001
A = 1010
B = 1011
C = 1100
D = 1101
E = 1110
F = 1111



Die andere Abfrage, nämlich


bit = (1 << (d / 2 - 1)) & 0x0f

überprüft ob ein Tile in eine bestimmte Richtung passierbar ist. Die Variable d gibt dabei die Richtung an (steht ja auch so in der Beschreibung der Methode). Je nach richtung steht 2, 4, 6 oder 8 in der Variable. Bei d / 2 - 1 kommt dir dementsprechend ein Wert zwischen 0 und 3 heraus.
Wenn du nun 1 (00000001 als Byte) um 0 bis 3 stellen verschiebst kommen dir dementsprechend 1 (00000001), 2 (00000010), 4 (00000100) oder 8 (00001000) heraus. Dadurch das du auch noch ein & mit 0x0f durchführst kannst du sicherstellen, dass du eine numerische Variable erhältst die entweder 0 ist wenn das Bit an dieser Stelle nicht gesetzt ist, oder größer als 0 wenn es gesetzt war.

Edit: Nach schnellem überfliegen der von dir angeschnittenen Methode (und vor allem der Kommentare), hab ich gerade herausgefunden, dass im Falle der Game_Map implementierung hier die einzelnen Bitflags nicht für Passierbarkeit sondern für Unpassierbarkeit stehen. Also steht in dem betreffenden Bit ein 1er so kann man das Tile an dieser Stelle nicht passieren

Cornix
14.01.2010, 12:40
Höchst interessant, vielen Dank.
Wie das Binär- und Hexadezimalsystem funktionieren habe ich bereits gewusst, doch an eine Umsetzung als boolean expression habe ich noch garnicht gedacht.
Ein ziemlich ausgeklügeltes System, das muss ich zugeben.

Größten Dank nocheinmal für diese höchst informative Erklärung, ich werde mich sofort ersteinmal daran setzen mir alles nocheinmal genauer durch zu schauen.
Eine Frage habe ich allerdings noch, die 4 bits am Anfang des Hexadezimalen Ausdrucks sind vollkommen belanglos und werden nicht gebraucht ist das korrekt?

Edit:
Nun verstehe ich wie es funktioniert.
Ich habe mir das Script nocheinmal angeschaut und verstehe nun denke ich wie die Begehbarkeit eines Tiles ermittelt wird.

Data ist eine 3 dimensionales Array welches alle Tiles der Map speichert. Indikatoren sind X-Position, Y-Position und der Layer auf welchem das Tile platziert wurde.
Data[0,0,0] zum Beispiel für das erste Teil des ersten Layers.

Die ID dieses Tiles wird dann an die Passages Variable übermittelt um einen hexadezimalen Wert über die einzelnen Pas-Directions zu erhalten.

Die Operation
(1 << 4) bedeutet soviel wie (2^4)*1 also (x << y) = (2^y)*x wobei y nicht negativ sein kann.
Die Operation (1 << (d/2 - 1)) & 0x0f verstehe ich allerdings noch nicht. Ich weis lediglich, dass die Werte
0 für d=0,
1 für d=2,
2 für d=4,
4 für d=6,
8 für d=8 und
0 für d=10
ausgegeben werden.

Diese werden dann in Hexadezimalschreibweise als Indikatoren dafür verwendet welche Richtungen von dem Tile unpassierbar sind.
Wenn @passages[tile_id] & bit != 0 gilt, dann ist die in bit angegebene Richtungen für dieses Tile unpassierbar, gilt @passages[tile_id] & 0x0f == 0x0f sind sogar alle 4 Richtungen für dieses Tile unpassierbar.

Soweit ist das Richtig hoffe ich?
Allerdings verstehe ich derzeit wirklich nicht wie der Operator '&' funktioniert.

The_Burrito
14.01.2010, 14:06
Der & Operator funktioniert im Prinzip wie der && (und) Operator. Der Unterschied besteht darin, dass der && Operator true zurück liefert, wenn beide Operanden true sind (Korrekterweise liefert er dann true zurück wenn keiner der beiden Operanden false oder nil ist), und sonst false.
Der & Operator macht jetzt im Prinzip das selbe, nur auf Bit ebene.
Er geht jedes Bit seine Operanden durch und liefert als Ergebnis einen Wert bei dem jedes Bit wo bei beiden Operanden an jener Stelle ein 1er war auch ein 1er steht und sonst 0.
Beispiele hab ich ja in meinem ersten Post schon gebracht.

Cornix
14.01.2010, 14:34
Jetzt verstehe ich. Vielen Dank.