Page 1 of 2
Help On Procedural Generation
Posted: Thu Jan 22, 2015 3:04 am
by Zilarrezko
So, for the past few days. I've been frantically looking for methods on procedural generation and random generation.
To be honest, I've found so much stuff on island generation, Dungeon and cave generation, and generation for platformer games. (Some of it is pretty interesting)
So I tried to sit down and think it through, but I'm so inexperienced in this area of concept that I have no idea on how to start.
What I trying to do so far is I'm doing a top down game, and I was looking for terrain generation that generates North, South, East, and West as an object/body travels in that direction.
I started with the idea of pages, that contain a square amount of tiles. Then a 2D array called world that contains pages. The problem I'm having here is how do I handle adding a page to the left, right, up, and down so that if a page is generated, it doesn't mess things up (like if I add a page to the left, then everything doesn't draw a whole nether page to the right [Hard to understand probably]) when it adds another row/column to the World array. To be honest if I can get this to work on it's own, I'd be ecstatic.
Another thing that made my head scratch is love.math.noise and how to use it. I messed around with it, and found that it isn't random(such as with a noise) but how to utilize it to make it random. Or even use for something that's more orderly, like a 2 step terrain (like RimWorld I guess, where you have a ground level, and a rock cliff type deal. Basically only 2 Z levels) but have something like a cliff face be more glob like where it looks natural.
This is very hard to explain, but I wouldn't ask if I wasn't frustrated with the subject and didn't want your guys' opinion.
Re: Help On Procedural Generation
Posted: Thu Jan 22, 2015 5:52 am
by Ulydev
Hello, Zilarrezko. I've also been looking for a method to implement infinite procedurally-generated maps in my game.
I'd recommend creating a two-dimensional array where generated tiles would be kept. Then, when you need to show them, you just have to loop through the part of the map you need.
love.math.noise is very ordered. All you need to do is :
-define a seed by yourself (ex : 40593) OR
-define a seed depending on os.time()
Once you have your seed, you must keep it all the time and use it to generate noise. This way, your terrain will always look ordered.
Here's what I use to generate tiles :
Code: Select all
local m = love.math
local value = m.noise(x*self.scale, y*self.scale, self.seed)
if value < 0.35 then --water
self[x][y] = {type="water", tile = self.tiles["water"], color = {255, 255, 255}}
elseif value < 0.45 then --sand
self[x][y] = {type="sand", tile = self.tiles["sand"], color = {255, 255, 255}}
elseif value < 0.6 then --ground
self[x][y] = {type="ground", tile = self.tiles["ground"], color = {255, 255, 255}}
elseif value < 0.75 then --forest
self[x][y] = {type="forest", tile = self.tiles["forest"], color = {255, 255, 255}}
else --mountain
self[x][y] = {type="mountain", tile = self.tiles["mountain"], color = {255, 255, 255}}
end
By checking the "height" of the noise, you can assign a tile type to each value.
Re: Help On Procedural Generation
Posted: Thu Jan 22, 2015 6:54 am
by Zilarrezko
I see, using the 3 dimensional noise and a seed as a Z is pretty clever.
Looks like a good base, though a little too random for my taste. I could probably think of some things to make a clump of mountain tiles be together, and surround and all water tiles with sand, and keep mountain tiles away from sand tiles and make a group of forest tiles. Though I think I would hit a wall very quickly.
Unfortunately it still looks like noise.
- noise.png (38.51 KiB) Viewed 11187 times
And I think I see where you are going with the scale. If I had a X scale and a Y scale, I still do a pages concept and every page, let's say to the right I would just have XScale + 1 and I would guess it would continue the generation seamlessly. But I don't think that's how noise works, and I still might get something like a cliffside of a mountain gets truncated and ends up straight into a water tile or something like that.
I don't know about you, but when you have a very high number for the seed, does the noise value just end up being 0.5 for you?
Re: Help On Procedural Generation
Posted: Thu Jan 22, 2015 7:03 am
by Wojak
This may be a thing that matches Your description:
viewtopic.php?p=58621#p58621
It builds a top down map with prefabricated blocks sticking a “matching” block to all the “open” corridors until there is any space on the map.
The North, South, East, and West open corridors all have a list of blocks that may connect to them.
The code is a horrible mess...
In case non of the version from that topic works I uploaded the 0.9.+ compatible version.
But if You are for looking a way to generate something from random noise, then this is a way to go:
http://www.raywenderlich.com/66062/proc ... ton-part-1
Re: Help On Procedural Generation
Posted: Thu Jan 22, 2015 7:26 am
by Zilarrezko
Actually that second link is exactly what I was imagining my end product of what the terrain generation would look like for cliff faces and ground. I'm not sure how I can implement it into seamless procedural generation, but it's definitely a good start. Can't wait to translate the code.
Although, I don't think I'm looking for your algorithm you made there (The l2d forum post you made there). It would be a good dungeon creator, and I may look through the code for some references on chucks and implementing them better.
Re: Help On Procedural Generation
Posted: Thu Jan 22, 2015 7:45 am
by Wojak
to simplify the 2 link:
1) create an implementations of life like cellular automata algorithm (Conway's game of life)
2) Apply a s345678b5678 rule (cells survive if they have 3 or more neighbors and are born with 5 or more)
3) Run the algorithm for about 5 steps on a noise in winch about 45% of the “cells” are “alive”.
4) some post processing if you need it
Re: Help On Procedural Generation
Posted: Thu Jan 22, 2015 8:29 am
by Zilarrezko
Wojak wrote:to simplify the 2 link:
1) create an implementations of life like cellular automata algorithm (Conway's game of life)
2) Apply a s345678b5678 rule (cells survive if they have 3 or more neighbors and are born with 5 or more)
3) Run the algorithm for about 5 steps on a noise in winch about 45% of the “cells” are “alive”.
4) some post processing if you need it
Could anyone ask for a more simplified explanation? Excellence man, +2 to you.
From this:
- noise1.png (28.83 KiB) Viewed 11162 times
To this:
- noise2.png (15.73 KiB) Viewed 11162 times
It's interesting. Though I find it interestingly huging the edges of the map (the edges are the screen), Not sure why it's happening. But it may or may not be a good thing once I add in page generation.
Pretty much the most progress I've made in a couple weeks.
Re: Help On Procedural Generation
Posted: Thu Jan 22, 2015 9:18 am
by Wojak
Zilarrezko wrote:
It's interesting. Though I find it interestingly huging the edges of the map (the edges are the screen), Not sure why it's happening. But it may or may not be a good thing once I add in page generation.
I think I can explain this as well. Basically this algorithm makes the more dens parts of the noise into walls and less dense parts into empty spaces, so if you will treat the edge of the world as solid (alive) the pattern will be attracted to it, but if you treat it as empty space (dead) then the pattern should avoid it.
Re: Help On Procedural Generation
Posted: Thu Jan 22, 2015 9:22 am
by Zilarrezko
Played with some of the possibilities:
- noise3.png (39.5 KiB) Viewed 11157 times
Right as I was writing this, you responded. I wasn't treating the edges as alive. Something weird I think, I had the 45% thing switched. But it might have been more than that.... If someone wants the source code. Here it is. (Copied directly, sorry if some API is weird)
Code: Select all
function love.load(arg)
function GenerateWorld()
World = {}
for X = 1, 160 do
World[X] = {}
for Y = 1, 90 do
local Value = randomInt(0, 100)
if Value < 45 then
World[X][Y] = {Alive = true}
else
World[X][Y] = {Alive = false}
end
end
end
WorldTimer = 0
WorldUpdateCounter = 0
end
WorldTimer = 0
WorldTimerLimit = 0.001
WorldUpdateCounter = 0
WorldUpdateLimit = 2
GenerateWorld()
end
function love.update(dt)
if WorldUpdateCounter ~= WorldUpdateLimit and WorldTimer >= WorldTimerLimit then
for X = 1, #World do
for Y = 1, #World[X] do
local Tile = World[X][Y]
local NeighborsAlive = 0
for I = 0, 9 do
if I ~= 4 then
XI = math.floor(I%3) - 1
YI = math.floor(I/3) - 1
if World[X+XI] and World[X+XI][Y+YI] and World[X+XI][Y+YI].Alive then
NeighborsAlive = NeighborsAlive + 1
end
end
end
if Tile.Alive and NeighborsAlive < 3 then
World[X][Y].Alive = false
end
if not Tile.Alive and NeighborsAlive > 5 then
World[X][Y].Alive = true
end
end
end
WorldTimer = WorldTimer - WorldTimerLimit
WorldUpdateCounter = WorldUpdateCounter + 1
end
WorldTimer = WorldTimer + dt
end
function love.render(dt)
for X = 1, #World do
for Y = 1, #World[X] do
local Tile = World[X][Y]
if Tile.Alive then
graphics.setColor(255, 255, 255)
else
graphics.setColor(100, 100, 100)
end
graphics.rectangle("fill", (X-1) * 8, (Y-1) * 8, 8, 8)
end
end
end
function love.keypressed(key)
if key == " " then
GenerateWorld()
end
end
Re: Help On Procedural Generation
Posted: Thu Jan 22, 2015 9:57 am
by Wojak
The rules you use aren't the same as in the tutorial:
Code: Select all
if Tile.Alive and NeighborsAlive <= 3 then
World[X][Y].Alive = false
end
if not Tile.Alive and NeighborsAlive >= 5 then
World[X][Y].Alive = true
end
And yes – with the way you handle the edges of the map it shouldn't “hug” the edges (but it's RNG do sometimes it may look that it is).
Though the tutorial suggests 45% nothing should stop you from experimenting with this ratio.
Also you can use combinations of different rules (few steps of this one and than few steps of something erosive like “nothing is born and if it has less then 7 neighbors it dies”).