Land generator for my game - please criticize

Miscellaneous Forums/General Discussion/Land generator for my game - please criticize

[edit] Last updated Feb 19 3:00 AM

Alright, I've banged together an early build of a terrain
generator I'm going to use for my game. Here are some very
early
shots of what it does so far. Please note that
everything is done procedurally, including(especially) the
rock texture itself. It means changes are very hard to
implement, but it's also a source of infinite textures! You
can't go wrong with that!



I would appreciate if some of you guys could run my code and
maybe tell me what you think? Or what you'd change? Or what
you hate?

I think it's a good start, but the colours need tweaking and
it might be a little bit too rocky. But nothing's for sure yet.

Here's an Exe (887Kb) and here's the Bmax source:
SuperStrict
Graphics 800, 600,,-1
'Include "drawthings.bmx"
SeedRnd MilliSecs()

Type rgbType
	Field r:Float, g:Float, b:Float
EndType

Local y:Float, y1:Float
Local averageY:Int, totalY:Int
Local initialMap:Int[800,600]
Local texture:Int[800, 600]
Local palette:rgbType[600]

For Local a:Int = 0 To 599
	palette:rgbType[a] = New rgbType
Next
'drawSky(initialMap, initialMap, Rand(5))
'drawBGHills(averageY)
paletteIndex(palette)

wait("Initializing...")
makeTexture(texture)


HideMouse
SetClsColor 20, 10, 40
Cls
Repeat
'	wait("Drawing...")
	For Local x:Int = 0 To 799
		For Local y:Int = 0 To 599
			initialMap[x,y]=0
		Next
	Next
	y = Rand(500)+50
	SetColor 20, 70, 10
	For Local x:Int = 0 To 799
		For Local yy:Int = y To 599
			Plot x,yy
			initialMap[x,yy]=255
		Next
		y:+y1
		totalY:+y
		y1:+(RndFloat()-.5)*.1
		If Rand(20)=1 Then y1:+ (RndFloat()-.5)
		If Abs(y1) > 2 Then y1=0
		If y1<-2 Then End
		If y <90 Then
			y1:+RndFloat()*.1
			If y< 45 Then y1 = RndFloat()*.3
		EndIf
		If y >580 Then 
			y1:-RndFloat()*.03
			If y> 590 Then y1 = -RndFloat()*.3
		EndIf
	Next
	averageY = totalY/800
	If averageY >200 Then			'draw floating platform (horizontal)
		Local platforms:Int = Rand(3)
		If averageY > 400 Then platforms:+2
		If averageY > 500 Then platforms:+4
		For Local aa:Int = 1 To platforms
			Local middleY:Int
			Local thickness:Int  = Rand(40)+10
			Local xStart:Int = Rand(800)-100, xLength:Int = Rand(250)+20
			Local yTop:Float = Rand(500 - averageY *.5)+120, yBottom:Float = yTop+Rand(10)+2
			Local yTop1:Float= -RndFloat()*2, yBottom1:Float = RndFloat()*2
			Local x:Int = xStart
			Repeat
				SetColor 20, 70, 10
				For Local y:Int = yTop To yBottom
					Plot x,y
					If x> -1 And y>-1 And y< 600 initialMap[x,y] = 255
				Next
				yTop:+yTop1
				yBottom:+yBottom1
				yBottom1:+(RndFloat()-.5)*.2
				yTop1:+(RndFloat()-.5)*.2
				If x > xStart+xLength Then yBottom1:-RndFloat(); yTop1:+RndFloat()
				If x = Int(xLength*.5+xStart) Then middleY = (yBottom+yTop)*.5
				If x Mod 6 = 1 Then
					If yBottom-yTop < 20 Then yTop1:-(RndFloat())*.2
					If yBottom-yTop > thickness Then yTop1:+(RndFloat())*.2
					If Abs(yTop1) > 1 Then yTop1:*RndFloat()
					If Abs(yBottom1) > 1 Then yBottom1:*RndFloat()
				EndIf
				x:+1
			Until yBottom<yTop Or x>799
			x = xLength*.5+xStart
			Local xLeft:Float, xRight:Float, xLeft1:Float, xRight1:Float
		Next
	EndIf
	Local lowResMap:Int[20, 15]
	For Local y:Int = 0 To 14
		For Local x:Int = 0 To 19
			If initialMap[x*40, y*40] = 255 Then 
				lowResMap[x,y] = 255
			Else
				lowResMap[x,y] = 0
			EndIf
		Next
	Next
	Local carvedMap:Int[800,600]
	For Local y:Int = 0 To 599
		For Local x:Int = 0 To 799
			carvedMap[x, y] = initialMap[x, y]
		Next
	Next
	Local xOffset:Int[14]
	'this code tests the bottom of the screen to see if there's enough terrain to create a cave
	For Local xx:Int = 1 To 18
		Local yy:Int = 14-Rand(4)
		SetColor 200, 200, 200
		'if we hit earth, then try to draw a cave system.  We'll start with the vertical shafts
		If lowResMap[xx,yy] = 255 Then
			For Local a:Int = 0 To 13
				xOffset[a] = 0
			Next
			Local xOffVar:Int
			For Local y:Int = 0 To 10
				SetColor 100, 0, 0
				xOffset[y] = xOffVar
				xOffVar:+Rand(3)-2
				If xx+xOffset[y]< 1 Then xOffVar:+1
				If xx+xOffset[y]> 18 Then xOffVar:-1
				If y carve (carvedMap, (xx+xOffset[y])*40+20, (yy-y)*40+20, (xx+xOffset[y-1])*40+20, (yy-y+1)*30+20)', 40+Rand(30))
				If lowResMap[xx+xOffset[y],yy-y] = 0 Or (y> 4 And Rand(5) = 1)Then Exit
				'This endif contains the code that branches the tunnels out horizontally from the shafts
				If Rand(4) = 1 Then
					Local yOffset:Int= 0, length:Int = Rand(5)+1, direction:Int = 1
					If Rand(2) = 1 Then direction = -1
					Local a:Int =0, oldx:Int, oldy:Int
					Repeat
						oldx = xx+xOffset[y]+a*direction
						oldy = yy-y+yOffset
						If oldX < 1 Or oldX > 19 Or oldY > 14 Then Exit
						If lowResMap[oldX, oldY] = 0 Then Exit
						oldX:*40
						oldY:*40
						If Rand(3) = 1 yOffset:+Rand(3)-2
						a:+1
						carve (carvedMap, oldX, oldY, (xx+xOffset[y]+a*direction)*40, (yy-y+yOffset)*40)', 30+Rand(30))
					Until a = length
				EndIf
			Next
			SetLineWidth 1
			xx:+2+Rand(4)
		EndIf
	Next
	SetColor 200, 200, 170
	DrawText "hit P to process this terrain, any other key to start over", 10, 10
	For Local y:Int = 0 To 14
		For Local x:Int = 0 To 19
			If lowResMap[x,y] = 255 Then Plot x*40, y*40
		Next
	Next
	Flip; WaitKey
	If KeyDown(key_p) Then wait("Cleaning...") Else wait("Drawing...")
	
	'this smooths the landscape
	If KeyDown(key_p) Then
		Local col:Int
		For Local b:Int = 0 To 2
			For Local y:Int = 1 To 598
				For Local x:Int = 1 To 798
					col:+ carvedMap[x-1,y]
					col:+ carvedMap[x+1,y]
					col:+ carvedMap[x,y-1]
					col:+ carvedMap[x,y+1]
					col:/4
					carvedMap[x,y] = col
				Next
				col = 0
			Next
		Next
		For Local y:Int = 0 To 599
			For Local x:Int = 0 To 799
				If carvedMap[x, y] < 100 Then
					carvedMap[x, y] = 0
					If initialMap[x, y] = 255 Then
						SetColor 40+Rand(10), 30+Rand(10), 20
						Plot x, y
					EndIf
				Else
					carvedMap[x, y] = 255
					SetColor 20+Rand(10), 70+Rand(10), 10
					Plot x, y
				EndIf
			Next
		Next
		DrawText "This is the finished texture mask.  Hit any key to texture.", 10, 10
		SetColor 120, 100, 30
		'drawl 1, 1, 798, 598, 2, BOX
		Flip;	WaitKey
		wait("Texturing...")
		texturize(carvedMap, initialMap, texture, palette)
		drawSky(carvedMap, initialMap, Rand(5))
		drawBGHills(averageY, carvedMap, initialMap, texture, palette)
		SetColor 200, 200, 200
		DrawText "Texturing technique - early version.  Hit P to try random new colours", 10, 10
		Flip;FlushKeys()
		Repeat
			WaitKey
			If KeyDown(key_p) Then
				wait("New colours...")
				paletteIndex(palette)
				texturize(carvedMap, initialMap, texture, palette)
				drawSky(carvedMap, initialMap, Rand(5))
				drawBGHills(averageY, carvedMap, initialMap, texture, palette)
				SetColor 255, 255, 255
				DrawText "Texturing technique - early version.  Hit P to try random new colours", 10, 10
				Flip;FlushKeys()
			Else
				Exit
			EndIf
		Forever
		Flip;Cls
		wait("Redrawing...")
	EndIf
	totalY=0
Until KeyDown(key_escape)
Cls
End


Function wait(text:String)
		Local width:Int = TextWidth(text)* 3
		Flip
		SetScale 3, 4
		SetColor 50, 30, 30
		DrawText text, 400-width*.5, 200
		SetColor 200, 200, 200
		DrawText text, 403-width*.5, 203
		SetScale 1, 1
		Flip;Cls
EndFunction

Function makeTexture(texture:Int[,] Var)
	SetClsColor 90, 90, 90
	Cls
	Local y:Int, x:Int, xSize:Float, ySize:Float, size:Float
	Local shade:Int, baseShade:Int, xDraw:Int, yDraw:Int
	For y = 576 To 600
		For x = 0 To 800
			shade = Rand(30)+66
			SetColor shade, shade, shade
			DrawOval x+Rand(5), y-Rand(Rand(40)+10), 2, 2
		Next
	Next
	SetBlend ALPHABLEND
	For Local b:Int = 0 To 2700
		x = Rand(800)
		y = Rand(470)
		If Rand(3) = 1 Then
			xSize = Rand(14)+10
			ySize = Rand(14)+10
		Else
			xSize = Rand(40)+20
			ySize = Rand(40)+20
		EndIf
		If b< 500 And Rand(2) = 1 Then
			xSize = Rand(90)+50
			ySize = Rand(90)+50
		EndIf
		baseShade:Int = 70+Rand(40)
		If b> 900 Then
			y = 599-Rand(Rand(60)+10)
			xSize = Rand(5)+2
			ySize = Rand(5)+2
			baseShade:Int = 60+Rand(20)
		EndIf
		size = (xSize+ySize)*.5																					'get an average
		For Local scale:Float = 1.0 To (RndFloat()-.5)*.3+.2 Step -.06		'draw the stone
			shade = baseShade-(20*scale)
			SetColor shade, shade, shade
			xDraw = xSize*scale
			yDraw = ySize*scale
			DrawOval x-xDraw*.3, y-yDraw*.3, xDraw, yDraw
		Next
	Next
	SetAlpha .4
	For y = 0 To 570 Step 6																						'small rocks all over
		For x = 0 To 800 Step 6
			shade = Rand(50)+60
			SetColor shade, shade, shade
			DrawOval x+Rand(20)-10, y+Rand(20)-10, Rand(4)+3, Rand(4)+3
		Next
	Next
	SetAlpha .4
	For y = 0 To 570 Step 3																						'more and smaller rocks
		For x = 0 To 800 Step 3
			shade = Rand(50)+60
			SetColor shade, shade, shade
			DrawOval x+Rand(20)-10, y+Rand(20)-10, Rand(3)+1, Rand(3)+1
		Next
	Next
	SetAlpha 1.0
	Local image:timage = CreateImage(800, 600, DYNAMICIMAGE)
	GrabImage image, 0, 0
	Local sample:Int
	Local pixmap:TPixmap = LockImage(image)
	For Local x:Int = 0 To 799
		For Local y:Int = 0 To 599
			sample = ReadPixel (pixmap, x, y)
			sample = (sample Shl 8) Shr 24						'since source is B&W, I can use just the red channel to get the brightness value
			texture[x, y] = sample '+Rand(15)-8
'			SetColor sample, sample, sample
'			Plot x, y
		Next
	Next
	Return																					'rem for debug
	DrawImage image, 0, 0
	Flip
	WaitKey
	End
	Cls
EndFunction

Function texturize(foreGround:Int[,] Var, backGround:Int[,] Var, texture:Int[,], set:rgbType[] Var)
	Local r:Int, g:Int, b:Int, fade:Float
	Local subSurface:Int = 0, subCaveFloor:Int = 0
	' the deeper under the surface we are, the higher subSurface will be
	For Local x:Int = 0 To 799
		subSurface = 0
		r = 0
		g = 0
		b = 0
		Local setNum:Int
		For Local y:Int = 0 To 599
			If foreGround[x, y] = 255 Or backGround[x, y] = 255 Then	'if I hit either BG or foreground, I'm gonna draw a pixel
				setNum = subSurface+texture[x,y]-75
				If setNum>599 setNum = 599 - Rand(6)
				If setNum<0 setNum = Rand(6)
				r = set[setNum].r
				g = set[setNum].g
				b = set[setNum].b
'				Local yy:Int
'				yy = subSurface
'				If yy > 599 Then Continue
'				r:+ texture[x, yy] -Rand(5)
'				g:+ texture[x, yy] -Rand(5)
'				b:+ texture[x, yy] -Rand(5)
				If foreGround[x, y] = 0 Then														'but if there's no FG
					r:*.3
					g:*.2
					b:*.1
					If backGround[x, y]  Then
						If subCaveFloor< 20 subCaveFloor:+1
					EndIf
				Else
					If subCaveFloor > 0 Then
						fade = subCaveFloor/20.0		'these 4 lines create a crossfade between two colours of pixel
						r = texture[x, 579+subCaveFloor]*fade + r*(1-fade)
						g = texture[x, 579+subCaveFloor]*fade + g*(1-fade)
						b = texture[x, 579+subCaveFloor]*fade + b*(1-fade)
					EndIf
					subCaveFloor:-1
					If subCaveFloor< 0 Then subCaveFloor = 0
				EndIf
				SetColor r, g, b
				Plot x, y
				subsurface:+1
			Else
				subCaveFloor = 0
				subsurface:-2
				If subSurface < 0 Then subSurface = 0
			EndIf
		Next
	Next
EndFunction

Function carve(collisionMap:Int[,] Var, xStart:Int, yStart:Int, xEnd:Int ..
							, yEnd:Int, size:Int = 45, variance:Int = 15, steps:Int = 8)
	Local yDist:Int = yEnd-yStart, xDist:Int = xEnd-xStart
	Local x:Float = xStart, y:Float = yStart, a:Int, xSize:Int, ySize:Int, xOffset:Int, yOffset:Int
	Repeat
		xSize = size+Rand(variance)-(variance*.5)
		ySize = size+Rand(variance)-(variance*.5)
		xOffset = Rand(variance)-(variance*.5)
		yOffset = Rand(variance)-(variance*.5)

		DrawOval x - xSize * .5 - xOffset, y - ySize * .5 - yOffset, xSize, ySize
		x:+xDist/steps
		y:+yDist/steps
		a:+1
	Until a > steps
	Local yMin:Int, yMax:Int, xMin:Int, xMax:Int
	xMin = xStart-size
	xMax = xEnd+size
	If xStart>xEnd Then xMin = xEnd-size; xMax = xStart+size
	yMin = yStart-size
	yMax = yEnd+size
	If yStart>yEnd Then yMin = yEnd-size; yMax = yStart+size
	If yMax>599 yMax = 599
	If xMax>799 xMax = 799
	Local image:timage = CreateImage (Abs(xMax-xMin), Abs(yMax-yMin), DYNAMICIMAGE)
	GrabImage image, xMin, yMin
	Local pixmap:TPixmap = LockImage (image)
	Local argb:Int, r:Int, g:Int, b:Int
	For Local y:Int = 0 To pixmap.height-1
		For Local x:Int = 0 To pixmap.width-1
			argb = ReadPixel (pixmap, x, y)
			r = (argb Shl 8) Shr 24
			g = (argb Shl 16) Shr 24
			b = (argb Shl 24) Shr 24
			If r > 80 And g < 20 And b < 20 Then 
				If xMin+x > 799 Or xMin+x<0 Or yMin+y > 599 Or yMin+y<0 Then Continue
				If collisionMap[xMin+x, yMin+y] = 255 Then 
					collisionMap[xMin+x, yMin+y] = 0
				EndIf
			EndIf
		Next
	Next
	UnlockImage(image)
	image = Null
EndFunction

Function paletteIndex(set:rgbType[] Var)
	For Local a:Int = 0 To 599
		set[a].r = 0;	set[a].g = 0; set[a].b = 0
	Next
	Local blah:Int = Rand (4)
'	blah = 2			'debug
	Select blah
	Case 1
		set[000].r = 40;	set[000].g = 100; set[000].b = 20
		set[020].r = 20;	set[020].g = 50;	set[020].b = 10
		set[022].r = 50;	set[022].g = 50;	set[022].b = 30
		set[080].r = 130;	set[080].g = 120;	set[080].b = 110
		set[082].r = 160;	set[082].g = 160;	set[082].b = 160
		set[089].r = 100;	set[089].g = 100;	set[089].b = 100
		set[095].r = 140;	set[095].g = 120;	set[095].b = 100
		set[150].r = 60;	set[150].g = 50;	set[150].b = 30
		set[155].r = 100;	set[155].g = 90;	set[155].b = 90
		set[180].r = 80;	set[180].g = 90;	set[180].b = 90
		set[215].r = 150;	set[215].g = 150;	set[215].b = 150
		set[225].r = 150;	set[225].g = 150;	set[225].b = 150
		set[280].r = 30;	set[280].g = 30;	set[280].b = 20
		set[290].r = 50;	set[290].g = 50;	set[290].b = 50
		set[380].r = 20;	set[380].g = 20;	set[380].b = 20
		set[580].r = 255;	set[580].g = 190;	set[580].b = 70
		set[599].r = 255;	set[599].g = 255;	set[599].b = 255
	Case 2
		set[000].r = 200;	set[000].g = 200;	set[000].b = 220
		set[010].r = 150;	set[010].g = 150;	set[010].b = 150
		set[020].r = 60;	set[020].g = 60;	set[020].b = 60
		set[026].r = 040;	set[026].g = 020;	set[026].b = 020
		set[100].r = 060;	set[100].g = 040;	set[100].b = 040
		set[190].r = 150;	set[190].g = 150;	set[190].b = 140
		set[220].r = 60;	set[220].g = 60;	set[220].b = 60
		set[229].r = 50;	set[229].g = 25;	set[229].b = 25
		set[325].r = 40;	set[325].g = 40;	set[325].b = 40
		set[355].r = 30;	set[355].g = 16;	set[355].b = 16
		set[500].r = 190;	set[500].g = 170;	set[500].b = 150
		set[510].r = 90;	set[510].g = 90;	set[510].b = 90
		set[599].r = 2;	set[599].g = 2;	set[599].b = 2
	Case 3
		set[000].r = 220;	set[000].g = 220;	set[000].b = 220
		set[020].r = 220;	set[020].g = 210;	set[020].b = 170
		set[110].r = 90;	set[110].g = 100;	set[110].b = 100
		If Rand(2) = 1 Then
			set[200].r = 40;	set[200].g = 40;	set[200].b = 40
			set[210].r = 50;	set[210].g = 45;	set[210].b = 45
			set[280].r = 80;	set[280].g = 80;	set[280].b = 70
			set[290].r = 21;	set[290].g = 21;	set[290].b = 21
			set[350].r = 50;	set[350].g = 50;	set[350].b = 50
		Else
			set[220].r = 60;	set[220].g = 60;	set[220].b = 60
			set[230].r = 160;	set[230].g = 160;	set[230].b = 160
			set[240].r = 60;	set[240].g = 60;	set[240].b = 60
		EndIf
		set[599].r = 20;	set[599].g = 10;	set[599].b = 7
	Case 4
		set[000].r = 235;	set[000].g = 235;	set[000].b = 255
		set[002].r = 235;	set[002].g = 235;	set[002].b = 255
		set[013].r = 120;	set[013].g = 120;	set[013].b = 140
		set[031].r = 100;	set[031].g = 100;	set[031].b = 100
		set[048].r = 60;	set[048].g = 46;	set[048].b = 46
		set[142].r = 100;	set[142].g = 100;	set[142].b = 110
		set[330].r = 50;	set[330].g = 30;	set[330].b = 30
		set[340].r = 60;	set[340].g = 50;	set[340].b = 40
		set[599].r = 05;	set[599].g = 05;	set[599].b = 05	
	EndSelect

	colourize(set)

	Cls;Return																											'rem for debug
	For Local a:Int = 0 To 599
		SetColor set[a].r, set[a].g, set[a].b
		DrawLine 50, a, 300, a
	Next
	Flip;WaitKey;End
EndFunction

Function colourize(set:rgbType[] Var)								'set is a 1 dimensional array of rgb objects.  Used to hold indexed colour.
	Local start:Int = 0, stop:Int, a:Int = start
	Repeat
		a:+1
		If set[a].r > 0 Or set[a].g > 0 Or set[a].b > 0 Then 
			SetColor 70, 70, 100
			DrawLine 0,a,800, a
			SetScale .9, .9
			SetColor 170, 170, 100
			DrawText a+" r"+Int(set[a].r)+" g"+Int(set[a].g)+" b"+Int(set[a].b), 300+Rand(400), a - 6
			SetScale 1, 1
			stop = a
			Local steps:Int = stop - start
			For Local b:Int = 0 To steps
				set[start+b].r = set[start].r + (set[stop].r-set[start].r)/steps*b
				set[start+b].g = set[start].g + (set[stop].g-set[start].g)/steps*b
				set[start+b].b = set[start].b + (set[stop].b-set[start].b)/steps*b
			Next
			start = stop
		EndIf
		If a>598 Then Return
	Forever
EndFunction

Function drawSky(carvedMap:Int[,] Var, initialMap:Int[,] Var, sky:Int)
	Local x:Int, y:Int, a:Int
	Local r:Float, g:Float, b:Float, r1:Int, r2:Int, g1:Int, g2:Int, b1:Int, b2:Int 
	Local arc:Int, xOff:Int, yOff:Int, wavelength:Int 
'	Repeat																'debug
'	sky = 5
	Select sky
		Case 1
			r1 = 040; g1 = 000; b1 = 000
			r2 = 90; g2 = 90; b2 = 190
			arc = 500- Rand(300); xOff = -Rand(160); yOff = 20+Rand(90)
			wavelength = 5
		Case 2
			r1 = 140; g1 = 140; b1 = 200
			r2 = 20; g2 = 0; b2 = 0
			arc = 500- Rand(300); xOff = -Rand(160); yOff = 20+Rand(90)
			wavelength = 5
		Case 3
			r1 = 100; g1 = 100; b1 = 220
			r2 = 240; g2 = 180; b2 = 180
			arc = 500- Rand(300); xOff = -Rand(160); yOff = 20+Rand(90)
			wavelength = 3
		Case 4
			r1 = 130; g1 = 100; b1 = 220
			r2 = 200; g2 = 180; b2 = 100
			arc = 200; xOff = -Rand(160); yOff = 140+Rand(30)
			wavelength = 3
		Case 5
			r1 = 100; g1 = 20; b1 = 20
			r2 = 20; g2 = 20; b2 = 70
			arc = 200- Rand(100); xOff = -Rand(160); yOff = 20+Rand(30)
			wavelength = 3
	EndSelect
	For x = 0 To 799
		Local yCurve:Int = Cos(x/wavelength-xOff)*arc
		For y = 0 To 599
			If carvedMap[x,y] = 255 Or initialMap[x, y] Then Continue
			a = (y-yCurve)/6-yOff
			r = (y/599.0)*(r2-r1)+r1
			g = (y/599.0)*(g2-g1)+g1
			b = (y/599.0)*(b2-b1)+b1
			r:+a - Rand(8)
			g:+a - Rand(8)
			b:+a - Rand(8)
			SetColor r, g, b
			Plot x, y
		Next
'		SetColor 55, 55, 55
'		Plot x, 400-a*2
	Next
	Return
	Flip;WaitKey
	If KeyDown(key_escape) End
'	Forever												'debug
	End
EndFunction

Function drawBGHills(averageY:Int Var, carvedMap:Int[,] Var, initialMap:Int[,] Var, texture:Int[,] Var, set:rgbType[] Var)
	'Local lastY:Int[800]
'	averageY = 300
	SetAlpha .3
	If averageY < 200 Then averageY = 200
	Local y:Float, y1:Float, currentY:Int, layers:Int, setNum:Int, r:Int, g:Int, b:Int, texOff:Int
'	Repeat
		'Cls
		currentY = averageY
		layers = 1 + Rand(4)
		For Local t:Int = 0 To layers
			y1 = 0
			y = currentY + Rand(30)-15
			texOff = Rand(200)
			For Local x:Int = 0 To 799
				For Local yy:Int = y To 599
					If carvedMap[x,yy] = 255 Or initialMap[x,yy] = 255 Then Continue
					setNum = texture[x,yy-y]+texOff
					If setNum>599 setNum = 599 - Rand(6)
					If setNum<0 setNum = Rand(6)
					r = set[setNum].r
					g = set[setNum].g
					b = set[setNum].b
					r = r *(0.4+t*.1) + 10 + (yy - currentY)*.4
					g = g *(0.4+t*.1) + 10 + (yy - currentY)*.4
					b = b *(0.4+t*.1) + 19 + (yy - currentY)*.4
					SetColor r, g, b
					Plot x, yy
				Next
				'lastY[x] = y
				y:+y1
				y1:+(RndFloat()-.5)*.1
				If y > currentY+ 90 Or y > 560 Then y1:-RndFloat()*.03
				If y < currentY-90 Or y < 200 Then y1:+RndFloat()*.03
				If Rand(40) = 1 Then y1:*.7
			Next
			currentY:+ 40+Rand(40)
		Next
		SetAlpha 1
'		DrawText y, 10, 10
'		Flip;WaitKey
'	Until KeyDown(key_escape)
'	End
EndFunction


My goal is to beat the awesomeness of my old map generator but it's proven to be surprisingly hard! Lol.

That's pretty sweet. The old demo rocks and only looks better, IMO, because it's at a lower res. When you've textured the caverns and sky it'll look awesome.

Are you planning on making it scrollable and having buildings? Is this gonna be like liero or something similar?

Love the beaker demo too.

Thanks, man. Speak of the Devil, I am right now writing code
to generate a cityscape. I'm pretty happy with it so far.

About the scrolling: I really, really want to do that, but I
need to limit myself to the simplest design possible or I fear
I might get in over my head (once again, wouldn't be a surprise).
Too many projects in the past have been abandoned because they
became too much to handle.

In the future though, for sure.

Nice. Worms?

yeah, I thought of worms straight away. Are you having these terrains being destructable.

Dude, totally keep us updated of your progress. One of my all time dream games revolves around your game's current state. Suppose you can get the same landscape from a seed?

Hey, good progress Drew. The first thing I notice is that it reminds me of low-resolution limited-color-palette landscapes that you would've seen on the Amiga, for example. It's not so much that the textural quality is bad, but that it looks as though there are only a limited number of colors in what looks to be a `scattered` arrangement. It seems as though the grass has the same blotchyness as the rock, which you'd think would have a different textural quality. Although the color changes are nice, the fact that every `layer` of earth has the same `pattern` kind of works against that. I think I would have a different texture for each layer and blend them together. Also you need the colors to be brighter, it's a bit dull. But that said, it is pretty interesting to see the finished landscape.

So I presume you are going to have land that `hangs in the air` rather than have it fall initially, like in worms?

lol.

I know you're all thinking "Worms", and so far the
similarities are there. Yes, the terrain's destruction is a
very important part of the game. But this game is actually
different from Worms in a bunch of ways. The action is in
realtime, for example. And the biggest, most exciting part
of this game (I say) will be the user-designed weapons.
I've designed and redesigned this system for a long time
now. It will work, and the strategy it will create should
be loads of fun.

Rimmsy: Yes, if I use, say 42 as my seed, I get the same
landscape every time. I will use this if I get to the point
of actually making a small campaign. But that's way, way
in the future.

So you're just going with one screen and no scrolling? Does that mean the characters etc would be fairly small?

Sadly, yes. I image the characters being slightly bigger than
your thumbnail when pressed against your monitor (on a 17")

You guys think that's too small? I've considered going
bigger, but the bigger the characters are, the less they can
do on the map.

But I still want a size where you can still see the details of
the animation (ie the little legs running around, the arm
tossing things, etc)

AngelDaniel:
but that it looks as though there are only a limited number of colors in what looks to be a `scattered` arrangement.

Well, you guessed it. I am indeed using indexed colours to
colour my terrain(gasp!). lol. Good eye. I like the look, personally.

Soo... what is the logic behind "Floating" land?

Drew this looks tremendous. I have seen your old stuff before and always wondered how you did it. Now I have the code but still haven't figured out what it does!

The idea of floating land is really one of many many solutions to the problem of having an `land` engine with attempts at realistic physics. If you think back to the earliest games like scorched earth/scorched tanks, blowing a hole in the land usually meant that you'd then `drop` the land that is overhanging one column of pixels at a time. That was one way of doing it. I think it was more or less until Worms came out that this was the most popular method. Some people implemented a little bit of `landslide` but otherwise it didnt' advance much. Them worms did away with the land drop, perhaps thinking it detracted from gameplay, or that it was more fun to have tunnels, because if you don't drop the land you automatically get spaces and overhangs.

To add `reasoning` to the overhanging land, all land would at least start out more or less `attached` and then holes created would be drawn as if a darkened or charred cavern background, that you could walk in front of, as if to suggest it was `supporting` the land above. Looks at the moment as though this is what drew is aiming for, so that you can have overhanging land and tunnels within land to add to the gameplay, even though it means land doesn't fall realistically anymore.

[edit] Hey Drew, you updated your screenshots and demo! I like the addition of the background, it helps the land to stand out and have presence. The sky is nice too, that it's not just a linear gradient. I'm actually growing to like your landscape system.

Thanks Nomen, or Mr. luni perhaps. Appreciate it.

And thanks AngelDaniel, once again, you're right. I'm allowing
floating land because 1: Tunnel/wall building is essential
to my gameplay and 2: BMax doesn't let me edit textures at a
proper speed - if I tried to do the scorched earth landslide
thing, the game would crawl to a halt (With my current
knowledge of Bmax)

I was seriously considering creating some code that did this:

But what do you guys think? Good idea after all? I think
it would add logic to the floating platforms, but at the cost
of blocking out the nice looking BG, cluttering the map just
a tiny bit more, and making a small headache for me to write
the shape and texture code.

Mmmm, I'm liking it. I like the day time lighting effects in the new version. Have you played Liero?

http://iworx5.webxtra.net/~lxallian/LXRS/

Check out the multiplayer option. Sorry to hijack the thread. I'm looking forward to seeing what you're up to, Mr. Drew.

And by the way, I am not making this game in response to Worms.
I wrote a version of this years ago after playing Gorillas
(That demo that came with QBasic)

So my inspiration was originally Gorillas, not Worms, ok? ;)

It was just the floating islands in the screenshots... One thing for the ground to be modded into floating islands.. another for it to start out with them.

I remember editing the source for gorrillas in QBasic (probably my first coding experience) and just basically making the blast radius enormous. I entitled my new version nuclear gorrillas. You sort of just fired one shot then watched as it all exploded. I love that game.

So my inspiration was originally Gorillas, not Worms, ok? ;)
Well Worms sucked anyway. Any game that gives you a tactical advantage from committing suicide (particularly if one of your worms has a good/bad position) needs to be rethought.

Landscape looks totally oldskool (which is good), and I'd definitely do the support things for the floating islands if I were you.

I agree I did not like Worms very much. I always found it very tacky and really not that inventive. Although it's sold a tonne of games and spinoffs, I don't think I'll ever be buying them.

Flameduck you were working on `minimum safe distance` which was a kind of worms-like game, right? One of your shelved projects? Any screenshots to show us?

I kind of like the added earth to connect to the floating platforms. You could make it as `minimal` in size as you like, so long as it still looks like it would support the land mass. Or... make a hole in it for the background to show through.

As to the land drop, yeah, it's not so easy with these new fangled drawing-focussed but not reading-focussed graphics API's.

If there are supports behind everything, then there is no logical flaw in 'floating' land. A floating bit would connect into the background. I like that solution.

I smell a Scorched Earth clone in the offing. Anyway, that's why I hope you're using this for because I love Scorched Earth. Funnily enough, every time I think I might write one myself, the hassle of generating dynamic land (and handling the subsequent destruction of said land) is one of the main things that always scares me off. Your land looks great.

SpaceAce

I agree about the connecting land making the overhangs more logical, so long as the user is convinced that the size of that connecting land is sturdy/wide-enough looking to support the weight of the size of the floating part. Otherwise you could have 1 pixel supporting a huge chunk of land which would obviously not be convincing.

If you are only going to have 1 screen of land stored in 1 texture and no scrolling it's really not hard to make changes to the backbuffer and grab the results back into the land texture/image each frame. Then you can modify the land and keep the changes, and implement whatever form of land-dropping you think is suitable. The easiest is to do it in columns of pixels. You could, with some kind of drawimagerect thing, draw individual columns from the texture and animate them falling into position.

Perhaps BRL needs to add an UpdateImage() command for GL and DX that copies an area of the backbuffer into an existing image, which is faster than GrabImage which allocates a whole new image. For GL it would call glCopyTexSubImage2D().

Or... make a hole in it for the background to show through.
Or you could always do the Worms thing an make a parallax scroll. Ofcourse this would mean you'd have to make scrolly maps... :o>

Flameduck you were working on `minimum safe distance` which was a kind of worms-like game, right?
Nope. I was working on NetBlaster, which was something completely different. I believe the SDS guys (Rob? Lucy?) where working on MSD.

As to the land drop, yeah, it's not so easy with these new fangled drawing-focussed but not reading-focussed graphics API's.
Which is why you need to do it on a second buffer in system memory, and then draw it to screen, preferably using a 'dirty rects' type algorithm.

FlameDuck,
Any game that gives you a tactical advantage from committing suicide ... needs to be rethought.

I guess you never played the Half Life mod which featured a Kevlar-reinforced Dynamite Suicide vest. Useful beast when you're down to a few health points and you can see a group of people in the distance. Find three (or more) people in a small room, run into the middle of them, and ka-boom.

You take a hit for fragging yourself, but then if you get everyone in the room...

There ARE ways to do a fully scrolling fully destructible landscape in realtime, it just takes some extra work. I'm working towards it myself.

FlameDuck:
I'd definitely do the support things for the floating islands if I were you.

Yeah, doing that now. Like I predicted, the logic and math
is a bit of a headache, but it should be a flexible system
by the time I'm done.

SpaceAce:
I smell a Scorched Earth clone in the offing.

Hey, I like scorched earth too, but the only
similarities my game has with Scorched earth is that there
are things shooting at other things. I have an original
game idea that I've been working on for a while now. And
the play mechanics are significantly different from Worms,
Gorillas, Scorched earth, etc, etc.

AngelDaniel:
it's really not hard to make changes to the backbuffer and grab the results back into the land texture/image each frame

Maybe, but not using pixmaps. I've done tests on 256x256
squares and have had enough slowdown to make the idea of
frame-by-frame editing a no-go. And even if I figured
out a smooth-as-butter falling-terrain algorithm, I can't
use it. My gameplay revolves around building tunnels etc.
You guys will see what I mean later.

FlameDuck:
Which is why you need to (edit image information) on a second buffer in system memory, and then draw it to screen, preferably using a 'dirty rects' type algorithm.

I would love to know how to do that.

FlameDuck:
you could always do the Worms thing an make a parallax scroll. Ofcourse this would mean you'd have to make scrolly maps...

And, AngelDaniel:
There ARE ways to do a fully scrolling fully destructible landscape in realtime

I agree! I don't know if you guys saw some of my other stuff,
but I've got scrolly/zoomy maps pretty much figured out.
I've even done a prototype of a zoomable/scrollable/
destructible terrain system. Yes I have! The thing is, there's
more to my game than the terrain system. Having this fancification
makes hit detection and AI (especially AI) very hard
to write. Not to mention that random land generation would
become prohibitively complicated and take much, much longer
to draw a single map.

You guys must understand this:
If I make this project too complicated, I will not finish it!
I've got to keep it painfully simple or it will not be done. And
it's taken a lot of self control for me to restrict myself so far.

Guys, don't temp me! Scrolly maps = bad! lol

lol.

All flameduck is saying is that you keep a copy of the land in main memory as a pixmap, and then if you need to change it you change the pixels in the pixmap with like WritePixel/ReadPixel, and then you also have access to the shape of the land using ReadPixel so that you can do your collision detection and so on. Then when you need to see the the changes you would transfer a rectangular portion of the pixmap to the graphics card, either by turning it into an image (where you have a grid of images making up the whole screen, say 64x64 size each, or smaller), or by directly transferring a rectangle that's changed (bounding box) to an existing texture/image using for example glTexSubImage2D() (opengl), or using DrawPixmap or similar to draw to backbuffer and grab into an image. You can grab to image fairly quickly, faster than to a pixmap.

But you said you didn't want to drop the land due to needing to keep tunnels and so on. But it would be an idea to put a duplicate copy of your landscape in a pixmap, as well as having it in an image (for drawing), so that you can do collision detection in main memory using the cpu.

Are you going to have it so that you can blow up some of the land, which leaves behind the `cave` texture?

Finally, I have written some code for columns to hold up the
floaty chunks of land. Phew, 2 weeks later and 6 more pages
of code added to my project and I've got this to show:





Sure ain't much. Hope you guys like it!

I want to know how this code runs on your machines, could
some of you run it and let me know how fast these terrains
render for you guys? (render time is displayed on the top
left corner).

I always get around 1.0 to 1.3 seconds per map.

I've got a 180Kb Exe this time, but no source, sorry. (It's now spread across two files)

I want to add buildings/walls/forts next, but I should
really get going on the actual game now eh? I've been
messing around with this land generator for far too long.

My average rendering time is about 13 seconds per map.

My laptop spec is:
Turion 64 MT-40 2.20Ghz
1Gb RAM
ATI X1600 256MB

And I'm running the 32bit version of Vista.

I must say, the more vivid snowy landscapes look wonderful. I love the rich blues, pinks and reds. And the strange straggly columns lend a wonderfully surreal feel to the landscapes. I'm not too keen on the maps that use more subdued and dreary gray colours. If I were you, I'd try to keep everything as rich and vibrant as possible.

It takes less than 1.1 seconds each time on my desktop
on my laptop (Celery 1.4GHz, 512MB ram, windows XP Home) it takes between 2 and 2.5 seconds

looking nice.

You said earlier that the game involved digging tunnels, wouldn't that be easier if there weren't tunnels there already?

Average time is 0.75 seconds. Nice.

P4 3mhz, 512mb ram, xp pro, gfx440mx

Stevie

My average rendering time is about 13 seconds per map.

My laptop spec is:
Turion 64 MT-40 2.20Ghz
1Gb RAM
ATI X1600 256MB

And I'm running the 32bit version of Vista.


Holy Vista Batman! Did you mean to type 1.3, maybe? Or does
that machine have troubles running other blitz programs as
well, then?

I'm not too keen on the maps that use more subdued and dreary gray colours.

Hmm, that's tough. I actually really like the "Muted evening"
and "Duststorm" sky themes the best. No matter, the user
will be allowed to decide in the end.

wouldn't (digging tunnels) be easier if there weren't tunnels there already?

I'm not really sure what you mean. It will be just as easy
as it would be with no tunnels there. A map that starts out
with areas carved out is instantly more interesting.

Yikes!

Hope I didn't worry you there, because, yes, it was a typo. I meant 1.3 seconds. one point three. :)

Here it takes about 3.2 seconds, on a 2.66GHz pentium 4 with 1 gig ram and Intel graphics controller.

I think that's pretty slow for a single screen landscape.

Are you doing all your rendering with the CPU?

@JustLuke: Phew!

@AngelDaniel: "Are you doing all your rendering with the CPU?"

Is there any other way with blitz? If there is, I'd be happy
to peruse a website or article that might show me new ways of
doing old things! Are you offering such a thing?

Sure ain't much. Hope you guys like it!
I do indeed. Some of the renders remind of Another World (which I love).
I'm getting around 4.6 secs per screen on my Sony VGN-TX2 Craptop.

Incidently, did you use the fast pixel plotting code from here? ..

http://www.blitzmax.com/Community/posts.php?topic=54727#609951

Seems like you're using plot. It might possibly be faster to do the kind of stuff you're doing with a Pixmap and writing your own pixels using pointers.

I also noticed you're doing a lot of draw-ovals. Can you not create an image containing various sized ovals and then use something like DrawImageRect to draw the oval? That will be faster than drawing a new oval each time because the oval contains a number of vertices whereas the image of the oval contains only 4.

You might also consider writing your own OpenGL code.

@AngelDaniel:
I was also concerned at first at the ton of drawovals I was doing too, but it only takes 0.3 seconds and it's only done
once (That's why the very first terrain takes a little longer to make). So I'll probably leave that alone. I might
just try that pixmap/pointer combo if it ends up being faster than Flameducks method though.

@Jim:
Thanks for that link, I can't believe I forgot about that. So, I was in the middle of shoehorning that fastpixel function
into my program when I suddenly realized that switching to OGL had made my program run 2.5x faster! (0.5 to 0.7 seconds
now) And it made my built exe 43kb smaller!?

And then OGL proceeded to do my taxes, mow my lawn and save me hundreds of dollars on my car insurance. Wow!

The only catch is that if I try to run in full screen, blitz tells me "Attempt to access field or method of null object"
on the very first graphics-related command. In this case it's SetBlend(AlphaBlend). What's up with that?

Admittedly, this particular question might be more suiting to the BMax forums.

If you used GLGraphics() to open your display it will not have set up any Max2D stuff so making any Max2D calls such as setblend, setcolor, drawtext, drawrect etc etc will all tell you something has not been defined. If you want to still use Max2D you have to open the display with Graphics() and then you're dealing with trying to use OpenGL at the same time as Max2D. If you only want to use Max2D commands you should just use Graphics(). You only need GLGraphics() when you want to set up your own display and handle everything manually.

Neither Graphics() or GLGraphics() allow me to use any Max2D functions.

This is basically my setup:
Framework BRL.GLMax2D
Import BRL.Random
SetGraphicsDriver GLMax2DDriver()
GLGraphics 800,600, 1


I guess all I really want to know is where I can find out
how to replace setblend, cls, flip, etc with their pure
OpenGL counterparts. Anyone?

Well thats because you're using a framework and not importing everything you need to compile.

Alright, I'll figure this out yet.

[edit] Fixed!

And with fastplot, terrains draw at 0.43 to 0.56 seconds.
That's gotta be fast enough for even you AngelDaniel!

[Double edit] I also added a nice, quick, bump mapping
feature to the texture, it slows the whole thing by a mere
.1 seconds, so it's worth it.

I'll start a new thread when my gameply is at the point
where I can present it. Thanks for the help, guys!