Seite 1 von 1

Fragen zu Sprites

Verfasst: Freitag 4. Januar 2013, 09:03
von The Hit-Man
Ich möchte gerne einen Sinus-Scrolltext mit SDL bauen. Für den Zeichensatz nehme ich einen C-64er Zeichensatz. Die Routine, die mir den Zeichensatz vom C64er in Surfaces umrechnet steht so weit und sieht so aus:

Code: Alles auswählen

class char ():
    def __init__ (self, filename):
        # Charset vom C64er laden
        self.charset = []
        data = open (filename, 'rb')
        line = data.read (512)
        for byte in range (0, len (line)):
            self.charset.append ((struct.unpack ('B', line [byte])[0]))

    def makeChar (self, char):
        # Bitmap bauen mit (ord) kann ein ASCII nach INT umgewandelt werden
        charsurface = pygame.Surface ((8, 8), 16)
        charsurface.fill ((0, 0 ,0 ))
        lineindex = 0

        # Zusammensetzen des Buchstaben
        for charindex in range ((ord (char) -96) *8 +2, (ord (char) -96) *8 +8 +2):
            if self.charset [charindex] & 128:
                charsurface.set_at ((1, lineindex), (255))
            if self.charset [charindex] & 64:
                charsurface.set_at ((2, lineindex), 255)
            if self.charset [charindex] & 32:
                charsurface.set_at ((3, lineindex), 255)
            if self.charset [charindex] & 16:
                charsurface.set_at ((4, lineindex), 255)
            if self.charset [charindex] & 8:
                charsurface.set_at ((5, lineindex), 255)
            if self.charset [charindex] & 4:
                charsurface.set_at ((6, lineindex), 255)
            if self.charset [charindex] & 2:
                charsurface.set_at ((7, lineindex), 255)
            if self.charset [charindex] & 1:
                charsurface.set_at ((8, lineindex), 255)
            lineindex = lineindex +1
        return (charsurface)

So weit so gut. Jedes einzelne Zeichen ( Buchstabe ), ist eine Klasseninstanz. Das brauche ich um jeden Buchstaben einzeld, Koordinaten zuzuteilen. Nun bin ich mit der Routine ein wenig unzufrieden. Denn jedes mal wenn ich einen neuen Buchstaben baue, wird im Constructor ja der C64er Zeichensatz geladen.
Ich brauche nur einen kleinen Denkanstoß, wie ich es hinbekomme, nur ein mal den Zeichensatz laden zu müssen? Möchte ungern unnötigen Speicher verballern. Weiß da jemand ne Lösung? Sollte man es überhaupt mit einer Klasse machen?

Re: Fragen zu Sprites

Verfasst: Freitag 4. Januar 2013, 12:12
von Sirius3
Hallo,

1) Deine Leertaste ist kaputt, sie macht immer eine Lücke zwischen Funktionsnamen und öffnender Klammer.
2) Du solltest Dir nochmals ein Tutorial über for-Schleifen durchlesen.
3) Für Deinen Fall wäre eine Zeichensatz-Klasse gut, die mit make_char eben ein Einzelzeichenobjekt zurückliefert.

Re: Fragen zu Sprites

Verfasst: Freitag 4. Januar 2013, 13:04
von pillmuncher
@The Hit-Man: Ich würde sowas machen (ungetestet):

Code: Alles auswählen

class CharMap(dict):

    def __init__(self, filename):
        with open(filename, 'rb') as data:
            self._bitmaps = [
                struct.unpack('B', byte)[0] for byte in data.read(512)]

    def __missing__(self, char, coors=range(8)):
        surface = pygame.Surface((8, 8), 16)
        surface.fill((0, 0, 0))
        c = (ord(char) - 96) * 8 + 2
        for row in coors:
            bitmap = self._bitmaps[row + c]
            for col in coors:
                if bitmap & (0x100 >> (8 - col)):
                    surface.set_at((col + 1, row), 255)
        self[char] = surface
        return surface

    def __getitem__(self, char):
        return dict.__getitem__(self, char).copy()


cm = CharMap('some_file.xyz')

a1 = cm['a']
a2 = cm['a']
assert a1 is not a2
Hierbei wird die Datei nur einmal gelesen, nicht jedesmal, wenn ein Buchstabe gebraucht wird. Die Methode dict.__missing__(self, key) wird von dict.__getitem__(self, key) automatisch aufgerufen, sofern unter key nichts gefunden wurde, dh. also jedes erste Mal wenn wir ein Surface-Objekt via cm[Buchstabe] holen wollen.

Die Methode __getitem__() habe ich überschrieben, damit man jedesmal ein neues Surface-Objekt bekommt.

Ob die Indizierungs-Formeln alle stimmen solltest du nochmal nachprüfen.

Re: Fragen zu Sprites

Verfasst: Freitag 4. Januar 2013, 14:58
von Sirius3
unpack ist ja gerade dazu da, »kompliziertere« Strukturen zu entpacken, da mit einzelnen Bytes daherzukommen, ...
ein einfaches map(ord,bytes) würde hier ja auch schon völlig ausreichen.

Ein Surface Pixel für Pixel aufzubauen ist auch alles andere als effektiv.

Für all die, die was laufen sehen wollen:

Code: Alles auswählen

import pygame
import struct

class CharMap(dict):
    def __init__(self, bytes):
        self._bitmaps = struct.unpack_from('>27Q',bytes,2)

    def __missing__(self, char, mask=[1<<k for k in range(63,-1,-1)]):
        bits = self._bitmaps[ord(char)-96]
        data = struct.pack('<64i', *(-bool(bits&m) for m in mask))
        return pygame.image.fromstring(data, (8,8), 'RGBA')

    def __getitem__(self, char):
        return dict.__getitem__(self, char).copy()


bytes="""
eJwtjSsOAzEMRI0W5QhVzxCYYxUW5HBBg1ZVUVRQrYKMquCAyO04XZMnf+ZZkpxlgEFVJjBVJ/tS
mpqMHRybWCmjNVKczfcPn4M5ZS7HGFPKcg0hXN53wf56jo9KYXkO3arfoR5HJ8217mX+7wN6/67e
c/Tb5vvlTf4H5z8ik3V5gJzyIjIPxbaQbvz3A90ciaI=
""".decode('base64').decode('zip')

cm = CharMap(bytes)
display = pygame.display.set_mode((255, 255))

for k,ch in enumerate('hallo'):
    display.blit(cm[ch], (20+k*8, 20))

pygame.display.flip()
while True:
    event = pygame.event.wait()
    if event.type == pygame.QUIT:
        break

Re: Fragen zu Sprites

Verfasst: Freitag 4. Januar 2013, 15:15
von The Hit-Man
Erst mal Danke an alle ... ja, mein Programmierstiel ist alles andere als sauber. Ich weiß :( ich programmiere eher immer so: gut getrickst ist halb gearbeitet.
Allerdings die methode __getitem__ kannte ich bis jetzt noch gar nicht.
Auch die Bytes einzelnd aus der Datei zu holen war eher mal schnell nen GoogleHack. Gesucht und gefunden.