Help On Procedural Generation

General discussion about LÖVE, Lua, game development, puns, and unicorns.
User avatar
Zilarrezko
Party member
Posts: 345
Joined: Mon Dec 10, 2012 5:50 am
Location: Oregon

Help On Procedural Generation

Post 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.
User avatar
Ulydev
Party member
Posts: 445
Joined: Mon Nov 10, 2014 10:46 pm
Location: Paris
Contact:

Re: Help On Procedural Generation

Post 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.
User avatar
Zilarrezko
Party member
Posts: 345
Joined: Mon Dec 10, 2012 5:50 am
Location: Oregon

Re: Help On Procedural Generation

Post 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
noise.png (38.51 KiB) Viewed 9898 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?
Wojak
Party member
Posts: 134
Joined: Tue Jan 24, 2012 7:15 pm

Re: Help On Procedural Generation

Post 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
Attachments
generator.love
(1.88 KiB) Downloaded 232 times
User avatar
Zilarrezko
Party member
Posts: 345
Joined: Mon Dec 10, 2012 5:50 am
Location: Oregon

Re: Help On Procedural Generation

Post 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.
Wojak
Party member
Posts: 134
Joined: Tue Jan 24, 2012 7:15 pm

Re: Help On Procedural Generation

Post 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
User avatar
Zilarrezko
Party member
Posts: 345
Joined: Mon Dec 10, 2012 5:50 am
Location: Oregon

Re: Help On Procedural Generation

Post 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
noise1.png (28.83 KiB) Viewed 9873 times
To this:
noise2.png
noise2.png (15.73 KiB) Viewed 9873 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.
Wojak
Party member
Posts: 134
Joined: Tue Jan 24, 2012 7:15 pm

Re: Help On Procedural Generation

Post 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.
User avatar
Zilarrezko
Party member
Posts: 345
Joined: Mon Dec 10, 2012 5:50 am
Location: Oregon

Re: Help On Procedural Generation

Post by Zilarrezko »

Played with some of the possibilities:
noise3.png
noise3.png (39.5 KiB) Viewed 9868 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
Wojak
Party member
Posts: 134
Joined: Tue Jan 24, 2012 7:15 pm

Re: Help On Procedural Generation

Post 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”).
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot] and 50 guests