Procedural Generation?

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
User avatar
Davidobot
Party member
Posts: 1226
Joined: Sat Mar 31, 2012 5:18 am
Location: Oxford, UK
Contact:

Procedural Generation?

Post by Davidobot »

Is there a way to procedurally generate terrain for example by adding on maps and stuff?
PM me on here or elsewhere if you'd like to discuss porting your game to Nintendo Switch via mazette!
personal page and a raycaster
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: Procedural Generation?

Post by Robin »

Yes. It's a trivial matter when you have Lua at your disposal (now good PG is a bit harder, that will require quite a lot of work, but then anything worth doing does).
Help us help you: attach a .love.
User avatar
paritybit
Citizen
Posts: 53
Joined: Thu Sep 06, 2012 3:52 am

Re: Procedural Generation?

Post by paritybit »

There is a lot of information available about procedural map generation, especially in the RogueLike forums and web sites. Here's an example of somebody who did it with Love2d and Lua.

But do a quick Google search with the key terms "procedural map generation", "lua" and "love2d" and you'll find many others. Your best bet is to learn Lua well and start by implementing an algorithm somebody else came up with ... then experiment until you have what you want.
User avatar
Roland_Yonaba
Inner party member
Posts: 1563
Joined: Tue Jun 21, 2011 6:08 pm
Location: Ouagadougou (Burkina Faso)
Contact:

Re: Procedural Generation?

Post by Roland_Yonaba »

Definitely yes. I was just looking at Anput.
User avatar
Inny
Party member
Posts: 652
Joined: Fri Jan 30, 2009 3:41 am
Location: New York

Re: Procedural Generation?

Post by Inny »

I wrote a few things that do procedural generation. The minicraft style terrain is done via some kind of smooth noise function, like perlin noise. I used a fractal technique (I forget the exact name) where it'll generate 4 random height values at the corners of the world, and then calculate the middle point's height as the average of the 4 plus some random factor. Then it recursively generates the mid point of the 4 quadrants contained. After writing the code, I wandered around in an infinitely generating world, looking at all of the 2d terrain, and realized how boring it was, so I stopped.

Here's the code for the random stuff. PlainMap (the superclass of Noisemap) is just a trivial 2d array define by width and height, that provides set and get functions that do range checking, so I'll omit it.

Code: Select all

NoiseMap = class( PlainMap )

function NoiseMap:init( x, y, w, h, c1, c2, c3, c4 )
  PlainMap.init(self, x, y, w, h)
  self.data = {}
  self:divide( x, y, self.width+1, self.height+1, c1, c2, c3, c4 )
end

function NoiseMap:displace( v )
  local max = v / (self.width + self.height) * 3
  return (math.random() - 0.5) * max
end

function NoiseMap:divide( x, y, w, h, c1, c2, c3, c4 )
  if w > 2 or h > 2 then
    local nW = w/2
    local nH = h/2
    local mid = ( c1 + c2 + c3 + c4 ) / 4 + self:displace(nW, nH)
    if mid < 0 then mid = 0 elseif mid > 1 then mid = 1 end

    local edge1 = (c1 + c2) / 2
    local edge2 = (c2 + c3) / 2
    local edge3 = (c3 + c4) / 2
    local edge4 = (c4 + c1) / 2

    self:divide(x, y, nW, nH, c1, edge1, mid, edge4);
    self:divide(x + nW, y, nW, nH, edge1, c2, edge2, mid);
    self:divide(x + nW, y + nH, nW, nH, mid, edge2, c3, edge3);
    self:divide(x, y + nH, nW, nH, edge4, mid, edge3, c4);
  else
    local c = (c1+c2+c3+c4)/4
    self:set( math.floor(x), math.floor(y), c )
  end
end
In order to make the world seamless, and dynamically generation: it divides up an endless 2d array into chunks, it pulls in the 8 surrounding chunks around the player's current chunk, and creates new chunks for nil blocks, picking the corners according to what existing chunks already have, or randomly generating whats missing. To produce an actual look, I cut the height map up so that the bottom of the range is water, the middle is dirt, the top is rock (muontain?).

It's a neat concept, maybe I'll package a love for it, but it's kinda dull overall.
coffee
Party member
Posts: 1206
Joined: Wed Nov 02, 2011 9:07 pm

Re: Procedural Generation?

Post by coffee »

Robin wrote:Yes. It's a trivial matter when you have Lua at your disposal (now good PG is a bit harder, that will require quite a lot of work, but then anything worth doing does).
And the question is also even more trivial when this forum is packed with a lot of threads about the subject and lots of examples of things being generated.
Even searching for that search.php?st=0&sk=t&sd=d&sr=posts&keyw ... eration%3F gives a lot to be entertaining.

BTW Davidbot I tried to check how your projects are going but your barturov site seems be gone.
User avatar
GijsB
Party member
Posts: 380
Joined: Wed Jul 20, 2011 10:19 pm
Location: Netherlands

Re: Procedural Generation?

Post by GijsB »

Inny wrote:I wrote a few things that do procedural generation. The minicraft style terrain is done via some kind of smooth noise function, like perlin noise. I used a fractal technique (I forget the exact name) where it'll generate 4 random height values at the corners of the world, and then calculate the middle point's height as the average of the 4 plus some random factor. Then it recursively generates the mid point of the 4 quadrants contained. After writing the code, I wandered around in an infinitely generating world, looking at all of the 2d terrain, and realized how boring it was, so I stopped
midpoint displacement technic ;)

i made one too :

3D

Code: Select all

math.randomseed(os.time())

sqaures ={
   {--one sqaure
      {0,0,math.random(1,4)},--left up
      {10,0,math.random(1,4)},--right up
      {0,10,math.random(1,4)},--left down
      {10,10,math.random(1,4)},--right down
   }
}
irritations = 9
rratio = 2^irritations
ratio = 2^irritations

function routine()
  	for i = 1,#sqaures do
      v = sqaures[i]
	  --make NEW points
      d = {--middle
         (v[1][1]+v[2][1]+v[3][1]+v[4][1])/4,--x
         (v[1][2]+v[2][2]+v[3][2]+v[4][2])/4,--y
         (v[1][3]+v[2][3]+v[3][3]+v[4][3])/4+math.random(-ratio,ratio)--z
      }
      np2 = {--top middle
         (v[1][1]+v[2][1])/2,
         (v[1][2]+v[2][2])/2,
         (v[1][3]+v[2][3])/2
      }
      np3 = {--right middle
         (v[2][1]+v[4][1])/2,
         (v[2][2]+v[4][2])/2,
         (v[2][3]+v[4][3])/2
      }
      np4 = {--bottom middle
         (v[3][1]+v[4][1])/2,
         (v[3][2]+v[4][2])/2,
         (v[3][3]+v[4][3])/2
      }
      np5 = {--left middle
         (v[1][1]+v[3][1])/2,
         (v[1][2]+v[3][2])/2,
         (v[1][3]+v[3][3])/2
      }
	  --make 4 sqaures of 1 with the new points
      s1 = {v[1],np2,np5,d}--left up
      s2 = {np2,v[2],d,np3}--right up
      s3 = {np5,d,v[3],np4}--left down
      s4 = {d,np3,np4,v[4]}--right down
	  --add sqaures, and delete the old one
      sqaures[i] = s1--old on replaced(deleted)
      table.insert(sqaures,s2)
      table.insert(sqaures,s3)
      table.insert(sqaures,s4)			 
	end
end

for i = 1,irritations do
routine()
ratio = ratio/2
end

imgData = love.image.newImageData(800,600)
for i,s in pairs(sqaures) do
	for i,p in pairs(s) do
		c = p[3]	
		if c < 0 then
			c = 0 
		end
		imgData:setPixel(p[1]*51, p[2]*51,c*(255/rratio),c*(255/rratio),c*(255/rratio), 255)
	end
end
img = love.graphics.newImage(imgData)
	
function love.draw()
   love.graphics.draw(img,0,0,0,1,1,0,0)
end
2D -- with smoothness

Code: Select all

function love.load()
	smoothness = 10
	iterations = 9
	points = {0,0}
	math.randomseed(os.time())
end

function love.draw()
	love.graphics.print("smoothness = "..smoothness ,10,10)
	for i = 1, #points - 1 do
		love.graphics.line(i, math.floor(points[i]+0.5)+250, i+1, math.floor(points[i+1]+0.5)+250)
	end
end

function love.keypressed(key)
	if key == "down" and smoothness > 1 then
		smoothness = smoothness - 1
		run()
	elseif key == "up" then
		smoothness = smoothness + 1
		run()
	end
end
		
function run()
	beginratio = math.floor((9^2-1)/(smoothness / 10))
	points = {0,0}
	for i = 1, iterations do
		routine()
		beginratio = beginratio/2
	end
end

function routine()
	add = 0
	for point = 1, #points do
		point = point+add
		if point >= #points then return end
		point1 = points[point]
		point2 = points[point+1]
		point3 = (point1+point2)/2+math.random(-beginratio,beginratio)
		table.insert(points, point+1, point3)
		add = add+1
	end
end
Post Reply

Who is online

Users browsing this forum: No registered users and 148 guests