main.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. //
  2. // main.cpp
  3. // auto_fill_jewel_v3
  4. //
  5. // Created by Red on 2024/11/22.
  6. //
  7. /*
  8. 需求:
  9. 1.给定宝石种类和每类数量
  10. 2.程序随机给出5种盘子组合
  11. 3.关卡由多个盘子组成,每个盘子包含若干不同层,每层上面包含宝石。
  12. 4.宝石有大、中、小三个尺度,按面积算: 1大=2中=4小
  13. 5.盘子有大、小、迷你3种,其容量分别对应 6个大宝石,3个大宝石,1个大宝石。(确认没有中盘子)
  14. 6.每个关卡最大有9个大盘子。
  15. 7.盘子之间的层数差异在0-1个。迷你盘子数量可以很多,这个是不是需要人工控制后面再问吧。
  16. 8.盘子会移动,但是盘子间不会重叠。
  17. 9.大中小号盘子有横的有竖着的。
  18. 10.重叠区百分比可以从0.05到0.2,程序自行判断最优值。
  19. 11.宝石只提供 80x80的资源,对应大。如果有中和小,需要程序缩放(0.75,0.50)。大、中、小是不同的宝石各消各的。
  20. */
  21. #include <iostream>
  22. #include <string>
  23. #include <vector>
  24. #include "SpriteData.hpp"
  25. #include "ajson5.hpp"
  26. #include "contourdata.h"
  27. #include "LevelGenerate.hpp"
  28. #include "FillGlobalConfig.hpp"
  29. #include "RandomGridFiller.hpp"
  30. #include "BoostGeometryTools.hpp"
  31. #include <opencv2/core.hpp>
  32. #include <opencv2/imgproc.hpp>
  33. #include <opencv2/highgui.hpp>
  34. #include <sstream>
  35. #include <ctime>
  36. #include <chrono>
  37. #include <tuple>
  38. #include <sstream>
  39. #include "LevelThumbTool.hpp"
  40. using namespace ArduinoJson;
  41. using namespace std;
  42. bool writeLevelJson(vector<tuple<int,vector<vector<FillResult>>>>& resultPlateFillResults,
  43. vector<ContourData::Point>& resultPlateCenterPointArr,
  44. string outfilename);
  45. int getGidByFileName(JsonArray *jTileSets, FillGlobalConfig::PlateItem* plate);
  46. int main(int argc, const char * argv[]) {
  47. cout<<"A program to generate level. 2024-11-23"<<endl;
  48. cout<<"usage:auto_fill_jewel_v3"<<endl;
  49. cout<<"version v3.0"<<endl ;
  50. // if( argc!=2 ) {
  51. // cout<<"缺少参数"<<endl;
  52. // return 11 ;
  53. // }
  54. string outname = "测试关卡100.json" ;
  55. FillGlobalConfig::getInstance() ; //inited
  56. vector<tuple<int,vector<vector<FillResult>>>> resultPlateFillResults;
  57. vector<ContourData::Point> resultPlateCenterPointArr;
  58. LevelGenerate genv3 ;
  59. genv3.generate( *FillGlobalConfig::getInstance()->getLevelData(100, 0),
  60. false,
  61. resultPlateFillResults,
  62. resultPlateCenterPointArr
  63. ) ;
  64. cout<<"write result to "<<outname<<endl;
  65. writeLevelJson(resultPlateFillResults, resultPlateCenterPointArr, outname);
  66. LevelThumbTool ltt ;
  67. ltt.makeThumb2(outname+"_thumb.png", resultPlateFillResults, resultPlateCenterPointArr) ;
  68. return 0;
  69. }
  70. int getGidByFileName(JsonArray &jTileSets, FillGlobalConfig::PlateItem* plate) {
  71. static int gid = 0;
  72. for (int i = 0; i < jTileSets.size(); i++){
  73. if (jTileSets[i]["image"] == plate->_pngName){
  74. return static_cast<int>(jTileSets[i]["firstgid"]);
  75. }
  76. }
  77. gid ++;
  78. JsonObject& obj = jTileSets.createNestedObject();
  79. obj["firstgid"] = gid;
  80. obj["image"] = plate->_pngName;
  81. obj["imageheight"] = plate->_bbhei;
  82. obj["imagewidth"] = plate->_bbwid;
  83. obj["margin"] = 0;
  84. obj["name"] = plate->_name;
  85. obj.createNestedObject("properties");
  86. obj["spacing"] = 0;
  87. obj["tileheight"] = plate->_bbhei;
  88. obj["tilewidth"] = plate->_bbwid;
  89. return gid;
  90. }
  91. bool writeLevelJson(vector<tuple<int,vector<vector<FillResult>>>>& resultPlateFillResults,
  92. vector<ContourData::Point>& resultPlateCenterPointArr,
  93. string outfilename)
  94. {
  95. auto fgc = FillGlobalConfig::getInstance() ;
  96. int totalJewelCnt = 0 ;
  97. for(auto itp = resultPlateFillResults.begin();itp!=resultPlateFillResults.end();++itp) {
  98. int plateId = std::get<0>( *itp ) ;
  99. vector<vector<FillResult>>& frArr = std::get<1>( *itp );
  100. for(auto itfr = frArr.begin(); itfr!=frArr.end();++itfr ) {
  101. totalJewelCnt+=itfr->size() ;
  102. }
  103. }
  104. DynamicJsonBuffer jsonBufferTiled;
  105. DynamicJsonBuffer jsonBuffer;
  106. JsonObject& tiledRoot = jsonBufferTiled.createObject();
  107. JsonObject& root = jsonBuffer.createObject();
  108. tiledRoot["height"] = 18;
  109. JsonArray& jLayerArr = tiledRoot.createNestedArray("layers");
  110. JsonObject& lyrObj = jLayerArr.createNestedObject();
  111. lyrObj["draworder"] = "topdown";
  112. lyrObj["height"] = 18;
  113. lyrObj["name"] = "Layer";
  114. JsonArray& jObjArr = lyrObj.createNestedArray("objects"); //盘子信息
  115. lyrObj["opacity"] = 1;
  116. lyrObj["type"] = "objectgroup";
  117. lyrObj["visible"] = true;
  118. lyrObj["width"] = 16;
  119. lyrObj["x"] = 0;
  120. lyrObj["y"] = 0;
  121. tiledRoot["nextobjectid"] = 4;
  122. tiledRoot["orientation"] = "orthogonal";
  123. tiledRoot.createNestedArray("properties");
  124. tiledRoot["renderorder"] = "right-down";
  125. tiledRoot["tileheight"] = 40;
  126. JsonArray& jTileSets = tiledRoot.createNestedArray("tilesets"); //盘子纹理图
  127. tiledRoot["tilewidth"] = 40;
  128. tiledRoot["version"] = 1;
  129. tiledRoot["width"] = 16;
  130. root.createNestedObject("target");//not used.
  131. root["bgtem"] = "no"; //背景redream文件
  132. root["jewel_count"] = totalJewelCnt ;
  133. JsonArray& jplatesArr = root.createNestedArray("plates");
  134. int ids = 1;
  135. for (int i = 0; i < resultPlateFillResults.size(); i ++){
  136. auto itp = resultPlateFillResults.begin() ;
  137. std::advance(itp, i) ;
  138. int plateId = std::get<0>( *itp ) ;
  139. JsonObject& tiledPlateObj = jObjArr.createNestedObject();
  140. tiledPlateObj["gid"] = getGidByFileName(jTileSets, fgc->getPlateItemById(plateId));
  141. tiledPlateObj["height"] = 0;
  142. tiledPlateObj["id"] = ids;
  143. tiledPlateObj["name"] = "plate";
  144. tiledPlateObj.createNestedObject("properties");
  145. tiledPlateObj["rotation"] = 0;
  146. tiledPlateObj["type"] = "";
  147. tiledPlateObj["visible"] = true;
  148. tiledPlateObj["width"] = 0;
  149. float platex = resultPlateCenterPointArr[i].x;
  150. float platey = resultPlateCenterPointArr[i].y;
  151. tiledPlateObj["x"] = platex - fgc->getPlateItemById(plateId)->_bbwid / 2;
  152. tiledPlateObj["y"] = platey - fgc->getPlateItemById(plateId)->_bbhei / 2;
  153. vector<vector<FillResult>>& frArr = std::get<1>( *itp );
  154. JsonObject& plateObj = jplatesArr.createNestedObject();
  155. plateObj["typeId"] = plateId ;
  156. plateObj["plateId"] = ids++;
  157. plateObj["x"] = platex;
  158. plateObj["y"] = platey;
  159. plateObj["sprite_frame_name"] = fgc->getPlateItemById(plateId)->_pngName;
  160. plateObj["sizeX"] = fgc->getPlateItemById(plateId)->_bbwid;
  161. plateObj["sizeY"] = fgc->getPlateItemById(plateId)->_bbhei;
  162. JsonArray& layerArr = plateObj.createNestedArray("layers");
  163. for(int il = 0 ; il < frArr.size() ; ++il ) {
  164. vector<FillResult>& frs = frArr[il];
  165. JsonObject& lyrObj = layerArr.createNestedObject();
  166. lyrObj["rotate"] = 0.0;
  167. lyrObj["scale_x"] = 1.0;
  168. lyrObj["scale_y"] = 1.0;
  169. lyrObj["scale"] = 1.0;
  170. lyrObj["sprite_frame_name"] = fgc->getPlateItemById(plateId)->_pngName;
  171. lyrObj["lyrId"] = ids++;
  172. lyrObj["zorder"] = il+1;
  173. JsonArray& posArr = lyrObj.createNestedArray("position");
  174. posArr.add(platex);
  175. posArr.add(platey);
  176. JsonArray& screwArr = lyrObj.createNestedArray("screws");
  177. for(int ij = 0 ;ij < frs.size();++ ij ) {
  178. FillResult& fr = frs[ij];
  179. FillGlobalConfig::JewelItem* jewPtr = fgc->getJewelItemById(fr._jewelTypeId);
  180. if( fr._jewelTypeId>=0 ) { // -1 is removed.
  181. JsonObject& jobj = screwArr.createNestedObject();
  182. jobj["rotate"] = fr._rotdeg;
  183. jobj["scale_x"] = jewPtr->_scale;
  184. jobj["scale_y"] = jewPtr->_scale;
  185. jobj["csx"] = 0;
  186. jobj["csy"] = 0;
  187. jobj["scale"] = jewPtr->_scale;
  188. jobj["sprite_frame_name"] = jewPtr->_pngName;
  189. jobj["screwId"] = ids++;
  190. jobj["typeId"] = fr._jewelTypeId ;
  191. JsonArray& posArr2 = jobj.createNestedArray("position");
  192. posArr2.add( fr._x ); // 钉子中心在游戏区域的坐标(原点左下角)
  193. posArr2.add( fr._y );
  194. }
  195. }
  196. }
  197. }
  198. string jsonText ;
  199. root.printTo(jsonText);
  200. ofstream ofs( outfilename.c_str() );
  201. if( ofs.good()==false ) return false;
  202. ofs<<jsonText;
  203. jsonText.clear();
  204. tiledRoot.printTo(jsonText);
  205. outfilename.insert(outfilename.size() - 5, "Tiled");
  206. ofstream ofsTiled( outfilename.c_str() );
  207. if( ofsTiled.good()==false ) return false;
  208. ofsTiled<<jsonText;
  209. return true;
  210. }