isometricGame.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973
  1. #define GLM_ENABLE_EXPERIMENTAL
  2. #include "glm/gtx/hash.hpp"
  3. #include <containers/isometricGame/isometricGame.h>
  4. #include <containers/isometricGame/isometricGameEditor.h>
  5. #include <glui/glui.h>
  6. #include <deque>
  7. #include <unordered_map>
  8. #include <safeSave/safeSave.h>
  9. bool IsometricGame::create(RequestedContainerInfo &requestedInfo, pika::StaticString<256> commandLineArgument)
  10. {
  11. renderer.create(requestedInfo.requestedFBO.fbo);
  12. tiles = pika::gl2d::loadTextureWithPixelPadding(PIKA_RESOURCES_PATH "iso/tiles/Isometric-Tiles.png", requestedInfo, 32, true);
  13. shadow = pika::gl2d::loadTexture(PIKA_RESOURCES_PATH "iso/tiles/shadow.png", requestedInfo, 32, true);
  14. tilesAtlas = gl2d::TextureAtlasPadding(16, 8, tiles.GetSize().x, tiles.GetSize().y);
  15. playerSprite = pika::gl2d::loadTexture(PIKA_RESOURCES_PATH "iso/tiles/IsoCharacter.png",
  16. requestedInfo, true);
  17. playerAtlas = gl2d::TextureAtlas(5, 4);
  18. itemsSprite = pika::gl2d::loadTexture(PIKA_RESOURCES_PATH "iso/tiles/items.png",
  19. requestedInfo, true);
  20. itemsAtlas = gl2d::TextureAtlas(3, 1);
  21. itemFrameSprite = pika::gl2d::loadTexture(PIKA_RESOURCES_PATH "iso/tiles/ui.png",
  22. requestedInfo, true);
  23. font = pika::gl2d::loadFont(PIKA_RESOURCES_PATH "mcDungeons/CommodorePixeled.ttf", requestedInfo);
  24. for (int i = 0; i < MAPS_COUNT; i++)
  25. {
  26. //editor.loadFromFile(renderer, commandLineArgument.to_string(), requestedInfo);
  27. size_t s = 0;
  28. std::string fileName = PIKA_RESOURCES_PATH "iso/maps/map" + std::to_string(i+1) + ".isomap";
  29. glm::ivec3 mapSize = {};
  30. bool created = 0;
  31. if (requestedInfo.readEntireFileBinary(fileName, &mapSize, sizeof(mapSize), 0))
  32. {
  33. if (requestedInfo.getFileSizeBinary(fileName, s))
  34. {
  35. if (s == mapSize.x * mapSize.y * mapSize.z * sizeof(Block) + sizeof(mapSize))
  36. {
  37. created = 1;
  38. levels[i].init(mapSize);
  39. requestedInfo.readEntireFileBinary(fileName,
  40. levels[i].mapData.data(), mapSize.x * mapSize.y * mapSize.z * sizeof(Block), sizeof(mapSize));
  41. }
  42. }
  43. }
  44. if (!created)
  45. {
  46. requestedInfo.consoleWrite("Error loading file: " + std::to_string(i) + "\n");
  47. return 0;
  48. }
  49. }
  50. size_t s = 0;
  51. if (requestedInfo.getFileSizeBinary(PIKA_RESOURCES_PATH "iso/save.bin", s))
  52. {
  53. char *buffer = new char[s];
  54. if (requestedInfo.readEntireFileBinary(PIKA_RESOURCES_PATH "iso/save.bin", buffer, s))
  55. {
  56. sfs::SafeSafeKeyValueData data;
  57. data.loadFromFileData(buffer, s);
  58. bool good = true;
  59. good = data.getFloat("life", life) == sfs::noError;
  60. if (good)
  61. {
  62. good = data.getInt("redstoneCount", redstoneCount) == sfs::noError;
  63. good = data.getInt("redstoneTorchesCount", redstoneTorchesCount) == sfs::noError;
  64. good = data.getInt("foodCount", foodCount) == sfs::noError;
  65. good = data.getInt("itemSelected", itemSelected) == sfs::noError;
  66. good = data.getInt("currentLevel", currentLevel) == sfs::noError;
  67. void *ptr = 0;
  68. size_t s = 0;
  69. good = data.getRawDataPointer("playerPosition", ptr, s) == sfs::noError;
  70. good = s == sizeof(playerPosition);
  71. if (good)
  72. {
  73. memcpy(&playerPosition, ptr, s);
  74. }
  75. else { return 0; }
  76. for (int i = 0; i < MAPS_COUNT; i++)
  77. {
  78. void *ptr = 0;
  79. size_t s = 0;
  80. data.getRawDataPointer("map" + std::to_string(i),
  81. ptr, s);
  82. good = s == sizeof(levels[i].mapData[0]) * levels[i].size.x
  83. * levels[i].size.y * levels[i].size.z;
  84. good = s == levels[i].mapData.size() * sizeof(levels[i].mapData[0]);
  85. if (good)
  86. {
  87. memcpy(levels[i].mapData.data(), ptr, s);
  88. }
  89. }
  90. if (!good) { return 0; }
  91. }
  92. }
  93. delete[] buffer;
  94. }
  95. return true;
  96. }
  97. static bool canPlayerStay(int type, int redstone)
  98. {
  99. return type == 0 || type == IsometricGameEditor::Blocks::redstone ||
  100. type == IsometricGameEditor::Blocks::redstoneTorch ||
  101. type == IsometricGameEditor::Blocks::chest ||
  102. type == IsometricGameEditor::Blocks::lever ||
  103. (type == IsometricGameEditor::Blocks::trapdor && redstone == 1);
  104. }
  105. bool IsometricGame::update(pika::Input input, pika::WindowState windowState, RequestedContainerInfo &requestedInfo)
  106. {
  107. #pragma region clear stuff
  108. glClear(GL_COLOR_BUFFER_BIT);
  109. renderer.updateWindowMetrics(windowState.windowW, windowState.windowH);
  110. #pragma endregion
  111. float size = 100;
  112. #pragma region Change Level
  113. {
  114. bool changedRoom = 0;
  115. if (currentLevel == 0)
  116. {
  117. if(
  118. playerPosition == glm::ivec3{0,1,10} ||
  119. playerPosition == glm::ivec3{0,1,11}
  120. )
  121. {currentLevel = 1; playerPosition = glm::ivec3(8, 1, 4); changedRoom = true;}
  122. else
  123. if(
  124. playerPosition == glm::ivec3{4,1,6} ||
  125. playerPosition == glm::ivec3{3,1,6}
  126. )
  127. {currentLevel = 2; playerPosition = glm::ivec3(3, 1, 7); changedRoom = true;};
  128. }
  129. else if (currentLevel == 1)
  130. {
  131. if (
  132. playerPosition == glm::ivec3{0,1,4}
  133. ){currentLevel = 3; playerPosition = glm::ivec3(8, 1, 2); changedRoom = true;}
  134. else if (playerPosition == glm::ivec3(9, 1, 4) ||
  135. playerPosition == glm::ivec3(9, 1, 5)
  136. )
  137. {
  138. currentLevel = 0; playerPosition = glm::ivec3(1, 1, 10); changedRoom = true;
  139. }
  140. }
  141. else if (currentLevel == 2)
  142. {
  143. if (
  144. playerPosition == glm::ivec3{3,1,9} ||
  145. playerPosition == glm::ivec3{2,1,9}
  146. )
  147. {
  148. currentLevel = 0; playerPosition = glm::ivec3(4, 1, 7); changedRoom = true;
  149. }
  150. }
  151. else if (currentLevel == 3)
  152. {
  153. if (
  154. playerPosition == glm::ivec3{9,1,2} ||
  155. playerPosition == glm::ivec3{9,1,3}
  156. )
  157. {
  158. currentLevel = 1; playerPosition = glm::ivec3(1, 1, 4); changedRoom = true;
  159. }else
  160. if (
  161. playerPosition == glm::ivec3{1,1,16} ||
  162. playerPosition == glm::ivec3{0,1,16} ||
  163. playerPosition == glm::ivec3{0,1,15}
  164. )
  165. {
  166. currentLevel = 4; playerPosition = glm::ivec3(13, 1, 3); changedRoom = true;
  167. }
  168. }
  169. else if (currentLevel == 4)
  170. {
  171. if (
  172. playerPosition == glm::ivec3{14,1,3} ||
  173. playerPosition == glm::ivec3{14,1,4}
  174. )
  175. {
  176. currentLevel = 3; playerPosition = glm::ivec3(2, 1, 16); changedRoom = true;
  177. }
  178. else if(playerPosition == glm::ivec3{6,1,14} ||
  179. playerPosition == glm::ivec3{5,1,14})
  180. {
  181. return 0;
  182. }
  183. }
  184. if (changedRoom)
  185. {
  186. path = {};
  187. }
  188. }
  189. #pragma endregion
  190. life -= input.deltaTime * 0.004;
  191. if (life <= 0) { return 0; }
  192. IsometricGameEditor::Map &map = levels[currentLevel];
  193. #pragma region Redstone
  194. auto getRedstoneStatusUnsafe = [&](glm::ivec3 v) -> RedstoneStatus &
  195. {
  196. return redstone[v.x * map.size.z * map.size.y + v.y * map.size.z + v.z];
  197. };
  198. {
  199. redstone.clear();
  200. redstone.resize(map.size.x * map.size.y * map.size.z);
  201. std::vector<glm::ivec3> emitors;
  202. for (int x = 0; x < map.size.x; x++)
  203. for (int y = 0; y < map.size.y; y++)
  204. for (int z = 0; z < map.size.z; z++)
  205. {
  206. auto b = map.getSafe({x,y,z});
  207. if (b->get().x == IsometricGameEditor::Blocks::redstoneBlock ||
  208. b->get().x == IsometricGameEditor::Blocks::redstoneTorch ||
  209. (b->get().x == IsometricGameEditor::Blocks::lever && b->get().y == 1)
  210. )
  211. {
  212. emitors.emplace_back(x, y, z);
  213. getRedstoneStatusUnsafe({x, y, z}).status = 1;
  214. }
  215. }
  216. while (!emitors.empty())
  217. {
  218. auto emitor = emitors.back();
  219. emitors.pop_back();
  220. auto check = [&](glm::ivec3 pos)
  221. {
  222. auto b = map.getSafe(pos);
  223. if(b)
  224. {
  225. if (getRedstoneStatusUnsafe(pos).status == 0)
  226. {
  227. getRedstoneStatusUnsafe(pos).status = 1;
  228. if (b->get().x == IsometricGameEditor::Blocks::redstone)
  229. {
  230. emitors.push_back(pos);
  231. }
  232. }
  233. }
  234. };
  235. check(emitor + glm::ivec3(1, 0, 0));
  236. check(emitor + glm::ivec3(-1, 0, 0));
  237. check(emitor + glm::ivec3(0, 1, 0));
  238. check(emitor + glm::ivec3(0, -1, 0));
  239. check(emitor + glm::ivec3(0, 0, 1));
  240. check(emitor + glm::ivec3(0, 0, -1));
  241. }
  242. }
  243. #pragma endregion
  244. #pragma region UI1
  245. glm::vec4 uiBox = {};
  246. {
  247. glui::Frame f({0, 0, windowState.windowW, windowState.windowH});
  248. uiBox = glui::Box().xLeftPerc(0.05).yTopPerc(0.02)
  249. .xDimensionPercentage(0.4).yDimensionPercentage(0.2);
  250. float boxSize = std::min(uiBox.z / 3.f, uiBox.w);
  251. uiBox.z = boxSize * 3;
  252. uiBox.w = boxSize;
  253. }
  254. #pragma endregion
  255. auto calculateBlockPos = [size](glm::vec3 in)
  256. {
  257. glm::vec2 position = {};
  258. position += glm::vec2(-size / 2.f, size / 4.f) * float(in.x);
  259. position += glm::vec2(size / 2.f, size / 4.f) * float(in.z);
  260. position += glm::vec2(0, -size / 2.f) * float(in.y);
  261. return position;
  262. };
  263. #pragma region camera
  264. //renderer.currentCamera.follow(calculateBlockPos({map.size.x / 2-1, 1, map.size.z / 2}),
  265. // 100, 0, 0, windowState.windowW, windowState.windowH);
  266. renderer.currentCamera.follow(calculateBlockPos({glm::vec3(playerPosition) + playerAnimations.delta}),
  267. input.deltaTime*180, 1, 90, windowState.windowW, windowState.windowH);
  268. #pragma endregion
  269. glm::ivec3 currentSelectedBlockDelete{-1};
  270. glm::ivec3 currentSelectedBlockPlace{-1};
  271. glm::ivec3 currentBlockInteract{-1};
  272. glm::ivec3 currentBlockMove{-1};
  273. auto viewRect = renderer.getViewRect();
  274. auto lerp = [](auto a, auto b, auto c)
  275. {
  276. return a * (1.f - c) + b * c;
  277. };
  278. glm::vec2 blockPositionScreen = lerp(glm::vec2(viewRect.x, viewRect.y),
  279. glm::vec2(viewRect.x + viewRect.z, viewRect.y + viewRect.w),
  280. glm::vec2(input.mouseX, input.mouseY) / glm::vec2(windowState.windowW, windowState.windowH));
  281. for (int y = 0; y < map.size.y; y++)
  282. for (int z = 0; z < map.size.z; z++)
  283. for (int x = 0; x < map.size.x; x++)
  284. {
  285. auto checkPointInBox = [&](int x, int y, int z, bool reverse = 0)
  286. {
  287. auto b = map.getSafe({x,y,z});
  288. if (!b) { return false; }
  289. if ((b->get().x != 0 && !reverse)
  290. || (b->get().x == 0 && reverse)
  291. )
  292. {
  293. glm::vec2 position = calculateBlockPos({x,y,z});
  294. glm::vec4 box = renderer.toScreen({position, size, size});
  295. //todo new functon
  296. box.x += 1;
  297. box.x /= 2.f;
  298. box.x *= renderer.windowW;
  299. box.y *= -1;
  300. box.y += 1;
  301. box.y /= 2.f;
  302. box.y *= renderer.windowH;
  303. box.z += 1;
  304. box.z /= 2.f;
  305. box.z *= renderer.windowW;
  306. box.w *= -1;
  307. box.w += 1;
  308. box.w /= 2.f;
  309. box.w *= renderer.windowH;
  310. box.z = box.z - box.x;
  311. box.w = box.w - box.y;
  312. if (IsometricGameEditor::pointInBox(glm::vec2(input.mouseX, input.mouseY), box)
  313. && !IsometricGameEditor::pointInBox(glm::vec2(input.mouseX, input.mouseY), uiBox)
  314. )
  315. {
  316. float manhatan1 = glm::dot((glm::vec2(input.mouseX, input.mouseY) - glm::vec2(box)), glm::vec2(1,1));
  317. float manhatan2 = glm::dot((glm::vec2(box) + glm::vec2(box.z, box.w)
  318. - glm::vec2(input.mouseX, input.mouseY)), glm::vec2(1, 1));
  319. if (manhatan1 > size / 4)
  320. if (manhatan2 > size / 4)
  321. {
  322. return true;
  323. }
  324. }
  325. }
  326. return false;
  327. };
  328. if (checkPointInBox(x,y,z))
  329. {
  330. //if (y != 1 && canPlayerStay(map.getSafe({x,y,z}))) {}
  331. currentSelectedBlockDelete = {x,y,z};
  332. if (checkPointInBox(x + 1, y, z, true))
  333. {
  334. currentSelectedBlockPlace = {x + 1,y,z};
  335. }
  336. if (checkPointInBox(x, y + 1, z, true))
  337. {
  338. currentSelectedBlockPlace = {x,y + 1,z};
  339. }
  340. if (checkPointInBox(x, y, z + 1, true))
  341. {
  342. currentSelectedBlockPlace = {x,y,z + 1};
  343. }
  344. }
  345. }
  346. if (currentSelectedBlockDelete.y == 0)
  347. {
  348. if (currentSelectedBlockPlace == currentSelectedBlockDelete + glm::ivec3(0, 1, 0))
  349. {
  350. currentBlockMove = currentSelectedBlockPlace;
  351. }
  352. }
  353. else if (currentSelectedBlockDelete.y == 1)
  354. {
  355. if (canPlayerStay(map.getSafe(currentSelectedBlockDelete)->get().x,
  356. getRedstoneStatusUnsafe(currentSelectedBlockDelete).status)
  357. )
  358. {
  359. currentBlockMove = currentSelectedBlockDelete;
  360. }
  361. else
  362. {
  363. currentBlockInteract = currentSelectedBlockDelete;
  364. }
  365. }
  366. else
  367. {
  368. currentSelectedBlockDelete = glm::vec3{-1};
  369. currentSelectedBlockPlace = glm::vec3{-1};
  370. }
  371. for (int y = 0; y < map.size.y; y++)
  372. for (int z = 0; z < map.size.z; z++)
  373. for (int x = 0; x < map.size.x; x++)
  374. {
  375. auto b = map.getSafe({x,y,z});
  376. if (b->get().x != 0)
  377. {
  378. glm::vec2 position = calculateBlockPos({x,y,z});
  379. glm::vec4 color = Colors_White;
  380. auto cr = glm::vec4(0.4, 0.2, 0.1, 1.0);
  381. if (b->get().x == IsometricGameEditor::Blocks::redstone)
  382. {
  383. if (getRedstoneStatusUnsafe({x,y,z}).status == 1)
  384. {
  385. color = glm::vec4(0.9, 0.25, 0.25, 1.0);
  386. cr = glm::vec4(0.9, 0.25, 0.25, 1.0);
  387. }
  388. else
  389. {
  390. color = glm::vec4(0.4, 0.1, 0.1, 1.0);
  391. cr = glm::vec4(0.4, 0.1, 0.1, 1.0);
  392. }
  393. }
  394. if (b->get().x == IsometricGameEditor::Blocks::redstone || b->get().x == IsometricGameEditor::Blocks::lever
  395. || b->get().x == IsometricGameEditor::Blocks::redstoneTorch
  396. )
  397. {
  398. auto b2 = map.getSafe({x,y,z - 1});
  399. if (b2 && IsometricGameEditor::redstoneWire(b2->type))
  400. {
  401. renderer.renderRectangle({position,size,size}, tiles, cr, {}, 0,
  402. tilesAtlas.get(IsometricGameEditor::Blocks::redstone, 1));
  403. }
  404. b2 = map.getSafe({x - 1,y,z});
  405. if (b2 && IsometricGameEditor::redstoneWire(b2->type))
  406. {
  407. renderer.renderRectangle({position,size,size}, tiles, cr, {}, 0,
  408. tilesAtlas.get(IsometricGameEditor::Blocks::redstone, 2));
  409. }
  410. b2 = map.getSafe({x + 1,y,z});
  411. if (b2 && IsometricGameEditor::redstoneWire(b2->type))
  412. {
  413. renderer.renderRectangle({position,size,size}, tiles, cr, {}, 0,
  414. tilesAtlas.get(IsometricGameEditor::Blocks::redstone, 3));
  415. }
  416. b2 = map.getSafe({x,y,z + 1});
  417. if (b2 && IsometricGameEditor::redstoneWire(b2->type))
  418. {
  419. renderer.renderRectangle({position,size,size}, tiles, cr, {}, 0,
  420. tilesAtlas.get(IsometricGameEditor::Blocks::redstone, 4));
  421. }
  422. //redstone on wall
  423. b2 = map.getSafe({x - 1,y + 1,z});
  424. if (b2 && IsometricGameEditor::redstoneWire(b2->type))
  425. {
  426. renderer.renderRectangle({position,size,size}, tiles, cr, {}, 0,
  427. tilesAtlas.get(IsometricGameEditor::Blocks::redstone, 2));
  428. renderer.renderRectangle({position,size,size}, tiles, cr, {}, 0,
  429. tilesAtlas.get(IsometricGameEditor::Blocks::redstone, 5));
  430. }
  431. b2 = map.getSafe({x,y + 1,z - 1});
  432. if (b2 && IsometricGameEditor::redstoneWire(b2->type))
  433. {
  434. renderer.renderRectangle({position,size,size}, tiles, cr, {}, 0,
  435. tilesAtlas.get(IsometricGameEditor::Blocks::redstone, 1));
  436. renderer.renderRectangle({position,size,size}, tiles, cr, {}, 0,
  437. tilesAtlas.get(IsometricGameEditor::Blocks::redstone, 6));
  438. }
  439. //redstone down
  440. b2 = map.getSafe({x + 1,y - 1,z});
  441. if (b2 && IsometricGameEditor::redstoneWire(b2->type))
  442. {
  443. renderer.renderRectangle({position,size,size}, tiles, cr, {}, 0,
  444. tilesAtlas.get(IsometricGameEditor::Blocks::redstone, 3));
  445. }
  446. b2 = map.getSafe({x,y - 1,z + 1});
  447. if (b2 && IsometricGameEditor::redstoneWire(b2->type))
  448. {
  449. renderer.renderRectangle({position,size,size}, tiles, cr, {}, 0,
  450. tilesAtlas.get(IsometricGameEditor::Blocks::redstone, 4));
  451. }
  452. }
  453. if (b->get().x == IsometricGameEditor::Blocks::trapdor)
  454. {
  455. renderer.renderRectangle({position,size,size}, tiles, {1,1,1,1}, {}, 0,
  456. tilesAtlas.get(b->get().x, getRedstoneStatusUnsafe({x,y,z}).status)
  457. );
  458. }
  459. else
  460. {
  461. renderer.renderRectangle({position,size,size}, tiles, color, {}, 0,
  462. tilesAtlas.get(b->get().x, b->get().y));
  463. }
  464. int advance = 1;
  465. for (int y2 = y + 2; y2 < map.size.y; y2++)
  466. {
  467. advance++;
  468. auto b2 = map.getSafe({x,y2,z});
  469. if (b2 && b2->get().x != 0 && b->get().x != IsometricGameEditor::Blocks::redstone
  470. && b->get().x != IsometricGameEditor::Blocks::lever)
  471. {
  472. renderer.renderRectangle({position,size,size}, shadow,
  473. {1,1,1,1.f / advance}
  474. );
  475. break;
  476. }
  477. }
  478. }
  479. if(playerPosition == glm::ivec3(x,y,z))
  480. {
  481. renderer.renderRectangle({calculateBlockPos(glm::vec3(playerPosition) + playerAnimations.delta),size,size}, playerSprite,
  482. Colors_White, {}, 0.f, playerAtlas.get(playerAnimations.indexX, playerAnimations.indexY));
  483. }
  484. //if (currentSelectedBlockDelete == glm::ivec3{x, y, z})
  485. //{
  486. // glm::vec2 position = calculateBlockPos({x,y,z});
  487. //
  488. // renderer.renderRectangle({position,size,size}, tiles, Colors_White, {}, 0,
  489. // tilesAtlas.get(0, 1));
  490. //}
  491. //if (currentSelectedBlockPlace == glm::ivec3{x, y, z})
  492. //{
  493. // glm::vec2 position = calculateBlockPos({x,y,z});
  494. //
  495. // renderer.renderRectangle({position,size,size}, tiles, {0.1,0.1,0.1,0.1}, {}, 0,
  496. // tilesAtlas.get(0, 1));
  497. //}
  498. if (currentBlockMove == glm::ivec3{x, y, z})
  499. {
  500. glm::vec2 position = calculateBlockPos({x,y,z});
  501. renderer.renderRectangle({position,size,size}, tiles, {0.5,0.1,0.1,0.6}, {}, 0,
  502. tilesAtlas.get(0, 1));
  503. }
  504. if (currentBlockInteract == glm::ivec3{x, y, z})
  505. {
  506. glm::vec2 position = calculateBlockPos({x,y,z});
  507. renderer.renderRectangle({position,size,size}, tiles, {1,0.1,0.1,0.6}, {}, 0,
  508. tilesAtlas.get(0, 1));
  509. }
  510. }
  511. #pragma region render player
  512. {
  513. playerAnimations.timer -= input.deltaTime;
  514. if (path.empty())
  515. {
  516. playerAnimations.indexY = 0;
  517. }
  518. else
  519. {
  520. playerAnimations.indexY = 2;
  521. }
  522. if (playerAnimations.timer <= 0)
  523. {
  524. playerAnimations.timer += 0.2;
  525. playerAnimations.indexX += 1;
  526. if (playerAnimations.indexX >= 5)
  527. {
  528. playerAnimations.indexX = 0;
  529. }
  530. }
  531. }
  532. #pragma endregion
  533. #pragma region Move
  534. if (path.empty())
  535. {
  536. timerPath = 0.2;
  537. if (input.lMouse.pressed() && currentBlockMove.x >= 0)
  538. {
  539. std::deque<glm::ivec2> positionsToSearch;
  540. positionsToSearch.push_back({currentBlockMove.x,currentBlockMove.z});
  541. std::unordered_map<glm::ivec2, glm::ivec2> searcehedPositions;
  542. searcehedPositions[glm::ivec2{currentBlockMove.x, currentBlockMove.z}] = glm::ivec2{currentBlockMove.x,currentBlockMove.z};
  543. while (!positionsToSearch.empty())
  544. {
  545. auto currentBlock = positionsToSearch.front();
  546. positionsToSearch.pop_front();
  547. if (currentBlock == glm::ivec2{playerPosition.x,playerPosition.z})
  548. {
  549. playerAnimations.lastPosition = currentBlock;
  550. currentBlock = searcehedPositions[currentBlock];
  551. while (true)
  552. {
  553. currentBlock = searcehedPositions[currentBlock];
  554. path.push_back(currentBlock);
  555. if (currentBlock == glm::ivec2{currentBlockMove.x, currentBlockMove.z})
  556. {
  557. break;
  558. }
  559. }
  560. break;
  561. }
  562. auto tryBlock = [&](int x, int z)
  563. {
  564. auto b = map.getSafe({currentBlock.x + x, 1, currentBlock.y + z});
  565. if (b && canPlayerStay(b->get().x,
  566. getRedstoneStatusUnsafe({currentBlock.x + x, 1, currentBlock.y + z}).status)
  567. && map.getSafe({currentBlock.x + x, 0, currentBlock.y + z})->get().x != 0 //not walking on air
  568. )
  569. {
  570. if (searcehedPositions.find({currentBlock.x + x, currentBlock.y + z})
  571. == searcehedPositions.end())
  572. {
  573. searcehedPositions[glm::ivec2{currentBlock.x + x, currentBlock.y + z}]
  574. = glm::ivec2{currentBlock.x, currentBlock.y};
  575. positionsToSearch.push_back({currentBlock.x + x, currentBlock.y + z});
  576. }
  577. }
  578. };
  579. tryBlock(1, 0);
  580. tryBlock(-1, 0);
  581. tryBlock(0, 1);
  582. tryBlock(0, -1);
  583. }
  584. }
  585. }
  586. else
  587. {
  588. timerPath -= input.deltaTime;
  589. while (timerPath <= 0)
  590. {
  591. timerPath += 0.2;
  592. playerPosition = glm::vec3{path[0].x, 1, path[0].y};
  593. playerAnimations.lastPosition = glm::ivec2(playerPosition.x, playerPosition.z);
  594. path.erase(path.begin());
  595. }
  596. {
  597. glm::vec2 delta = glm::mix(
  598. glm::vec2(path[0].x, path[0].y),
  599. glm::vec2(playerAnimations.lastPosition),
  600. timerPath / 0.2f) - glm::vec2(playerAnimations.lastPosition);
  601. playerAnimations.delta = {delta.x, 0, delta.y};
  602. }
  603. //reached end
  604. if (path.empty())
  605. {
  606. auto b = map.getSafe(playerPosition);
  607. if (b->get().x == IsometricGameEditor::Blocks::lever)
  608. {
  609. //flip lever
  610. b->secondType = !b->get().y;
  611. }
  612. else if (b->get().x == IsometricGameEditor::Blocks::redstone)
  613. {
  614. b->set(0,0);
  615. redstoneCount++;
  616. }
  617. else if (b->get().x == IsometricGameEditor::Blocks::redstoneTorch)
  618. {
  619. b->set(0, 0);
  620. redstoneTorchesCount++;
  621. }
  622. else if (b->get().x == IsometricGameEditor::Blocks::chest)
  623. {
  624. b->set(0, 0);
  625. foodCount++;
  626. }
  627. else if (b->get().x == 0)
  628. {
  629. if (itemSelected == 0 && redstoneCount)
  630. {
  631. //itemSelected = -1;
  632. redstoneCount--;
  633. b->set(IsometricGameEditor::Blocks::redstone, 0);
  634. }else
  635. if (itemSelected == 1 && redstoneTorchesCount)
  636. {
  637. //itemSelected = -1;
  638. redstoneTorchesCount--;
  639. b->set(IsometricGameEditor::Blocks::redstoneTorch, 0);
  640. }
  641. }
  642. saveData(requestedInfo);
  643. }
  644. }
  645. #pragma endregion
  646. #pragma region UI2
  647. if (1)
  648. {
  649. if (itemSelected == 0 && !redstoneCount)
  650. {
  651. itemSelected = -1;
  652. }
  653. if (itemSelected == 1 && !redstoneTorchesCount)
  654. {
  655. itemSelected = -1;
  656. }
  657. renderer.pushCamera();
  658. {
  659. glui::Frame f(uiBox);
  660. renderer.renderRectangle(uiBox, {0.1,0.1,0.1,0.5});
  661. {
  662. auto healthBox = uiBox;
  663. healthBox.y += healthBox.w;
  664. healthBox.w *= 0.3;
  665. healthBox.z *= life;
  666. renderer.renderRectangle(healthBox, {0.9,0.1,0.1,0.5});
  667. }
  668. float boxSize = uiBox.z / 3.f;
  669. if (redstoneCount)
  670. renderer.renderRectangle({uiBox.x, uiBox.y, boxSize, boxSize}, itemsSprite, {1,1,1,0.9},
  671. {}, 0.f, itemsAtlas.get(0, 0));
  672. if (redstoneTorchesCount)
  673. renderer.renderRectangle({uiBox.x + boxSize, uiBox.y, boxSize, boxSize}, itemsSprite, {1,1,1,0.9},
  674. {}, 0.f, itemsAtlas.get(1, 0));
  675. if (foodCount)
  676. renderer.renderRectangle({uiBox.x + boxSize * 2, uiBox.y, boxSize, boxSize}, itemsSprite, {1,1,1,0.9},
  677. {}, 0.f, itemsAtlas.get(2, 0));
  678. if (itemSelected != -1)
  679. {
  680. renderer.renderRectangle({uiBox.x + boxSize * itemSelected, uiBox.y, boxSize, boxSize}, itemFrameSprite);
  681. }
  682. redstone;
  683. if (redstoneCount)
  684. renderer.renderText({uiBox.x + boxSize * 0.75, uiBox.y + boxSize * 0.75},
  685. std::to_string(redstoneCount).c_str(), font, Colors_White);
  686. if (redstoneTorchesCount)
  687. renderer.renderText({uiBox.x + boxSize * 1.75, uiBox.y + boxSize * 0.75},
  688. std::to_string(redstoneTorchesCount).c_str(), font, Colors_White);
  689. if (foodCount)
  690. renderer.renderText({uiBox.x + boxSize * 2.75, uiBox.y + boxSize * 0.75},
  691. std::to_string(foodCount).c_str(), font, Colors_White);
  692. if (input.lMouse.pressed())
  693. {
  694. if (IsometricGameEditor::pointInBox(glm::vec2(input.mouseX, input.mouseY), {uiBox.x, uiBox.y, boxSize, boxSize}))
  695. {
  696. if (itemSelected == 0)
  697. {
  698. itemSelected = -1;
  699. }
  700. else
  701. {
  702. itemSelected = 0;
  703. }
  704. }
  705. if (IsometricGameEditor::pointInBox(glm::vec2(input.mouseX, input.mouseY), {uiBox.x + boxSize, uiBox.y, boxSize, boxSize}))
  706. {
  707. if (itemSelected == 1)
  708. {
  709. itemSelected = -1;
  710. }
  711. else
  712. {
  713. itemSelected = 1;
  714. }
  715. }
  716. if (IsometricGameEditor::pointInBox(glm::vec2(input.mouseX, input.mouseY), {uiBox.x + boxSize * 2, uiBox.y, boxSize, boxSize}))
  717. {
  718. if (foodCount > 0)
  719. {
  720. foodCount--;
  721. life = 1.f;
  722. }
  723. }
  724. }
  725. }
  726. renderer.popCamera();
  727. };
  728. #pragma endregion
  729. //ImGui::Begin("Game debug");
  730. //
  731. //ImGui::DragInt3("player position", &playerPosition[0], 1, 0, 20);
  732. //
  733. //ImGui::End();
  734. renderer.flush();
  735. return true;
  736. }
  737. void IsometricGame::destruct(RequestedContainerInfo &requestedInfo)
  738. {
  739. renderer.cleanup();
  740. }
  741. void IsometricGame::saveData(RequestedContainerInfo &requestedInfo)
  742. {
  743. sfs::SafeSafeKeyValueData data;
  744. data.setFloat("life", life);
  745. data.setInt("redstoneCount", redstoneCount);
  746. data.setInt("redstoneTorchesCount", redstoneTorchesCount);
  747. data.setInt("foodCount", foodCount);
  748. data.setInt("itemSelected", itemSelected);
  749. data.setInt("currentLevel", currentLevel);
  750. data.setRawData("playerPosition", &playerPosition[0], sizeof(playerPosition));
  751. for (int i = 0; i < MAPS_COUNT; i++)
  752. {
  753. data.setRawData("map" + std::to_string(i),
  754. levels[i].mapData.data(),
  755. sizeof(levels[i].mapData[0]) * levels[i].size.x
  756. * levels[i].size.y * levels[i].size.z
  757. );
  758. }
  759. auto fileData = data.formatIntoFileDataBinary();
  760. requestedInfo.writeEntireFileBinary(PIKA_RESOURCES_PATH "iso/save.bin", fileData.data(), fileData.size());
  761. }