LevelLoader.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. /*
  2. * 2D Game Engine
  3. * LevelLoader.cpp.c:
  4. * Based on pikuma.com 2D game engine in C++ and Lua course
  5. * Copyright (c) 2021 986-Studio. All rights reserved.
  6. *
  7. * Created by Manoël Trapier on 28/02/2021.
  8. */
  9. #include <math.h>
  10. #include <fstream>
  11. #include <sol/sol.hpp>
  12. #include <LevelLoader.h>
  13. #include <Game.h>
  14. #include <Components/Animation.h>
  15. #include <Components/Transform.h>
  16. #include <Components/RigidBody.h>
  17. #include <Components/Sprite.h>
  18. #include <Components/BoxCollider.h>
  19. #include <Components/KeyboardControl.h>
  20. #include <Components/CameraFollow.h>
  21. #include <Components/Heakth.h>
  22. #include <Components/ProjectileEmitter.h>
  23. #include <Components/TextLabel.h>
  24. #include <Components/Script.h>
  25. LevelLoader::LevelLoader()
  26. {
  27. }
  28. LevelLoader::~LevelLoader()
  29. {
  30. }
  31. void LevelLoader::loadAssetTable(sol::table &assetsTable,
  32. const std::unique_ptr<AssetStore> &assetStore,
  33. SDL_Renderer *renderer)
  34. {
  35. int i = 0;
  36. while(true)
  37. {
  38. sol::optional<sol::table> hasAsset = assetsTable[i];
  39. if (hasAsset == sol::nullopt)
  40. {
  41. break;
  42. }
  43. sol::table asset = assetsTable[i];
  44. std::string assetType = asset["type"];
  45. if (assetType == "texture")
  46. {
  47. assetStore->addTexture(renderer, asset["id"], asset["file"]);
  48. }
  49. else if (assetType == "font")
  50. {
  51. assetStore->addFont(asset["id"], asset["file"], asset["font_size"]);
  52. }
  53. i++;
  54. }
  55. }
  56. void LevelLoader::loadTileMap(sol::table &tileMap,
  57. const std::unique_ptr<Registry> &registry)
  58. {
  59. int tileSize = tileMap["tile_size"];
  60. double tileScale = tileMap["scale"];
  61. int mapNumCols = tileMap["num_cols"];
  62. int mapNumRows = tileMap["num_rows"];
  63. std::string tilesetId = tileMap["texture_asset_id"];
  64. std::fstream mapFile;
  65. std::string mapFilePath = tileMap["map_file"];
  66. mapFile.open(mapFilePath.c_str());
  67. if (!mapFile.is_open())
  68. {
  69. Logger::Error("Cannot open the mapfile '%s'!!", mapFilePath.c_str());
  70. }
  71. for (int y = 0; y < mapNumRows; y++)
  72. {
  73. for (int x = 0; x < mapNumCols; x++)
  74. {
  75. char ch[2] = {0, 0};
  76. mapFile.get(ch[0]);
  77. int srcRectY = atoi(ch) * tileSize;
  78. mapFile.get(ch[0]);
  79. int srcRectX = atoi(ch) * tileSize;
  80. mapFile.ignore();
  81. Entity tile = registry->createEntity();
  82. tile.addComponent<TransformComponent>(glm::vec2(x * (tileScale * tileSize), y * (tileScale * tileSize)), glm::vec2(tileScale, tileScale), 0.0);
  83. tile.addComponent<SpriteComponent>(tilesetId, 0, tileSize, tileSize, false, srcRectX, srcRectY);
  84. tile.group("tiles");
  85. }
  86. }
  87. mapFile.close();
  88. Game::mapWidth = mapNumCols * tileSize * tileScale;
  89. Game::mapHeight = mapNumRows * tileSize * tileScale;
  90. }
  91. void LevelLoader::loadEntities(sol::table &entitiesTable,
  92. const std::unique_ptr<Registry> &registry)
  93. {
  94. uint32_t i;
  95. for(i = 0; i <= entitiesTable.size(); i++)
  96. {
  97. sol::table entity = entitiesTable[i];
  98. Entity newEntity = registry->createEntity();
  99. sol::optional<std::string> tag = entity["tag"];
  100. if (tag != sol::nullopt)
  101. {
  102. newEntity.tag(tag->c_str());
  103. }
  104. sol::optional<std::string> group = entity["group"];
  105. if (group != sol::nullopt)
  106. {
  107. newEntity.group(group->c_str());
  108. }
  109. sol::table componentTable = entity["components"];
  110. for (const auto& key_value_pair : componentTable ) {
  111. sol::object key = key_value_pair.first;
  112. sol::table component = key_value_pair.second;
  113. std::string componentName = key.as<std::string>();
  114. if (componentName == "transform")
  115. {
  116. newEntity.addComponent<TransformComponent>(glm::vec2(component["position"]["x"], component["position"]["y"]),
  117. glm::vec2(component["scale"]["x"], component["scale"]["y"]),
  118. component["rotation"]);
  119. }
  120. else if (componentName == "rigidbody")
  121. {
  122. newEntity.addComponent<RigidBodyComponent>(glm::vec2(component["velocity"]["x"], component["velocity"]["y"]));
  123. }
  124. else if (componentName == "sprite")
  125. {
  126. newEntity.addComponent<SpriteComponent>(component["texture_asset_id"],
  127. component["z_index"],
  128. component["width"],
  129. component["height"],
  130. component["fixed"].get_or(false),
  131. component["src_rect_x"].get_or(0),
  132. component["src_rect_y"].get_or(0));
  133. }
  134. else if (componentName == "animation")
  135. {
  136. newEntity.addComponent<AnimationComponent>(component["num_frames"].get_or(1),
  137. component["speed_rate"].get_or(1),
  138. true);
  139. }
  140. else if (componentName == "boxcollider")
  141. {
  142. newEntity.addComponent<BoxColliderComponent>(component["width"],
  143. component["height"],
  144. glm::vec2(component["offset"]["x"].get_or(0), component["offset"]["y"].get_or(0)));
  145. }
  146. else if (componentName == "health")
  147. {
  148. newEntity.addComponent<HealthComponent>(component["health_percentage"].get_or(100));
  149. }
  150. else if (componentName == "projectile_emitter")
  151. {
  152. double projectileDuration = component["projectile_duration"];
  153. double repeatFrequency = component["repeat_frequency"];
  154. newEntity.addComponent<ProjectileEmitterComponent>(glm::vec2(component["projectile_velocity"]["x"], component["projectile_velocity"]["y"]),
  155. repeatFrequency * 1000,
  156. projectileDuration * 1000,
  157. component["hit_percentage_damage"],
  158. component["friendly"]);
  159. }
  160. else if (componentName == "keyboard_controller")
  161. {
  162. newEntity.addComponent<KeyboardControlComponent>(glm::vec2(component["up_velocity"]["x"], component["up_velocity"]["y"]),
  163. glm::vec2(component["right_velocity"]["x"], component["right_velocity"]["y"]),
  164. glm::vec2(component["down_velocity"]["x"], component["down_velocity"]["y"]),
  165. glm::vec2(component["left_velocity"]["x"], component["left_velocity"]["y"]));
  166. }
  167. else if (componentName == "camera_follow")
  168. {
  169. newEntity.addComponent<CameraFollowComponent>();
  170. }
  171. else if (componentName == "on_update_script")
  172. {
  173. sol::function func = component[0];
  174. newEntity.addComponent<ScriptComponent>(func);
  175. }
  176. else
  177. {
  178. Logger::Error("Unknown component: %s for entity id#%d", componentName.c_str(), newEntity.getId());
  179. }
  180. }
  181. }
  182. }
  183. void LevelLoader::LoadLevel(sol::state &lua,
  184. const std::unique_ptr<Registry> &registry,
  185. const std::unique_ptr<AssetStore> &assetStore,
  186. SDL_Renderer *renderer,
  187. int levelNumber)
  188. {
  189. char luaFileName[50];
  190. sprintf(luaFileName, "assets/scripts/Level%d.lua", levelNumber);
  191. sol::load_result script = lua.load_file(luaFileName);
  192. if (!script.valid())
  193. {
  194. Logger::Error("Error in the Lua script for level #%d:", levelNumber);
  195. sol::error err = script;
  196. std::string errorMessage = err.what();
  197. Logger::Error(errorMessage.c_str());
  198. return;
  199. }
  200. lua.script_file(luaFileName);
  201. Logger::Info("Opened level #%d", levelNumber);
  202. sol::table level = lua["Level"];
  203. sol::table assetsTable = level["assets"];
  204. sol::table tileMap = level["tilemap"];
  205. sol::table entitiesTable = level["entities"];
  206. this->loadAssetTable(assetsTable, assetStore, renderer);
  207. this->loadTileMap(tileMap, registry);
  208. this->loadEntities(entitiesTable, registry);
  209. }