tileBlocks.py 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. #!/usr/local/bin/python3
  2. # -*- coding: utf-8 -*-
  3. import torch
  4. import torch.nn as nn
  5. import torch.nn.functional as F
  6. import torch.utils.data as tudata
  7. import numpy as np
  8. import sys
  9. import json
  10. import os
  11. import sqlite3
  12. #将block信息保存到数据库中,方便后续查询
  13. class BlockDB:
  14. def __init__(self):
  15. self.blocks = []
  16. self.conn = sqlite3.connect('blocks.db')
  17. if self.conn is None:
  18. print("open db failed")
  19. else:
  20. cursor = self.conn.cursor()
  21. cursor.execute("SELECT * FROM blocks")
  22. rows = cursor.fetchall()
  23. for row in rows:
  24. block = {}
  25. block['id'] = row[0]
  26. self.blocks.add(block)
  27. def add_block(self, block):
  28. # 检查必要信息是否存在
  29. if 'id' not in block:
  30. return
  31. self.blocks.add(block)
  32. def get_block(self, block):
  33. if block in self.blocks:
  34. return block
  35. else:
  36. return None
  37. def dump(self):
  38. cursor = self.conn.cursor()
  39. cursor.execute("CREATE TABLE IF NOT EXISTS blocks (id TEXT)")
  40. for block in self.blocks:
  41. cursor.execute("INSERT INTO blocks (id) VALUES (?)", (block['id'],))
  42. self.conn.commit()
  43. #将数据输出到一个json文件,便于在tiled进行观察,可以是单层或者多层的,多层的话,层级按照从小到大排列(层级是布局层级,不是视觉层级)
  44. def output_to_json(slices, suffix="ex"):
  45. with open("/Users/xulianxin/Documents/develop/game/TileMatch/TileManor.Lv/TileManor/templates/tm_0000.json", 'r') as f:
  46. json_temp = json.load(f)
  47. for i in range(0, len(slices)):
  48. with open("/Users/xulianxin/Documents/develop/game/TileMatch/TileManor.Lv/TileManor/slices/slice_%d_%s.json" % (i, suffix), "w") as out_f:
  49. json_temp["layers"][0]["data"] = slices[i]
  50. json.dump(json_temp, out_f)
  51. def output_block(block, size, suffix):
  52. with open("/Users/xulianxin/Documents/develop/game/TileMatch/TileManor.Lv/TileManor/templates/tm_0000.json", 'r') as f:
  53. json_temp = json.load(f)
  54. with open("/Users/xulianxin/Documents/develop/game/TileMatch/TileManor.Lv/TileManor/blocks/block_%s.json" % (suffix,), "w") as out_f:
  55. for pos in block:
  56. x,y,z = pos
  57. # 0 是 mark
  58. json_temp["layers"][z+1]["data"][y*size[1]+x] = '1'
  59. json.dump(json_temp, out_f)
  60. def get_block_from(tiles_from, tiles_by_pos):
  61. block = set()
  62. stack = [p for p in tiles_from]
  63. while len(stack) > 0:
  64. tile = stack.pop()
  65. block.add(tile)
  66. x,y,z = tile
  67. while z > 0:
  68. for adj in [(0,0), (0,1), (0,-1), (1,0), (-1,0), (-1,-1), (1,1), (-1,1), (1,-1)]:
  69. pos = (x+adj[0], y+adj[1], z-1)
  70. if pos in tiles_by_pos:
  71. stack.append(pos)
  72. z -= 1
  73. return block
  74. # 将 tiles_at_top 按照连通性,划分成若干个组
  75. # tiles_at_top只有xy坐标,无z
  76. def split_shapes(tiles_at_top):
  77. # 从第一个tile开始,逐个tile进行遍历,如果该tile的上下左右有tile,则将其加入到一个组中,直至所有的tile都被处理
  78. shapes = []
  79. for tile in tiles_at_top:
  80. shape_aleary = None
  81. for shape in shapes:
  82. if tile in shape:
  83. shape_aleary = shape
  84. break
  85. if shape_aleary == None:
  86. shape_aleary = set()
  87. shape_aleary.add(tile)
  88. shapes.append(shape_aleary)
  89. x,y = tile
  90. for adj in [(0,2), (0,-2), (1,2), (1,-2), (-1,2), (-1,-2), (2,0), (-2,0), (2,1), (-2,1), (2,-1), (-2,-1)]:
  91. adj_x = x + adj[0]
  92. adj_y = y + adj[1]
  93. pos = (adj_x, adj_y)
  94. if pos in tiles_at_top:
  95. # 如果该位置已经在某个shape里面,则将两个shape合并
  96. shape1 = None
  97. for shape in shapes:
  98. if pos in shape:
  99. shape1 = shape
  100. break
  101. if shape1 != None and shape1 != shape_aleary:
  102. shape_aleary.update(shape1)
  103. shapes.remove(shape1)
  104. else:
  105. shape_aleary.add(pos)
  106. return shapes
  107. # 解析一个关卡文件,得到各层的数据,是按照视觉层次划分的
  108. def parse_blocks(jsonLv):
  109. jsonData = ""
  110. tilesByPos = {}
  111. maxZ = 0
  112. w = 0
  113. h = 0
  114. # 处理各层的tile数据
  115. with open(jsonLv, 'r') as f:#, encoding='utf-8'
  116. jsonData = json.load(f)
  117. # 得到宽高信息
  118. w = int(jsonData['width'])
  119. h = int(jsonData['height'])
  120. for item in jsonData['layers']:
  121. name = item['name']
  122. if not name.startswith('Tile_'):
  123. # stacked
  124. continue
  125. z = int(name[5:])
  126. data = item['data']
  127. for i in range(0, len(data)):
  128. if data[i] == 0:
  129. continue
  130. tile_x = (int)(i % w)
  131. tile_y = (int)(i / h)
  132. tile_z = z
  133. # 一些统计信息
  134. tilesByPos[(tile_x, tile_y, tile_z)] = [1,0] # [tile类型,zView--视觉层级,默认是0]
  135. if tile_z > maxZ:
  136. maxZ = tile_z
  137. # 根据上面的布局信息,得到视觉顶层的所有tile
  138. tiles_at_top = []
  139. for z in range(0, maxZ+1):
  140. z = maxZ - z
  141. for x in range(0, w+1):
  142. for y in range(0, h+1):
  143. if (x,y,z) in tilesByPos:
  144. tile = tilesByPos[(x, y, z)]
  145. adjs = [(x,y),(x,y+1),(x,y-1),(x+1,y),(x+1,y+1),(x+1,y-1),(x-1,y),(x-1,y-1),(x-1,y+1)]
  146. # 确定视觉层级
  147. zvMax = -1
  148. for zup in range(z+1, maxZ+1):
  149. for adj in adjs:
  150. if (adj[0],adj[1],zup) in tilesByPos:
  151. zv = tilesByPos[adj[0],adj[1],zup][1]
  152. if zv > zvMax:
  153. zvMax = zv
  154. zv = zvMax + 1
  155. tilesByPos[(x, y, z)][1] = zv
  156. if zv == 0:
  157. tiles_at_top.append((x, y, z))
  158. # 将 tiles_at_top 按照连通性,划分成若干个组
  159. tops = [(x,y) for x,y,z in tiles_at_top]
  160. print("tops:", tops)
  161. shapes = split_shapes(tops)
  162. print("shapes:", shapes)
  163. # 对每一个组,得到其block
  164. blocks = []
  165. for i in range(0, len(shapes)):
  166. shape = shapes[i]
  167. ts = [(x,y,z) for x,y,z in tiles_at_top if (x,y) in shape]
  168. block = get_block_from(ts, tilesByPos)
  169. if len(block) > len(ts):
  170. blocks.append(block)
  171. return blocks, (w,h)
  172. # 测试获取视觉层级的数据是否ok
  173. def test_parse_blocks():
  174. parse_blocks("/Users/xulianxin/Documents/develop/game/TileMatch/TileManor.Lv/TileManor/templates/tm_0004.json")
  175. #评估一个布局的好坏,返回一个分数
  176. #布局的好坏,可以从几个方面来评估:
  177. #1. 是否超出范围;
  178. #2. 是否有某种对称性;
  179. #3. tile的数量是否合理;
  180. def eva_layout():
  181. pass
  182. # 生成一个随机的
  183. def generate_tops():
  184. pass
  185. if __name__ == '__main__':
  186. blocks_lib = set()
  187. for directory in ["/Users/xulianxin/Documents/develop/game/TileMatch/TileManor.Lv/TileManor/tf_templates", ]:
  188. for filename in os.listdir(directory):
  189. filepath = os.path.join(directory, filename)
  190. if os.path.isfile(filepath) and filepath.endswith('.json'):
  191. blocks, size = parse_blocks(filepath)
  192. for i in range(len(blocks)):
  193. block = blocks[i]
  194. # 将block都挪动到左上角,进行排重
  195. minx = min([x for x,y,z in block])
  196. miny = min([y for x,y,z in block])-1
  197. block = tuple((x-minx, y-miny, z) for x,y,z in block)
  198. if block not in blocks_lib:
  199. blocks_lib.add(block)
  200. output_block(block, size, filename.split(".")[0] + "_%d" % (i,))
  201. else:
  202. print("dumplicated!")
  203. pass