π
<-

2D level generator (terraria-like)

Pour TI-Nspire OS 3.0 ou ultérieur.

2D level generator (terraria-like)

Unread postby 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: Select all
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: )
Last edited by technolapin on 27 Nov 2014, 19:02, edited 2 times in total.
Votez Kasane Teto 2017
User avatar
technolapin
Niveau 13: CU (Calculateur Universel)
Niveau 13: CU (Calculateur Universel)
Level up: 97.8%
 
Posts: 514
Images: 25
Joined: 31 Dec 2012, 10:48
Location: Chez moi
Gender: Male
Calculator(s):
MyCalcs profile
Class: Chui en vacance ducon

Re: 2D level generator (terraria-like)

Unread postby Ti64CLi++ » 25 Nov 2014, 19:33

Cool car cela me dirais bien de faire un warm.
Image
User avatar
Ti64CLi++Modo
Niveau 16: CC2 (Commandeur des Calculatrices)
Niveau 16: CC2 (Commandeur des Calculatrices)
Level up: 32.5%
 
Posts: 3446
Images: 75
Joined: 04 Jul 2014, 14:40
Location: Clermont-Ferrand 63
Gender: Male
Calculator(s):
MyCalcs profile
Class: ENS Rennes
GitHub: Ti64CLi

Re: 2D level generator (terraria-like)

Unread postby 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: Select all
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)
You do not have the required permissions to view the files attached to this post.

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...)
My calculator programs
Mes programmes pour calculatrices
User avatar
AdriwebAdmin
Niveau 16: CC2 (Commandeur des Calculatrices)
Niveau 16: CC2 (Commandeur des Calculatrices)
Level up: 80%
 
Posts: 14842
Images: 1133
Joined: 01 Jun 2007, 00:00
Location: France
Gender: Male
Calculator(s):
MyCalcs profile
Twitter: adriweb
GitHub: adriweb

Re: 2D level generator (terraria-like)

Unread postby 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
User avatar
technolapin
Niveau 13: CU (Calculateur Universel)
Niveau 13: CU (Calculateur Universel)
Level up: 97.8%
 
Posts: 514
Images: 25
Joined: 31 Dec 2012, 10:48
Location: Chez moi
Gender: Male
Calculator(s):
MyCalcs profile
Class: Chui en vacance ducon

Re: 2D level generator (terraria-like)

Unread postby 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: Select all
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
User avatar
technolapin
Niveau 13: CU (Calculateur Universel)
Niveau 13: CU (Calculateur Universel)
Level up: 97.8%
 
Posts: 514
Images: 25
Joined: 31 Dec 2012, 10:48
Location: Chez moi
Gender: Male
Calculator(s):
MyCalcs profile
Class: Chui en vacance ducon


Return to Nspire-Lua

Who is online

Users browsing this forum: ClaudeBot [spider] and 4 guests

-
Search
-
Social TI-Planet
-
Featured topics
Comparaisons des meilleurs prix pour acheter sa calculatrice !
"1 calculatrice pour tous", le programme solidaire de Texas Instruments. Reçois gratuitement et sans aucune obligation d'achat, 5 calculatrices couleur programmables en Python à donner aux élèves les plus nécessiteux de ton lycée. Tu peux recevoir au choix 5 TI-82 Advanced Edition Python ou bien 5 TI-83 Premium CE Edition Python.
Enseignant(e), reçois gratuitement 1 exemplaire de test de la TI-82 Advanced Edition Python. À demander d'ici le 31 décembre 2024.
Aidez la communauté à documenter les révisions matérielles en listant vos calculatrices graphiques !
1234
-
Donations / Premium
For more contests, prizes, reviews, helping us pay the server and domains...
Donate
Discover the the advantages of a donor account !
JoinRejoignez the donors and/or premium!les donateurs et/ou premium !


Partner and ad
Notre partenaire Jarrety Calculatrices à acheter chez Calcuso
-
Stats.
4012 utilisateurs:
>3978 invités
>27 membres
>7 robots
Record simultané (sur 6 mois):
7582 utilisateurs (le 25/06/2025)
-
Other interesting websites
Texas Instruments Education
Global | France
 (English / Français)
Banque de programmes TI
ticalc.org
 (English)
La communauté TI-82
tout82.free.fr
 (Français)