Created
October 8, 2012 14:56
-
-
Save Bradshaw/3852957 to your computer and use it in GitHub Desktop.
Génération de terrain par bruit interpolé dans Lua
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--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