From c87bab8808948d4b616189224b533a58095dca88 Mon Sep 17 00:00:00 2001 From: lindaandersson Date: Mon, 10 Feb 2014 14:00:14 +0100 Subject: [PATCH] GL - started using the lvl format. Objects on client have pos, rot and scale (not verified) --- Code/Code.rar | Bin 0 -> 81567 bytes Code/Game/DanBiasGame/DanBiasGame.vcxproj | 9 + .../DanBiasGame/GameClientState/C_Object.cpp | 67 ++++++ .../DanBiasGame/GameClientState/C_Object.h | 27 ++- .../GameClientState/C_obj/C_DynamicObj.cpp | 7 +- .../GameClientState/C_obj/C_DynamicObj.h | 1 - .../GameClientState/C_obj/C_Player.cpp | 9 +- .../GameClientState/C_obj/C_Player.h | 9 +- .../GameClientState/C_obj/C_StaticObj.cpp | 12 +- .../GameClientState/C_obj/C_StaticObj.h | 1 - .../GameClientState/C_obj/C_UIobject.cpp | 3 +- .../DanBiasGame/GameClientState/GameState.cpp | 227 ++++++++++++------ .../DanBiasGame/GameClientState/GameState.h | 10 +- .../GameClientState/LanMenuState.cpp | 7 +- .../LevelLoader/LevelLoader.cpp | 35 +++ .../GameClientState/LevelLoader/LevelLoader.h | 42 ++++ .../LevelLoader/LevelParser.cpp | 190 +++++++++++++++ .../GameClientState/LevelLoader/LevelParser.h | 31 +++ .../GameClientState/LevelLoader/Loader.cpp | 22 ++ .../GameClientState/LevelLoader/Loader.h | 28 +++ .../LevelLoader/ObjectDefines.h | 172 +++++++++++++ .../LevelLoader/ParseFunctions.cpp | 111 +++++++++ .../LevelLoader/ParseFunctions.h | 28 +++ .../GameClientState/LobbyState.cpp | 9 +- .../GameClientState/LoginState.cpp | 22 +- Code/Game/GameLogic/Game.cpp | 3 +- Code/Game/GameLogic/GameLogic.vcxproj | 4 +- Code/Game/GameLogic/GameMode.cpp | 15 -- Code/Game/GameLogic/GameModeType.cpp | 15 ++ .../GameLogic/{GameMode.h => GameModeType.h} | 10 +- Code/Game/GameLogic/Game_PlayerData.cpp | 2 +- Code/Game/GameLogic/Level.cpp | 173 +++++++++++++ Code/Game/GameLogic/Level.h | 9 +- Code/Game/GameLogic/Object.cpp | 4 +- Code/Game/GameLogic/Object.h | 1 + Code/OysterPhysics3D/RigidBody.cpp | 4 +- 36 files changed, 1160 insertions(+), 159 deletions(-) create mode 100644 Code/Code.rar create mode 100644 Code/Game/DanBiasGame/GameClientState/LevelLoader/LevelLoader.cpp create mode 100644 Code/Game/DanBiasGame/GameClientState/LevelLoader/LevelLoader.h create mode 100644 Code/Game/DanBiasGame/GameClientState/LevelLoader/LevelParser.cpp create mode 100644 Code/Game/DanBiasGame/GameClientState/LevelLoader/LevelParser.h create mode 100644 Code/Game/DanBiasGame/GameClientState/LevelLoader/Loader.cpp create mode 100644 Code/Game/DanBiasGame/GameClientState/LevelLoader/Loader.h create mode 100644 Code/Game/DanBiasGame/GameClientState/LevelLoader/ObjectDefines.h create mode 100644 Code/Game/DanBiasGame/GameClientState/LevelLoader/ParseFunctions.cpp create mode 100644 Code/Game/DanBiasGame/GameClientState/LevelLoader/ParseFunctions.h delete mode 100644 Code/Game/GameLogic/GameMode.cpp create mode 100644 Code/Game/GameLogic/GameModeType.cpp rename Code/Game/GameLogic/{GameMode.h => GameModeType.h} (63%) diff --git a/Code/Code.rar b/Code/Code.rar new file mode 100644 index 0000000000000000000000000000000000000000..e048199d0ab00c9b70f45a73f0ffee88a754c309 GIT binary patch literal 81567 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 I4-W8u0Z~xL#sB~S literal 0 HcmV?d00001 diff --git a/Code/Game/DanBiasGame/DanBiasGame.vcxproj b/Code/Game/DanBiasGame/DanBiasGame.vcxproj index 01a92481..83806118 100644 --- a/Code/Game/DanBiasGame/DanBiasGame.vcxproj +++ b/Code/Game/DanBiasGame/DanBiasGame.vcxproj @@ -205,6 +205,10 @@ + + + + @@ -219,6 +223,11 @@ + + + + + diff --git a/Code/Game/DanBiasGame/GameClientState/C_Object.cpp b/Code/Game/DanBiasGame/GameClientState/C_Object.cpp index 840e6267..11d4dd7d 100644 --- a/Code/Game/DanBiasGame/GameClientState/C_Object.cpp +++ b/Code/Game/DanBiasGame/GameClientState/C_Object.cpp @@ -1,4 +1,71 @@ #include "C_Object.h" using namespace DanBias::Client; +void C_Object::Init(ModelInitData modelInit) +{ + position = modelInit.position; + rotation = modelInit.rotation; + scale = modelInit.scale; + updateWorld(); +} +void C_Object::updateWorld() +{ + Oyster::Math3D::Float4x4 translation = Oyster::Math3D::TranslationMatrix(this->position); + Oyster::Math3D::Float4x4 rot = Oyster::Math3D::RotationMatrix(this->rotation); + //Oyster::Math3D::Float4x4 scale = Oyster::Math3D::; + Oyster::Math3D::Float4x4 scale = Oyster::Math3D::Matrix::identity; + scale.v[0].x = this->scale[0]; + scale.v[1].y = this->scale[1]; + scale.v[2].z = this->scale[2]; + world = translation * rot * scale; +} +void C_Object::setWorld(Oyster::Math::Float4x4 world) +{ +} +Oyster::Math::Float4x4 C_Object::getWorld() const +{ + return world; +} +void C_Object::setPos(Oyster::Math::Float3 newPos) +{ + this->position = newPos; + updateWorld(); +} +void C_Object::addPos(Oyster::Math::Float3 deltaPos) +{ + this->position += deltaPos; + updateWorld(); +} +Oyster::Math::Float3 C_Object::getPos() const +{ + return this->position; +} +void C_Object::setRot(Oyster::Math::Quaternion newRot) +{ + this->rotation = newRot; + updateWorld(); +} +void C_Object::addRot(Oyster::Math::Quaternion deltaRot) +{ + this->rotation += deltaRot; + updateWorld(); +} +Oyster::Math::Quaternion C_Object::getRotation() const +{ + return this->rotation; +} +void C_Object::setScale(Oyster::Math::Float3 newScale) +{ + this->scale = newScale; + updateWorld(); +} +void C_Object::addScale(Oyster::Math::Float3 deltaScale) +{ + this->scale += deltaScale; + updateWorld(); +} +Oyster::Math::Float3 C_Object::getScale() const +{ + return this->scale; +} diff --git a/Code/Game/DanBiasGame/GameClientState/C_Object.h b/Code/Game/DanBiasGame/GameClientState/C_Object.h index 1b87174b..4782270c 100644 --- a/Code/Game/DanBiasGame/GameClientState/C_Object.h +++ b/Code/Game/DanBiasGame/GameClientState/C_Object.h @@ -10,21 +10,38 @@ namespace DanBias { int id; std::wstring modelPath; - Oyster::Math::Float4x4 world; + Oyster::Math::Float3 position; + Oyster::Math::Quaternion rotation; + Oyster::Math::Float3 scale; bool visible; }; class C_Object { private: - + Oyster::Math::Float4x4 world; + Oyster::Math::Float3 position; + Oyster::Math::Quaternion rotation; + Oyster::Math::Float3 scale; + void updateWorld(); public: - virtual void Init(ModelInitData modelInit) = 0; - virtual void setPos(Oyster::Math::Float4x4 world) = 0; + virtual void Init(ModelInitData modelInit); + + void setWorld(Oyster::Math::Float4x4 world); + Oyster::Math::Float4x4 getWorld() const; + void setPos(Oyster::Math::Float3 newPos); + Oyster::Math::Float3 getPos() const; + void addPos(Oyster::Math::Float3 deltaPos); + void setRot(Oyster::Math::Quaternion newRot); + Oyster::Math::Quaternion getRotation() const; + void addRot(Oyster::Math::Quaternion deltaRot); + void setScale(Oyster::Math::Float3 newScale); + void addScale(Oyster::Math::Float3 deltaScale); + Oyster::Math::Float3 getScale() const; virtual void Render() = 0; virtual void Release() = 0; - virtual int GetId() = 0; + int GetId(); };};}; #endif diff --git a/Code/Game/DanBiasGame/GameClientState/C_obj/C_DynamicObj.cpp b/Code/Game/DanBiasGame/GameClientState/C_obj/C_DynamicObj.cpp index 3df74e40..71c46f4a 100644 --- a/Code/Game/DanBiasGame/GameClientState/C_obj/C_DynamicObj.cpp +++ b/Code/Game/DanBiasGame/GameClientState/C_obj/C_DynamicObj.cpp @@ -21,17 +21,14 @@ C_DynamicObj::~C_DynamicObj(void) } void C_DynamicObj::Init(ModelInitData modelInit) { + C_Object::Init(modelInit); // load models privData = new myData(); privData->model = Oyster::Graphics::API::CreateModel(modelInit.modelPath); - privData->model->WorldMatrix = modelInit.world; privData->model->Visible = modelInit.visible; + privData->model->WorldMatrix = getWorld(); privData->ID = modelInit.id; } -void C_DynamicObj::setPos(Oyster::Math::Float4x4 world) -{ - privData->model->WorldMatrix = world; -} void C_DynamicObj::Render() { diff --git a/Code/Game/DanBiasGame/GameClientState/C_obj/C_DynamicObj.h b/Code/Game/DanBiasGame/GameClientState/C_obj/C_DynamicObj.h index ee25a992..d8e7023a 100644 --- a/Code/Game/DanBiasGame/GameClientState/C_obj/C_DynamicObj.h +++ b/Code/Game/DanBiasGame/GameClientState/C_obj/C_DynamicObj.h @@ -14,7 +14,6 @@ public: C_DynamicObj(void); virtual ~C_DynamicObj(void); void Init(ModelInitData modelInit); - void setPos(Oyster::Math::Float4x4 world); void Render(); void Release(); diff --git a/Code/Game/DanBiasGame/GameClientState/C_obj/C_Player.cpp b/Code/Game/DanBiasGame/GameClientState/C_obj/C_Player.cpp index 49c450b5..5e5525e9 100644 --- a/Code/Game/DanBiasGame/GameClientState/C_obj/C_Player.cpp +++ b/Code/Game/DanBiasGame/GameClientState/C_obj/C_Player.cpp @@ -13,6 +13,7 @@ struct C_Player::myData }privData; C_Player::C_Player(void) + :C_DynamicObj() { } @@ -24,18 +25,16 @@ C_Player::~C_Player(void) void C_Player::Init(ModelInitData modelInit) { + C_Object::Init(modelInit); // load models privData = new myData(); privData->model = Oyster::Graphics::API::CreateModel(modelInit.modelPath); - privData->model->WorldMatrix = modelInit.world; privData->model->Visible = modelInit.visible; + privData->model->WorldMatrix = getWorld(); privData->ID = modelInit.id; privData->lookDir = Oyster::Math3D::Float4 (0,0,1,0); } -void C_Player::setPos(Oyster::Math::Float4x4 world) -{ - privData->model->WorldMatrix = world; -} + void C_Player::Render() { diff --git a/Code/Game/DanBiasGame/GameClientState/C_obj/C_Player.h b/Code/Game/DanBiasGame/GameClientState/C_obj/C_Player.h index 794bf51a..556fd6dc 100644 --- a/Code/Game/DanBiasGame/GameClientState/C_obj/C_Player.h +++ b/Code/Game/DanBiasGame/GameClientState/C_obj/C_Player.h @@ -1,21 +1,20 @@ #ifndef DANBIAS_CLIENT_CPLAYER_H #define DANBIAS_CLIENT_CPLAYER_H -#include "../C_Object.h" +#include "C_DynamicObj.h" namespace DanBias { namespace Client { -class C_Player : public C_Object +class C_Player : public C_DynamicObj { private: struct myData; myData* privData; - //Oyster::Graphics:: LIght + public: C_Player(void); - ~C_Player(void); + virtual ~C_Player(void); void Init(ModelInitData modelInit); - void setPos(Oyster::Math::Float4x4 world); void Render(); void Release(); diff --git a/Code/Game/DanBiasGame/GameClientState/C_obj/C_StaticObj.cpp b/Code/Game/DanBiasGame/GameClientState/C_obj/C_StaticObj.cpp index 177b032b..6e7a20e9 100644 --- a/Code/Game/DanBiasGame/GameClientState/C_obj/C_StaticObj.cpp +++ b/Code/Game/DanBiasGame/GameClientState/C_obj/C_StaticObj.cpp @@ -8,9 +8,7 @@ struct C_StaticObj::myData myData(){} Oyster::Graphics::Model::Model *model; int ID; - // light - // sound - // effect + }privData; C_StaticObj::C_StaticObj(void) { @@ -23,18 +21,16 @@ C_StaticObj::~C_StaticObj(void) } void C_StaticObj::Init(ModelInitData modelInit) { + C_Object::Init(modelInit); // load models privData = new myData(); privData->model = Oyster::Graphics::API::CreateModel(modelInit.modelPath); - privData->model->WorldMatrix = modelInit.world; privData->model->Visible = modelInit.visible; + privData->model->WorldMatrix = getWorld(); privData->ID = modelInit.id; } -void C_StaticObj::setPos(Oyster::Math::Float4x4 world) -{ - privData->model->WorldMatrix = world; -} + void C_StaticObj::Render() { diff --git a/Code/Game/DanBiasGame/GameClientState/C_obj/C_StaticObj.h b/Code/Game/DanBiasGame/GameClientState/C_obj/C_StaticObj.h index 799c0982..3bae1961 100644 --- a/Code/Game/DanBiasGame/GameClientState/C_obj/C_StaticObj.h +++ b/Code/Game/DanBiasGame/GameClientState/C_obj/C_StaticObj.h @@ -14,7 +14,6 @@ public: C_StaticObj(void); virtual ~C_StaticObj(void); void Init(ModelInitData modelInit); - void setPos(Oyster::Math::Float4x4 world); void Render(); void Release(); diff --git a/Code/Game/DanBiasGame/GameClientState/C_obj/C_UIobject.cpp b/Code/Game/DanBiasGame/GameClientState/C_obj/C_UIobject.cpp index fa5dff04..fc9c7d53 100644 --- a/Code/Game/DanBiasGame/GameClientState/C_obj/C_UIobject.cpp +++ b/Code/Game/DanBiasGame/GameClientState/C_obj/C_UIobject.cpp @@ -19,11 +19,12 @@ C_UIobject::~C_UIobject(void) } void C_UIobject::Init(ModelInitData modelInit) { + C_Object::Init(modelInit); // load models privData = new myData(); privData->model = Oyster::Graphics::API::CreateModel(modelInit.modelPath); - privData->model->WorldMatrix = modelInit.world; privData->model->Visible = modelInit.visible; + privData->model->WorldMatrix = getWorld(); privData->ID = modelInit.id; } diff --git a/Code/Game/DanBiasGame/GameClientState/GameState.cpp b/Code/Game/DanBiasGame/GameClientState/GameState.cpp index d8547943..8dfd99f5 100644 --- a/Code/Game/DanBiasGame/GameClientState/GameState.cpp +++ b/Code/Game/DanBiasGame/GameClientState/GameState.cpp @@ -1,20 +1,16 @@ #include "GameState.h" #include "DllInterfaces/GFXAPI.h" -#include "C_obj/C_Player.h" -#include "C_obj/C_DynamicObj.h" #include #include "NetworkClient.h" #include "Camera.h" #include using namespace DanBias::Client; - +using namespace Oyster::Math; struct GameState::myData { myData(){} - Oyster::Math3D::Float4x4 view; - Oyster::Math3D::Float4x4 proj; - std::vector object; + //std::vector object; int modelCount; Oyster::Network::NetworkClient* nwClient; gameStateState state; @@ -49,39 +45,123 @@ bool GameState::Init(Oyster::Network::NetworkClient* nwClient) GameState::gameStateState GameState::LoadGame() { Oyster::Graphics::Definitions::Pointlight plight; - plight.Pos = Oyster::Math::Float3(315, 0 ,5); - plight.Color = Oyster::Math::Float3(0.9,0.7,0.2); + plight.Pos = Float3(315, 0 ,5); + plight.Color = Float3(0.9f,0.7f,0.2f); plight.Radius = 100; - plight.Bright = 0.9; + plight.Bright = 0.9f; Oyster::Graphics::API::AddLight(plight); - plight.Pos = Oyster::Math::Float3(10,350,5); - plight.Color = Oyster::Math::Float3(0.9,0.7,0.3); + plight.Pos = Float3(10,350,5); + plight.Color = Float3(0.9f,0.7f,0.3f); plight.Radius = 200; - plight.Bright = 0.7; + plight.Bright = 0.7f; Oyster::Graphics::API::AddLight(plight); - plight.Pos = Oyster::Math::Float3(350,350,5); - plight.Color = Oyster::Math::Float3(0.9,0.7,0.3); + plight.Pos = Float3(350,350,5); + plight.Color = Float3(0.9f,0.7f,0.3f); plight.Radius = 200; - plight.Bright = 0.7; + plight.Bright = 0.7f; Oyster::Graphics::API::AddLight(plight); - plight.Pos = Oyster::Math::Float3(10,350,350); - plight.Color = Oyster::Math::Float3(0.9,0.7,0.3); + plight.Pos = Float3(10,350,350); + plight.Color = Float3(0.9f,0.7f,0.3f); plight.Radius = 200; - plight.Bright = 0.7; + plight.Bright = 0.7f; Oyster::Graphics::API::AddLight(plight); - plight.Pos = Oyster::Math::Float3(10,-15,5); - plight.Color = Oyster::Math::Float3(0,0,1); + plight.Pos = Float3(10,-15,5); + plight.Color = Float3(0,0,1); plight.Radius = 50; plight.Bright = 2; Oyster::Graphics::API::AddLight(plight); - LoadModels(L"map"); - InitCamera(Oyster::Math::Float3(0,0,20.0f)); + LoadModels("3bana.bias"); + Float3 startPos = Float3(0,0,20.0f); + InitCamera(startPos); return gameStateState_playing; } -bool GameState::LoadModels(std::wstring mapFile) +bool GameState::LoadModels(std::string mapFile) { - // open file + GameLogic::LevelLoader levelLoader; + std::vector> objects; + objects = levelLoader.LoadLevel(mapFile); + + int objCount = objects.size(); + int modelId = 0; + ModelInitData modelData; + for (int i = 0; i < objCount; i++) + { + GameLogic::ObjectTypeHeader* obj = objects.at(i); + + switch (obj->typeID) + { + case GameLogic::ObjectType::ObjectType_LevelMetaData: + + break; + case GameLogic::ObjectType::ObjectType_Static: + { + GameLogic::ObjectHeader* staticObjData = ((GameLogic::ObjectHeader*)obj); + + modelData.modelPath.assign(staticObjData->ModelFile.begin(), staticObjData->ModelFile.end()); + modelData.visible = true; + //modelData.position = ; + //modelData.rotation = Oyster::Math::Quaternion(Oyster::Math::Float3(2,2,-2), 1); + //modelData.scale = Oyster::Math::Float3(2,2,2); + modelData.id = modelId++; + + this->staticObjects.Push(new C_StaticObj()); + this->staticObjects[this->staticObjects.Size() -1 ]->Init(modelData); + } + break; + case GameLogic::ObjectType::ObjectType_Dynamic: + { + GameLogic::ObjectHeader* dynamicObjData = ((GameLogic::ObjectHeader*)obj); + //modelData.position = ; + //modelData.rotation = Oyster::Math::Quaternion(Oyster::Math::Float3(2,2,-2), 1); + //modelData.scale = Oyster::Math::Float3(2,2,2); + modelData.modelPath.assign(dynamicObjData->ModelFile.begin(), dynamicObjData->ModelFile.end()); + modelData.visible = true; + modelData.id = modelId++; + + this->dynamicObjects.Push(new C_DynamicObj()); + this->dynamicObjects[this->dynamicObjects.Size() -1 ]->Init(modelData); + } + break; + case GameLogic::ObjectType::ObjectType_Light: + { + GameLogic::BasicLight* lightData = ((GameLogic::BasicLight*)obj); + + if(lightData->lightType == GameLogic::LightType_PointLight) + { + Oyster::Graphics::Definitions::Pointlight plight; + plight.Pos = ((GameLogic::PointLight*)lightData)->position; + plight.Color = lightData->diffuseColor; + plight.Radius = 100; + plight.Bright = 0.9f; + Oyster::Graphics::API::AddLight(plight); + } + } + break; + default: + break; + } + } + myId += modelId++; + // add player model + //modelData.position = ; + //modelData.rotation = Oyster::Math::Quaternion(Oyster::Math::Float3(2,2,-2), 1); + //modelData.scale = Oyster::Math::Float3(2,2,2); + + + modelData.visible = true; + modelData.modelPath = L"char_still_sizeref.dan"; + modelData.id = myId; + // load models + this->dynamicObjects.Push(new C_DynamicObj()); + this->dynamicObjects[this->dynamicObjects.Size() -1 ]->Init(modelData); + + /*C_Player* obj = new C_Player(); + privData->object.push_back(obj); + privData->object[privData->object.size() -1 ]->Init(modelData); + */ + return true; + /*// open file // read file // init models int nrOfBoxex = 20; @@ -199,27 +279,18 @@ bool GameState::LoadModels(std::wstring mapFile) // load models obj = new C_Player(); privData->object.push_back(obj); - privData->object[privData->object.size() -1 ]->Init(modelData); - - return true; + privData->object[privData->object.size() -1 ]->Init(modelData); */ } -bool GameState::InitCamera(Oyster::Math::Float3 startPos) +bool GameState::InitCamera(Float3 startPos) { - Oyster::Math::Float3 dir = Oyster::Math::Float3(0,0,1); - Oyster::Math::Float3 up =Oyster::Math::Float3(0,1,0); - Oyster::Math::Float3 pos = Oyster::Math::Float3(0, 0, 20); - + Float3 dir = Float3(0,0,1); + Float3 up = Float3(0,1,0); + Float3 pos = Float3(0, 0, 20); camera->LookAt(pos, dir, up); - camera->SetLens(3.14f/2, 1024/768, 1, 1000); - - privData->proj = Oyster::Math3D::ProjectionMatrix_Perspective(Oyster::Math::pi/4,1024.0f/768.0f,.1f,1000); - //privData->proj = Oyster::Math3D::ProjectionMatrix_Orthographic(1024, 768, 1, 1000); - Oyster::Graphics::API::SetProjection(privData->proj); + camera->SetLens(pi/4, 1024/768, 1, 1000); camera->UpdateViewMatrix(); - privData->view = camera->View(); - privData->view = Oyster::Math3D::ViewMatrix_LookAtDirection(Oyster::Math::Float3(0,0,-1),Oyster::Math::Float3(0,1,0),startPos); - privData->view = Oyster::Math3D::OrientationMatrix_LookAtDirection(Oyster::Math::Float3(0,0,-1),Oyster::Math::Float3(0,1,0),startPos); - privData->view = Oyster::Math3D::InverseOrientationMatrix(privData->view); + Oyster::Graphics::API::SetProjection(camera->Proj()); + return true; } void GameState::setClientId(int id) @@ -263,25 +334,28 @@ GameClientState::ClientState GameState::Update(float deltaTime, InputClass* KeyI bool GameState::Render() { Oyster::Graphics::API::SetView(camera->View()); - //Oyster::Graphics::API::SetProjection(camera->Proj()); - //Oyster::Graphics::API::SetView(privData->view); - Oyster::Graphics::API::SetProjection(privData->proj); + Oyster::Graphics::API::NewFrame(); - for (unsigned int i = 0; i < privData->object.size(); i++) + for (unsigned int i = 0; i < staticObjects.Size(); i++) { - privData->object[i]->Render(); + staticObjects[i]->Render(); } + for (unsigned int i = 0; i < dynamicObjects.Size(); i++) + { + dynamicObjects[i]->Render(); + } + Oyster::Graphics::API::EndFrame(); return true; } bool GameState::Release() { - for (unsigned int i = 0; i < privData->object.size(); i++) + /*for (unsigned int i = 0; i < privData->object.size(); i++) { - privData->object[i]->Release(); - delete privData->object[i]; - privData->object[i] = NULL; - } + privData->object[i]->Release(); + delete privData->object[i]; + privData->object[i] = NULL; + }*/ delete privData; privData = NULL; @@ -440,13 +514,17 @@ void GameState::Protocol(ProtocolStruct* pos) void GameState::Protocol( PlayerPos* pos ) { - Oyster::Math::Float4x4 world, translate; + //Oyster::Math::Float4x4 world, translate; - world = Oyster::Math::Float4x4::identity; - translate = Oyster::Math::Float4x4::identity; - translate = Oyster::Math3D::TranslationMatrix(Oyster::Math::Float3(pos->playerPos[0],pos->playerPos[1],pos->playerPos[2])); - world = world * translate; - privData->object[0]->setPos( world ); + //world = Oyster::Math::Float4x4::identity; + //translate = Oyster::Math::Float4x4::identity; + //translate = Oyster::Math3D::TranslationMatrix(Oyster::Math::Float3(pos->playerPos[0],pos->playerPos[1],pos->playerPos[2])); + //world = world * translate; + ////privData->object[0]->setPos( world ); + //for (unsigned int i = 0; i < dynamicObjects.Size(); i++) + //{ + // dynamicObjects[i]->Render(); + //} } void GameState::Protocol( ObjPos* pos ) @@ -457,21 +535,21 @@ void GameState::Protocol( ObjPos* pos ) world[i] = pos->worldPos[i]; } //printf("pos for obj %d, ",pos->object_ID ); - for (unsigned int i = 0; i < privData->object.size(); i++) + for (unsigned int i = 0; i < dynamicObjects.Size(); i++) { - if(privData->object[i]->GetId() == pos->object_ID) + if(dynamicObjects[i]->GetId() == pos->object_ID) { - privData->object[i]->setPos(world); + dynamicObjects[i]->setWorld(world); - if(i == myId) // playerobj + if(dynamicObjects[i]->GetId() == myId) // playerobj { - Oyster::Math::Float3 right = Oyster::Math::Float3(world[0], world[1], world[2]); - Oyster::Math::Float3 up = Oyster::Math::Float3(world[4], world[5], world[6]); - Oyster::Math::Float3 objForward = (Oyster::Math::Float3(world[8], world[9], world[10])); - Oyster::Math::Float3 pos = Oyster::Math::Float3(world[12], world[13], world[14]); + Float3 right = Float3(world[0], world[1], world[2]); + Float3 up = Float3(world[4], world[5], world[6]); + Float3 objForward = Float3(world[8], world[9], world[10]); + Float3 pos = Float3(world[12], world[13], world[14]); - Oyster::Math::Float3 cameraLook = camera->GetLook(); - Oyster::Math::Float3 cameraUp = camera->GetUp(); + Float3 cameraLook = camera->GetLook(); + Float3 cameraUp = camera->GetUp(); @@ -506,28 +584,29 @@ void GameState::Protocol( NewObj* newObj ) } ModelInitData modelData; - modelData.world = world; + //modelData.world = world; modelData.visible = true; modelData.id = newObj->object_ID; //not sure if this is good parsing rom char* to wstring const char* path = newObj->path; modelData.modelPath = std::wstring(path, path + strlen(path)); // load models - C_Object* player = new C_Player(); + C_DynamicObj* player = new C_DynamicObj(); player->Init(modelData); - privData->object.push_back(player); + dynamicObjects.Push(player); } void DanBias::Client::GameState::Protocol( RemoveObj* obj ) { - for (unsigned int i = 0; i < privData->object.size(); i++) + for (unsigned int i = 0; i < dynamicObjects.Size(); i++) { - if(privData->object[i]->GetId() == obj->object_ID) + if(dynamicObjects[i]->GetId() == obj->object_ID) { - privData->object.at(i)->Release(); - privData->object.erase(privData->object.begin() + i ); + //dynamicObjects[i]->Release(); + dynamicObjects[i].Release(); + //dynamicObjects.erase(privData->object.begin() + i ); } } //privData->object[obj->object_ID]->Release( ); diff --git a/Code/Game/DanBiasGame/GameClientState/GameState.h b/Code/Game/DanBiasGame/GameClientState/GameState.h index d555134c..425fb2be 100644 --- a/Code/Game/DanBiasGame/GameClientState/GameState.h +++ b/Code/Game/DanBiasGame/GameClientState/GameState.h @@ -4,6 +4,11 @@ #include "OysterMath.h" #include #include "Camera.h" +#include "LevelLoader/LevelLoader.h" +#include "C_obj/C_Player.h" +#include "C_obj/C_DynamicObj.h" +#include "C_obj/C_StaticObj.h" +#include "DynamicArray.h" namespace DanBias { namespace Client @@ -30,12 +35,15 @@ private: float pitch; struct myData; myData* privData; + Utility::DynamicMemory::DynamicArray> staticObjects; + Utility::DynamicMemory::DynamicArray> dynamicObjects; + Utility::DynamicMemory::DynamicArray> playObjects; public: GameState(void); ~GameState(void); bool Init(Oyster::Network::NetworkClient* nwClient); GameClientState::ClientState Update(float deltaTime, InputClass* KeyInput) override; - bool LoadModels(std::wstring mapFile) ; + bool LoadModels(std::string mapFile) ; bool InitCamera(Oyster::Math::Float3 startPos) ; gameStateState LoadGame(); void setClientId(int id); diff --git a/Code/Game/DanBiasGame/GameClientState/LanMenuState.cpp b/Code/Game/DanBiasGame/GameClientState/LanMenuState.cpp index 8df39bfa..092307af 100644 --- a/Code/Game/DanBiasGame/GameClientState/LanMenuState.cpp +++ b/Code/Game/DanBiasGame/GameClientState/LanMenuState.cpp @@ -64,15 +64,16 @@ bool LanMenuState::LoadModels(std::wstring file) ModelInitData modelData; - modelData.world = Oyster::Math3D::Float4x4::identity; + modelData.position = Oyster::Math::Float3(0,0,0); + modelData.rotation = Oyster::Math::Quaternion::identity; + modelData.scale = Oyster::Math::Float3(1,1,1); modelData.visible = true; modelData.modelPath = L"..\\Content\\Models\\box_2.dan"; // load models privData->object[0] = new C_StaticObj(); privData->object[0]->Init(modelData); - Oyster::Math3D::Float4x4 translate = Oyster::Math3D::TranslationMatrix(Oyster::Math::Float3(-2,-2,-2)); - modelData.world = modelData.world * translate; + modelData.position = Oyster::Math::Float3(-2, -2, -2); privData->object[1] = new C_DynamicObj(); privData->object[1]->Init(modelData); diff --git a/Code/Game/DanBiasGame/GameClientState/LevelLoader/LevelLoader.cpp b/Code/Game/DanBiasGame/GameClientState/LevelLoader/LevelLoader.cpp new file mode 100644 index 00000000..55a39725 --- /dev/null +++ b/Code/Game/DanBiasGame/GameClientState/LevelLoader/LevelLoader.cpp @@ -0,0 +1,35 @@ +////////////////////////////////// +// Created by Sam Svensson 2013 // +////////////////////////////////// + +#include "LevelLoader.h" +#include "LevelParser.h" + +using namespace GameLogic; +using namespace GameLogic::LevelFileLoader; + +struct LevelLoader::PrivData +{ + LevelParser parser; + std::string folderPath; +}; + +LevelLoader::LevelLoader() + : pData(new PrivData) +{ + pData->folderPath = "Standard path"; +} + +LevelLoader::~LevelLoader() +{ +} + +std::vector> LevelLoader::LoadLevel(std::string fileName) +{ + return pData->parser.Parse(fileName); +} + +LevelMetaData LevelLoader::LoadLevelHeader(std::string fileName) +{ + return pData->parser.ParseHeader(fileName); +} \ No newline at end of file diff --git a/Code/Game/DanBiasGame/GameClientState/LevelLoader/LevelLoader.h b/Code/Game/DanBiasGame/GameClientState/LevelLoader/LevelLoader.h new file mode 100644 index 00000000..bcd6e587 --- /dev/null +++ b/Code/Game/DanBiasGame/GameClientState/LevelLoader/LevelLoader.h @@ -0,0 +1,42 @@ +////////////////////////////////// +// Created by Sam Svensson 2013 // +////////////////////////////////// + +#ifndef LEVELLOADER_H +#define LEVELLOADER_H + +#include +#include +#include "../Misc/Utilities.h" +#include "ObjectDefines.h" + +namespace GameLogic +{ + class LevelLoader + { + + public: + LevelLoader(); + ~LevelLoader(); + + /******************************************************** + * Loads the level and objects from file. + * @param fileName: Path to the level-file that you want to load. + * @return: Returns all structs with objects and information about the level. + ********************************************************/ + std::vector> LoadLevel(std::string fileName); + + /******************************************************** + * Just for fast access for the meta information about the level. + * @param fileName: Path to the level-file that you want to load. + * @return: Returns the meta information about the level. + ********************************************************/ + LevelMetaData LoadLevelHeader(std::string fileName); //. + + private: + struct PrivData; + Utility::DynamicMemory::SmartPointer pData; + }; +} + +#endif \ No newline at end of file diff --git a/Code/Game/DanBiasGame/GameClientState/LevelLoader/LevelParser.cpp b/Code/Game/DanBiasGame/GameClientState/LevelLoader/LevelParser.cpp new file mode 100644 index 00000000..088c3916 --- /dev/null +++ b/Code/Game/DanBiasGame/GameClientState/LevelLoader/LevelParser.cpp @@ -0,0 +1,190 @@ +#include "LevelParser.h" + +#include "Loader.h" +#include "ParseFunctions.h" + +using namespace GameLogic; +using namespace ::LevelFileLoader; +using namespace Utility::DynamicMemory; + +LevelParser::LevelParser() +{ + formatVersion.formatVersionMajor = 1; + formatVersion.formatVersionMinor = 0; +} + +LevelParser::~LevelParser() +{ +} + +std::vector> LevelParser::Parse(std::string filename) +{ + int bufferSize = 0; + int counter = 0; + + std::vector> objects; + + //Read entire level file. + Loader loader; + char* buffer = (char*)loader.LoadFile(filename.c_str(), bufferSize); + + //Read format version + FormatVersion levelFormatVersion; + ParseObject(&buffer[counter], &levelFormatVersion, sizeof(levelFormatVersion)); + counter += sizeof(levelFormatVersion); + if(this->formatVersion != levelFormatVersion) + { + //Do something if it's not the same version + } + + while(counter < bufferSize) + { + //Get typeID + ObjectTypeHeader typeID; + ParseObject(&buffer[counter], &typeID, sizeof(typeID)); + switch((int)typeID.typeID) + { + case ObjectType_LevelMetaData: + { + LevelMetaData* header = new LevelMetaData; + ParseLevelMetaData(&buffer[counter], *header, counter); + objects.push_back(header); + break; + } + + //This is by design, static and dynamic is using the same converter. Do not add anything inbetween them. + case ObjectType_Static: case ObjectType_Dynamic: + { + ObjectHeader* header = new ObjectHeader; + ParseObject(&buffer[counter], *header, counter); + objects.push_back(header); + break; + } + + case ObjectType_Light: + { + LightType lightType; + + //Get Light type + ParseObject(&buffer[counter+4], &lightType, sizeof(lightType)); + + switch(lightType) + { + case LightType_PointLight: + { + PointLight* header = new PointLight; + ParseObject(&buffer[counter], header, sizeof(*header)); + counter += sizeof(*header); + objects.push_back(header); + break; + } + case LightType_DirectionalLight: + { + DirectionalLight* header = new DirectionalLight; + ParseObject(&buffer[counter], header, sizeof(*header)); + counter += sizeof(*header); + objects.push_back(header); + break; + } + case LightType_SpotLight: + { + SpotLight* header = new SpotLight; + ParseObject(&buffer[counter], header, sizeof(*header)); + counter += sizeof(*header); + objects.push_back(header); + break; + } + default: + //Undefined LightType. + break; + } + break; + } + default: + //Couldn't find typeID. FAIL!!!!!! + break; + } + } + + return objects; +} + +//för meta information om leveln. +LevelMetaData LevelParser::ParseHeader(std::string filename) +{ + int bufferSize = 0; + int counter = 0; + + LevelMetaData levelHeader; + levelHeader.typeID = ObjectType::ObjectType_Unknown; + + //Read entire level file. + Loader loader; + char* buffer = (char*)loader.LoadFile(filename.c_str(), bufferSize); + + //Read format version + FormatVersion levelFormatVersion; + ParseObject(&buffer[counter], &levelFormatVersion, sizeof(formatVersion)); + counter += sizeof(levelFormatVersion); + if(this->formatVersion != levelFormatVersion) + { + //Do something if it's not the same version + } + + //Find the header in the returned string. + while(counter < bufferSize) + { + ObjectTypeHeader typeID; + ParseObject(&buffer[counter], &typeID, sizeof(typeID)); + + switch(typeID.typeID) + { + case ObjectType_LevelMetaData: + ParseLevelMetaData(&buffer[counter], levelHeader, counter); + return levelHeader; + break; + + //This is by design, static and dynamic is using the same converter. Do not add anything inbetween them. + case ObjectType_Static: case ObjectType_Dynamic: + { + ObjectHeader header; + ParseObject(&buffer[counter], header, counter); + break; + } + + case ObjectType_Light: + { + LightType lightType; + ParseObject(&buffer[counter+4], &lightType, sizeof(lightType)); + + switch(lightType) + { + case LightType_PointLight: + { + counter += sizeof(PointLight); + break; + } + case LightType_DirectionalLight: + { + counter += sizeof(DirectionalLight); + break; + } + case LightType_SpotLight: + { + counter += sizeof(SpotLight); + break; + } + default: + //Undefined LightType. + break; + } + } + + default: + //Couldn't find typeID. FAIL!!!!!! + break; + } + } + + return levelHeader; +} \ No newline at end of file diff --git a/Code/Game/DanBiasGame/GameClientState/LevelLoader/LevelParser.h b/Code/Game/DanBiasGame/GameClientState/LevelLoader/LevelParser.h new file mode 100644 index 00000000..9ad30642 --- /dev/null +++ b/Code/Game/DanBiasGame/GameClientState/LevelLoader/LevelParser.h @@ -0,0 +1,31 @@ +#ifndef LEVEL_PARSER_H +#define LEVEL_PARSER_H + +#include +#include +#include "ObjectDefines.h" +#include "../Misc/Utilities.h" + +namespace GameLogic +{ + namespace LevelFileLoader + { + class LevelParser + { + public: + LevelParser(); + ~LevelParser(); + + // + std::vector> Parse(std::string filename); + + // + LevelMetaData ParseHeader(std::string filename); + + private: + FormatVersion formatVersion; + + }; + } +} +#endif \ No newline at end of file diff --git a/Code/Game/DanBiasGame/GameClientState/LevelLoader/Loader.cpp b/Code/Game/DanBiasGame/GameClientState/LevelLoader/Loader.cpp new file mode 100644 index 00000000..3e15315c --- /dev/null +++ b/Code/Game/DanBiasGame/GameClientState/LevelLoader/Loader.cpp @@ -0,0 +1,22 @@ +////////////////////////////////// +// Created by Sam Svensson 2013 // +////////////////////////////////// + +#include "Loader.h" +#include + +using namespace GameLogic::LevelFileLoader; +using namespace Oyster::Resource; +using namespace std; + +char* Loader::LoadFile(std::string fileName, int &size) +{ + //convert from string to wstring + std::wstring temp(fileName.begin(), fileName.end()); + + //convert from wstring to wchar then loads the file + char* buffer = (char*)OysterResource::LoadResource(temp.c_str(), Oyster::Resource::ResourceType::ResourceType_Byte_Raw, -1 , false); + + size = OysterResource::GetResourceSize(buffer); + return buffer; +} \ No newline at end of file diff --git a/Code/Game/DanBiasGame/GameClientState/LevelLoader/Loader.h b/Code/Game/DanBiasGame/GameClientState/LevelLoader/Loader.h new file mode 100644 index 00000000..198c2a87 --- /dev/null +++ b/Code/Game/DanBiasGame/GameClientState/LevelLoader/Loader.h @@ -0,0 +1,28 @@ +////////////////////////////////// +// Created by Sam Svensson 2013 // +////////////////////////////////// + +#ifndef LOADER_H +#define LOADER_H + +#include "..\Misc\Resource\OysterResource.h" +#include + +namespace GameLogic +{ + namespace LevelFileLoader + { + class Loader + { + public: + Loader (){}; + ~Loader(){}; + char* LoadFile(std::string fileName, int &size); + + //TODO: + //Add functionality to load physicsObjects (hitboxes) + }; + } +} + +#endif; \ No newline at end of file diff --git a/Code/Game/DanBiasGame/GameClientState/LevelLoader/ObjectDefines.h b/Code/Game/DanBiasGame/GameClientState/LevelLoader/ObjectDefines.h new file mode 100644 index 00000000..8287dafb --- /dev/null +++ b/Code/Game/DanBiasGame/GameClientState/LevelLoader/ObjectDefines.h @@ -0,0 +1,172 @@ +#ifndef OBJECT_DEFINES_H +#define OBJECT_DEFINES_H + +#include +#include + +namespace GameLogic +{ + /************************************ + Enums + *************************************/ + + enum ObjectType + { + ObjectType_LevelMetaData, + ObjectType_Static, + ObjectType_Dynamic, + ObjectType_Light, + //Etc + + ObjectType_NUM_OF_TYPES, + + ObjectType_Unknown = -1 + }; + + enum UsePhysics + { + UsePhysics_UseFullPhysics, + UsePhysics_IgnoreGravity, + UsePhysics_IgnorePhysics, + UsePhysics_IgnoreCollision, + + UsePhysics_Count, + UsePhysics_Unknown = -1 + }; + + enum CollisionGeometryType + { + CollisionGeometryType_Box, + CollisionGeometryType_Sphere, + + CollisionGeometryType_Count, + CollisionGeometryType_Unknown = -1 + }; + + enum LightType + { + LightType_PointLight, + LightType_DirectionalLight, + LightType_SpotLight, + + LightType_Count, + LightType_Unknown = -1 + }; + + //Should this be moved somewhere else? + enum GameMode + { + GameMode_FreeForAll, + GameMode_TeamDeathMatch, + //Etc + + GameMode_Count, + GameMode_Unknown = -1 + }; + + enum WorldSize + { + WorldSize_Tiny, + WorldSize_Small, + WorldSize_Medium, + WorldSize_Big, + WorldSize_Humongous, + + WorldSize_Count, + WorldSize_Unknown = -1 + }; + + + /************************************ + Structs + *************************************/ + + struct FormatVersion + { + unsigned int formatVersionMajor; + unsigned int formatVersionMinor; + + bool operator ==(const FormatVersion& obj) + { + return (this->formatVersionMajor != obj.formatVersionMajor && this->formatVersionMinor != obj.formatVersionMinor); + } + + bool operator !=(const FormatVersion& obj) + { + return !(*this == obj); + } + }; + + struct ObjectTypeHeader + { + ObjectType typeID; + }; + + struct PhysicsObject + { + UsePhysics usePhysics; + float mass; + float inertiaMagnitude[3]; + float inertiaRotation[3]; + float frictionCoeffStatic; + float frictionCoeffDynamic; + CollisionGeometryType geometryType; + }; + + struct LevelMetaData : public ObjectTypeHeader + { + std::string levelName; + unsigned int levelVersion; + std::string levelDescription; + std::string levelAuthor; + unsigned int maxNumberOfPlayer; + WorldSize worldSize; + std::string overviewPicturePath; + std::vector gameModesSupported; + }; + + struct ObjectHeader : public ObjectTypeHeader, public PhysicsObject + { + //Model, + std::string ModelFile; + //Position + float position[3]; + //Rotation + float rotation[3]; + float angle; + //Scale + float scale[3]; + }; + + + /************************************ + Lights + *************************************/ + + struct BasicLight : public ObjectTypeHeader + { + LightType lightType; + float ambientColor[3]; + float diffuseColor[3]; + float specularColor[3]; + }; + + struct PointLight : public BasicLight + { + float position[3]; + }; + + struct DirectionalLight : public BasicLight + { + float direction[3]; + }; + + struct SpotLight : public BasicLight + { + float direction[3]; + float range; + float attenuation[3]; + }; +} + +#endif \ No newline at end of file diff --git a/Code/Game/DanBiasGame/GameClientState/LevelLoader/ParseFunctions.cpp b/Code/Game/DanBiasGame/GameClientState/LevelLoader/ParseFunctions.cpp new file mode 100644 index 00000000..08823d3d --- /dev/null +++ b/Code/Game/DanBiasGame/GameClientState/LevelLoader/ParseFunctions.cpp @@ -0,0 +1,111 @@ +////////////////////////////////// +// Created by Sam Svensson 2013 // +////////////////////////////////// + +#include "ParseFunctions.h" +#include "../../../../Misc/Packing/Packing.h" +#include + +using namespace Oyster::Packing; +using namespace GameLogic::LevelFileLoader; +using namespace GameLogic; +using namespace std; + +namespace GameLogic +{ + namespace LevelFileLoader + { + void ParseObject(char* buffer, void *header, int size) + { + memcpy(header, buffer, size); + } + + void ParseObject(char* buffer, ObjectHeader& header, int& size) + { + char tempName[128]; + unsigned int tempSize = 0; + int start = 0; + + memcpy(&header.typeID, &buffer[start], 4); + start += 4; + + memcpy(&tempSize, &buffer[start], 4); + start += 4; + + memcpy(&tempName, &buffer[start], tempSize); + header.ModelFile.assign(&tempName[0], &tempName[tempSize]); + start += tempSize; + + //3 float[3], 1 float + memcpy(&header.position, &buffer[start], 40); + start += 40; + + //2 float[3], 3 float, 2 uint + memcpy(&header.usePhysics, &buffer[start], 44); + start += 44; + + size += start; + } + + void ParseLevelMetaData(char* buffer, LevelMetaData &header, int &size) + { + int start = 0; + unsigned int tempSize; + char tempName[128]; + + memcpy(&header.typeID, &buffer[start], 4); + start += 4; + + memcpy(&tempSize , &buffer[start], 4); + start += 4; + + memcpy(&tempName, &buffer[start], tempSize); + header.levelName.assign(&tempName[0], &tempName[tempSize]); + start += tempSize; + + memcpy(&header.levelVersion, &buffer[start], 4); + start += 4; + + memcpy(&tempSize, &buffer[start], 4); + start +=4; + + memcpy(&tempName, &buffer[start], tempSize); + header.levelDescription.assign(&tempName[0], &tempName[tempSize]); + start += tempSize; + + memcpy(&tempSize, &buffer[start], 4); + start += 4; + + memcpy(&tempName, &buffer[start], tempSize); + header.levelAuthor.assign(&tempName[0], &tempName[tempSize]); + start += tempSize; + + memcpy(&header.maxNumberOfPlayer, &buffer[start], 4); + start += 4; + + memcpy(&header.worldSize, &buffer[start], 4); + start += 4; + + memcpy(&tempSize, &buffer[start], 4); + start += 4; + + memcpy(&tempName, &buffer[start], tempSize); + header.overviewPicturePath.assign(&tempName[0], &tempName[tempSize]); + start += tempSize; + + memcpy(&tempSize, &buffer[start], 4); + start += 4; + + int temp; + + for(int i = 0; i < tempSize; i++) + { + memcpy(&temp, &buffer[start], 4); + start += 4; + header.gameModesSupported.push_back((GameMode)temp); + } + + size += start; + } + } +} \ No newline at end of file diff --git a/Code/Game/DanBiasGame/GameClientState/LevelLoader/ParseFunctions.h b/Code/Game/DanBiasGame/GameClientState/LevelLoader/ParseFunctions.h new file mode 100644 index 00000000..f68a9289 --- /dev/null +++ b/Code/Game/DanBiasGame/GameClientState/LevelLoader/ParseFunctions.h @@ -0,0 +1,28 @@ +////////////////////////////////// +// Created by Sam Svensson 2013 // +////////////////////////////////// + +#ifndef PARSERFUNCTIONS_H +#define PARSERFUNCTIONS_H +#include "ObjectDefines.h" + +namespace GameLogic +{ + namespace LevelFileLoader + { + /* + These functions will copy data from where the buffer pointer points. + header is the destination where the data will be copied. + size is either the size of the data to be copied (if it is NOT sent by reference). + Or the current index that is being used to parse the entire file (if it is sent by reference) this means you have to increase size with the appropiate size after you have copied. + + */ + + void ParseObject(char* buffer, void *header, int size); + void ParseObject(char* buffer, ObjectHeader& header, int& size); + void ParseLevelMetaData(char* buffer, LevelMetaData &header, int &size); + } +} + + +#endif \ No newline at end of file diff --git a/Code/Game/DanBiasGame/GameClientState/LobbyState.cpp b/Code/Game/DanBiasGame/GameClientState/LobbyState.cpp index 538408c5..07bf8d42 100644 --- a/Code/Game/DanBiasGame/GameClientState/LobbyState.cpp +++ b/Code/Game/DanBiasGame/GameClientState/LobbyState.cpp @@ -53,17 +53,18 @@ bool LobbyState::LoadModels(std::wstring file) ModelInitData modelData; - modelData.world = Oyster::Math3D::Float4x4::identity; + modelData.position = Oyster::Math::Float3(0,0,0); + modelData.rotation = Oyster::Math::Quaternion::identity; + modelData.scale = Oyster::Math::Float3(1,1,1); modelData.visible = true; modelData.modelPath = L"..\\Content\\Models\\box_2.dan"; // load models privData->object[0] = new C_StaticObj(); privData->object[0]->Init(modelData); - Oyster::Math3D::Float4x4 translate = Oyster::Math3D::TranslationMatrix(Oyster::Math::Float3(2,2,2)); - modelData.world = modelData.world * translate; + modelData.position = Oyster::Math::Float3(2,2,2); - privData->object[1] = new C_DynamicObj(); + privData->object[1] = new C_StaticObj(); privData->object[1]->Init(modelData); return true; } diff --git a/Code/Game/DanBiasGame/GameClientState/LoginState.cpp b/Code/Game/DanBiasGame/GameClientState/LoginState.cpp index 4a244a8b..1bc3af72 100644 --- a/Code/Game/DanBiasGame/GameClientState/LoginState.cpp +++ b/Code/Game/DanBiasGame/GameClientState/LoginState.cpp @@ -53,26 +53,18 @@ bool LoginState::LoadModels(std::wstring file) ModelInitData modelData; - modelData.world = Oyster::Math3D::Float4x4::identity; + modelData.rotation = Oyster::Math::Quaternion::identity; + modelData.scale = Oyster::Math::Float3(1,1,1); modelData.visible = true; modelData.modelPath = L"identityPlane.dan"; - // load models - Oyster::Math3D::Float4x4 translate = Oyster::Math3D::TranslationMatrix(Oyster::Math::Float3(2,2,-2)); - Oyster::Math3D::Float4x4 rot = Oyster::Math3D::RotationMatrix(Oyster::Math::Float3(0 ,Utility::Value::Radian(90.0f), 0)); - Oyster::Math3D::Float4x4 scale = Oyster::Math3D::Float4x4::identity; - int scaling = 2; - scale.v[0].x = scaling; - scale.v[1].y = scaling; - scale.v[2].z = scaling; + - modelData.world = translate; //scale * translate * rot; - privData->object[0] = new C_DynamicObj(); + modelData.position = Oyster::Math::Float3(2,2,2); + privData->object[0] = new C_StaticObj(); privData->object[0]->Init(modelData); - translate = Oyster::Math3D::TranslationMatrix(Oyster::Math::Float3(0,0,-2)); - modelData.world = translate ;//* rot; - - privData->object[1] = new C_DynamicObj(); + modelData.position = Oyster::Math::Float3(0,0,-2); + privData->object[1] = new C_StaticObj(); privData->object[1]->Init(modelData); return true; } diff --git a/Code/Game/GameLogic/Game.cpp b/Code/Game/GameLogic/Game.cpp index 6aecc900..8077c6bf 100644 --- a/Code/Game/GameLogic/Game.cpp +++ b/Code/Game/GameLogic/Game.cpp @@ -81,7 +81,8 @@ Game::LevelData* Game::CreateLevel() if(this->level) return this->level; this->level = new LevelData(); - this->level->level->InitiateLevel(1000); + //this->level->level->InitiateLevel(1000); + this->level->level->InitiateLevel("3bana.bias"); return this->level; } diff --git a/Code/Game/GameLogic/GameLogic.vcxproj b/Code/Game/GameLogic/GameLogic.vcxproj index 674773bf..7ae78fac 100644 --- a/Code/Game/GameLogic/GameLogic.vcxproj +++ b/Code/Game/GameLogic/GameLogic.vcxproj @@ -181,7 +181,7 @@ - + @@ -203,7 +203,7 @@ - + diff --git a/Code/Game/GameLogic/GameMode.cpp b/Code/Game/GameLogic/GameMode.cpp deleted file mode 100644 index ba240fca..00000000 --- a/Code/Game/GameLogic/GameMode.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "GameMode.h" - -using namespace GameLogic; - - -GameMode::GameMode() -{ - -} - - -GameMode::~GameMode(void) -{ - -} diff --git a/Code/Game/GameLogic/GameModeType.cpp b/Code/Game/GameLogic/GameModeType.cpp new file mode 100644 index 00000000..b48fd475 --- /dev/null +++ b/Code/Game/GameLogic/GameModeType.cpp @@ -0,0 +1,15 @@ +#include "GameModeType.h" + +using namespace GameLogic; + + +GameModeType::GameModeType() +{ + +} + + +GameModeType::~GameModeType(void) +{ + +} diff --git a/Code/Game/GameLogic/GameMode.h b/Code/Game/GameLogic/GameModeType.h similarity index 63% rename from Code/Game/GameLogic/GameMode.h rename to Code/Game/GameLogic/GameModeType.h index d910c78c..8cc9fa37 100644 --- a/Code/Game/GameLogic/GameMode.h +++ b/Code/Game/GameLogic/GameModeType.h @@ -3,16 +3,16 @@ ////////////////////////////////////////////////// -#ifndef GAMEMODE_H -#define GAMEMODE_H +#ifndef GAMEMODETYPE_H +#define GAMEMODETYPE_H namespace GameLogic { - class GameMode + class GameModeType { public: - GameMode(void); - ~GameMode(void); + GameModeType(void); + ~GameModeType(void); private: diff --git a/Code/Game/GameLogic/Game_PlayerData.cpp b/Code/Game/GameLogic/Game_PlayerData.cpp index ee535868..d4657998 100644 --- a/Code/Game/GameLogic/Game_PlayerData.cpp +++ b/Code/Game/GameLogic/Game_PlayerData.cpp @@ -19,7 +19,7 @@ Game::PlayerData::PlayerData() Oyster::Physics::ICustomBody *rigidBody = Oyster::Physics::API::Instance().CreateRigidBody(sbDesc).Release(); //create player with this rigid body - this->player = new Player(rigidBody,Player::DefaultCollisionAfter, Player::PlayerCollision, OBJECT_TYPE::OBJECT_TYPE_PLAYER); + this->player = new Player(rigidBody,Level::LevelCollisionBefore, Player::PlayerCollision, OBJECT_TYPE::OBJECT_TYPE_PLAYER); this->player->GetRigidBody()->SetCustomTag(this); /*Oyster::Physics::ICustomBody::State state; this->player->GetRigidBody()->GetState(state); diff --git a/Code/Game/GameLogic/Level.cpp b/Code/Game/GameLogic/Level.cpp index 81c71de6..a954e11b 100644 --- a/Code/Game/GameLogic/Level.cpp +++ b/Code/Game/GameLogic/Level.cpp @@ -13,10 +13,183 @@ Level::Level(void) Level::~Level(void) { } +void Level::parseObjectType(ObjectTypeHeader* obj) +{ + /*switch (obj->objectTypeID) + { + case skySphere: + // save the skysphere to be able to rotate it + break; + case jumppad: + // save direction + break; + case portal: + // save portal destination + break; + case world: + // add gravitation well here + // add outer limit of the world + case spawn: + // save spawnpoint pos + break; + default: + break; + }*/ +} +void Level::parsePhysicsObj(PhysicsObject* obj) +{ + // offset physObj med modelObj +} void Level::InitiateLevel(std::string levelPath) { + LevelLoader ll; + std::vector> objects; + objects = ll.LoadLevel(levelPath); + int objCount = objects.size(); + int modelCount = 0; + for (int i = 0; i < objCount; i++) + { + ObjectTypeHeader* obj = objects.at(i); + int id = obj->typeID; + switch (obj->typeID) + { + case ObjectType::ObjectType_LevelMetaData: + { + LevelMetaData* LevelObjData = ((LevelMetaData*)obj); + std::string levelName = LevelObjData->levelName; + // LevelObjData->worldSize; + } + break; + case ObjectType::ObjectType_Static: + { + + ObjectHeader* staticObjData = ((ObjectHeader*)obj); + PhysicsObject* staticObjPhysicData = ((ObjectHeader*)obj); + staticObjData->ModelFile; + ICustomBody* rigidBody_Static; + if( staticObjPhysicData->geometryType = CollisionGeometryType_Box) + { + API::SimpleBodyDescription sbDesc_Static; + + sbDesc_Static.centerPosition = staticObjData->position; + sbDesc_Static.ignoreGravity = false; // because it is static + sbDesc_Static.rotation = Oyster::Math::Float3(staticObjData->rotation[0], staticObjData->rotation[1],staticObjData->rotation[2]);//Oyster::Math::Float3(0 ,Utility::Value::Radian(90.0f), 0); + + + //sbDesc_Static.inertiaTensor.Cuboid(staticObjPhysicData->mass); + sbDesc_Static.mass = staticObjPhysicData->mass; + sbDesc_Static.frictionCoeff_Static = staticObjPhysicData->frictionCoeffStatic; + sbDesc_Static.frictionCoeff_Dynamic = staticObjPhysicData->frictionCoeffDynamic; + //sbDesc_Static.restitutionCoeff = + sbDesc_Static.size = Oyster::Math::Float3(40,40,40); + rigidBody_Static = API::Instance().CreateRigidBody(sbDesc_Static).Release(); + if(rigidBody_Static) + { + this->staticObjects.Push(new StaticObject(rigidBody_Static,Object::DefaultCollisionBefore, Object::DefaultCollisionAfter, OBJECT_TYPE::OBJECT_TYPE_GENERIC)); + int id = this->staticObjects.Size()-1; + rigidBody_Static->SetCustomTag(this->staticObjects[this->staticObjects.Size()-1]); + } + } + if( staticObjPhysicData->geometryType = CollisionGeometryType_Sphere) + { + API::SphericalBodyDescription sbDesc_Static; + + sbDesc_Static.centerPosition = staticObjData->position; + sbDesc_Static.ignoreGravity = true; // because it is static + sbDesc_Static.rotation = Oyster::Math::Float3(staticObjData->rotation[0], staticObjData->rotation[1],staticObjData->rotation[2]);//Oyster::Math::Float3(0 ,Utility::Value::Radian(90.0f), 0); + + //sbDesc_Static.inertiaTensor.Sphere(staticObjPhysicData->mass); + + sbDesc_Static.mass = staticObjPhysicData->mass; + sbDesc_Static.frictionCoeff_Static = staticObjPhysicData->frictionCoeffStatic; + sbDesc_Static.frictionCoeff_Dynamic = staticObjPhysicData->frictionCoeffDynamic; + //sbDesc_Static.restitutionCoeff = + //sbDesc_Static.radius = + rigidBody_Static = API::Instance().CreateRigidBody(sbDesc_Static).Release(); + if(rigidBody_Static) + { + this->staticObjects.Push(new StaticObject(rigidBody_Static,Object::DefaultCollisionBefore, Object::DefaultCollisionAfter, OBJECT_TYPE::OBJECT_TYPE_GENERIC)); + int id = this->staticObjects.Size()-1; + rigidBody_Static->SetCustomTag(this->staticObjects[this->staticObjects.Size()-1]); + } + + if (OBJECT_TYPE::OBJECT_TYPE_WORLD) + { + API::Gravity gravityWell; + gravityWell.gravityType = API::Gravity::GravityType_Well; + gravityWell.well.mass = 1e17f; + gravityWell.well.position = Oyster::Math::Float4(0,0,0,1); + API::Instance().AddGravity(gravityWell); + } + } + } + break; + case ObjectType::ObjectType_Dynamic: + { + ObjectHeader* staticObjData = ((ObjectHeader*)obj); + PhysicsObject* staticObjPhysicData = ((ObjectHeader*)obj); + staticObjData->ModelFile; + + ICustomBody* rigidBody_Dynamic; + if( staticObjPhysicData->geometryType = CollisionGeometryType_Box) + { + API::SimpleBodyDescription sbDesc_Dynamic; + + sbDesc_Dynamic.centerPosition = staticObjData->position; + sbDesc_Dynamic.ignoreGravity = false; // because it is static + sbDesc_Dynamic.rotation = Oyster::Math::Float3(staticObjData->rotation[0], staticObjData->rotation[1],staticObjData->rotation[2]);//Oyster::Math::Float3(0 ,Utility::Value::Radian(90.0f), 0); + + + //sbDesc_Static.inertiaTensor.Cuboid(staticObjPhysicData->mass); + sbDesc_Dynamic.mass = staticObjPhysicData->mass; + sbDesc_Dynamic.frictionCoeff_Static = staticObjPhysicData->frictionCoeffStatic; + sbDesc_Dynamic.frictionCoeff_Dynamic = staticObjPhysicData->frictionCoeffDynamic; + //sbDesc_Static.restitutionCoeff = + sbDesc_Dynamic.size = Oyster::Math::Float3(40,40,40); + rigidBody_Dynamic = API::Instance().CreateRigidBody(sbDesc_Dynamic).Release(); + if(rigidBody_Dynamic) + { + rigidBody_Dynamic->SetSubscription(Level::PhysicsOnMoveLevel); + this->dynamicObjects.Push(new DynamicObject(rigidBody_Dynamic,Object::DefaultCollisionBefore, Object::DefaultCollisionAfter, OBJECT_TYPE::OBJECT_TYPE_GENERIC)); + int id = this->dynamicObjects.Size()-1; + rigidBody_Dynamic->SetCustomTag(this->dynamicObjects[this->dynamicObjects.Size()-1]); + } + } + if( staticObjPhysicData->geometryType = CollisionGeometryType_Sphere) + { + API::SphericalBodyDescription sbDesc_Dynamic; + + sbDesc_Dynamic.centerPosition = staticObjData->position; + sbDesc_Dynamic.ignoreGravity = false; // use gravity on dynamic obj + sbDesc_Dynamic.rotation = Oyster::Math::Float3(staticObjData->rotation[0], staticObjData->rotation[1],staticObjData->rotation[2]);//Oyster::Math::Float3(0 ,Utility::Value::Radian(90.0f), 0); + + //sbDesc_Static.inertiaTensor.Sphere(staticObjPhysicData->mass); + + sbDesc_Dynamic.mass = staticObjPhysicData->mass; + sbDesc_Dynamic.frictionCoeff_Static = staticObjPhysicData->frictionCoeffStatic; + sbDesc_Dynamic.frictionCoeff_Dynamic = staticObjPhysicData->frictionCoeffDynamic; + //sbDesc_Static.restitutionCoeff = + //sbDesc_Static.radius = + rigidBody_Dynamic = API::Instance().CreateRigidBody(sbDesc_Dynamic).Release(); + if(rigidBody_Dynamic) + { + rigidBody_Dynamic->SetSubscription(Level::PhysicsOnMoveLevel); + this->dynamicObjects.Push(new DynamicObject(rigidBody_Dynamic,Object::DefaultCollisionBefore, Object::DefaultCollisionAfter, OBJECT_TYPE::OBJECT_TYPE_GENERIC)); + int id = this->dynamicObjects.Size()-1; + rigidBody_Dynamic->SetCustomTag(this->dynamicObjects[this->dynamicObjects.Size()-1]); + } + } + } + break; + case ObjectType::ObjectType_Light: + // read on client + break; + default: + break; + } + } } void Level::InitiateLevel(float radius) { diff --git a/Code/Game/GameLogic/Level.h b/Code/Game/GameLogic/Level.h index cc34408b..64b09f5c 100644 --- a/Code/Game/GameLogic/Level.h +++ b/Code/Game/GameLogic/Level.h @@ -8,11 +8,12 @@ #include "Player.h" #include "StaticObject.h" #include "DynamicObject.h" -#include "GameMode.h" +#include "GameModeType.h" #include "Player.h" #include "PhysicsAPI.h" #include "TeamManager.h" #include "DynamicArray.h" +#include "LevelLoader/LevelLoader.h" namespace GameLogic { @@ -29,8 +30,10 @@ namespace GameLogic * @param levelPath: Path to a file that contains all information on the level ********************************************************/ void InitiateLevel(std::string levelPath); - void Level::InitiateLevel(float radius); + void InitiateLevel(float radius); + void parseObjectType(ObjectTypeHeader* obj); + void parsePhysicsObj(PhysicsObject* obj); /******************************************************** * Creates a team in the level * @param teamSize: The size of the team you want to create @@ -69,7 +72,7 @@ namespace GameLogic TeamManager teamManager; Utility::DynamicMemory::DynamicArray> staticObjects; Utility::DynamicMemory::DynamicArray> dynamicObjects; - GameMode gameMode; + GameModeType gameMode; Utility::DynamicMemory::SmartPointer rigidBodyLevel; StaticObject *levelObj; diff --git a/Code/Game/GameLogic/Object.cpp b/Code/Game/GameLogic/Object.cpp index ebd5c275..1a1f7338 100644 --- a/Code/Game/GameLogic/Object.cpp +++ b/Code/Game/GameLogic/Object.cpp @@ -178,13 +178,13 @@ void Object::EndFrame() //300, 0,0, //1,0,0 - /*if( pos.GetLength() < 303.5f) + if( pos.GetLength() < 303.5f) { Oyster::Math::Float moveUp = 303.5 - pos.GetLength(); up *= moveUp; currPhysicsState.SetCenterPosition(pos + up); - }*/ + } if(currPhysicsState.GetLinearMomentum() !=currPhysicsState.GetLinearMomentum()) diff --git a/Code/Game/GameLogic/Object.h b/Code/Game/GameLogic/Object.h index c484701c..91559734 100644 --- a/Code/Game/GameLogic/Object.h +++ b/Code/Game/GameLogic/Object.h @@ -27,6 +27,7 @@ namespace GameLogic // API overrides OBJECT_TYPE GetObjectType() const; + void setID(int id); int GetID() const; Oyster::Math::Float3 GetPosition(); Oyster::Math::Float4x4 GetOrientation(); diff --git a/Code/OysterPhysics3D/RigidBody.cpp b/Code/OysterPhysics3D/RigidBody.cpp index d9f2f69d..f7a5646e 100644 --- a/Code/OysterPhysics3D/RigidBody.cpp +++ b/Code/OysterPhysics3D/RigidBody.cpp @@ -51,8 +51,8 @@ void RigidBody::Update_LeapFrog( Float updateFrameLength ) // updating the linear //Decrease momentum with 1% as "fall-off" //! HACK: @todo Add real solution with fluid drag - //this->momentum_Linear = this->momentum_Linear*0.99f; - //this->momentum_Angular = this->momentum_Angular*0.99f; + this->momentum_Linear = this->momentum_Linear*0.99f; + this->momentum_Angular = this->momentum_Angular*0.99f; // ds = dt * Formula::LinearVelocity( m, avg_G ) = dt * avg_G / m = (dt / m) * avg_G Float3 delta = AverageWithDelta( this->momentum_Linear, this->impulse_Linear );