π
<-
Chat plein-écran
[^]

2D level generator (terraria-like)

Pour TI-Nspire OS 3.0 ou ultérieur.

2D level generator (terraria-like)

Message non lude technolapin » 25 Nov 2014, 19:08

Enfin je finis un programme!
J'ai mis au point une génération aléatoire de map, qui ressemblent un peu à celles de terraria ou autres jeux utilisant des fractales à multiples dimension compliquées pour générer leur mondes (évidement, moi j'ai trouvé plus simple et assez potable quand même).
Je poste ça ici parce que la probabilité que j'en fasse quelque chose est quasi-nulle et parce que cela pourrait être utile à d'autres.

Code: Tout sélectionner
local rand = math.random
local floor = math.floor
local abs = math.abs
local pow = math.pow
local sqrt = math.sqrt

local biomesList = {
  {.1, 8, 32, 8}
, {1, 4, 8, 4}
}


function on.resize (ww, hh)
width, height = ww, hh
w, h = width, height/2
mat = gen()
map = convertMat (mat)
end

function dist2 (x1, y1, x2, y2)
return pow(x1-x2, 2)+pow(y1-y2, 2)
end


function gen ()
local m = genMat()
local biomes = genBiomes(24, 32)
genSphericalNoise (m, biomes)
genLeveling (m, 255)
genSmoothCorner (m, 2)
return m
end

function genBiomes (min, max)
local biomes = {}
local a = 1
while a < w do
  local r = rand(min, max)
  local b = rand(#biomesList)
  biomes[#biomes+1] = {type=b, x1=a, x2 = a+r, size = r}
  a = a+r
end
biomes[#biomes].x2 = w
return biomes
end




function genLeveling (m, tol)
for a = 1, w do
  local n = 0
  for b = 1, h do
   n=n+m[a][b]
  end
  n = math.floor(n/tol)
  for b = 1, h do
   if n > 0 then m[a][b] = tol
   else m[a][b] = 0 end
   n = n-1
  end
end
end

function genSphericalNoise(m, biomes)
for _, bio in pairs (biomes) do
  local n, min, max, v = unpack (biomesList[bio.type])
  for i = 1, n*bio.size do
   local r = rand (min, max)
   local r2 = r*r
   local x = rand (bio.x1, bio.x2)
   local y = rand (h)
   for a = x-r, x+r do
    for b = y-r, y+r do
     local d = dist2(a, b, x, y)
     if d <=r2 then
      pcall (function () m[a][b] = sqrt(d)*v end)
     end
    end
   end
  end
end
end


function genSmoothCorner (m, tol)
local he = {}
for a = 1, w do
  he[a] = 0
  for b = 1, h do
   he[a] = he[a]+m[a][b]/255
  end
end
for a = 2, w-1 do
  local med = floor((he[a-1]+he[a+1])/2)
  if abs (med-he[a]) > tol then
   for b = 1, h do
    if med > 0 then m[a][b] = 255 else m[a][b] = 0 end
    med = med-1
   end
  end
end
end


function genMat ()
local m = {}
for a = 1, w do
  m[a] = {}
  for b = 1, h do
   m[a][b] = 0
  end
end
return m
end


function convertMat (m)
local l = {}
for a = 1, w do
  l[a] = 0
  for b = 1, h do
   if m[a][b] == 0 then l[a] = l[a]+1 end
  end
end
return l
end



function on.paint (gc)
for a = 1, w do
  gc: fillRect (a, height-map[a], 0, map[a])
end
end
   



La map consiste en une matrice bidimensionnelle dont deux valeurs sont possible: 255 (l'air en blanc) et 0 (le sol).

Au lieu d'utiliser des fractales très louches comme le fait terraria, je fait un bruit aléatoire consistant en des cercles dégradés de tailles différentes. La somme des cases de chaque colonne est ensuite convertie en hauteur, un petit dernier traitement est appliqué pour éliminer les pics moches et incongrus.

J'utilise une fonction qui créé une liste avec les hauteurs pour les afficher avec des rectangles de 1 de large parce que c'est (beaucoup) plus rapide à afficher.

Quelques images ainsi générées:
4113
4112
4111

Encore une fois, si ce code intéresse quelqu'un (tout est possible de nos jours :p ), je donne tous les droits pour l'implémenter dans n'importe quel programme. Ma seule condition est de mettre dans les crédits de ce programme "Gloire à technolapin, qui m'oblige à mettre cette phrase à la noix dans les crédits pour que je puisse utiliser sa génération de map foireuse" (mot pour mot :troll: )
Dernière édition par technolapin le 27 Nov 2014, 19:02, édité 2 fois.
Votez Kasane Teto 2017
Avatar de l’utilisateur
technolapin
Niveau 13: CU (Calculateur Universel)
Niveau 13: CU (Calculateur Universel)
Prochain niv.: 97.8%
 
Messages: 514
Images: 25
Inscription: 31 Déc 2012, 10:48
Localisation: Chez moi
Genre: Homme
Calculatrice(s):
MyCalcs profile
Classe: Chui en vacance ducon

Re: 2D level generator (terraria-like)

Message non lude Ti64CLi++ » 25 Nov 2014, 19:33

Cool car cela me dirais bien de faire un warm.
Image
Avatar de l’utilisateur
Ti64CLi++Modo
Niveau 16: CC2 (Commandeur des Calculatrices)
Niveau 16: CC2 (Commandeur des Calculatrices)
Prochain niv.: 32.3%
 
Messages: 3441
Images: 75
Inscription: 04 Juil 2014, 14:40
Localisation: Clermont-Ferrand 63
Genre: Homme
Calculatrice(s):
MyCalcs profile
Classe: ENS Rennes
GitHub: Ti64CLi

Re: 2D level generator (terraria-like)

Message non lude Adriweb » 25 Nov 2014, 19:34

Ca me rappelle ce que Jim avait codé d'apres ma suggestion pour le terrain (enfin, j'avais vu l'algo quelque part et je lui en avais parlé):

Image

Code: Tout sélectionner
function getMidPoint(line)
    local xdif    = math.abs(line[3]-line[1])
    local ydif    = math.abs(line[4]-line[2])
    local x    = math.min(line[3], line[1]) + xdif/2
    local y    = math.min(line[4], line[2]) + ydif/2
    return x, y
end

function terrain(bline, range, roughness)
    local lines    = {bline}
    local lines2    = {}

    local midX, midY

    for times=1, 10 do
        for index, line in pairs(lines) do
            midX, midY    = getMidPoint(line)
            midY    = midY + math.random(-range, range)

            table.insert(lines2, {line[1], line[2], midX, midY})
            table.insert(lines2, {midX, midY, line[3], line[4]})
        end
        lines    = lines2
        lines2    = {}
        range    = range * (roughness*2^-roughness)
    end

    return lines
end

lines    = terrain({0,120,318,120}, 100, 0.6)
function on.paint(gc)
    for index, line in pairs(lines) do
        gc:drawLine(line[1], line[2], line[3], line[4])
    end
end


Il a ensuite fait quelques essais avec le moteur physique (cf. piece jointe pour le code complet du gif)
Fichiers joints
terainphysics.lua
(5.95 Kio) Téléchargé 72 fois
Image

MyCalcs: Help the community's calculator documentations by filling out your calculators info!
MyCalcs: Aidez la communauté à documenter les calculatrices en donnant des infos sur vos calculatrices !
Inspired-Lua.org: All about TI-Nspire Lua programming (tutorials, wiki/docs...)
Avatar de l’utilisateur
AdriwebAdmin
Niveau 16: CC2 (Commandeur des Calculatrices)
Niveau 16: CC2 (Commandeur des Calculatrices)
Prochain niv.: 80.2%
 
Messages: 14616
Images: 1218
Inscription: 01 Juin 2007, 00:00
Localisation: France
Genre: Homme
Calculatrice(s):
MyCalcs profile
Twitter/X: adriweb
GitHub: adriweb

Re: 2D level generator (terraria-like)

Message non lude technolapin » 27 Nov 2014, 10:32

Oui, mais le système ce génération est juste totalement random, et ne donne pas de résultats potables pour des grandes maps. Alors que le mien est potable pour un jeu .
J'ai implémenté la possibilité de générer différents "biomes" avec des reliefs spécifiques, et la taille de la map ne change plus la tête des reliefs (le nombre de sphères random s'adaptant à la taille du biome). Je mettrais cette version en ligne dès que j'aurais accès à mon pc (peux pas avec ceux du lycée).
Votez Kasane Teto 2017
Avatar de l’utilisateur
technolapin
Niveau 13: CU (Calculateur Universel)
Niveau 13: CU (Calculateur Universel)
Prochain niv.: 97.8%
 
Messages: 514
Images: 25
Inscription: 31 Déc 2012, 10:48
Localisation: Chez moi
Genre: Homme
Calculatrice(s):
MyCalcs profile
Classe: Chui en vacance ducon

Re: 2D level generator (terraria-like)

Message non lude technolapin » 27 Nov 2014, 19:06

J'ai implémenté une différenciation des blocs, qui sont fait en multipart maintenant (c'est juste joli et plus long à afficher :troll: )

Code: Tout sélectionner
local rand = math.random
local floor = math.floor
local abs = math.abs
local pow = math.pow
local sqrt = math.sqrt
local cx, cy = 0, 0

local biomesList = {
  {.1, 8, 32, 8}
, {1, 4, 8, 4}
}


function on.resize (ww, hh)
width, height = ww, hh
w, h = floor(width/4), floor(height/8)
t = 8
mat = gen()
end

function dist2 (x1, y1, x2, y2)
return pow(x1-x2, 2)+pow(y1-y2, 2)
end


function gen ()
local m = genMat()
local biomes = genBiomes(8, 32)
genSphericalNoise (m, biomes)
genLeveling (m, 255)
genSmoothCorner (m, 2)
he = mapToHeight (m)
m = heightToBlocs (he)
return m
end

function genBiomes (min, max)
local biomes = {}
local a = 1
while a < w do
  local r = rand(min, max)
  local b = rand(#biomesList)
  biomes[#biomes+1] = {type=b, x1=a, x2 = a+r, size = r}
  a = a+r
end
biomes[#biomes].x2 = w
return biomes
end




function genLeveling (m, tol)
for a = 1, w do
  local n = 0
  for b = 1, h do
   n=n+m[a][b]
  end
  n = math.floor(n/tol)
  for b = 1, h do
   if n > 0 then m[a][b] = tol
   else m[a][b] = 0 end
   n = n-1
  end
end
end

function genSphericalNoise(m, biomes)
for _, bio in pairs (biomes) do
  local n, min, max, v = unpack (biomesList[bio.type])
  for i = 1, n*bio.size do
   local r = rand (min, max)
   local r2 = r*r
   local x = rand (bio.x1, bio.x2)
   local y = rand (h)
   for a = x-r, x+r do
    for b = y-r, y+r do
     local d = dist2(a, b, x, y)
     if d <=r2 then
      pcall (function () m[a][b] = sqrt(d)*v end)
     end
    end
   end
  end
end
end


function genSmoothCorner (m, tol)
local he = {}
for a = 1, w do
  he[a] = 0
  for b = 1, h do
   he[a] = he[a]+m[a][b]/255
  end
end
for a = 2, w-1 do
  local med = floor((he[a-1]+he[a+1])/2)
  if abs (med-he[a]) > tol then
   for b = 1, h do
    if med > 0 then m[a][b] = 255 else m[a][b] = 0 end
    med = med-1
   end
  end
end
end


function genMat ()
local m = {}
for a = 1, w do
  m[a] = {}
  for b = 1, h do
   m[a][b] = 0
  end
end
return m
end


function mapToHeight (m)
local l = {}
for a = 1, w do
  l[a] = 0
  for b = 1, h do
   if m[a][b] == 0 then l[a] = l[a]+1 end
  end
end
return l
end

color = {
  [0] = {255, 255, 255}
, [1] = {150, 150, 150}
, [2] = {200, 150, 0}
, [3] = {0, 200, 0}
}
function getBloc(m, x, y)
assert (m[x][y])
return m[x][y]
end

function getSides (m, x, y, e)
local sides = {}
local bool = {}
bool[1], sides[1] = pcall (getBloc, m, x-1, y)
bool[2], sides[2] = pcall (getBloc, m, x, y-1)
bool[3], sides[3] = pcall (getBloc, m, x+1, y)
bool[4], sides[4] = pcall (getBloc, m, x, y+1)
for a = 1, 4 do
  if not bool[a] then
   sides[a] = makeBloc(e,e,e,e)
  end
end
return  makeBloc( sides[1].right or e
                 , sides[2].down or e
                 , sides[3].left or e
                 , sides[4].up or e)
end


function makeBloc (l, u, r, d)
return {left=l, up=u, right=r, down=d}
end

function heightToBlocs (t)
local m = {}
for a = 1, w do
  local he = t[a]
  m[a] = {}
  -- set air
  for b = 1, h-he do
   m[a][b] = makeBloc (0,0,0,0)
  end
end
for a = 1, w do
  local he = t[a]
  -- set grass
  local b = h-he
  local s = getSides (m, a, b, 2, 2)
  for c, d in pairs (s) do
    if d == 0 then s[c]=3
elseif d == 1 then s[c]=2
   end
  end
  m[a][b] = makeBloc (s.left or 0, 3, s.right or 0, s.down or 0)
  -- set dirt
  for b = h-he+1, h-he+1+floor(he/5) do
   m[a][b] = makeBloc (2, 2, 2, 2)
  end
  -- set stone
  for b = h-he+1+floor(he/5), h do
   m[a][b] = makeBloc (1,1,1,1)
  end
end
return m
end




function drawBloc (gc, a, b, x, y)
gc: setColorRGB (unpack(color[mat[a][b].left]))
gc: fillPolygon ({x, y, x, y+t, x+t/2, y+t/2})
gc: setColorRGB (unpack(color[mat[a][b].up]))
gc: fillPolygon ({x, y, x+t, y, x+t/2, y+t/2})
gc: setColorRGB (unpack(color[mat[a][b].right]))
gc: fillPolygon ({x+t, y, x+t, y+t, x+t/2, y+t/2})
gc: setColorRGB (unpack(color[mat[a][b].down]))
gc: fillPolygon ({x, y+t, x+t, y+t, x+t/2, y+t/2})
end

function on.paint (gc)
for a = 1, w do
  for b = 1, h do
   pcall(drawBloc, gc, a, b, (a-1)*t-cx, (b-1-h)*t+height-cy)
  end
end
end

function on.arrowKey (k)
    if k == "left" then
     cx = cx-t
elseif k == "right" then
     cx = cx+t
elseif k == "up" then
     cy = cy-t
elseif k == "down" then
     cy = cy+t
end
platform.window: invalidate ()
end



Votez Kasane Teto 2017
Avatar de l’utilisateur
technolapin
Niveau 13: CU (Calculateur Universel)
Niveau 13: CU (Calculateur Universel)
Prochain niv.: 97.8%
 
Messages: 514
Images: 25
Inscription: 31 Déc 2012, 10:48
Localisation: Chez moi
Genre: Homme
Calculatrice(s):
MyCalcs profile
Classe: Chui en vacance ducon


Retourner vers Nspire-Lua

Qui est en ligne

Utilisateurs parcourant ce forum: Aucun utilisateur enregistré et 18 invités

-
Rechercher
-
Social TI-Planet
-
Sujets à la une
Comparaisons des meilleurs prix pour acheter sa calculatrice !
Aidez la communauté à documenter les révisions matérielles en listant vos calculatrices graphiques !
Phi NumWorks jailbreak
123
-
Faire un don / Premium
Pour plus de concours, de lots, de tests, nous aider à payer le serveur et les domaines...
Faire un don
Découvrez les avantages d'un compte donateur !
JoinRejoignez the donors and/or premium!les donateurs et/ou premium !


Partenaires et pub
Notre partenaire Jarrety Calculatrices à acheter chez Calcuso
-
Stats.
1575 utilisateurs:
>1552 invités
>19 membres
>4 robots
Record simultané (sur 6 mois):
6892 utilisateurs (le 07/06/2017)
-
Autres sites intéressants
Texas Instruments Education
Global | France
 (English / Français)
Banque de programmes TI
ticalc.org
 (English)
La communauté TI-82
tout82.free.fr
 (Français)