Necrown - Devlog #08 [Engine Dev] : Gestion de l'affichage et instantané des variables globales
Splix Il y a 7 mois Premium Pro - Adhésion à vie0

Salut les gamecodeurs et gamecodeuses!!!

Aujourd’hui nous allons continuer notre petit moteur en nous attaquant tout d’abord à la gestion de la fenêtre et de l’affichage… Nous allons donc créer un nouveau fichier dans la partie Core de notre moteur, et nous l’appellerons displaying.lua. L’objet display avait déjà été créé dans le fichier conf lors d’un précédent devlog. Nous allons ici lui rajouter de nouvelles valeurs et des fonctions pour gérer notre fenêtre:

display.s = 1
display.winW = display.w
display.winH = display.h
display.winPos = nil
display.focus = true

function love.focus(p_focus)
  display.focus = p_focus
end

local function toFullscreen()
  settings.video.fullscreen = true
  love.window.setFullscreen(true)
  
  local w = love.graphics.getWidth()
  local h = love.graphics.getHeight()
  
  display.s = math.ceil(((w / display.winW) + (h / display.winH)) / 2)
  display.w = w / display.s
  display.h = h / display.s
end

local function toWindowed()
  settings.video.fullscreen = false
  love.window.setFullscreen(false)
  
  display.w = display.winW
  display.h = display.winH
  display.s = 1
end

Vous voyez que l’on créé ici une fonction locale toFullscreen et toWindowed qui gérerons le passage au fullscreen et au fenêtré. Les valeurs display.winW et display.winH enregistrent la largeur et la hauteur de la fenêtre en mode fenêtré, et display.s enregistre l’échelle (un entier qui en mode fenêtré sera égale à 1). Quand on passe en fullscreen, l’échelle est calculée par rapport à la largeur et la hauteur de l’écran. Si les fonctions toFullscreen et toWindowed sont notées locales, c’est parce qu l’on va passer par une autre fonction pour changer le mode de la fenêtre:

function display.init()
  if settings.video.fullscreen then toFullscreen() end
  display.winPos = love.window.getPosition()
end

function display.toggleFullscreen()
  if settings.video.fullscreen then toWindowed()
  else toFullscreen() end
  
  settings.video.save()
end

function display.isMoved()
  local winPos = love.window.getPosition()
  if display.winPos ~= winPos then
    display.winPos = winPos
    return true
  end
  return false
end

C’est la fonction display.toggleFullscreen qui s’en chargera, et la fonction display.init sera appelée dans love.init pour tout préparer. La fonction display.isMoved nous sera utile plus tard, elle nous permet de savoir quand la fenêtre est déplacée, et nous nous en servirons pour éviter certains bugs dans ce cas là. Passons maintenant à un nouvel objet: camera. Il s’agit d’une caméra virtuelle qui sera utilisée pour l’affichage du jeu:

camera = {}
camera.x = 0
camera.y = 0

function camera.reset()
  camera.x = 0
  camera.y = 0
end

function camera.setPos(p_x, p_y)
  camera.x = math.floor(p_x - display.w / 2)
  camera.y = math.floor(p_y - display.h / 2)
end

function camera.move(p_x, p_y)
  camera.setPos(camera.x + p_x, camera.y + p_y)
end

function camera.update() end

La fonction camera.update nous permettra d’appliquer des changements automatiques à la position de la caméra, sinon les déplacements que nous lui indiqueront devront passer par la fonction camera.setPos ou camera.move.

Voici pour résumer à quoi ressemble la fonction update de love dans engine:

function love.update(p_dt)
  if not display.isMoved() then
    controls.update()
    keyboard.update()
    mouse.update()
    
    if controls.fullscreen.isPressed then
      display.toggleFullscreen()
    end
    
    camera.update()
  end

  mouse.postUpdate()
  inputs.postUpdate()
end

Maintenant le jeu peu passer de fullscreen à windowed en appuyant sur f11, et comme la fonction display.toggleFullscreen demande à sauvegarder les video settings à chaque changement, si vous quittez le jeu en fullscreen ou windowed, il se relancera automatiquement dans ce mode. Avant de nous quitter, nous allons d’abord nous amuser à développer notre mode de debug pour l’inDev. Nous allons prendre des instantanés des variables globales au début de engine:

local envLog = nil
if game.inDev then
  envLog = {}
  envLog["Framework"] = {}
  for k, _ in pairs(_G) do
    if tostring(k) ~= "game" and tostring(k) ~= "display" and tostring(k) ~= "envLog" then
      table.insert(envLog["Framework"], tostring(k))
    end
  end
end

La variable _G est une variable lua qui contient toutes les variables globales du projet. On enregistre tous leurs noms ici, hormis envLog et les variables créées dans conf, ce qui nous donne toutes les variables globales du lua et de love2d. On va réaliser la même opération à la fin du chargement du moteur, en n’enregistrant que les nouvelles variables, ce qui nous donnera toutes les variables globales ajoutées par le moteur. Puis nous allons rajouter une fonction print à envLog:

function envLog.print(p_state)
    local env = {}
    
    if p_state == "Game" then
      for k, _ in pairs(_G) do
        if not table.contains(envLog["Framework"], tostring(k)) and not table.contains(envLog["Engine"], tostring(k)) then
          table.insert(env, tostring(k))
        end
      end
    else      
      for _, v in pairs(envLog[p_state]) do
        table.insert(env, tostring(v))
      end
    end
    
    string.sort(env)
  
    print(p_state.." environement :")
    print("{")
    for _, v in ipairs(env) do print("\t"..v) end
    print("}".."\n")
  end

Avec cette fonction, nous pouvons afficher à tout moment un instantané des variables globales du framework, du moteur et du jeu. On va par la même occasion créer une fonction print à l’objet classes, fonctionnant de la même manière que envLog.print, qui nous permettra d’afficher toutes nos classes. Vous remarquerez peut-être la fonction string.sort, il s’agit encore d’un ajout à l’objet string que nous réalisons dans le fichier stdLib, et qui permet de trier un tableau de string par ordre alphabétique:

local function compare(p_a, p_b)
  p_a = tostring(p_a)
  p_b = tostring(p_b)
  
  local pattern = '^(.-)%s*(%d+)$'
  local _, _, col1, num1 = p_a:find(pattern)
  local _, _, col2, num2 = p_b:find(pattern)
  
  if (col1 and col2) and col1 == col2 then
    return tonumber(num1) < tonumber(num2)
  else
    return p_a < p_b
  end
end

function string.sort(p_table)
  table.sort(p_table, compare)
end

Et voilà, en ajoutant quelques controls, et en vérifiant dans love.update si ils sont pressés, on peut facilement afficher dans la console de love des listes de variables globales ou la liste des classes:

C’est une petite astuce qui peut s’avérer sympa et dont on peut décliner le concept comme on l’entend. Voilà, c’était un devlog asses long. Même si nous avons encore quelques gros points à travailler dans notre moteur, nous allons bientôt pouvoir commencer à vraiment travailler sur le jeu en lui-même. Mais en attendant…

Bon code à tous et à bientôt!!!

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.