Dies ist ein Fallow-Up Blogpost und heute beleuchten wir die Funktion uvTexture() ein wenig näher.

local tile = uvTexture(texture, region_width, region_height, i, j, explicit)

Wie ich dir schon im letzten Beitrag sagte, kannst du mit Hilfe dieser wunderbaren Funktion, alles über die UV-Koordinaten aus jedem beliebigen Spritesheet erfahren. Ich möchte zuerst etwas über die Parameter erzählen, die uvTexture empfangen kann. Im Anschluss zeige ich dir was die Funktion überhaupt zurückliefert und wie du es nutzen kannst. Fangen wir an.

Der erste Pflicht-Parameter ist texture. Hier musst du eine Bilddatei (JPEG, PNG) übergeben. In Codea wird die Grafik zunächst mittels readImage("Dropbox:spritesheet") in den RAM Speicher eingelesen und das Resultat sollte schließlich an uvTexture weitergegeben werden.

Die Pflich-Parameter an zweiter und dritter Stelle sind region_width und region_height. Damit stellst du die Größe jedes einzelnen Frames (=Tiles/Sprites) auf dem Spritescheet ein.

Allein mit diesen drei Datenfetzen kann uvTexture bereits den größten Teil der Informationen errechnen. Nun kennt uvTexture die Grafik, die Gesamtgröße der Grafik und die Größe der einzelnen Tiles auf ihr. Es kennt nun auch die Anzahl an Spalten (columns) und Zeilen (rows) und kann die Tiles darin einordnen. - Noch weiß uvTexture aber nicht, über welchen Bereich es Erkundigungen einholen soll. Willst du nur ein einziges Tile haben oder eine größere Selektion? Und dafür gibt es den vierten Pflich-Parameter i und den optionalen fünften Parameter j!

Mit diesen beiden wird die (rechtwinklige) Selektion definiert über die wir etwas erfahren wollen.


Im Grunde bezieht sich i und j jeweils auf ein Tile aus dem selektierten Rechteck. Dabei markiert i den linken oberen Punkt der Selektion und j den rechten unteren.

i und j können entweder als Zahlen, Vektoren, oder als ein Gemisch aus beidem, übergeben werden. Und wenn man nur ein einziges Tile auswählen möchte, dann kann man j auch ganz weglassen - uvTexture weiß dann bescheid!

Im folgenden Beispiel haben wir ein Spritesheet, das 16x16 Tiles aufweist. Es gibt also 16 Spalten und 16 Zeilen. Jedes Tile (also jede Zelle) ist 32x32px groß. Das gesamte Spritesheet hat somit eine Größe von 512x512px. Wir selektieren ein einziges Tile. Das Tile hat die ID 101 - oder vec2(5,7) - wenn man in Spalten und Zeilen denkt.

Für das angefragte Tile bekommst du nun ein Table zurück, das wie folgt aussieht:

{
    x = 128.0,
    y = 128.0,
    width  = 32.0,
    height = 32.0,
    uv = {
        x1 = 0.25,
        y1 = 0.5625,
        x2 = 0.3125,
        y2 = 0.625,
        w  = 0.0625,
        h  = 0.0625
    }
}

Aus dem Table kannst du entnehmen, dass das angefragte Tile eine Größe von 32x32px hat und sich auf dem Spritesheet an Position x = 128 und y = 128 befindet. Mit diesen Infos könntest du, in Codea auf die herkömmliche Art, das Tile wie folgt zeichnen.

function setup()
    x, y = 0, 0
    texture = readImage("Dropbox:spritesheet")
    region = uvTexture(texture, 32, 32, 101)
end

function draw()
    clip(region.x + x, region.y + y, region.width, region.height)
    sprite(texture, x, y)
end

Und dann gibt es da noch die UV Koordinaten, die ja bekanntlich den Zahlenbereich zwischen 0 und 1 abdecken. Diese würde man in Verbindung mit Meshes verwenden wollen! Und das ist genau das, was ich mit der Funktion ssprite() mache, die ich im letzten Beitrag vorgestellt habe.

  • x1,y1 sind die Koordinaten für die linke untere Ecke der Selektion
  • x2,y2 ist die rechte obere Ecke der Selektion
  • w,h definiert die Größe der Selektion

Nun wollen wir aber die Selektion ausweiten und mehrere Tiles auf einmal zeichnen. Und bei dieser Gelegenheit erkläre ich dir auch was der letzte *optionale* Parameter **explicit** bewirkt.

Wenn wir nun beispielsweise die vier Grass-Tiles zeichnen wollten (siehe oberes Bild), würden wir unsere Selektion zwischen i = 31 und j = 48 definieren. Oder in der Vektor-Schreibweise: i = vec2(15, 2) und j = vec2(16, 3). Das ist ok so, aber es ergibt sich nun ein Problem. Zwischen Tile 31 und 48 liegen 14 andere Tiles. Wir brauchen aber nur unsere 4 Stück, die innerhalb der Auswahl-Box liegen. Und genau dafür setzen wir das flag explicit auf true! Nun weiß uvTexture, dass es alle anderen Tiles, die außerhalb der eigentlichen Auswahl-Box liegen streichen kann. Hier ist die Ausgabe, die uns uvTexture gibt:

{
    x = 448.0,
    y = 416.0,
    width  = 64.0,
    height = 64.0,
    uv = {
        x1 = 0875,
        y1 = 0.8125,
        x2 = 1.0,
        y2 = 0.9375,
        w  = 0.125,
        h  = 0.125
    }
}

Und dann gibt es da noch eine Kleinigkeit zu erwähnen. Die von mir angeführten Ausgaben von uvTexture beziehen sich allein auf die Auswahl-Box die wir zwischen zwei Tiles definiert haben. Aber was wäre, wenn wir die gleiche Auflistung für jedes Tile separat haben wollten? Jedes Tile soll ein eigenes Table mit UV, etc. ausgegeben bekommen. - Ganz leicht, denn uvTexture gibt eigentlich zwei Tables zurück! Hier der Aufruf für das vorliegende Beispiel in der kompletten Schreibweise:

local region, tiles = uvTexture(texture, 32, 32, 31, 48, true)

Die Ausgabe vom region-Table kennen wir schon. Die Ausgabe für das tiles-Table sieht so aus:

{
    [1] = {
        id = 47,
        x = 448.0,
        y = 416.0,
        col = 15.0,
        row = 14.0,
        height = 32,
        width = 32,
        uv = {
            x1 = 0.875,
            y1 = 0.8125,
            x2 = 0.9375,
            y2 = 0.875,
            w  = 0.0625,
            h = 0.0625
        }
    }
    [2] = {
        id = 48,
        x = 480.0,
        y = 416.0,
        col = 16.0,
        row = 14.0,
        height = 32,
        width = 32,
        uv = {
            x1 = 0.9375,
            y1 = 0.8125,
            x2 = 1.0,
            y2 = 0.875,
            w = 0.0625,
            h = 0.0625
        }
    }
    [3] = {
        id = 31,
        x = 448.0,
        y = 448.0,
        col = 15.0,
        row = 15.0,
        height = 32,
        width = 32,
        uv = {
            x1 = 0.875,
            y1 = 0.875,
            x2 = 0.9375,
            y2 = 0.9375,
            w = 0.0625,
            h = 0.0625
        }
    }
    [4] = {
        id = 32,
        x = 480.0,
        y = 448.0,
        col = 16.0,
        row = 15.0,
        height = 32,
        width = 32,
        uv = {
            x1 = 0.9375,
            y1 = 0.875,
            x2 = 1.0,
            y2 = 0.9375,
            w = 0.0625,
            h = 0.0625
        }
    }
}

Alle vier Tiles aus unserer Selektion, schön säuberlich mit allen Informationen getrennt gelistet. - Wunderbar nicht?! Nun kannst du diese Daten nach belieben verwenden, wie ich es zum Beispiel weiter oben gezeigt habe. Schau dir doch noch einmal die Funktion ssprite{} an, um ein noch besseres Verständnis zu bekommen, wie man uvTexture sinnvoll einsetzen kann.