diff --git a/2DGameEngine/2DGameEngine/assets/scripts/level1.lua b/2DGameEngine/2DGameEngine/assets/scripts/level1.lua new file mode 100644 index 0000000..1373aba --- /dev/null +++ b/2DGameEngine/2DGameEngine/assets/scripts/level1.lua @@ -0,0 +1,93 @@ +-- Define a table with the values of the first level +Level = { + + assets = { + [0] = + { type = "texture", id = "tilemap-texture", file = "./assets/tilemaps/jungle.png" }, + { type = "texture", id = "chopper-texture", file = "./assets/images/chopper-green-spritesheet.png" }, + { type = "texture", id = "tank-texture", file = "./assets/images/tank-tiger-up.png" }, + { type = "texture", id = "crab-texture", file = "./assets/images/blue_crab_attack.png" }, + }, + + + tilemap = { + map_file = "./assets/tilemaps/jungle.map", + texture_asset_id = "tilemap-texture", + num_rows = 20, + num_cols = 25, + tile_size = 32, + scale = 2.0 + }, + + + entities = { + [0] = + { + -- Helicopter + components = { + transform = { + position = { x = 242, y = 110 }, + scale = { x = 1.0, y = 1.0 }, + rotation = 0.0, -- degrees + }, + rigidbody = { + velocity = { x = 0.0, y = 0.0 } + }, + sprite = { + texture_asset_id = "chopper-texture", + width = 32, + height = 32, + z_index = 4, + src_rect_x = 0, + src_rect_y = 0 + }, + animation = { + num_frames = 2, + speed_rate = 10 -- fps + }, + boxcollider = { + width = 32, + height = 25, + offset = { x = 0, y = 5 } + }, + health = { + health_percentage = 100 + }, + projectile_emitter = { + projectile_velocity = { x = 200, y = 200 }, + projectile_duration = 10, -- seconds + repeat_frequency = 0, -- seconds + hit_percentage_damage = 10, + friendly = true + }, + keyboard_controller = { + up_velocity = { x = 0, y = -50 }, + right_velocity = { x = 50, y = 0 }, + down_velocity = { x = 0, y = 50 }, + left_velocity = { x = -50, y = 0 } + }, + camera_follow = { + follow = true + } + } + }, + { + -- Tank + group = "enemies", + components = { + transform = { + position = { x = 200, y = 497 }, + scale = { x = 1.0, y = 1.0 }, + rotation = 0.0, -- degrees + }, + sprite = { + texture_asset_id = "tank-texture", + width = 32, + height = 32, + z_index = 2 + } + } + + } + } +} \ No newline at end of file diff --git a/2DGameEngine/2DGameEngine/src/Components/ScriptComponent.h b/2DGameEngine/2DGameEngine/src/Components/ScriptComponent.h new file mode 100644 index 0000000..ac5f9fa --- /dev/null +++ b/2DGameEngine/2DGameEngine/src/Components/ScriptComponent.h @@ -0,0 +1,13 @@ +#pragma once +#include + +struct ScriptComponent +{ + sol::function func; + + ScriptComponent(sol::function func = sol::lua_nil) + { + this->func = func; + } + +}; \ No newline at end of file diff --git a/2DGameEngine/2DGameEngine/src/Game/LevelLoader.cpp b/2DGameEngine/2DGameEngine/src/Game/LevelLoader.cpp new file mode 100644 index 0000000..9d224fa --- /dev/null +++ b/2DGameEngine/2DGameEngine/src/Game/LevelLoader.cpp @@ -0,0 +1,217 @@ +#include "LevelLoader.h" +#include "../Components/TransformComponent.h" +#include "../Components/RigidBodyComponent.h" +#include "../Components/SpriteComponent.h" +#include "../Components/AnimationComponent.h" +#include +#include "Game.h" +#include "sol/sol.hpp"" +#include + +LevelLoader::LevelLoader() +{ + + + +} + +LevelLoader::~LevelLoader() +{ + + + +} + +void LevelLoader::LoadLevel(sol::state& lua, std::unique_ptr& registry, const std::unique_ptr& assetStore, + SDL_Renderer* renderer, int levelNumber) +{ + sol::load_result script = lua.script_file("./assets/scripts/level" + std::to_string(levelNumber) + ".lua"); + + + // Check syntax of the script + + if (!script.valid()) + { + sol::error err = script; + std::string errorMessage = err.what(); + Logger::Err("Error loading the lua script: " + errorMessage); + return; + } + + lua.script_file("./assets/scripts/level" + std::to_string(levelNumber) + ".lua"); + + sol::table level = lua["Level"]; + + // Reading the level assets from the Lua + sol::table assets = level["assets"]; + + + // Adding assets through the Lua code + int i = 0; + while (true) + { + sol::optional hasAsset = assets[i]; + if (hasAsset == sol::nullopt) + { + break; + } + + + sol::table asset = assets[i]; + + std::string assetType = asset["type"]; + std::string assetId = asset["id"]; + if (assetType == "texture") + { + assetStore->AddTexture(renderer, assetId, asset["file"]); + } + + i++; + } + + // Setting up the tilemap through Lua + sol::table map = level["tilemap"]; + std::string mapFilePath = map["map_file"]; + std::string mapTextureAssetId = map["texture_asset_id"]; + int mapNumRows = map["num_rows"]; + int mapNumCols = map["num_cols"]; + int tileSize = map["tile_size"]; + double mapScale = map["scale"]; + std::fstream mapFile; + mapFile.open(mapFilePath); + for (int y = 0; y < mapNumRows; y++) { + for (int x = 0; x < mapNumCols; x++) { + char ch; + mapFile.get(ch); + int srcRectY = std::atoi(&ch) * tileSize; + mapFile.get(ch); + int srcRectX = std::atoi(&ch) * tileSize; + mapFile.ignore(); + + Entity tile = registry->CreateEntity(); + tile.AddComponent(glm::vec2(x * (mapScale * tileSize), y * (mapScale * tileSize)), glm::vec2(mapScale, mapScale), 0.0); + tile.AddComponent(mapTextureAssetId, tileSize, tileSize, 0, srcRectX, srcRectY); + } + } + mapFile.close(); + Game::mapWidth = mapNumCols * tileSize * mapScale; + Game::mapHeight = mapNumRows * tileSize * mapScale; + + + // Adding the entities and components through the Lua script + sol::table entities = level["entities"]; + i = 0; + while (true) { + sol::optional hasEntity = entities[i]; + if (hasEntity == sol::nullopt) { + break; + } + + sol::table entity = entities[i]; + + Entity newEntity = registry->CreateEntity(); + + /* + sol::optional tag = entity["tag"]; + if (tag != sol::nullopt) { + newEntity.Tag(entity["tag"]); + } + + sol::optional group = entity["group"]; + if (group != sol::nullopt) { + newEntity.Group(entity["group"]); + } + */ + + sol::optional hasComponents = entity["components"]; + if (hasComponents != sol::nullopt) { + + sol::optional transform = entity["components"]["transform"]; + if (transform != sol::nullopt) { + newEntity.AddComponent( + glm::vec2( + entity["components"]["transform"]["position"]["x"], + entity["components"]["transform"]["position"]["y"] + ), + glm::vec2( + entity["components"]["transform"]["scale"]["x"].get_or(1.0), + entity["components"]["transform"]["scale"]["y"].get_or(1.0) + ), + entity["components"]["transform"]["rotation"].get_or(0.0) + ); + } + + // Adding the RigidBody component and values + sol::optional rigidbody = entity["components"]["rigidbody"]; + if (rigidbody != sol::nullopt) { + newEntity.AddComponent( + glm::vec2( + entity["components"]["rigidbody"]["velocity"]["x"].get_or(0.0), + entity["components"]["rigidbody"]["velocity"]["y"].get_or(0.0) + ) + ); + } + + // Sprite components and values + sol::optional sprite = entity["components"]["sprite"]; + if (sprite != sol::nullopt) { + newEntity.AddComponent( + entity["components"]["sprite"]["texture_asset_id"], + entity["components"]["sprite"]["width"], + entity["components"]["sprite"]["height"], + entity["components"]["sprite"]["z_index"].get_or(1), + entity["components"]["sprite"]["src_rect_x"].get_or(0), + entity["components"]["sprite"]["src_rect_y"].get_or(0) + ); + } + + // Animation component and values + sol::optional animation = entity["components"]["animation"]; + if (animation != sol::nullopt) { + newEntity.AddComponent( + entity["components"]["animation"]["num_frames"].get_or(1), + entity["components"]["animation"]["speed_rate"].get_or(1) + ); + } + + } + + i++; + } + // Adding assets to the asset store + assetStore->AddTexture(renderer, "tank-image", "./assets/images/tank-panther-right.png"); + assetStore->AddTexture(renderer, "truck-image", "./assets/images/truck-ford-right.png"); + assetStore->AddTexture(renderer, "chopper-image", "./assets/images/chopper.png"); + assetStore->AddTexture(renderer, "crab-image", "./assets/images/blue_crab_attack.png"); + assetStore->AddTexture(renderer, "radar-image", "./assets/images/radar.png"); + assetStore->AddTexture(renderer, "tilemap-image", "./assets/tilemaps/jungle.png"); + + + + // Creating entities + //Entity tank = registry->CreateEntity(); + Entity chopper = registry->CreateEntity(); + Entity crab = registry->CreateEntity(); + Entity radar = registry->CreateEntity(); + + // Adding components to entities + //tank.AddComponent(glm::vec2(10.0, 10.0), glm::vec2(1.0, 1.0), 0.0); + //tank.AddComponent(glm::vec2(50, 0)); + //tank.AddComponent("tank-image", 64, 64, 1); + + chopper.AddComponent(glm::vec2(20.0, 200.0), glm::vec2(4.0, 4.0), 0.0); + chopper.AddComponent(glm::vec2(50, 0)); + chopper.AddComponent("chopper-image", 32, 32, 1); + chopper.AddComponent(2, 10, true); + + radar.AddComponent(glm::vec2(Game::windowWidth - 74, 10.0), glm::vec2(1.0, 1.0), 0.0); + radar.AddComponent(glm::vec2(0.0, 0.0)); + radar.AddComponent("radar-image", 64, 64, 1); + radar.AddComponent(8, 5, true); + + // Crab entity + crab.AddComponent(glm::vec2(150.0, 80.0), glm::vec2(0.7, 0.7), 90.0); + crab.AddComponent(glm::vec2(50, 0)); + crab.AddComponent("crab-image", 762, 733, 1); + +} \ No newline at end of file diff --git a/2DGameEngine/2DGameEngine/src/Game/LevelLoader.h b/2DGameEngine/2DGameEngine/src/Game/LevelLoader.h new file mode 100644 index 0000000..b8f7226 --- /dev/null +++ b/2DGameEngine/2DGameEngine/src/Game/LevelLoader.h @@ -0,0 +1,18 @@ +#pragma once +#include "../ECS/ECS.h" +#include "../AssetManager/AssetStore.h" +#include +#include +#include + +class LevelLoader +{ + +public: + LevelLoader(); + ~LevelLoader(); + + void LoadLevel(sol::state& lua, std::unique_ptr& registry, const std::unique_ptr& assetStore, SDL_Renderer* renderer, int level); + +} +; \ No newline at end of file diff --git a/2DGameEngine/2DGameEngine/src/Systems/ScriptSystem.h b/2DGameEngine/2DGameEngine/src/Systems/ScriptSystem.h new file mode 100644 index 0000000..475d7fa --- /dev/null +++ b/2DGameEngine/2DGameEngine/src/Systems/ScriptSystem.h @@ -0,0 +1,36 @@ +#pragma once + +#include "../ECS/ECS.h" +#include "../Components/ScriptComponent.h" +#include "../Components/TransformComponent.h" + +class ScriptSystem : public System { +public: + ScriptSystem() + { + RequireComponent(); + } + + void CreateLuaBindings(sol::state& lua) { + lua.new_usertype( + "entity", + "get_id", &Entity::GetId, + //"destroy", &Entity::Kill, + //"has_tag", &Entity::HasTag, + //"belongs_to_group", &Entity::BelongsToGroup + ); + + // Create all the bindings between C++ and Lua functions + //lua.set_function("set_position", SetEntityPosition); + } + + void Update() + { + // Invoke the lua function of entities that have a script component + for (auto entity : GetSystemEntities()) + { + const auto script = entity.GetComponent(); + script.func(); + } + } +}; diff --git a/2DGameEngine/2DGameEngine/src/WwiseAudioEngine.cpp b/2DGameEngine/2DGameEngine/src/WwiseAudioEngine.cpp new file mode 100644 index 0000000..22e66bf --- /dev/null +++ b/2DGameEngine/2DGameEngine/src/WwiseAudioEngine.cpp @@ -0,0 +1,227 @@ + + +#include +#include +#include +#include +#include + +//Wwise Sound engine +#include + +//Memory manager interface +#include + +//Default memory manager +#include + +//Music engine +#include + + +//Streaming manager +#include + +#include + +#include + +//Spatial audio +#include + +//Communications +#include + +//Low level implementation + +#include +#include + +CAkDefaultIOHookBlocking g_blockingDevice; + +//IDs generated by Wwise +#include + +namespace AK +{ + void* dRealloc(size_t s) { return malloc(s); } + void Free(void* p) { free(p); } +} + +bool InitSoundEngine() +{ + //Initializing the memory manager + AkMemSettings memSettings; + AK::MemoryMgr::GetDefaultSettings(memSettings); + + if (AK::MemoryMgr::Init(&memSettings) != AK_Success) + { + assert(! "Could not create memory manager"); + return false; + } + + + //Creation of default streaming manager + + AkStreamMgrSettings stmSettings; + AK::StreamMgr::GetDefaultSettings(stmSettings); + + if (!AK::StreamMgr::Create(stmSettings)) + { + assert(!"Could not create the Streaming Manager"); + return false; + } + + + //Streaming device with default low level I/O + AkDeviceSettings deviceSettings; + AK::StreamMgr::GetDefaultDeviceSettings(deviceSettings); + + if (g_blockingDevice.Init(deviceSettings) != AK_Success) + { + assert(!"Could not create streaming device and low level I/O system"); + return false; + } + + + //Creating the sound engine using default initialization parameters + + AkInitSettings initSettings; + AkPlatformInitSettings platformInitSettings; + AK::SoundEngine::GetDefaultInitSettings(initSettings); + AK::SoundEngine::GetDefaultPlatformInitSettings(platformInitSettings); + + if (AK::SoundEngine::Init(&initSettings, &platformInitSettings) != AK_Success) + { + assert(!"Could not initialize sound engine"); + return false; + } + + //Initializing the music engine + + AkMusicSettings musicInit; + AK::MusicEngine::GetDefaultInitSettings(musicInit); + + if (AK::MusicEngine::Init(&musicInit) != AK_Success) + { + assert(!"Could not initialize the music system"); + return false; + } + + //Initializing spatial audio + + AkSpatialAudioInitSettings spatialSettings; + + if (AK::SpatialAudio::Init(spatialSettings) != AK_Success) + { + assert(!"Could not initialize spatial audio"); + return false; + } + + //Initializing communications +#ifndef AK_OPTIMIZED + + AkCommSettings commSettings; + AK::Comm::GetDefaultInitSettings(commSettings); + + if (AK::Comm::Init(commSettings) != AK_Success) + { + assert(!"Communications could not be initialized."); + return false; + } + + +#endif AK_OPTIMIZED + + + //Setting base path for banks + g_blockingDevice.SetBasePath(AKTEXT("C:\\Program Files (x86)\\Audiokinetic\\Wwise 2021.1.2.7629\\Cube\\Wwise-101_v2019.1\\Lesson 1\\WwiseSoundEnginePractice\\GeneratedSoundBanks\\Windows")); + + //Set the current language + //AK::StreamMgr::SetCurrentLanguage(AKTEXT("English(US")); + + //Loading sound banks from Wwise project + AkBankID bankID; + + AKRESULT eResult = AK::SoundEngine::LoadBank(L"Init.bnk", bankID); + assert(eResult == AK_Success); + + eResult = AK::SoundEngine::LoadBank(L"SFX.bnk", bankID); + assert(eResult == AK_Success); + + return true; + +} + + + +void TermSoundEngine() +{ + //Terminate the communications module +#ifndef AK_OPTIMIZED + + AK::Comm::Term(); + +#endif AK_OPTIMIZED + + //Terminate music engine + AK::MusicEngine::Term(); + + //Unload banks + AK::SoundEngine::UnloadBank(L"SFX.bnk", nullptr); + AK::SoundEngine::UnloadBank(L"Init.bnk", nullptr); + + //Terminate the sound engine + AK::SoundEngine::Term(); + + //Terminate streaming device and stream manager + g_blockingDevice.Term(); + + if (AK::IAkStreamMgr::Get()) + { + AK::IAkStreamMgr::Get()->Destroy(); + } + + //Terminate memory manager + AK::MemoryMgr::Term(); +} + +void PlaySound() +{ + //Registering game object + AkGameObjectID gameObject = 1; + AK::SoundEngine::RegisterGameObj(gameObject, "GameObj1"); + + //Post event using its ID + AK::SoundEngine::PostEvent(AK::EVENTS::PLAY_SFX_1, gameObject); + AK::SoundEngine::UnregisterGameObj(gameObject); +} + +void PseudoGameMainLoop() +{ + //Function to replicate game loop + int frameCount = 0; + while (frameCount++ < 300) + { + auto time = std::chrono::milliseconds(30); + std::this_thread::sleep_for(time); + AK::SoundEngine::RenderAudio(); + } +} + +int main() +{ + std::cout << "Initializing Wwise" << std::endl;; + if (InitSoundEngine()) + { + //auto time = std::chrono::seconds(20); + //std::this_thread::sleep_for(time); + + std::cout << "Playing sound" << std::endl; + PlaySound(); + PseudoGameMainLoop(); + } + + std::cout << "Terminating Wwise" << std::endl; + TermSoundEngine(); +} \ No newline at end of file