Skip to content

Instantly share code, notes, and snippets.

@Bradshaw
Created October 8, 2012 14:56
Show Gist options
  • Save Bradshaw/3852957 to your computer and use it in GitHub Desktop.
Save Bradshaw/3852957 to your computer and use it in GitHub Desktop.
Génération de terrain par bruit interpolé dans Lua
--Décommenter la ligne suivante pour avoir un résultat différent à chaque utilisation.
--math.randomseed(os.time())
--Génération d'une "graine", on spécifie ici des variables aléatoires qui définiront le comportement de notre générateur de bruit
mults = {} -- Tableau de multiplicateurs
adds = {} -- Tableau de sommateurs?
for i = 1,20 do
mults[i] = math.random()*1000
adds[i] = math.random()*1000
end
-- Table qui contiendra nos fonctions de génération de bruit.
noise = {}
-- Fonction qui renvoie une valeur entre 0 et 1, depuis des coordonnées entières.
-- Chaque point d'un système de coordonnées quelquonque est lié à une valeur par cette fonction.
function noise.rand(n, dim)
if type(n)=="table" then
local d = 0
for i,v in ipairs(n) do
d = d+ (math.floor(v+adds[((i+v)%#adds)+1])*mults[((i+v)%#mults)+1])
end
return math.fmod(math.abs(math.sin(d)),1)
end
end
-- Pour faire une interpolation intéressante, il nous faut une fonction qui glisse de 0 à 1 en forme de S.
function noise.hermite(t)
return 6*t^5-15*t^4+10*t^3
end
-- Nous pouvons donc trouver une valeur entre a et b avec v le point mitoyen.
-- Si v == 0 on le retour est égal à b, pour v==1 le retour est égal à a
-- Entre les deux, on interpole joliment.
function noise.interp(a,b,v)
local h = noise.hermite(math.fmod(v,1))
return a*(1-h)+b*h
end
-- Simple fonction de clonage de tableau, avec multiplication de ses nombres
function noise.tabclone(t,val)
local t2 = {}
local val = val or 1
for k,v in pairs(t) do
if type(v)=="number" then
t2[k]=v*val
else
t2[k]=v
end
end
return t2
end
-- A partir de coordonnées dans a, crée des tables t qui sont évalués et interpolés
function noise.interGen(a,t)
local t = t or {}
if #a>=1 then
local t1 = noise.tabclone(t)
local t2 = noise.tabclone(t)
table.insert(t1,math.floor(a[1]))
table.insert(t2,math.floor(a[1]+1))
local ra = noise.tabclone(a)
table.remove(ra,1)
local r1 = noise.interGen(ra,t1)
local r2 = noise.interGen(ra,t2)
return noise.interp(r1,r2,a[1])
else
return noise.rand(t)
end
end
-- Fait une somme d'une série de bruits à des fréquences grandissantes et amplitudes déscendantes
function noise.octGen(t,o)
if o>=1 then
return noise.interGen(t)+noise.octGen(noise.tabclone(t,2),o-1)/2
else
return 0
end
end
-- Obtient une valeur qui suit l'augmentation d'amplitude avec l'ajout d'octaves
function noise.getmid(n,v)
local v = v or 2
if n<=1 then
return 1/v
else
return (1+noise.getmid(n-1))/v
end
end
-- Contiendra des fonctions de création de terrain procédural
local terrain = {}
-- Ici on se contente de mapper des valeurs différentes à différents charactères représentant des types de terrain.
function terrain.val(x,y,oct)
local oct = oct or 6
local v = noise.octGen({x,y},oct)
if v<noise.getmid(oct,2) then
return " " -- Eau
elseif v<noise.getmid(oct,1.7) then
return "." -- Plage
elseif v<noise.getmid(oct,1.5) then
return "," -- Plaines
elseif v<noise.getmid(oct,1.3) then
return "$" -- Forêt
else
return "#" -- Forêt noire
end
end
-- Ici un test de sortie
-- Niveau de zoom (les charactères d'un terminal sont plus haut que larges, alors je zoome différemment dans les deux sens)
xscale = 6
yscale = 12
-- Taille de la "fenêtre" qu'on va dessiner
tailleX, tailleY = 15,40
-- Niveau de détail, garder en dessous du niveau de zoom, sinon on fait des calculs inutiles.
oct = 3
-- Faire le haut de la boîte
io.write("+")
for i=1,tailleY do
io.write("-")
end
io.write("+\n")
-- Enregistrer le temps de départ
time = os.clock()
-- Créer une chaîne de charactères pour stocker les données
s = ""
-- Pour chaque ligne
for i=1,tailleX do
-- Faire le gauche de la boîte
s=s.."|"
-- Pour chaque colonne
for j = 1,tailleY do
-- Regarder la valeur de la case visée
s = s..terrain.val(i/xscale,j/yscale,oct)
end
-- Faire la droite de la boîte
s = s.."|\n"
end
-- Afficher le terrain et faire le bas de la boîte
io.write(s.."+")
for i=1,tailleY do
io.write("-")
end
io.write("+\n")
-- Afficher le nombre d'octaves et le temps total de calcul et affichage
print("Octaves: "..oct.."\nTime: "..os.clock()-time.."\n")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment