#!/usr/local/bin/python3 # -*- coding: utf-8 -*- import torch import torch.nn as nn import torch.nn.functional as F import torch.utils.data as tudata import numpy as np import sys import json import os import sqlite3 #将block信息保存到数据库中,方便后续查询 class BlockDB: def __init__(self): self.blocks = [] self.conn = sqlite3.connect('blocks.db') if self.conn is None: print("open db failed") else: cursor = self.conn.cursor() cursor.execute("SELECT * FROM blocks") rows = cursor.fetchall() for row in rows: block = {} block['id'] = row[0] self.blocks.add(block) def add_block(self, block): # 检查必要信息是否存在 if 'id' not in block: return self.blocks.add(block) def get_block(self, block): if block in self.blocks: return block else: return None def dump(self): cursor = self.conn.cursor() cursor.execute("CREATE TABLE IF NOT EXISTS blocks (id TEXT)") for block in self.blocks: cursor.execute("INSERT INTO blocks (id) VALUES (?)", (block['id'],)) self.conn.commit() #将数据输出到一个json文件,便于在tiled进行观察,可以是单层或者多层的,多层的话,层级按照从小到大排列(层级是布局层级,不是视觉层级) def output_to_json(slices, suffix="ex"): with open("/Users/xulianxin/Documents/develop/game/TileMatch/TileManor.Lv/TileManor/templates/tm_0000.json", 'r') as f: json_temp = json.load(f) for i in range(0, len(slices)): with open("/Users/xulianxin/Documents/develop/game/TileMatch/TileManor.Lv/TileManor/slices/slice_%d_%s.json" % (i, suffix), "w") as out_f: json_temp["layers"][0]["data"] = slices[i] json.dump(json_temp, out_f) def output_block(block, size, suffix): with open("/Users/xulianxin/Documents/develop/game/TileMatch/TileManor.Lv/TileManor/templates/tm_0000.json", 'r') as f: json_temp = json.load(f) with open("/Users/xulianxin/Documents/develop/game/TileMatch/TileManor.Lv/TileManor/blocks/block_%s.json" % (suffix,), "w") as out_f: for pos in block: x,y,z = pos # 0 是 mark json_temp["layers"][z+1]["data"][y*size[1]+x] = '1' json.dump(json_temp, out_f) def get_block_from(tiles_from, tiles_by_pos): block = set() stack = [p for p in tiles_from] while len(stack) > 0: tile = stack.pop() block.add(tile) x,y,z = tile while z > 0: for adj in [(0,0), (0,1), (0,-1), (1,0), (-1,0), (-1,-1), (1,1), (-1,1), (1,-1)]: pos = (x+adj[0], y+adj[1], z-1) if pos in tiles_by_pos: stack.append(pos) z -= 1 return block # 将 tiles_at_top 按照连通性,划分成若干个组 # tiles_at_top只有xy坐标,无z def split_shapes(tiles_at_top): # 从第一个tile开始,逐个tile进行遍历,如果该tile的上下左右有tile,则将其加入到一个组中,直至所有的tile都被处理 shapes = [] for tile in tiles_at_top: shape_aleary = None for shape in shapes: if tile in shape: shape_aleary = shape break if shape_aleary == None: shape_aleary = set() shape_aleary.add(tile) shapes.append(shape_aleary) x,y = tile 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)]: adj_x = x + adj[0] adj_y = y + adj[1] pos = (adj_x, adj_y) if pos in tiles_at_top: # 如果该位置已经在某个shape里面,则将两个shape合并 shape1 = None for shape in shapes: if pos in shape: shape1 = shape break if shape1 != None and shape1 != shape_aleary: shape_aleary.update(shape1) shapes.remove(shape1) else: shape_aleary.add(pos) return shapes # 解析一个关卡文件,得到各层的数据,是按照视觉层次划分的 def parse_blocks(jsonLv): jsonData = "" tilesByPos = {} maxZ = 0 w = 0 h = 0 # 处理各层的tile数据 with open(jsonLv, 'r') as f:#, encoding='utf-8' jsonData = json.load(f) # 得到宽高信息 w = int(jsonData['width']) h = int(jsonData['height']) for item in jsonData['layers']: name = item['name'] if not name.startswith('Tile_'): # stacked continue z = int(name[5:]) data = item['data'] for i in range(0, len(data)): if data[i] == 0: continue tile_x = (int)(i % w) tile_y = (int)(i / h) tile_z = z # 一些统计信息 tilesByPos[(tile_x, tile_y, tile_z)] = [1,0] # [tile类型,zView--视觉层级,默认是0] if tile_z > maxZ: maxZ = tile_z # 根据上面的布局信息,得到视觉顶层的所有tile tiles_at_top = [] for z in range(0, maxZ+1): z = maxZ - z for x in range(0, w+1): for y in range(0, h+1): if (x,y,z) in tilesByPos: tile = tilesByPos[(x, y, z)] 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)] # 确定视觉层级 zvMax = -1 for zup in range(z+1, maxZ+1): for adj in adjs: if (adj[0],adj[1],zup) in tilesByPos: zv = tilesByPos[adj[0],adj[1],zup][1] if zv > zvMax: zvMax = zv zv = zvMax + 1 tilesByPos[(x, y, z)][1] = zv if zv == 0: tiles_at_top.append((x, y, z)) # 将 tiles_at_top 按照连通性,划分成若干个组 tops = [(x,y) for x,y,z in tiles_at_top] print("tops:", tops) shapes = split_shapes(tops) print("shapes:", shapes) # 对每一个组,得到其block blocks = [] for i in range(0, len(shapes)): shape = shapes[i] ts = [(x,y,z) for x,y,z in tiles_at_top if (x,y) in shape] block = get_block_from(ts, tilesByPos) if len(block) > len(ts): blocks.append(block) return blocks, (w,h) # 测试获取视觉层级的数据是否ok def test_parse_blocks(): parse_blocks("/Users/xulianxin/Documents/develop/game/TileMatch/TileManor.Lv/TileManor/templates/tm_0004.json") #评估一个布局的好坏,返回一个分数 #布局的好坏,可以从几个方面来评估: #1. 是否超出范围; #2. 是否有某种对称性; #3. tile的数量是否合理; def eva_layout(): pass # 生成一个随机的 def generate_tops(): pass if __name__ == '__main__': blocks_lib = set() for directory in ["/Users/xulianxin/Documents/develop/game/TileMatch/TileManor.Lv/TileManor/tf_templates", ]: for filename in os.listdir(directory): filepath = os.path.join(directory, filename) if os.path.isfile(filepath) and filepath.endswith('.json'): blocks, size = parse_blocks(filepath) for i in range(len(blocks)): block = blocks[i] # 将block都挪动到左上角,进行排重 minx = min([x for x,y,z in block]) miny = min([y for x,y,z in block])-1 block = tuple((x-minx, y-miny, z) for x,y,z in block) if block not in blocks_lib: blocks_lib.add(block) output_block(block, size, filename.split(".")[0] + "_%d" % (i,)) else: print("dumplicated!") pass