giovedì 4 settembre 2025

LOVE2D - Grafica "scalare"

 Ho creato uno o due giochetti in pixelart ed uno dei problemi che ho dovuto affrontare è stato... "scalare" la grafica per evitare di fare un "gioco per formiche".

Questo è un piccolo tutorial che spiega cosa serve fare per gestire "scaling" (più avanti ci sarà un post sul fullscreen).

Per prima cosa, è necessario scegliere una dimensione "standard" da cui partire. Per ottenere il miglior effetto di "scaling", bisogna che la grafica di arrivo (ad esempio, la risoluzione -ormai standard- 1920x1080) sia un moltiplicatore esatto della grafica di partenza.

Le due opzioni più sensate sono il x3 ed il x4, che hanno rispettivamente le seguenti dimensioni:

x3    640x360
x4    480x270
x5    384x216

Nota: si può ovviamente lavorare ad un progetto con risoluzioni iniziali "standard", ad esempio 640x480, bisogna però "ridurre" il moltiplicatore e gestire il translate.


La prima cosa da fare è inserire il filtro "nearest" per disegnare i pixel senza "blur". Questo va fatto prima di qualsiasi aggiunta di asset (creati con newImage), in questo modo tutto sarà "nitido":

love.graphics.setDefaultFilter("nearest", "nearest")

Definiamo, a questo punto, una dimensione standard (quella utilizzata per il gioco, di norma indicata come "virtuale" -VR-) e la dimensione "finale" in finestra:

DIM_VR = {
    W = 384 ,
    H = 216
}

DIM = {
    W = 384 * 2 ,
    H = 216 * 2
}

Per far partire il gioco alla dimensione corretta, impostare gli stessi valori di DIM anche nel love.conf(t):

function love.conf(t)
    t.window.width = 384
    t.window.height = 216
end

Eventualmente, si possono impostare gli stessi valori nel love.load():

function love.load()
    local w, h, flags = love.window.getMode()

    if w ~= DIM.W or h ~= DIM.H then
        love.window.setMode(DIM.W, DIM.H, flags)
    end
end

Concentriamoci sul love.draw(t), dove andremo a "sistemare" la scala della grafica.
Per disegnare correttamente il tutto, useremo un "buffer" e "scaleremo" quello.

I passaggi necessari sono questi:

  • recupero delle dimensioni della finestra
  • creazione del canvas
  • calcolo della scala come "moltiplicatore intero"
  • impostazione del canvas
  • impostazione della scala
  • eventuale traslazione per disegnare il tutto
  • disegno della schermata di gioco
  • chiusura del canvas
  • disegno a video del tutto

Il codice, quindi, è:

function love.draw(dt)
    -- dimensioni finestra
    local screenSizeX, screenSizeY = love.graphics.getDimensions()

    -- creazione canvas
    local framebuffer = love.graphics.newCanvas(screenSizeX, screenSizeY)

    -- calcolo scala
    local scale = math.floor(math.min(screenSizeX / DIM_VR.W, screenSizeY / DIM_VR.H))

    -- gestione del canvas e scala
    love.graphics.setCanvas(framebuffer)
    love.graphics.push()
    love.graphics.scale(scale, scale)

    -- gestione del translate
    trans_x = (screenSizeX - DIM_VR.W * scale) / 2
    trans_y = (screenSizeY - DIM_VR.H * scale) / 2

    love.graphics.translate(trans_x, trans_y)

    -- DISEGNO DELLA SCHERMATA DI GIOCO
    love.graphics.draw(Asset)

    -- reset
    love.graphics.setCanvas()
    love.graphics.pop()

    -- disegno del canvas
    love.graphics.draw(framebuffer, 0, 0)
end

Innestando questo codice, il sistema disegnerà la pagina della dimensione voluta in modo "scalato". Se la scala effettiva non è "intera", il disegno verrà centrato nella schermata.

Nota: a questo punto bisogna solo ricordarsi che l'intera grafica è "scalata", per cui se si utilizza il mouse come input, per ottenere la posizione corretta è necessario dividere il valore di X e Y per la scala!

Nessun commento:

Posta un commento