In older civilization games the ai would put a fleet of ships into small area's of water. Here I coded a floodfill routine to number the connected water tiles. You can then count a number to see how big of a area it is. Then you would be able to let the ai decide not to put ships in it if there are to little tiles of water.
Code below :
Import mojo
Const mapwidth:Int=640/16
Const mapheight:Int=480/16
Const tilewidth:Int=16
Const tileheight:Int=16
Global map:Int[mapwidth][]
Global watermap:Int[mapwidth][]
Global numland:Int = 0
Global percland:Float = 1.7
Global remakecnt:Int=0
Class Openlist
Field x:Int, y:Int
Method New(x:Int,y:Int)
Self.x = x
Self.y = y
End Method
End Class
Class MyGame Extends App
Method OnCreate()
SetUpdateRate(5)
Seed = Millisecs()
'Set up the map array to be multi dimensional
For Local i=0 Until mapwidth
map[i] = New Int[mapheight]
watermap[i] = New Int[mapheight]
Next
' make the map the first time
percland = Rnd(2.0,3.5)
makemap
makewatermap
End Method
Method OnUpdate()
' how much land must it have numoflandtiles </mapsize/percland
remakecnt+=1
If remakecnt > 10
remakecnt=0
percland = Rnd(2.0,3.5)
makemap
makewatermap
End If
End Method
Method OnRender()
Cls 0,0,0
drawmap
Local numwater=getnumberwater()
SetColor 10,10,10
SetAlpha 0.6
DrawRect 0,0,200,numwater*15+15
SetAlpha 1
SetColor 255,255,255
DrawText "Water floodfill to number the water surfaces.",0,0
DrawText "(bugs) In civ games lots of sea units where put into tiny area's of water.",0,15
For Local y=1 To numwater
DrawText "Water mass "+y+" is "+getwatermass(y)+" tiles.",0,y*15+30
Next
End Method
End Class
Function makewatermap:Void()
'first clear the array
For Local y=0 Until mapheight
For Local x=0 Until mapwidth
watermap[x][y] = 0
Next
Next
' create an open list
Local openlist:List<Openlist> = New List<Openlist>
Local currentwaternum:Int=0
' loop through the array
For Local y1=0 Until mapheight
For Local x1=0 Until mapwidth
' if land tile and not indexed as island
If map[x1][y1]<5 And watermap[x1][y1] = 0
currentwaternum+=1
openlist.Clear()
'move this position onto the openlist
openlist.AddLast(New Openlist(x1,y1))
Local tx:Int=0, ty:Int=0
While openlist.IsEmpty() = False
' get a x,y value from the open list
For Local i:=Eachin openlist
tx = i.x
ty = i.y
openlist.Remove i
Exit
Next
' get 8 new positions
For Local y2=-1 To 1
For Local x2=-1 To 1
Local x3:Int=tx+x2
Local y3:Int=ty+y2
If x3>=0 And y3>=0 And x3<mapwidth And y3<mapheight
' if land tile and not assisgned before a island
If map[x3][y3]<5
If watermap[x3][y3] = 0
' add to open list
openlist.AddLast(New Openlist(x3,y3))
' set current connected landmass
watermap[x3][y3] = currentwaternum
End If
End If
End If
Next
Next
Wend
End If
Next
Next
End Function
Function drawmap:Void()
For Local y=0 Until mapheight
For Local x=0 Until mapwidth
Local val:Int=map[x][y]
' tile 1,2,3,4 is sea
If val<5 Then SetColor 0,0,val*10+100
' tile 5 6 7 8 is grasslands/trees
If val>=5 And val <9 Then SetColor 0,val*15,0
'tiles 9 10 11 12 13 is mountains
If val>=9 Then SetColor val*15,val*4,0
' draw the tile
DrawRect x*tilewidth,y*tileheight,tilewidth,tileheight
Next
Next
SetColor 255,255,255
For Local y=0 Until mapheight
For Local x=0 Until mapwidth
DrawText watermap[x][y],x*tilewidth+tilewidth/2,y*tileheight+tileheight/2,0.5,0.5
Next
Next
End Function
Function makemap:Void()
numland=0
' exit loop if conditions on land percentage is good
While numland<(mapwidth*mapheight/percland)
' erase the old data
For Local y=0 Until mapheight
For Local x=0 Until mapwidth
map[x][y] = 0
Next
Next
'lowest hold the highest tile value
Local lowest = 0
' while land height is below 13
While lowest < 13
Local x1 = Rnd(mapwidth)
Local y1 = Rnd(mapheight)
' create a radius for draw oval
Local radius = Rnd(3,6)
' loop and create oval
For Local y2=-radius To radius
For Local x2=-radius To radius
If ((x2*x2)+(y2*y2)) <= radius*radius+radius*0.8
Local x3 = x1+x2
Local y3 = y1+y2
If x3>=0 And y3>=0 And x3<mapwidth And y3<mapheight
' add current position with added older tile value
map[x3][y3]=map[x3][y3]+1
' if current value is higher then lowest loop value
' then store it in the loop exit variable
If map[x3][y3] > lowest Then lowest = map[x3][y3]
End If
End If
Next
Next
Wend
'Count the number of land tiles
numland=0
For Local y=0 Until mapheight
For Local x=0 Until mapwidth
' if the value is above 4 then add landtile counter
If map[x][y] >= 5 Then numland+=1
Next
Next
Wend
End Function
Function getwatermass:Int(waternumber:Int=1)
Local totaltiles:Int=0
For Local y=0 Until mapheight
For Local x=0 Until mapwidth
If watermap[x][y] = waternumber Then totaltiles+=1
Next
Next
Return totaltiles
End Function
Function getnumberwater:Int()
Local highestnumber:Int=0
For Local y=0 Until mapheight
For Local x=0 Until mapwidth
If watermap[x][y] > highestnumber Then highestnumber = watermap[x][y]
Next
Next
Return highestnumber
End Function
Function Main()
New MyGame()
End Function
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.