123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286 |
- import json
- import math
- import xml.etree.ElementTree as ET
- import re
- import os
- from logging import setLoggerClass
- # 使用python3.x
- # 2024-11-01 盘子按层分组,每层可以有一个或者多个盘子,一个CCNode就表示一层。
- # 钉子的图片名-ID映射表
- #screw_pic_to_id_map = {"sg_screw1.png":1,"sg_screw2.png":2,"sg_screw3.png":3}
- # 盘子的图片名-ID映射表
- #plate_pic_to_id_map = {"sg_plant1.png":1,"sg_plant0.png":2}
- # 目标盒子的图片名-ID映射表
- #target_pic_to_id_map = {"sg-目标容器-1.png":1,"sg-目标容器-2.png":2}
- def xml_to_dict(root: ET.Element):
- """将XML文件解析为python dict"""
- ret_arr = []
- ret_dict = {}
- if root.tag == "dict":
- idx = 0
- while idx < len(root):
- if root[idx].tag == "key":
- ret_dict[root[idx].text] = xml_to_dict(root[idx + 1])
- idx += 1
- idx += 1
- return ret_dict
- elif root.tag == "array":
- idx = 0
- while idx < len(root):
- ret_arr.append(xml_to_dict(root[idx]))
- idx += 1
- return ret_arr
- elif root.tag == "plist":
- for child in root:
- ret_dict["plist"] = xml_to_dict(child)
- break
- return ret_dict
- else:
- return root.text
- def get_ccnode_list(conf_dict: dict):
- """从node_graph字典下获取target(任务目标)和element(元素)的list"""
- node_graph_dict = conf_dict["plist"]["nodeGraph"]["children"]
- return node_graph_dict[0]["children"]
- def get_all_target(target_list: list):
- """获取所有target的list"""
- all_target_list = []
- for dic in target_list:
- propertieIdx = 0
- while True:
- propertie = dic["properties"][propertieIdx]
- if propertie["name"] == "displayFrame":
- displayFrame = propertie["value"][1]
- break
- propertieIdx = propertieIdx+1
- displayFrame = os.path.basename(displayFrame)
- resTagrgetId = target_pic_to_id_map[displayFrame]
- screwIds = []
- for target_dict in dic["children"]:
- # 展示的目标名称可能和采用的图片不一样 所以先不用这个
- # display_name_str = target_dict["displayName"]
- target_properties_list = target_dict["properties"]
- propertieIdx = 0
- while True:
- propertie = target_properties_list[propertieIdx]
- if propertie["name"] == "displayFrame":
- target_pic_name = propertie["value"][1]
- break
- propertieIdx = propertieIdx+1
- target_pic_name = os.path.basename(target_pic_name)
- # print (target_pic_name)
- if target_pic_name not in screw_pic_to_id_map.keys():
- screw_pic_to_id_map[target_pic_name] = len(screw_pic_to_id_map) + 1
- screwIds.append(screw_pic_to_id_map[target_pic_name])
- all_target_list.append({"targetResId":resTagrgetId, "screwIds":screwIds})
- return all_target_list
- def get_node_position( elem ):
- for ppt in elem["properties"]:
- if( ppt["name"] == "position"):
- return ppt["value"][0],ppt["value"][1]
- return 0,0
- def is_point_in_plane(point, plane):
- a, b, c = plane
- x, y = point
- return a * x + b * y + c > 0
- def is_intersect(p, a, b):
- px, py = p
- x1, y1 = a
- x2, y2 = b
- if (py < y1 and py < y2) or (py > y1 and py > y2):
- return False
- if px > max(x1, x2):
- return False
- if x1 == x2:
- return True
- k = (y2 - y1) / (x2 - x1)
- x = (py - y1) / k + x1
- if x > px:
- return True
- else:
- return False
- # 判断点是否落在多边形内部
- def isPointInsidePolygon(point , polygon_points):
- intersect_cnt = 0
- for i in range(len(polygon_points)-1) :
- p = polygon_points[i]
- next_p = polygon_points[i+1]
- if is_intersect(point, p, next_p):
- intersect_cnt += 1
- return intersect_cnt % 2 == 1
- # 读取盘子轮廓多边形点数据
- def readPlatePolygonPoints( jsonFilename ):
- points = []
- with open(jsonFilename,'r') as json_file:
- points = json.load(json_file)
- return points
- # 单点坐标变换
- def pointTransform(point, scalex, scaley, parent_posi , rotate_deg ):
- radians = - rotate_deg * math.pi / 180
- point[0] = point[0] * scalex
- point[1] = point[1] * scaley
- tempx = point[0]*math.cos(radians) - point[1]*math.sin(radians)
- tempy = point[0]*math.sin(radians) + point[1]*math.cos(radians)
- point[0] = tempx + parent_posi[0]
- point[1] = tempy + parent_posi[1]
- return point
- # 全部点坐标变换
- def pointsTransform( points, scalex, scaley, parent_posi , rotate_deg ):
- new_points = []
- for pt in points:
- pt = pointTransform(pt,scalex,scaley,parent_posi , rotate_deg)
- new_points.append(pt)
- return new_points
- def get_plate_data_list(elem_list: list):
- """获取盘子信息列表"""
- layers_data = []
- plateId = 1
- screwId = 1
- # for each layer
- for dic in elem_list:
- # dic 为一个 CCNode
- plates_data = []
- screws_data = []
- ccnodex, ccnodey = get_node_position( dic )
- ccnodex = float(ccnodex)
- ccnodey = float(ccnodey)
- # for each srew and plate
- for elem_dict in dic["children"]:
- # elem_dict 为一个钉子或者盘子
- # CCNode 下面盘子和钉子由关卡编辑人员摆放,不在人工添加层级信息,
- # 由程序负责判断钉子归宿某个盘子,如果钉子不属于任何盘子那么丢弃。
- if elem_dict["displayName"] == "盘子":
- plate_property = elem_dict["properties"]
- # 处理盘子的信息
- one_plate_data = {}
- one_plate_data["rotate"] = 0.0
- one_plate_data["scale_x"] = 1.0
- one_plate_data["scale_y"] = 1.0
- spriteFrameName = ""
- for ele in plate_property:
- dict_values = ele.values()
- if "displayFrame" in dict_values:
- spriteFrameName = ele["value"][1]
- one_plate_data["sprite_frame_name"] = spriteFrameName # new added.
- elif "rotation" in dict_values:
- one_plate_data["rotate"] = round(float(ele["value"]), 1)
- elif "scale" in dict_values:
- one_plate_data["scale"] = round(float(ele["value"][0]), 1) # deprecated
- one_plate_data["scale_x"] = round(float(ele["value"][0]), 1)
- one_plate_data["scale_y"] = round(float(ele["value"][1]), 1)
- elif "position" in dict_values:
- one_plate_data["position"] = [round(ccnodex + float(ele["value"][0])),
- round(ccnodey + float(ele["value"][1]), 1)]
- # print("plate:"+spriteFrameName)
- one_plate_data["plateId"] = plateId # this is useless.
- plateId += 1
- one_plate_data["zorder"] = len(plates_data) + 1 # the plates appeared in plist are in bottom first order.
- plates_data.append(one_plate_data)
- else:
- # 钉子
- screw_property = elem_dict["properties"]
- one_screw_dict = {}
- one_screw_dict["rotate"] = 0.0
- one_screw_dict["scale_x"] = 1.0
- one_screw_dict["scale_y"] = 1.0
- for ele in screw_property:
- dict_values = ele.values()
- if "displayFrame" in dict_values:
- spriteFrameName = ele["value"][1]
- one_screw_dict["sprite_frame_name"] = spriteFrameName # new added.
- elif "rotation" in dict_values:
- one_screw_dict["rotate"] = round(float(ele["value"]), 1)
- elif "scale" in dict_values:
- one_screw_dict["scale"] = round(float(ele["value"][0]), 1)
- one_screw_dict["scale_x"] = round(float(ele["value"][0]), 1)
- one_screw_dict["scale_y"] = round(float(ele["value"][1]), 1)
- elif "position" in dict_values:
- one_screw_dict["position"] = [round(ccnodex + float(ele["value"][0])),
- round(ccnodey + float(ele["value"][1]), 1)]
- # print(" --> screw:" + one_screw_dict["sprite_frame_name"])
- one_screw_dict["screwId"] = screwId # this is useless.
- screwId=screwId+1
- screws_data.append(one_screw_dict)
- #end if...else...
- # endfor each screw and plate
- # 判断钉子属于哪个盘子,然后把钉子放到盘子里
- for plateX in plates_data:
- plateX["screws"] = []
- # read polygon points
- plate_points =readPlatePolygonPoints( "../轮廓/sg_盘子轮廓/" + plateX["sprite_frame_name"] + ".json" ) # read from file
- plate_points = pointsTransform(plate_points, plateX["scale_x"], plateX["scale_y"], plateX["position"] , plateX["rotate"] )
- for screwX in screws_data:
- screw_posi = screwX["position"]
- if( isPointInsidePolygon(screw_posi, plate_points) ):
- plateX["screws"].append( screwX )
- print( "debug lyr ", len(layers_data) + 1, "-> plate ", plateX["plateId"] , "--> screw " , screwX["screwId"] )
- # 构建一个层对象
- layer1 = {}
- layer1["layerId"] = len(layers_data) + 1
- layer1["plates"] = plates_data
- layers_data.append(layer1)
- # endfor each layer
- return layers_data
- def py_dict_to_json_file(py_dict: dict, json_path: str):
- """将python dict写到JSON文件中"""
- #file_name = re.findall(r"(?=/).*(?=.red)", xml_path)[0]
- #file_name = re.findall(r"[^/]+$", file_name)[0]
- #file_name += ".json"
- j_data = json.dumps(py_dict)
- #jsonFilename="../config/" + file_name
- print("output: " + json_path)
- with open(json_path, "w") as file:
- file.write(j_data)
- if __name__ == "__main__":
- # 遍历关卡目录(../关卡)下全部 *关卡*.red 文件,将其转换为json格式,存储在 ../config 目录下。
- for (root,dirs,files) in os.walk('../关卡',topdown=True):
- #print("Directory path: %s"%root)
- #print("Directory Names: %s"%dirs)
- #print("Files Names: %s"%files)
- for fname in files:
- if( "关卡" in fname and ".red" in fname and ( "测试" in fname or "old" in fname ) ):
- jsonName = fname.replace(".red",".json")
- xml_path = root+"/"+fname
- out_json_path = "../config/"+jsonName
- print("input: "+xml_path)
- element_tree = ET.parse(xml_path)
- conf_dict = xml_to_dict(element_tree.getroot())
- ccnode_list = get_ccnode_list(conf_dict)
- target_and_plateData_dict = {
- "target": {},
- "layerData": get_plate_data_list(ccnode_list)
- }
- py_dict_to_json_file(target_and_plateData_dict, out_json_path)
|