Abbilden einer Spielemap in Listen möglich?

Hier werden alle anderen GUI-Toolkits sowie Spezial-Toolkits wie Spiele-Engines behandelt.
Benutzeravatar
Ravetracer
User
Beiträge: 7
Registriert: Montag 10. Dezember 2007, 14:50

Abbilden einer Spielemap in Listen möglich?

Beitragvon Ravetracer » Montag 10. Dezember 2007, 15:00

Hallo zusammen.
Das ist hier mein erster Beitrag und schon komme ich mit einer Frage an ;).

Ich möchte eine Map für ein Spiel in einer Liste(Array) abbilden, und zwar 2D. Wie ist das am besten möglich?

Die Map hat eine definierte Größe. Auf ein Tile möchte ich per z.B. map[x][y] zugreifen, so dass mir am Ende an der Position map[10][13] die Nummer des Tiles angezeigt wird, was dort gezeichnet werden soll. Außerdem sollte auch die Tilenummer an der angegebenen Position geändert werden können.
Ich habe vor langer Zeit mal Maps in Pascal über ein 2D-Array abgebildet, habe aber irgendwie keine Ahnung, wie ich das nun in Python realisieren kann. Irgendwelche Tipps?

Danke schonmal,
Christian
Benutzeravatar
BlackVivi
User
Beiträge: 762
Registriert: Samstag 9. Dezember 2006, 14:29
Kontaktdaten:

Beitragvon BlackVivi » Montag 10. Dezember 2007, 15:06

Öhm, man macht zuerst'ne Liste aus "Konstanten", sozusagen oO Wo dann die Tiles beschrieben werden:

Code: Alles auswählen

tiles = ["gras", "sand"] #Natürlich kann man das auch mit anderen Objekten füllen...


Dann macht man anschließend ein Feld:

Code: Alles auswählen

felder = [[0, 1, 0],
          [1, 0, 1]]


Und dann darstellen, hier mal in'r Konsole:

Code: Alles auswählen

for zeile in feld:
    for feld in zeile:
        print tiles[feld],
    print


Oder wie meinst du das oO
Benutzeravatar
Ravetracer
User
Beiträge: 7
Registriert: Montag 10. Dezember 2007, 14:50

Beitragvon Ravetracer » Montag 10. Dezember 2007, 15:13

Mhh... jo, das haut ja so hin. Ich stand irgendwie auf'm Schlauch.

Also wird quasi in der Liste für jede Zeile (Y-Koordinate) ein komplettes Array der Spalten (X-Koordinate) gemacht mit der Tilenummer. Warum ich da nicht drauf gekommen bin.
Kann aber auch daran liegen, dass ich eigentlich arbeiten sollte und nebenbei wieder an Spieleprogrammierung denke *gg*.

Danke dir :D
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Beitragvon sma » Samstag 15. Dezember 2007, 12:17

Mein Tipp: Bau dir deine eigene Abstraktion für die Karte. Wenn du mit `map[x, y]` auf die Felder zugreifen können willst, dann lass deine Karte ein Exemplar der folgenden Klasse sein:

Code: Alles auswählen

class Map(object):
  def __getitem__(self, (x, y)):
    """add your code here..."""

Intern könntest du eine unveränderliche Karte als Tupel speichern.

Code: Alles auswählen

class Map(object):
  fields = (water, plain, forest, water, plain, desert, swamp, plain, forest)
  def __getitem__(self, (x, y)):
    return self.fields[x + y * 3]
BlackJack

Beitragvon BlackJack » Samstag 15. Dezember 2007, 13:15

Alternativ kann man auch ein Dictionary benutzen und ein Tupel aus den Koordinaten als Schlüssel verwenden. Zugriff dann auch mit ``map[x, y]``.
Benutzeravatar
nkoehring
User
Beiträge: 543
Registriert: Mittwoch 7. Februar 2007, 17:37
Wohnort: naehe Halle/Saale
Kontaktdaten:

Beitragvon nkoehring » Samstag 15. Dezember 2007, 18:24

mmh... ich glaube BlackJacks Vorschlag ist nicht unbedingt der performanteste, oder?

@sma: Map ist eine fertige Funktion in Python. Evtl sollte man den Namen also meiden.

Die Daten sollen doch folgende Form haben:

fuer eine ID bestehend aus x- und y-Koordinate bekomme ich eine beliebiges Objekt zurueck (zB eine Zahl, eine Klasse, einen String... ein Objekt eben).

Also hier mal was entsprechendes. Ich denke mal, wenn ich verstanden habe, was du haben moechtest, wird dir das sehr behilflich sein - eine Komplettloesung sozusagen:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-

# how to map a map


import sys
from pprint import pprint


class GameMap(object):
    def __init__(self, initial_size=(100, 100)):
        mapdata = list()
       
        # Karte mit Nullen initialisieren
        x, y = initial_size
        for i in xrange(x):
            mapdata.append(list("0"*y))
           
        self._mapdata = mapdata
       
    def set_field(self, koords, id):
        """ setzt den Wert `id` an die Koordinaten `koords`
        Argumente:
            koords (tuple or list)
            id (int or long or whatever you want ^^ )
        """
        try:
            x, y = koords
        except TypeError:
            raise AttributeError, "First argument must be a tuple or list!"
        except ValueError:
            raise AttributeError, "Koordinate list must be of length 2!"
        self._mapdata[x][y] = id
       
    def get_field(self, koords):
        """ gibt die id auf den Koordinaten `koords` zurueck
        Argumente:
            koords (tuple or list)
        """
        x, y = koords
        return self._mapdata[x][y]


if __name__ == '__main__':
    # kreiere eine Karte der Groesse 10x10 (Standardgroesse 100x100 Felder)
    myMap = GameMap((10, 10))
   
    # setze beliebige Felder mit set_fields(koord-tuple, value):
    myMap.set_field((1, 8), 3)
    myMap.set_field((3, 6), 5)
    myMap.set_field((5, 4), 7)
    myMap.set_field((7, 2), 11)
    myMap.set_field((9, 0), 13)
   
    # "drucke" die Karte zur Veranschaulichung:
    pprint(myMap._mapdata)


...mit Sicherheit gibt es auch noch bessere Moeglichkeiten, aber das war die Erstbeste die mir einfiel ;)
BlackJack

Beitragvon BlackJack » Samstag 15. Dezember 2007, 19:12

Was gibt's an einem Dictionary auszusetzen!? Zumindest der Zugriff ist in O(1) Zeit möglich. Ich sehe da keinen gravierenden Nachteil gegenüber einer Liste. Falls die Karte nur spärlich mit betretbaren Feldern besetzt ist, hätte man sogar einen Speichervorteil wenn man ein `collections.defaultdict` verwendet, dass ein "Wand"-Feld für Koordinaten zurück gibt, die nicht im Dictionary enthalten sind.
Benutzeravatar
nkoehring
User
Beiträge: 543
Registriert: Mittwoch 7. Februar 2007, 17:37
Wohnort: naehe Halle/Saale
Kontaktdaten:

Beitragvon nkoehring » Samstag 15. Dezember 2007, 19:30

Oh, das stimmt natuerlich... Das waere bei groesseren Karten wirklich sehr speicherschonend... da hab ich doch gleich mal umgebaut:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-

# how to map a map


import collections


class GameMap(collections.defaultdict):
    def __init__(self, default_value=0):
        self.default = default_value
        collections.defaultdict.__init__(self, self.default_value)
       
    def default_value(self):
        return self.default


if __name__ == '__main__':
    # kreiere eine Karte der Groesse 10x10 (Standardgroesse 100x100 Felder)
    myMap = GameMap((10, 10))
   
    # setze beliebige Felder, zB:
    myMap[(1, 0)] = 3
    myMap[(3, 2)] = 5
    myMap[(5, 4)] = 7
    myMap[(7, 6)] = 11
    myMap[(9, 8)] = 13
   
    # "drucke" die Karte zur Veranschaulichung (das wird hier n bissl umstaendlicher...):
    for x in xrange(10):
        print ""
        for y in xrange(10):
            print str(myMap[(x, y)]).zfill(2),



Natuerlich muss man sich was beim Speichern ausdenken wenn man den "Spareffekt" erhalten moechte.
Benutzeravatar
Ravetracer
User
Beiträge: 7
Registriert: Montag 10. Dezember 2007, 14:50

Beitragvon Ravetracer » Freitag 21. Dezember 2007, 10:01

Oha... habe 'ne Weile nicht reingeschaut, da ich nicht dazu gekommen bin. Sorry dafür. Hier hat sich ja einiges getan, doch in der Zwischenzeit habe ich meine Lösung schon gefunden und programmiere gerade einen Map-Editor.
Dieser funktioniert soweit schon recht gut, nur bekomme ich das Undo noch nicht so recht hin. Naja, mal sehen.
Trotzdem vielen Dank für eure Antworten und Lösungen.

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder