Guest User

Untitled

a guest
Mar 30th, 2015
665
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.76 KB | None | 0 0
  1. import pygame, sys, random
  2.  
  3. from pygame.locals import *
  4.  
  5. def draw_screen(height_map, square):
  6.  
  7. render_map(height_map, square)
  8.  
  9. pygame.display.update()
  10.  
  11. def convert(grid):
  12.  
  13. # initialize an empty MAP_SIZE x MAP_SIZE array
  14. out = [[0 for y in xrange(MAP_SIZE)] for x in xrange(MAP_SIZE)]
  15.  
  16. largest = 0
  17. smallest = MAP_SIZE * 3.0
  18.  
  19. for x in xrange(MAP_SIZE):
  20.  
  21. for y in xrange(MAP_SIZE):
  22.  
  23. # average surrounding points to get square's value
  24. val = (grid[x][y] + grid[x+1][y] + grid[x][y+1] + grid[x+1][y+1]) \
  25. / 4.0
  26.  
  27. out[x][y] = val
  28.  
  29. # find largest and smallest while we're at it
  30. if val > largest:
  31.  
  32. largest = val
  33.  
  34. if val < smallest:
  35.  
  36. smallest = val
  37.  
  38. smallest = float(smallest)
  39.  
  40. #print largest
  41. #print smallest
  42.  
  43. # if any point below 0, bump everything up by that amount
  44. if smallest < 0:
  45.  
  46. bump = 0 - smallest
  47.  
  48. else:
  49.  
  50. bump = 0
  51.  
  52. #print bump
  53.  
  54. largest = float(largest + bump)
  55.  
  56. # compress to 8-bits or whatever
  57. for x in xrange(MAP_SIZE):
  58.  
  59. for y in xrange(MAP_SIZE):
  60.  
  61. out[x][y] = int(((out[x][y] + bump) / largest) * 255)
  62.  
  63. return out
  64.  
  65. def render_map(height_map, square):
  66.  
  67. for x in xrange(MAP_SIZE):
  68.  
  69. for y in xrange(MAP_SIZE):
  70.  
  71. val = height_map[x][y]
  72.  
  73. color = (val, val, val)
  74.  
  75. pygame.draw.rect(DISPLAYSURF, color, (x * square, y * square,
  76. x * square + square, y * square + square))
  77.  
  78. def generate(size):
  79.  
  80. # the size of the first square, or, the size of the height map itself
  81. extent = size
  82.  
  83. # half the size of the heightmap
  84. # coincidentally, the middle index number as well
  85. # ex: size = 4, [0, 1, 2, 3, 4], 4 / 2 = 2 = middle index
  86. half = size / 2
  87.  
  88. # initialize an empty grid with dimensions size + 1
  89. # example: a 16x16 heightmap calls for a 17x17 grid
  90. points = [[0 for y in xrange(size + 1)] for x in xrange(size + 1)]
  91.  
  92. # "noise" happens here
  93. scale = half * 1.5
  94.  
  95. # randomize corners
  96. points[0][0] = half + random.uniform(-scale, scale)
  97. points[size][0] = half + random.uniform(-scale, scale)
  98. points[0][size] = half + random.uniform(-scale, scale)
  99. points[size][size] = half + random.uniform(-scale, scale)
  100.  
  101. # when size is 1, there are no more points to fill in
  102. # I don't know why some people's algorithms say "while size > 0",
  103. # since there is nothing more to do to a square like (0, 0), (1, 0),
  104. # (0, 1), (1, 1)
  105. while size > 1:
  106.  
  107. #print "half:", half
  108. #print "scale:", scale
  109.  
  110. # square step
  111.  
  112. # here we step through both dimensions, with a stride of the current
  113. # square size
  114. #
  115. # example: a 4 x 4 heightmap
  116. # our range on the first iteration is (0, 4, 4)
  117. # first square found lies at (0, 0)
  118. # then we take 1 stride of length 4, which puts us at (4, 4),
  119. # which is out of range (ours is 0-4 exclusive)
  120. # so only 1 square is found
  121. #
  122. # next iteration size is 2, so we work on 4 squares, located at:
  123. # (0, 0), (0, 2), (2, 0), (2, 2)
  124. # and so on
  125. for x in xrange(0, extent, size):
  126.  
  127. for y in xrange(0, extent, size):
  128.  
  129. # the 4 corners of this square are averaged
  130. sq_avg = (points[x][y] + points[x+size][y] + \
  131. points[x][y+size] + points[x+size][y+size]) / 4.0
  132.  
  133. # set center point to avg + "noise"
  134. points[x+half][y+half] = sq_avg + random.uniform(-scale, scale)
  135.  
  136. # diamond step
  137.  
  138. # for each square, we also need to set the values of the "diamond"
  139. # points, that is, the ones to the left, right, above, and below our
  140. # newly created square center points
  141. #
  142. # to avoid errors, we only use 3 points for averaging points along the
  143. # edges, since the 4th is off the map/non-existent
  144. for y in xrange(0, extent, size):
  145.  
  146. for x in xrange(0, extent, size):
  147.  
  148. # the top point of the diamond
  149. if y > 0:
  150.  
  151. # 4 points to average,
  152. # the upper left point, upper right, middle, and
  153. # the middle of the square above it
  154. avg = (points[x][y] + points[x+size][y] + \
  155. points[x+half][y+half] + points[x+half][y-half]) / 4.0
  156.  
  157. else:
  158.  
  159. # otherwise, we use all but the middle of the above
  160. avg = (points[x][y] + points[x+size][y] + \
  161. points[x+half][y+half]) / 3.0
  162.  
  163. # set top point to that average + noise
  164. points[x+half][y] = avg + random.uniform(-scale, scale)
  165.  
  166. # the bottom point of the diamond
  167. if y < extent - size:
  168.  
  169. # 4 points to average
  170. avg = (points[x+size][y+size] + points[x+half][y+half] + \
  171. points[x+size][y+size] + points[x+half][y+size+half]) \
  172. / 4.0
  173.  
  174. else:
  175.  
  176. # only 3 points
  177. avg = (points[x+size][y+size] + points[x+half][y+half] + \
  178. points[x+size][y+size]) / 3.0
  179.  
  180. points[x+half][y+size] = avg + random.uniform(-scale, scale)
  181.  
  182. # the left point of the diamond
  183. if x > 0:
  184.  
  185. # 4 points to average
  186. avg = (points[x][y] + points[x+half][y+half] + \
  187. points[x][y+size] + points[x-half][y+half]) / 4.0
  188.  
  189. else:
  190.  
  191. # only 3 points
  192. avg = (points[x][y] + points[x+half][y+half] + \
  193. points[x][y+size]) / 3.0
  194.  
  195. points[x][y+half] = avg + random.uniform(-scale, scale)
  196.  
  197. # the right point of the diamond
  198. if x < extent - size:
  199.  
  200. # 4 points to average
  201. avg = (points[x+size][y+size] + points[x+half][y+half] + \
  202. points[x+size][y+size] + points[x+size+half][y+half]) \
  203. / 4.0
  204.  
  205. else:
  206.  
  207. # only 3 points
  208. avg = (points[x+size][y+size] + points[x+half][y+half] + \
  209. points[x+size][y+size]) / 3.0
  210.  
  211. points[x+size][y+half] = avg + random.uniform(-scale, scale)
  212.  
  213. # end of this iteration
  214. # halve size of squares and size of half squares
  215. size /= 2
  216. half /= 2
  217.  
  218. # the scale, or "noise", is also reduced for each iteration
  219. scale = half * 1.5
  220.  
  221. return points
  222.  
  223. #################################### setup #####################################
  224.  
  225. pygame.init()
  226.  
  227. # size of visible window
  228. WIN = 900
  229.  
  230. # size of height map to be generated, needs to be a power of 2
  231. MAP_SIZE = 256
  232.  
  233. # size of squares for display
  234. SQUARE = WIN / float(MAP_SIZE)
  235.  
  236. # initialize surface and window
  237. DISPLAYSURF = pygame.display.set_mode((WIN, WIN))
  238. pygame.display.set_caption('Diamond-Square Terrain')
  239.  
  240. def main():
  241.  
  242. # generate a grid based on the diamond-square algo
  243. grid = generate(MAP_SIZE)
  244.  
  245. # convert that to a height map of size MAP_SIZE, with values 0-255
  246. height_map = convert(grid)
  247.  
  248. draw_screen(height_map, SQUARE)
  249.  
  250. while True:
  251.  
  252. for event in pygame.event.get():
  253.  
  254. if event.type == QUIT:
  255. pygame.quit()
  256. sys.exit()
  257.  
  258. #draw_screen(height_map, SQUARE)
  259.  
  260. if __name__ == '__main__':
  261.  
  262. main()
Advertisement
Add Comment
Please, Sign In to add comment