diff --git a/Code/DanBias.sln b/Code/DanBias.sln index c825e6ee..51ad5665 100644 --- a/Code/DanBias.sln +++ b/Code/DanBias.sln @@ -776,6 +776,5 @@ Global {2EC4DDED-8F75-4C86-A10B-E1E8EB29F3EE} = {1322B12B-5E37-448A-AAAF-F637460DCB23} {604A12A7-07BF-4482-BDF3-7101C811F121} = {C83A6FAD-E71F-4B1E-9D63-E93E61DDC012} {C8CBA520-5D7D-4D61-A8DA-6E05FD132BCB} = {C83A6FAD-E71F-4B1E-9D63-E93E61DDC012} - {67D0FB00-FF1F-4DE4-84BD-664AE93D25EE} = {C83A6FAD-E71F-4B1E-9D63-E93E61DDC012} EndGlobalSection EndGlobal diff --git a/Code/Game/GameClient/DanBiasGame_Impl.cpp b/Code/Game/GameClient/DanBiasGame_Impl.cpp index e5df1557..8eabffb3 100644 --- a/Code/Game/GameClient/DanBiasGame_Impl.cpp +++ b/Code/Game/GameClient/DanBiasGame_Impl.cpp @@ -9,6 +9,7 @@ #include "GameClientState\MainState.h" #include "GameClientState\LanMenuState.h" #include "GameClientState\NetLoadState.h" +#include "Utilities.h" #include #include "NetworkClient.h" #include @@ -51,11 +52,12 @@ namespace DanBias DanBiasGamePrivateData() { - this->sharedStateContent.network = nullptr; - this->sharedStateContent.mouseDevice = nullptr; - this->sharedStateContent.keyboardDevice = nullptr; - this->serverOwner = false; - this->capFrame = 0; + this->sharedStateContent.network = nullptr; + this->sharedStateContent.mouseDevice = nullptr; + this->sharedStateContent.keyboardDevice = nullptr; + this->sharedStateContent.mouseSensitivity = Utility::Value::Radian( 0.1f ); + this->serverOwner = false; + this->capFrame = 0; } ~DanBiasGamePrivateData() @@ -115,7 +117,6 @@ namespace DanBias float dt = (float)data.timer.getElapsedSeconds(); data.timer.reset(); - Graphics::API::Update( dt ); data.capFrame += dt; if(data.capFrame > 0.03f) @@ -127,6 +128,8 @@ namespace DanBias case Result_error: return DanBiasClientReturn_Error; default: break; } + + Graphics::API::Update( data.capFrame ); if(Render() != S_OK) return DanBiasClientReturn_Error; data.capFrame -= 0.03f; diff --git a/Code/Game/GameClient/GameClientState/C_obj/C_DynamicObj.cpp b/Code/Game/GameClient/GameClientState/C_obj/C_DynamicObj.cpp index 73dd20b5..26619c0e 100644 --- a/Code/Game/GameClient/GameClientState/C_obj/C_DynamicObj.cpp +++ b/Code/Game/GameClient/GameClientState/C_obj/C_DynamicObj.cpp @@ -3,6 +3,7 @@ using namespace DanBias::Client; C_DynamicObj::C_DynamicObj(void) + :C_Object() { } diff --git a/Code/Game/GameClient/GameClientState/C_obj/C_StaticObj.cpp b/Code/Game/GameClient/GameClientState/C_obj/C_StaticObj.cpp index 42a12acd..22734a96 100644 --- a/Code/Game/GameClient/GameClientState/C_obj/C_StaticObj.cpp +++ b/Code/Game/GameClient/GameClientState/C_obj/C_StaticObj.cpp @@ -3,6 +3,7 @@ using namespace DanBias::Client; C_StaticObj::C_StaticObj(void) + :C_Object() { } diff --git a/Code/Game/GameClient/GameClientState/GameState.cpp b/Code/Game/GameClient/GameClientState/GameState.cpp index 608e1d8f..123b3fb2 100644 --- a/Code/Game/GameClient/GameClientState/GameState.cpp +++ b/Code/Game/GameClient/GameClientState/GameState.cpp @@ -34,7 +34,8 @@ struct GameState::MyData ::std::map> *dynamicObjects; ::std::map> *lights; - C_Player player; + //C_Player player; + ::std::map> players; Camera_FPSV2 camera; int myId; @@ -77,7 +78,7 @@ bool GameState::Init( SharedStateContent &shared ) this->privData->camera.SetPerspectiveProjection( Utility::Value::Radian(90.0f), aspectRatio, 0.1f, 1000.0f ); Graphics::API::SetProjection( this->privData->camera.GetProjectionMatrix() ); gfxOp.AmbientValue = 0.5f; - gfxOp.GlobalGlowTint = Math::Float3(2,1,1); + gfxOp.GlobalGlowTint = Math::Float3(1,1,1); gfxOp.GlobalTint = Math::Float3(1,1,1); Graphics::API::SetOptions(gfxOp); @@ -96,7 +97,7 @@ bool GameState::Init( SharedStateContent &shared ) } // create UI states - this->gameUI = new GamingUI(this->privData->mouseInput, this->privData->keyboardInput, this->privData->nwClient, &this->privData->camera); + this->gameUI = new GamingUI(&shared, &this->privData->camera); this->respawnUI = new RespawnUI(this->privData->nwClient, 20); this->statsUI = new StatsUI(); this->currGameUI = gameUI; @@ -117,8 +118,8 @@ void GameState::InitiatePlayer( int id, const std::string &modelName, const floa modelData.position = position; modelData.rotation = ArrayToQuaternion( rotation ); modelData.scale = scale; - StringToWstring( modelName, modelData.modelPath ); modelData.id = id; + StringToWstring(modelName,modelData.modelPath); // RB DEBUG RBInitData RBData; @@ -127,37 +128,30 @@ void GameState::InitiatePlayer( int id, const std::string &modelName, const floa RBData.scale = scale; RBData.type = RB_Type_Cube; // !RB DEBUG - if( isMyPlayer ) + C_Player *p = new C_Player(); + if( p->Init(modelData) ) { - if( this->privData->player.Init(modelData) ) - { - // RB DEBUG - this->privData->player.InitRB( RBData ); - // !RB DEBUG + // RB DEBUG + p->InitRB( RBData ); + // !RB DEBUG + // start with runing animation + p->playAnimation( L"run_forwards", true ); + (this->privData->players)[id] = p; + + if( isMyPlayer ) + { this->privData->myId = id; - this->privData->camera.SetPosition( this->privData->player.getPos() ); + this->privData->camera.SetPosition( p->getPos() ); Float3 offset = Float3( 0.0f ); // DEBUG position of camera so we can see the player model - //offset.y = this->privData->player.getScale().y * 5.0f; - //offset.z = this->privData->player.getScale().z * -5.0f; + offset.y = p->getScale().y * 5.0f; + offset.z = p->getScale().z * -5.0f; // !DEBUG this->privData->camera.SetHeadOffset( offset ); this->privData->camera.UpdateOrientation(); } } - else - { - C_DynamicObj *p = new C_DynamicObj(); - if( p->Init(modelData) ) - { - // RB DEBUG - this->privData->player.InitRB( RBData ); - // !RB DEBUG - - (*this->privData->dynamicObjects)[id] = p; - } - } } GameClientState::ClientState GameState::Update( float deltaTime ) @@ -191,7 +185,17 @@ bool GameState::Render() Oyster::Graphics::API::NewFrame(); // for debugging to be replaced with render weapon - this->privData->player.Render(); + auto playerObject = this->privData->players.begin(); + for( ; playerObject != this->privData->players.end(); ++playerObject ) + { + if(playerObject->second) + { + //if( this->privData->myId != playerObject->second->GetId() ) + { + playerObject->second->Render(); + } + } + } auto staticObject = this->privData->staticObjects->begin(); for( ; staticObject != this->privData->staticObjects->end(); ++staticObject ) @@ -214,11 +218,21 @@ bool GameState::Render() { Oyster::Graphics::API::StartRenderWireFrame(); - Oyster::Math3D::Float4x4 translation = Oyster::Math3D::TranslationMatrix(Float3( 0,132, 20)); - Oyster::Math3D::Float4x4 scale = Oyster::Math3D::ScalingMatrix(Float3( 0.5f, 0.5f, 0.5f)); - Oyster::Math3D::Float4x4 world = translation * scale; - Oyster::Graphics::API::RenderDebugCube( world ); - Oyster::Graphics::API::RenderDebugCube(this->privData->player.getRBWorld()); + playerObject = this->privData->players.begin(); + for( ; playerObject != this->privData->players.end(); ++playerObject ) + { + if(playerObject->second) + { + if( playerObject->second->getBRtype() == RB_Type_Cube) + { + Oyster::Graphics::API::RenderDebugCube( playerObject->second->getRBWorld()); + } + if( playerObject->second->getBRtype() == RB_Type_Sphere) + { + Oyster::Graphics::API::RenderDebugSphere( playerObject->second->getRBWorld()); + } + } + } staticObject = this->privData->staticObjects->begin(); for( ; staticObject != this->privData->staticObjects->end(); ++staticObject ) @@ -278,6 +292,12 @@ bool GameState::Release() Graphics::API::Option o = Graphics::API::GetOption(); if( privData ) { + auto playerObject = this->privData->players.begin(); + for( ; playerObject != this->privData->players.end(); ++playerObject ) + { + playerObject->second = nullptr; + } + auto staticObject = this->privData->staticObjects->begin(); for( ; staticObject != this->privData->staticObjects->end(); ++staticObject ) { @@ -465,42 +485,29 @@ const GameClientState::NetEvent & GameState::DataRecieved( const GameClientState Protocol_ObjectPositionRotation decoded(data); Float3 position = decoded.position; Quaternion rotation = Quaternion( Float3(decoded.rotationQ), decoded.rotationQ[3] ); - - // if is this player. Remember to change camera - if( this->privData->myId == decoded.object_ID ) + C_Object *object; + object = (this->privData->players)[decoded.object_ID]; + if( !object) { - if( !Within(position.Dot(position), 2500.0f, 90000.0f) ) - { // HACK: bug trap - const char *breakPoint = "Something is wrong."; - position = Float3( 0.0f, 160.0f, 0.0f ); - } - - this->privData->camera.SetPosition( position ); - this->privData->camera.SetRotation( rotation ); - this->privData->player.setPos( position ); - this->privData->player.setRot( rotation ); - this->privData->player.updateWorld(); - // RB DEBUG - this->privData->player.setRBPos ( position ); - this->privData->player.setRBRot ( rotation ); - this->privData->player.updateRBWorld(); - // !RB DEBUG + // if it is not a player + object = (*this->privData->dynamicObjects)[decoded.object_ID]; } - else - { - C_DynamicObj *object = (*this->privData->dynamicObjects)[decoded.object_ID]; - if( object ) + if( object ) + { + if( this->privData->myId == decoded.object_ID ) { - object->setPos( position ); - object->setRot( rotation ); - object->updateWorld(); - // RB DEBUG - object->setRBPos ( position ); - object->setRBRot ( rotation ); - object->updateRBWorld(); - // !RB DEBUG + this->privData->camera.SetPosition( position ); + this->privData->camera.SetRotation( rotation ); } + object->setPos( position ); + object->setRot( rotation ); + object->updateWorld(); + // RB DEBUG + object->setRBPos ( position ); + object->setRBRot ( rotation ); + object->updateRBWorld(); + // !RB DEBUG } } return GameClientState::event_processed; @@ -540,7 +547,7 @@ const GameClientState::NetEvent & GameState::DataRecieved( const GameClientState RBData.rotation = ArrayToQuaternion( decoded.position ); RBData.scale = Float3( decoded.scale ); - this->privData->player.InitRB( RBData ); + object->InitRB( RBData ); // !RB DEBUG (*this->privData->dynamicObjects)[decoded.object_ID] = object; @@ -559,17 +566,29 @@ const GameClientState::NetEvent & GameState::DataRecieved( const GameClientState case protocol_Gameplay_ObjectWeaponEnergy: break; /** @todo TODO: implement */ case protocol_Gameplay_ObjectRespawn: { - // set player pos Protocol_ObjectRespawn decoded(data); - // move player. Remember to change camera - this->privData->camera.SetPosition( decoded.position ); - this->privData->player.setPos( decoded.position ); - this->privData->player.updateWorld(); - // RB DEBUG - this->privData->player.setRBPos ( decoded.position ); - this->privData->player.updateRBWorld(); - // !RB DEBUG + C_Object *object; + object = (this->privData->players)[decoded.objectID]; + if( !object) + { + // if it is not a player + object = (*this->privData->dynamicObjects)[decoded.objectID]; + } + + if( object ) + { + if( this->privData->myId == decoded.objectID ) + { + this->privData->camera.SetPosition( decoded.position ); + } + object->setPos( decoded.position ); + object->updateWorld(); + // RB DEBUG + object->setRBPos ( decoded.position ); + object->updateRBWorld(); + // !RB DEBUG + } this->currGameUI = this->gameUI; } return GameClientState::event_processed; @@ -587,7 +606,7 @@ const GameClientState::NetEvent & GameState::DataRecieved( const GameClientState return GameClientState::event_processed; case protocol_Gameplay_ObjectDisconnectPlayer: { - //Removes + //Remove the disconnected player Protocol_ObjectDisconnectPlayer decoded(data); auto object = this->privData->dynamicObjects->find( decoded.objectID ); if( object != this->privData->dynamicObjects->end() ) diff --git a/Code/Game/GameClient/GameClientState/GamingUI.cpp b/Code/Game/GameClient/GameClientState/GamingUI.cpp index 68e62f10..ce08fa16 100644 --- a/Code/Game/GameClient/GameClientState/GamingUI.cpp +++ b/Code/Game/GameClient/GameClientState/GamingUI.cpp @@ -13,20 +13,16 @@ GamingUI::GamingUI() : GameStateUI() { /* Should never be called! */ - this->mouseInput = nullptr; - this->keyboardInput = nullptr; - this->netClient = nullptr; - this->camera = nullptr; - this->plane = nullptr; - this->text = nullptr; + this->sharedData = nullptr; + this->camera = nullptr; + this->plane = nullptr; + this->text = nullptr; } -GamingUI::GamingUI( Mouse *mouseInput, Keyboard *keyboardInput, NetworkClient *connection, Camera_FPSV2 *camera ) : +GamingUI::GamingUI( SharedStateContent* shared, Camera_FPSV2 *camera ) : GameStateUI() { - this->mouseInput = mouseInput; - this->keyboardInput = keyboardInput; - this->netClient = connection; + this->sharedData = shared; this->camera = camera; } @@ -38,9 +34,12 @@ bool GamingUI::Init() this->plane = new Plane_UI(L"box_tex.png", Float3(0.5f, 0.0f, 0.5f), Float2(0.3f, 0.1f)); this->text = new Text_UI(L"hej", Float3(0.5f,0.0f,0.1f), Float2(0.1f,0.1f)); + this->sharedData = sharedData; + // setting input mode to all raw - this->keyboardInput->Activate(); - this->mouseInput->Activate(); + this->sharedData->keyboardDevice->Activate(); + this->sharedData->mouseDevice->Activate(); + this->sharedData->mouseDevice->AddMouseEvent(this); return true; } @@ -77,6 +76,9 @@ bool GamingUI::Release() delete this->plane; if(this->text) delete this->text; + + this->sharedData = 0; + return true; } void GamingUI::SetHPtext( std::wstring hp ) @@ -85,31 +87,31 @@ void GamingUI::SetHPtext( std::wstring hp ) } void GamingUI::ReadKeyInput() { - if( this->keyboardInput->IsKeyDown(::Input::Enum::SAKI_W) ) + if( this->sharedData->keyboardDevice->IsKeyDown(::Input::Enum::SAKI_W) ) { // move forward - this->netClient->Send( Protocol_PlayerMovementForward() ); + this->sharedData->network->Send( Protocol_PlayerMovementForward() ); } - if( this->keyboardInput->IsKeyDown(::Input::Enum::SAKI_S) ) + if( this->sharedData->keyboardDevice->IsKeyDown(::Input::Enum::SAKI_S) ) { // move backward - this->netClient->Send( Protocol_PlayerMovementBackward() ); + this->sharedData->network->Send( Protocol_PlayerMovementBackward() ); } - if( this->keyboardInput->IsKeyDown(::Input::Enum::SAKI_A) ) + if( this->sharedData->keyboardDevice->IsKeyDown(::Input::Enum::SAKI_A) ) { // strafe left - this->netClient->Send( Protocol_PlayerMovementLeft() ); + this->sharedData->network->Send( Protocol_PlayerMovementLeft() ); } - if( this->keyboardInput->IsKeyDown(::Input::Enum::SAKI_D) ) + if( this->sharedData->keyboardDevice->IsKeyDown(::Input::Enum::SAKI_D) ) { // strafe right - this->netClient->Send( Protocol_PlayerMovementRight() ); + this->sharedData->network->Send( Protocol_PlayerMovementRight() ); } - if( this->keyboardInput->IsKeyDown(::Input::Enum::SAKI_Space) ) + if( this->sharedData->keyboardDevice->IsKeyDown(::Input::Enum::SAKI_Space) ) { // jump if(!this->key_Jump) { - this->netClient->Send( Protocol_PlayerJump() ); + this->sharedData->network->Send( Protocol_PlayerJump() ); this->key_Jump = true; } } @@ -117,7 +119,7 @@ void GamingUI::ReadKeyInput() this->key_Jump = false; // shoot - if( this->mouseInput->IsBtnDown(::Input::Enum::SAMI_MouseLeftBtn) ) + if( this->sharedData->mouseDevice->IsBtnDown(::Input::Enum::SAMI_MouseLeftBtn) ) { if( !this->key_Shoot ) { @@ -125,14 +127,14 @@ void GamingUI::ReadKeyInput() playerShot.primaryPressed = true; playerShot.secondaryPressed = false; playerShot.utilityPressed = false; - this->netClient->Send( playerShot ); + this->sharedData->network->Send( playerShot ); this->key_Shoot = true; } } else this->key_Shoot = false; - if( this->mouseInput->IsBtnDown(::Input::Enum::SAMI_MouseRightBtn) ) + if( this->sharedData->mouseDevice->IsBtnDown(::Input::Enum::SAMI_MouseRightBtn) ) { if( !this->key_Shoot ) { @@ -140,14 +142,14 @@ void GamingUI::ReadKeyInput() playerShot.primaryPressed = false; playerShot.secondaryPressed = true; playerShot.utilityPressed = false; - this->netClient->Send( playerShot ); + this->sharedData->network->Send( playerShot ); this->key_Shoot = true; } } else this->key_Shoot = false; - if( this->mouseInput->IsBtnDown(::Input::Enum::SAMI_MouseMiddleBtn) ) + if( this->sharedData->mouseDevice->IsBtnDown(::Input::Enum::SAMI_MouseMiddleBtn) ) { if( !this->key_Shoot ) { @@ -155,29 +157,28 @@ void GamingUI::ReadKeyInput() playerShot.primaryPressed = false; playerShot.secondaryPressed = false; playerShot.utilityPressed = true; - this->netClient->Send( playerShot ); + this->sharedData->network->Send( playerShot ); this->key_Shoot = true; } } else this->key_Shoot = false; - //send delta mouse movement - { - static const float mouseSensitivity = Radian( 1.0f ); - ::Input::Struct::SAIPointFloat2D deltaPos; - this->mouseInput->GetDeltaPosition( deltaPos ); - - this->camera->PitchDown( deltaPos.y * mouseSensitivity );; - //if( deltaPos.x != 0.0f ) //This made the camera reset to a specific rotation. Why? - { - this->netClient->Send( Protocol_PlayerLeftTurn(deltaPos.x * mouseSensitivity) ); - } - } - - if( this->keyboardInput->IsKeyDown(::Input::Enum::SAKI_Escape) ) + if( this->sharedData->keyboardDevice->IsKeyDown(::Input::Enum::SAKI_Escape) ) { this->nextState = GameStateUI::UIState_shut_down; } } + +void GamingUI::OnMouseMoveVelocity ( Input::Struct::SAIPointInt2D coordinate, Input::Mouse* sender ) +{ + //send delta mouse movement + { + this->camera->PitchDown( (-coordinate.y) * this->sharedData->mouseSensitivity );; + //if( deltaPos.x != 0.0f ) //This made the camera reset to a specific rotation. Why? + { + this->sharedData->network->Send( Protocol_PlayerLeftTurn((coordinate.x) * this->sharedData->mouseSensitivity, this->camera->GetLook()) ); + } + } +} \ No newline at end of file diff --git a/Code/Game/GameClient/GameClientState/GamingUI.h b/Code/Game/GameClient/GameClientState/GamingUI.h index c5346004..c4e34441 100644 --- a/Code/Game/GameClient/GameClientState/GamingUI.h +++ b/Code/Game/GameClient/GameClientState/GamingUI.h @@ -6,13 +6,15 @@ #include "Camera_FPSV2.h" #include "Buttons\Text_UI.h" #include "Buttons\Plane_UI.h" +#include "InputManager.h" +#include "SharedStateContent.h" namespace DanBias { namespace Client { - class GamingUI : public GameStateUI + class GamingUI : public GameStateUI, Input::Mouse::MouseEvent { public: - GamingUI( ::Input::Mouse *mouseInput, ::Input::Keyboard *keyboardInput, ::Oyster::Network::NetworkClient *connection, Camera_FPSV2 *camera ); + GamingUI( SharedStateContent* shared, Camera_FPSV2 *camera ); virtual ~GamingUI(); bool Init(); @@ -24,10 +26,17 @@ namespace DanBias { namespace Client bool Release(); void SetHPtext( std::wstring hp ); + private: /* Overidden mouse methods */ + void OnMouse ( const Input::Struct::MouseEventData& eventData ) override { } + void OnMousePress ( Input::Enum::SAMI key, Input::Mouse* sender ) override { } + void OnMouseDown ( Input::Enum::SAMI key, Input::Mouse* sender ) override { } + void OnMouseRelease ( Input::Enum::SAMI key, Input::Mouse* sender ) override { } + void OnMouseMovePixelPos ( Input::Struct::SAIPointInt2D coordinate, Input::Mouse* sender ) override { } + void OnMouseMoveVelocity ( Input::Struct::SAIPointInt2D coordinate, Input::Mouse* sender ) override; + void OnMouseScroll ( int delta, Input::Mouse* sender ) override { } + private: - ::Input::Mouse *mouseInput; - ::Input::Keyboard *keyboardInput; - ::Oyster::Network::NetworkClient *netClient; + SharedStateContent *sharedData; Camera_FPSV2 *camera; // TODO add multiple UI elements diff --git a/Code/Game/GameClient/GameClientState/LanMenuState.cpp b/Code/Game/GameClient/GameClientState/LanMenuState.cpp index 4d7304c8..8e07cc9f 100644 --- a/Code/Game/GameClient/GameClientState/LanMenuState.cpp +++ b/Code/Game/GameClient/GameClientState/LanMenuState.cpp @@ -66,6 +66,7 @@ bool LanMenuState::Init( SharedStateContent &shared ) this->privData->connectIP->ReserveLines( 1 ); this->privData->connectIP->AppendText( L"127.0.0.1" ); //this->privData->connectIP->AppendText( L"194.47.150.206" ); // HACK: connecting to Dennis's server + //this->privData->connectIP->AppendText( L"194.47.150.189" ); // HACK: connecting to Robins server this->privData->connectIP->SetFontHeight( 0.035f ); this->privData->connectIP->SetLineSpacing( 0.005f ); this->privData->connectIP->SetBottomAligned(); diff --git a/Code/Game/GameClient/GameClientState/NetLoadState.cpp b/Code/Game/GameClient/GameClientState/NetLoadState.cpp index 9ef0dac9..5553303e 100644 --- a/Code/Game/GameClient/GameClientState/NetLoadState.cpp +++ b/Code/Game/GameClient/GameClientState/NetLoadState.cpp @@ -231,7 +231,7 @@ void NetLoadState::LoadGame( const ::std::string &fileName ) pointLight.Color = light->color; pointLight.Pos = light->position; pointLight.Bright = light->intensity; - pointLight.Radius = light->raduis; + pointLight.Radius = light->radius; C_Light *newLight = new C_Light( pointLight, objectID ); @@ -242,5 +242,7 @@ void NetLoadState::LoadGame( const ::std::string &fileName ) } } + Graphics::API::EndLoadingModels(); + this->privData->nextState = ClientState::ClientState_Game; } diff --git a/Code/Game/GameClient/GameClientState/SharedStateContent.h b/Code/Game/GameClient/GameClientState/SharedStateContent.h index cb722cec..2a72f9d5 100644 --- a/Code/Game/GameClient/GameClientState/SharedStateContent.h +++ b/Code/Game/GameClient/GameClientState/SharedStateContent.h @@ -29,6 +29,8 @@ namespace DanBias { namespace Client ::Input::Mouse *mouseDevice; ::Input::Keyboard *keyboardDevice; + + float mouseSensitivity; }; } } diff --git a/Code/Game/GameLogic/AttatchmentMassDriver.cpp b/Code/Game/GameLogic/AttatchmentMassDriver.cpp index 89de1f3e..b988451f 100644 --- a/Code/Game/GameLogic/AttatchmentMassDriver.cpp +++ b/Code/Game/GameLogic/AttatchmentMassDriver.cpp @@ -56,18 +56,14 @@ void AttatchmentMassDriver::Update(float dt) //update position of heldObject if there is an object being held if(hasObject) { - //Oyster::Physics::ICustomBody::State state; - //state = heldObject->GetState(); Oyster::Math::Float3 ownerPos = owner->GetPosition(); Oyster::Physics::ICustomBody::State ownerState = owner->GetRigidBody()->GetState(); Oyster::Math::Float3 up = -ownerState.GetOrientation().v[2]; up *= -0.3f; - Oyster::Math::Float3 pos = ownerPos + (owner->GetLookDir().GetNormalized()*5); - - //state.centerPos = pos; + Oyster::Math::Float3 pos = ownerPos + (owner->GetLookDir().GetNormalized()*2); heldObject->SetPosition(pos); + heldObject->SetLinearVelocity(Oyster::Math::Float3::null); - //heldObject->SetState(state); } } @@ -82,8 +78,7 @@ void AttatchmentMassDriver::ForcePush(const GameLogic::WEAPON_FIRE &usage, float if(hasObject) { - Oyster::Physics::API::Instance().ReleaseFromLimbo(heldObject); - pushForce = Oyster::Math::Float4(this->owner->GetLookDir()) * (400); + pushForce = Oyster::Math::Float4(this->owner->GetLookDir()) * (800); heldObject->ApplyImpulse((Oyster::Math::Float3)pushForce); hasObject = false; @@ -149,7 +144,7 @@ void AttatchmentMassDriver::ForcePull(const WEAPON_FIRE &usage, float dt) void AttatchmentMassDriver::PickUpObject(const WEAPON_FIRE &usage, float dt) { - Oyster::Math::Float3 pos = owner->GetPosition() + owner->GetLookDir().GetNormalized()*5; + Oyster::Math::Float3 pos = owner->GetPosition() + owner->GetLookDir().GetNormalized()*2; Oyster::Collision3D::Sphere *hitSphere = new Oyster::Collision3D::Sphere(pos,10); Oyster::Physics::API::Instance().ApplyEffect(hitSphere,this,AttemptPickUp); diff --git a/Code/Game/GameLogic/CollisionManager.cpp b/Code/Game/GameLogic/CollisionManager.cpp index 7b2b7ce1..90a2aefe 100644 --- a/Code/Game/GameLogic/CollisionManager.cpp +++ b/Code/Game/GameLogic/CollisionManager.cpp @@ -20,37 +20,50 @@ using namespace GameLogic; void Teleport(Oyster::Physics::ICustomBody &obj, Oyster::Math::Float3 target); //Physics::ICustomBody::SubscriptMessage - void Player::PlayerCollision(Oyster::Physics::ICustomBody *rigidBodyPlayer, Oyster::Physics::ICustomBody *obj, Oyster::Math::Float kineticEnergyLoss) + void Player::PlayerCollision(Oyster::Physics::ICustomBody *objA, Oyster::Physics::ICustomBody *objB, Oyster::Math::Float kineticEnergyLoss) { - Player *player = ((Player*)(rigidBodyPlayer->GetCustomTag())); - Object *realObj = (Object*)obj->GetCustomTag(); //needs to be changed? + Object *realObjA = ((Object*)(objA->GetCustomTag())); + Player *player; + Object *realObjB = (Object*)objB->GetCustomTag(); //needs to be changed? - if(!realObj) + if(!realObjA) return; - if(!player) + if(!realObjB) return; - switch (realObj->GetObjectType()) + //check who is player and who is the object + if(realObjA->GetObjectType() == ObjectSpecialType::ObjectSpecialType_Player) + { + player = (Player*)realObjA; + } + else + { + player = (Player*)realObjB; + realObjB = realObjA; + } + + + switch (realObjB->GetObjectType()) { case ObjectSpecialType::ObjectSpecialType_Generic: - PlayerVObject(*player,*realObj, kineticEnergyLoss); + PlayerVObject(*player,*realObjB, kineticEnergyLoss); //return Physics::ICustomBody::SubscriptMessage_none; break; case ObjectSpecialType::ObjectSpecialType_StandardBox: - PlayerVObject(*player,*realObj, kineticEnergyLoss); + PlayerVObject(*player,*realObjB, kineticEnergyLoss); //return Physics::ICustomBody::SubscriptMessage_none; break; case ObjectSpecialType::ObjectSpecialType_Player: //return Physics::ICustomBody::SubscriptMessage_none; break; case ObjectSpecialType::ObjectSpecialType_World: - PlayerVObject(*player,*realObj, kineticEnergyLoss); + PlayerVObject(*player,*realObjB, kineticEnergyLoss); //player->playerState = PLAYER_STATE::PLAYER_STATE_WALKING; break; case ObjectSpecialType::ObjectSpecialType_CrystalFormation: - PlayerVLethalObject(*player,*realObj, kineticEnergyLoss,realObj->GetExtraDamageOnCollision()); + PlayerVLethalObject(*player,*realObjB, kineticEnergyLoss,realObjB->GetExtraDamageOnCollision()); //player->playerState = PLAYER_STATE::PLAYER_STATE_WALKING; break; } @@ -95,13 +108,31 @@ using namespace GameLogic; obj.SetPosition(target); } - void ExplosiveCrate::ExplosiveCrateCollision(Oyster::Physics::ICustomBody *rigidBodyCrate, Oyster::Physics::ICustomBody *obj, Oyster::Math::Float kineticEnergyLoss) + void ExplosiveCrate::ExplosiveCrateCollision(Oyster::Physics::ICustomBody *objA, Oyster::Physics::ICustomBody *objB, Oyster::Math::Float kineticEnergyLoss) { - int forceThreashHold = 200000; //how much force for the box to explode of the impact + - Object *realObj = (Object*)obj->GetCustomTag(); //needs to be changed? + Object *realObjA = ((Object*)(objA->GetCustomTag())); + Object *realObjB = (Object*)objB->GetCustomTag(); //needs to be changed? + ExplosiveCrate* crate; - switch (realObj->GetObjectType()) + if(!realObjA) + return; + if(!realObjB) + return; + + //check who is player and who is the object + if(realObjA->GetObjectType() == ObjectSpecialType::ObjectSpecialType_RedExplosiveBox) + { + crate = (ExplosiveCrate*)realObjA; + } + else + { + crate = (ExplosiveCrate*)realObjB; + realObjB = realObjA; + } + + switch (realObjB->GetObjectType()) { case ObjectSpecialType::ObjectSpecialType_Generic: break; @@ -109,29 +140,15 @@ using namespace GameLogic; break; case ObjectSpecialType::ObjectSpecialType_Player: - ExplosiveCrate* crate = ((ExplosiveCrate*)rigidBodyCrate->GetCustomTag()); - - - Oyster::Math::Float3 pos = rigidBodyCrate->GetState().centerPos; + if(crate->hasExploaded) return; + Oyster::Math::Float3 pos = crate->GetRigidBody()->GetState().centerPos; Oyster::Collision3D::Sphere *hitSphere = new Oyster::Collision3D::Sphere(pos,crate->ExplosionRadius); Oyster::Physics::API::Instance().ApplyEffect(hitSphere,crate,Explode); - + crate->hasExploaded = true; delete hitSphere; break; } - /*if(kineticEnergyLoss > forceThreashHold) - { - ExplosiveCrate* crate = ((ExplosiveCrate*)rigidBodyCrate->GetCustomTag()); - - - Oyster::Math::Float3 pos = rigidBodyCrate->GetState().centerPos; - Oyster::Collision3D::Sphere *hitSphere = new Oyster::Collision3D::Sphere(pos,crate->ExplosionRadius); - - Oyster::Physics::API::Instance().ApplyEffect(hitSphere,crate,Explode); - - delete hitSphere; - }*/ } void ExplosiveCrate::Explode(Oyster::Physics::ICustomBody *obj, void* args) @@ -142,16 +159,17 @@ using namespace GameLogic; Oyster::Math::Float3 explosionCenterPos = ExplosionSource->GetPosition(); Oyster::Math::Float3 hitObjectPos = obj->GetState().centerPos; Oyster::Math::Float3 force = (((hitObjectPos- explosionCenterPos).GetNormalized()) * ExplosionSource->pushForceMagnitude); - + + if(realObj->GetObjectType() == ObjectSpecialType::ObjectSpecialType_Player) { Player *hitPlayer = (Player*)realObj; - - //hitPlayer->DamageLife(ExplosionSource->getExtraDamageOnCollision()); + hitPlayer->DamageLife(ExplosionSource->extraDamageOnCollision); + //hitPlayer->GetRigidBody()->ApplyImpulse(force); //do shredding damage } - realObj->GetRigidBody()->ApplyImpulse(force); + } @@ -160,13 +178,32 @@ using namespace GameLogic; //Collision between a player and a general static or dynamic object //use kinetic energyloss of the collision in order too determin how much damage to take //use as part of the damage algorithm - int damageDone = 0; - int forceThreashHold = 200000; + Oyster::Math::Float3 objPrevVel = obj.GetRigidBody()->GetState().previousVelocity; + Oyster::Math::Float3 playerPrevVel = player.GetRigidBody()->GetState().previousVelocity; - if(kineticEnergyLoss > forceThreashHold) //should only take damage if the force is high enough + Oyster::Math::Float3 deltaPos = (player.GetPosition() - obj.GetPosition()); + Oyster::Math::Float deltaSpeed = (objPrevVel - playerPrevVel).GetMagnitude(); + Oyster::Math::Float angularFactor = deltaPos.GetNormalized().Dot( (objPrevVel - playerPrevVel).GetNormalized()); + + Oyster::Math::Float impactPower = deltaSpeed * angularFactor; + Oyster::Math::Float damageFactor = 0.01f; + + + int damageDone = 0; + int forceThreashHold = 30; //FIX: balance this + + if(impactPower > forceThreashHold) //should only take damage if the force is high enough { - damageDone = (int)(kineticEnergyLoss * 0.10f); - //player.DamageLife(damageDone); + if(obj.GetRigidBody()->GetState().mass == 0) + { + damageDone = impactPower * damageFactor; + } + else + { + damageDone = (impactPower * obj.GetRigidBody()->GetState().mass)* damageFactor; + } + + player.DamageLife(damageDone); } } @@ -236,6 +273,7 @@ using namespace GameLogic; case ObjectSpecialType::ObjectSpecialType_StandardBox: weapon->heldObject = obj; //weapon now holds the object weapon->hasObject = true; + break; } diff --git a/Code/Game/GameLogic/DynamicObject.cpp b/Code/Game/GameLogic/DynamicObject.cpp index 6df5bef0..e6d9ff49 100644 --- a/Code/Game/GameLogic/DynamicObject.cpp +++ b/Code/Game/GameLogic/DynamicObject.cpp @@ -2,37 +2,76 @@ #include "CollisionManager.h" using namespace GameLogic; +using namespace Oyster::Math; DynamicObject::DynamicObject() :Object() { - + this->isReleased = false; + this->isActive = true; } DynamicObject::DynamicObject(Oyster::Physics::ICustomBody *rigidBody , void (*EventOnCollision)(Oyster::Physics::ICustomBody *proto,Oyster::Physics::ICustomBody *deuter,Oyster::Math::Float kineticEnergyLoss), ObjectSpecialType type, int objectID) :Object(rigidBody, EventOnCollision, type, objectID) { - + this->isReleased = false; + this->isActive = true; } DynamicObject::DynamicObject(Oyster::Physics::ICustomBody *rigidBody , Oyster::Physics::ICustomBody::SubscriptMessage (*EventOnCollision)(Oyster::Physics::ICustomBody *proto,Oyster::Physics::ICustomBody *deuter,Oyster::Math::Float kineticEnergyLoss), ObjectSpecialType type, int objectID) :Object(rigidBody, EventOnCollision, type, objectID) { - + this->isReleased = false; + this->isActive = true; } DynamicObject::DynamicObject(Oyster::Physics::ICustomBody *rigidBody , void (*EventOnCollision)(Oyster::Physics::ICustomBody *proto,Oyster::Physics::ICustomBody *deuter,Oyster::Math::Float kineticEnergyLoss), ObjectSpecialType type, int objectID, Oyster::Math::Float extraDamageOnCollision) :Object(rigidBody, EventOnCollision, type, objectID) { this->extraDamageOnCollision = extraDamageOnCollision; + this->isReleased = false; + this->isActive = true; } DynamicObject::DynamicObject(Oyster::Physics::ICustomBody *rigidBody , Oyster::Physics::ICustomBody::SubscriptMessage (*EventOnCollision)(Oyster::Physics::ICustomBody *proto,Oyster::Physics::ICustomBody *deuter,Oyster::Math::Float kineticEnergyLoss), ObjectSpecialType type, int objectID, Oyster::Math::Float extraDamageOnCollision) :Object(rigidBody, EventOnCollision, type, objectID) { this->extraDamageOnCollision = extraDamageOnCollision; + this->isReleased = false; + this->isActive = true; } DynamicObject::~DynamicObject(void) { +} + +void DynamicObject::ReleaseDynamicObject() +{ + //TODO: Inactivate the physics object + if(this->isReleased) return; + + this->isReleased = true; + this->isActive = false; + this->lookDirection = Float3::null; + this->forwardDirection = Float3::null; + this->scale = Float3::null; + this->extraDamageOnCollision = 0; + +} +bool DynamicObject::IsReleased() +{ + return this->isReleased; +} +bool DynamicObject::IsActive() +{ + return this->isActive; +} +void DynamicObject::Inactivate() +{ + this->isActive = false; +} +void DynamicObject::Activate() +{ + this->isActive = true; + this->isReleased = false; } \ No newline at end of file diff --git a/Code/Game/GameLogic/DynamicObject.h b/Code/Game/GameLogic/DynamicObject.h index 2d5fa617..8a32e849 100644 --- a/Code/Game/GameLogic/DynamicObject.h +++ b/Code/Game/GameLogic/DynamicObject.h @@ -22,7 +22,15 @@ namespace GameLogic ~DynamicObject(void); + void ReleaseDynamicObject(); + bool IsReleased(); + bool IsActive(); + void Inactivate(); + void Activate(); + private: + bool isActive; + bool isReleased; }; diff --git a/Code/Game/GameLogic/ExplosiveCrate.cpp b/Code/Game/GameLogic/ExplosiveCrate.cpp index d236d400..cf011ce4 100644 --- a/Code/Game/GameLogic/ExplosiveCrate.cpp +++ b/Code/Game/GameLogic/ExplosiveCrate.cpp @@ -7,6 +7,7 @@ ExplosiveCrate::ExplosiveCrate(void) { this->pushForceMagnitude = 0; this->ExplosionRadius = 0; + this->hasExploaded = false; } ExplosiveCrate::ExplosiveCrate(Oyster::Physics::ICustomBody *rigidBody,ObjectSpecialType type, int objectID,Oyster::Math::Float extraDamageOnCollision, Oyster::Math::Float pushForceMagnitude, Oyster::Math::Float ExplosionRadius) @@ -15,6 +16,7 @@ ExplosiveCrate::ExplosiveCrate(Oyster::Physics::ICustomBody *rigidBody,ObjectSpe this->extraDamageOnCollision = extraDamageOnCollision; this->pushForceMagnitude = pushForceMagnitude; this->ExplosionRadius = ExplosionRadius; + this->hasExploaded = false; } ExplosiveCrate::~ExplosiveCrate(void) diff --git a/Code/Game/GameLogic/ExplosiveCrate.h b/Code/Game/GameLogic/ExplosiveCrate.h index 75afdc4a..b6054266 100644 --- a/Code/Game/GameLogic/ExplosiveCrate.h +++ b/Code/Game/GameLogic/ExplosiveCrate.h @@ -18,6 +18,7 @@ namespace GameLogic private: Oyster::Math::Float pushForceMagnitude; Oyster::Math::Float ExplosionRadius; + bool hasExploaded; }; diff --git a/Code/Game/GameLogic/Game.cpp b/Code/Game/GameLogic/Game.cpp index 8dd7ffa6..0e1ab178 100644 --- a/Code/Game/GameLogic/Game.cpp +++ b/Code/Game/GameLogic/Game.cpp @@ -43,6 +43,9 @@ Game::Game(void) : initiated(false) , onMoveFnc(0) , onDisableFnc(0) + , onDamageTakenFnc(0) + , onRespawnFnc(0) + , onDeadFnc(0) , frameTime(1.0f/120.0f) {} @@ -67,6 +70,17 @@ void Game::GetAllPlayerPositions() const Game::PlayerData* Game::CreatePlayer() { + //Se if there is a free player somewhere in our list + for (unsigned int i = 0; i < this->players.Size(); i++) + { + if(this->players[i] && this->players[i]->player->IsReleased()) + { + //We give the body to someone else + this->players[i]->player->Activate(); + return this->players[i]; + } + } + // Find a free space in array or insert at end int insert = InsertObject(this->players, (PlayerData*)0); int freeID = 0; @@ -145,7 +159,18 @@ void Game::SetSubscription(GameEvent::ObjectMovedFunction functionPointer) void Game::SetSubscription(GameEvent::ObjectDisabledFunction functionPointer) { this->onDisableFnc = functionPointer; - +} +void Game::SetHpSubscription(GameEvent::ObjectHpFunction functionPointer) +{ + this->onDamageTakenFnc = functionPointer; +} +void Game::SetRespawnSubscription(GameEvent::ObjectRespawnedFunction functionPointer) +{ + this->onRespawnFnc = functionPointer; +} +void Game::SetDeadSubscription(GameEvent::ObjectDeadFunction functionPointer) +{ + this->onDeadFnc = functionPointer; } bool Game::Initiate() diff --git a/Code/Game/GameLogic/Game.h b/Code/Game/GameLogic/Game.h index 5ab19ba2..37abe97f 100644 --- a/Code/Game/GameLogic/Game.h +++ b/Code/Game/GameLogic/Game.h @@ -40,11 +40,11 @@ namespace GameLogic Oyster::Math::Float3 GetScale() override; Oyster::Math::Float4x4 GetOrientation() override; int GetID() const override; - void Rotate(const Oyster::Math3D::Float3& lookDir, const Oyster::Math3D::Float3& right) override; + void SetLookDir(const Oyster::Math3D::Float3& lookDir) override; void TurnLeft(Oyster::Math3D::Float deltaLeftRadians ) override; ObjectSpecialType GetObjectType() const override; - - + void Inactivate() override; + void Release() override; Player *player; }; @@ -80,6 +80,10 @@ namespace GameLogic void SetFrameTimeLength( float seconds ) override; void SetSubscription(GameEvent::ObjectMovedFunction functionPointer) override; void SetSubscription(GameEvent::ObjectDisabledFunction functionPointer) override; + void SetHpSubscription(GameEvent::ObjectHpFunction functionPointer) override; + void SetRespawnSubscription(GameEvent::ObjectRespawnedFunction functionPointer) override; + void SetDeadSubscription(GameEvent::ObjectDeadFunction functionPointer) override; + bool Initiate() override; float GetFrameTime() const; @@ -91,9 +95,11 @@ namespace GameLogic LevelData* level; float frameTime; bool initiated; - GameEvent::ObjectDisabledFunction onDisableFnc; - GameEvent::ObjectMovedFunction onMoveFnc; - + GameEvent::ObjectDisabledFunction onDisableFnc; + GameEvent::ObjectMovedFunction onMoveFnc; + GameEvent::ObjectHpFunction onDamageTakenFnc; + GameEvent::ObjectRespawnedFunction onRespawnFnc; + GameEvent::ObjectDeadFunction onDeadFnc; }; } diff --git a/Code/Game/GameLogic/GameAPI.h b/Code/Game/GameLogic/GameAPI.h index 66cf5ea2..0c79f33d 100644 --- a/Code/Game/GameLogic/GameAPI.h +++ b/Code/Game/GameLogic/GameAPI.h @@ -27,6 +27,9 @@ namespace GameLogic { typedef void(*ObjectMovedFunction)(IObjectData* object); // Callback method that recieves and object typedef void(*ObjectDisabledFunction)(IObjectData* object, float seconds); // Callback method that recieves and object + typedef void(*ObjectHpFunction)(IObjectData* object, float hp); // Callback method that sends obj HP + typedef void(*ObjectRespawnedFunction)(IObjectData* object, Oyster::Math::Float3 spawnPos ); // Callback method that sends spawnPos + typedef void(*ObjectDeadFunction)(IObjectData* object, float seconds); // Callback method that sends death timer //etc... }; @@ -85,7 +88,7 @@ namespace GameLogic * @param x: The relative x axis * @param y: The relative y axis **/ - virtual void Rotate(const Oyster::Math3D::Float3& lookDir, const Oyster::Math3D::Float3& right) = 0; + virtual void SetLookDir(const Oyster::Math3D::Float3& lookDir) = 0; /** Relative rotation around given axis * @param leftRadians: The relative amount of radians to turn @@ -106,6 +109,9 @@ namespace GameLogic * @return The current player state ********************************************************/ virtual PLAYER_STATE GetState() const = 0; + + virtual void Inactivate() = 0; + virtual void Release() = 0; }; class ILevelData :public IObjectData @@ -175,6 +181,9 @@ namespace GameLogic * @param */ virtual void SetSubscription(GameEvent::ObjectDisabledFunction functionPointer) = 0; + virtual void SetHpSubscription(GameEvent::ObjectHpFunction functionPointer) = 0; + virtual void SetRespawnSubscription(GameEvent::ObjectRespawnedFunction functionPointer) = 0; + virtual void SetDeadSubscription(GameEvent::ObjectDeadFunction functionPointer) = 0; }; } diff --git a/Code/Game/GameLogic/Game_PlayerData.cpp b/Code/Game/GameLogic/Game_PlayerData.cpp index 045da742..ad409e3b 100644 --- a/Code/Game/GameLogic/Game_PlayerData.cpp +++ b/Code/Game/GameLogic/Game_PlayerData.cpp @@ -86,11 +86,19 @@ ObjectSpecialType Game::PlayerData::GetObjectType() const { return this->player->GetObjectType(); } -void Game::PlayerData::Rotate(const Oyster::Math3D::Float3& lookDir, const Oyster::Math3D::Float3& right) +void Game::PlayerData::SetLookDir(const Oyster::Math3D::Float3& lookDir) { - this->player->Rotate(lookDir, right); + this->player->SetLookDir(lookDir); } void Game::PlayerData::TurnLeft(Oyster::Math3D::Float deltaLeftRadians ) { this->player->TurnLeft(deltaLeftRadians); +} +void Game::PlayerData::Inactivate() +{ + this->player->Inactivate(); +} +void Game::PlayerData::Release() +{ + this->player->ReleaseDynamicObject(); } \ No newline at end of file diff --git a/Code/Game/GameLogic/Level.cpp b/Code/Game/GameLogic/Level.cpp index c9938dbd..922d2a8f 100644 --- a/Code/Game/GameLogic/Level.cpp +++ b/Code/Game/GameLogic/Level.cpp @@ -69,9 +69,9 @@ Object* Level::CreateGameObj(ObjectHeader* obj, ICustomBody* rigidBody) break; case ObjectSpecialType_RedExplosiveBox: { - Oyster::Math::Float dmg = 50; - Oyster::Math::Float force = 50; - Oyster::Math::Float radie = 50; + Oyster::Math::Float dmg = 90; + Oyster::Math::Float force = 500; + Oyster::Math::Float radie = 3; gameObj = new ExplosiveCrate(rigidBody, (ObjectSpecialType)obj->specialTypeID, objID++, dmg, force, radie); } break; @@ -422,5 +422,5 @@ void Level::PhysicsOnMoveLevel(const ICustomBody *object) // function call from physics update when object was moved Object* temp = (Object*)object->GetCustomTag(); ((Game*)&Game::Instance())->onMoveFnc(temp); - } + diff --git a/Code/Game/GameLogic/Level.h b/Code/Game/GameLogic/Level.h index 9dce227d..27f0bab6 100644 --- a/Code/Game/GameLogic/Level.h +++ b/Code/Game/GameLogic/Level.h @@ -66,6 +66,7 @@ namespace GameLogic int getNrOfDynamicObj(); Object* GetObj( int ID ) const; + static void PhysicsOnMoveLevel(const Oyster::Physics::ICustomBody *object); diff --git a/Code/Game/GameLogic/Player.cpp b/Code/Game/GameLogic/Player.cpp index 5b855785..69569d44 100644 --- a/Code/Game/GameLogic/Player.cpp +++ b/Code/Game/GameLogic/Player.cpp @@ -29,6 +29,8 @@ Player::Player(Oyster::Physics::ICustomBody *rigidBody, void (*EventOnCollision) key_strafeLeft = 0; key_jump = 0; invincibleCooldown = 0; + this->deathTimeLeft = 0; + this->deathTime = 5; this->previousPosition = Oyster::Math::Float3(0,0,0); @@ -54,7 +56,8 @@ Player::Player(Oyster::Physics::ICustomBody *rigidBody, Oyster::Physics::ICustom key_strafeLeft = 0; key_jump = 0; invincibleCooldown = 0; - + this->deathTimeLeft = 0; + this->deathTime = 5; this->previousPosition = Oyster::Math::Float3(0,0,0); this->moveDir = Oyster::Math::Float3(0,0,0); this->moveSpeed = 20; @@ -74,137 +77,142 @@ Player::~Player(void) void Player::BeginFrame() { - //weapon->Update(0.002f); - //Object::BeginFrame(); + if( this->playerState != PLAYER_STATE_DEAD) + { + weapon->Update(0.002f); - Oyster::Math::Float maxSpeed = 30; + Oyster::Math::Float maxSpeed = 30; - // Rotate player accordingly - this->rigidBody->SetUp(this->rigidBody->GetState().centerPos.GetNormalized()); - Oyster::Math::Quaternion firstUp = this->rigidBody->GetState().quaternion; - this->rigidBody->SetRotationAsAngularAxis(Oyster::Math3D::Float4(this->rigidBody->GetState().centerPos.GetNormalized(), this->rotationUp)); - Oyster::Math::Quaternion secondTurn = this->rigidBody->GetState().quaternion; + // Rotate player accordingly + this->rigidBody->SetUp(this->rigidBody->GetState().centerPos.GetNormalized()); + Oyster::Math::Quaternion firstUp = this->rigidBody->GetState().quaternion; + this->rigidBody->SetRotationAsAngularAxis(Oyster::Math3D::Float4(this->rigidBody->GetState().centerPos.GetNormalized(), this->rotationUp)); + Oyster::Math::Quaternion secondTurn = this->rigidBody->GetState().quaternion; - this->rigidBody->SetRotation(secondTurn*firstUp); + this->rigidBody->SetRotation(secondTurn*firstUp); - // Direction data - Oyster::Math::Float4x4 xform; - xform = this->rigidBody->GetState().GetOrientation(); + // Direction data + Oyster::Math::Float4x4 xform; + xform = this->rigidBody->GetState().GetOrientation(); - Oyster::Math::Float3 forwardDir = xform.v[2]; - Oyster::Math::Float3 upDir = xform.v[1]; - Oyster::Math::Float3 rightDir = xform.v[0]; - forwardDir.Normalize(); - upDir.Normalize(); - rightDir.Normalize(); + Oyster::Math::Float3 forwardDir = xform.v[2]; + Oyster::Math::Float3 upDir = xform.v[1]; + Oyster::Math::Float3 rightDir = xform.v[0]; + forwardDir.Normalize(); + upDir.Normalize(); + rightDir.Normalize(); - // Previous velocities data - Oyster::Math::Float3 linearVelocity = this->rigidBody->GetLinearVelocity(); - Oyster::Math::Float3 forwardVelocity = linearVelocity*Oyster::Math::Float3(fabs(forwardDir.x), fabs(forwardDir.y), fabs(forwardDir.z)); - Oyster::Math::Float forwardSpeed = (linearVelocity*forwardDir).GetLength(); - Oyster::Math::Float3 rightVelocity = linearVelocity*Oyster::Math::Float3(fabs(rightDir.x), fabs(rightDir.y), fabs(rightDir.z)); - Oyster::Math::Float rightSpeed = (linearVelocity*rightDir).GetLength(); - Oyster::Math::Float3 upVelocity = linearVelocity*Oyster::Math::Float3(fabs(upDir.x), fabs(upDir.y), fabs(upDir.z)); + // Previous velocities data + Oyster::Math::Float3 linearVelocity = this->rigidBody->GetLinearVelocity(); + Oyster::Math::Float3 forwardVelocity = linearVelocity*Oyster::Math::Float3(fabs(forwardDir.x), fabs(forwardDir.y), fabs(forwardDir.z)); + Oyster::Math::Float forwardSpeed = (linearVelocity*forwardDir).GetLength(); + Oyster::Math::Float3 rightVelocity = linearVelocity*Oyster::Math::Float3(fabs(rightDir.x), fabs(rightDir.y), fabs(rightDir.z)); + Oyster::Math::Float rightSpeed = (linearVelocity*rightDir).GetLength(); + Oyster::Math::Float3 upVelocity = linearVelocity*Oyster::Math::Float3(fabs(upDir.x), fabs(upDir.y), fabs(upDir.z)); - // Walking data - Oyster::Math::Float3 walkDirection = Oyster::Math::Float3(0.0, 0.0, 0.0); - Oyster::Math::Float walkSpeed = this->moveSpeed*0.2f; + // Walking data + Oyster::Math::Float3 walkDirection = Oyster::Math::Float3(0.0, 0.0, 0.0); + Oyster::Math::Float walkSpeed = this->moveSpeed*0.2f; - // Check for input - if(key_forward > 0.001) - { - key_forward -= gameInstance->GetFrameTime(); - walkDirection += forwardDir; - } - if(key_backward > 0.001) - { - key_backward -= gameInstance->GetFrameTime(); - walkDirection -= forwardDir; - } - if(key_strafeRight > 0.001) - { - key_strafeRight -= gameInstance->GetFrameTime(); - walkDirection += rightDir; - } - if(key_strafeLeft > 0.001) - { - key_strafeLeft -= gameInstance->GetFrameTime(); - walkDirection -= rightDir; - } - - // Dampen velocity if certain keys are not pressed - if(key_jump <= 0.001 && this->rigidBody->GetLambda() < 0.9f) - { - if(key_forward <= 0.001 && key_backward <= 0.001) + // Check for input + if(key_forward > 0.001) { - forwardVelocity *= Oyster::Math::Float3(0.2f*fabs(forwardDir.x), 0.2f*fabs(forwardDir.y), 0.2f*fabs(forwardDir.z)); + key_forward -= gameInstance->GetFrameTime(); + walkDirection += forwardDir; } - if(key_strafeRight <= 0.001 && key_strafeLeft <= 0.001) + if(key_backward > 0.001) { - rightVelocity *= Oyster::Math::Float3(0.2f*fabs(rightDir.x), 0.2f*fabs(rightDir.y), 0.2f*fabs(rightDir.z)); + key_backward -= gameInstance->GetFrameTime(); + walkDirection -= forwardDir; } - } - - // Walk if walkdirection is something - if(walkDirection != Oyster::Math::Float3::null) - { - walkDirection.Normalize(); - - // If on the ground, accelerate normally - if(this->rigidBody->GetLambda() < 0.9f) + if(key_strafeRight > 0.001) { - if(forwardSpeed < maxSpeed) + key_strafeRight -= gameInstance->GetFrameTime(); + walkDirection += rightDir; + } + if(key_strafeLeft > 0.001) + { + key_strafeLeft -= gameInstance->GetFrameTime(); + walkDirection -= rightDir; + } + + // Dampen velocity if certain keys are not pressed + if(key_jump <= 0.001 && this->rigidBody->GetLambda() < 0.9f) + { + if(key_forward <= 0.001 && key_backward <= 0.001) { - forwardVelocity += walkDirection*Oyster::Math::Float3(fabs(forwardDir.x), fabs(forwardDir.y), fabs(forwardDir.z)) * walkSpeed; + forwardVelocity *= Oyster::Math::Float3(0.2f*fabs(forwardDir.x), 0.2f*fabs(forwardDir.y), 0.2f*fabs(forwardDir.z)); } - if(rightSpeed < maxSpeed) + if(key_strafeRight <= 0.001 && key_strafeLeft <= 0.001) { - rightVelocity += walkDirection*Oyster::Math::Float3(fabs(rightDir.x), abs(rightDir.y), fabs(rightDir.z)) * walkSpeed; + rightVelocity *= Oyster::Math::Float3(0.2f*fabs(rightDir.x), 0.2f*fabs(rightDir.y), 0.2f*fabs(rightDir.z)); } } - // If in the air, accelerate slower - if(this->rigidBody->GetLambda() >= 0.9f) + + // Walk if walkdirection is something + if(walkDirection != Oyster::Math::Float3::null) { - if(forwardSpeed < maxSpeed) + walkDirection.Normalize(); + + // If on the ground, accelerate normally + if(this->rigidBody->GetLambda() < 0.9f) { - forwardVelocity += walkDirection*Oyster::Math::Float3(fabs(forwardDir.x), fabs(forwardDir.y), fabs(forwardDir.z)) * walkSpeed*0.2f; + if(forwardSpeed < maxSpeed) + { + forwardVelocity += walkDirection*Oyster::Math::Float3(fabs(forwardDir.x), fabs(forwardDir.y), fabs(forwardDir.z)) * walkSpeed; + } + if(rightSpeed < maxSpeed) + { + rightVelocity += walkDirection*Oyster::Math::Float3(fabs(rightDir.x), abs(rightDir.y), fabs(rightDir.z)) * walkSpeed; + } } - if(rightSpeed < maxSpeed) + // If in the air, accelerate slower + if(this->rigidBody->GetLambda() >= 0.9f) { - rightVelocity += walkDirection*Oyster::Math::Float3(fabs(rightDir.x), fabs(rightDir.y), fabs(rightDir.z)) * walkSpeed*0.2f; + if(forwardSpeed < maxSpeed) + { + forwardVelocity += walkDirection*Oyster::Math::Float3(fabs(forwardDir.x), fabs(forwardDir.y), fabs(forwardDir.z)) * walkSpeed*0.2f; + } + if(rightSpeed < maxSpeed) + { + rightVelocity += walkDirection*Oyster::Math::Float3(fabs(rightDir.x), fabs(rightDir.y), fabs(rightDir.z)) * walkSpeed*0.2f; + } + } + } + + // Adjust velocities so no squaring occurs + forwardVelocity *= Oyster::Math::Float3(fabs(forwardDir.x), fabs(forwardDir.y), fabs(forwardDir.z)); + rightVelocity *= Oyster::Math::Float3(fabs(rightDir.x), fabs(rightDir.y), fabs(rightDir.z)); + upVelocity *= Oyster::Math::Float3(fabs(upDir.x), fabs(upDir.y), fabs(upDir.z)); + + this->rigidBody->SetLinearVelocity(forwardVelocity+rightVelocity+upVelocity); + + //Jump + if(key_jump > 0.001) + { + this->key_jump -= this->gameInstance->GetFrameTime(); + if(this->rigidBody->GetLambda() < 0.9f) + { + Oyster::Math::Float3 up = this->rigidBody->GetState().centerPos.GetNormalized(); + this->rigidBody->ApplyImpulse(up*this->rigidBody->GetState().mass*20); + this->playerState = PLAYER_STATE::PLAYER_STATE_JUMPING; } } } - - // Adjust velocities so no squaring occurs - forwardVelocity *= Oyster::Math::Float3(fabs(forwardDir.x), fabs(forwardDir.y), fabs(forwardDir.z)); - rightVelocity *= Oyster::Math::Float3(fabs(rightDir.x), fabs(rightDir.y), fabs(rightDir.z)); - upVelocity *= Oyster::Math::Float3(fabs(upDir.x), fabs(upDir.y), fabs(upDir.z)); - - this->rigidBody->SetLinearVelocity(forwardVelocity+rightVelocity+upVelocity); - - //Jump - if(key_jump > 0.001) + else { - this->key_jump -= this->gameInstance->GetFrameTime(); - if(this->rigidBody->GetLambda() < 0.9f) + // player is dead + // TODO move this logic to lvl + this->deathTimeLeft -= gameInstance->GetFrameTime(); + if( this->deathTimeLeft <= 0) { - Oyster::Math::Float3 up = this->rigidBody->GetState().centerPos.GetNormalized(); - this->rigidBody->ApplyImpulse(up*this->rigidBody->GetState().mass*20); - this->playerState = PLAYER_STATE::PLAYER_STATE_JUMPING; + Respawn( Oyster::Math::Float3( -50, 180, 0)); } } - - - - - //this->weapon->Update(0.01f); } void Player::EndFrame() { - - //Object::EndFrame(); } @@ -258,16 +266,21 @@ void Player::UseWeapon(const WEAPON_FIRE &usage) void Player::Respawn(Oyster::Math::Float3 spawnPoint) { - this->life = 100; - this->playerState = PLAYER_STATE::PLAYER_STATE_IDLE; - this->lookDir = Oyster::Math::Float4(1,0,0); - this->rigidBody->SetPosition(spawnPoint); + if( this->playerState == PLAYER_STATE_DEAD) + { + this->life = 100; + this->playerState = PLAYER_STATE::PLAYER_STATE_IDLE; + //this->lookDir = Oyster::Math::Float4(1,0,0); + this->rigidBody->SetPosition(spawnPoint); + this->gameInstance->onRespawnFnc( this, spawnPoint); + this->gameInstance->onDamageTakenFnc( this, this->life); + } } -void Player::Rotate(const Oyster::Math3D::Float3& lookDir, const Oyster::Math3D::Float3& right) +void Player::SetLookDir(const Oyster::Math3D::Float3& lookDir) { // this is the camera right vector - this->lookDir = lookDir; + this->lookDir = -lookDir; } void Player::TurnLeft(Oyster::Math3D::Float deltaRadians) @@ -293,6 +306,11 @@ bool Player::IsIdle() return (this->playerState == PLAYER_STATE::PLAYER_STATE_IDLE); } +void Player::Inactivate() +{ + //this-> +} + Oyster::Math::Float3 Player::GetPosition() const { return (Oyster::Math::Float3) this->rigidBody->GetState().centerPos; @@ -316,13 +334,17 @@ PLAYER_STATE Player::GetState() const void Player::DamageLife(int damage) { - this->life -= damage; - this->life = 0; - - if(this->life <= 0) + if( this->playerState != PLAYER_STATE_DEAD) { - this->life = 0; - playerState = PLAYER_STATE_DEAD; - this->gameInstance->onDisableFnc(this, 0.0f); + this->life -= damage; + this->gameInstance->onDamageTakenFnc( this, this->life); + + if(this->life <= 0) + { + this->life = 0; + playerState = PLAYER_STATE_DEAD; + this->deathTimeLeft = this->deathTime; + this->gameInstance->onDeadFnc(this, this->deathTimeLeft); + } } } diff --git a/Code/Game/GameLogic/Player.h b/Code/Game/GameLogic/Player.h index 13c6e300..001c9141 100644 --- a/Code/Game/GameLogic/Player.h +++ b/Code/Game/GameLogic/Player.h @@ -46,7 +46,7 @@ namespace GameLogic void Respawn(Oyster::Math::Float3 spawnPoint); - void Rotate(const Oyster::Math3D::Float3& lookDir, const Oyster::Math3D::Float3& right); + void SetLookDir(const Oyster::Math3D::Float3& lookDir); void TurnLeft(Oyster::Math3D::Float deltaRadians); @@ -56,13 +56,15 @@ namespace GameLogic * @param rigidBodyPlayer: physics object of the player * @param obj: physics object for the object that collided with the player ********************************************************/ - static void PlayerCollision(Oyster::Physics::ICustomBody *rigidBodyPlayer, Oyster::Physics::ICustomBody *obj, Oyster::Math::Float kineticEnergyLoss); + static void PlayerCollision(Oyster::Physics::ICustomBody *objA, Oyster::Physics::ICustomBody *objB, Oyster::Math::Float kineticEnergyLoss); bool IsWalking(); bool IsJumping(); bool IsIdle(); + void Inactivate(); + Oyster::Math::Float3 GetPosition() const; Oyster::Math::Float3 GetLookDir() const; Oyster::Math::Float4x4 GetOrientation() const; @@ -98,6 +100,8 @@ namespace GameLogic Oyster::Math::Float rotationUp; + float deathTime; + float deathTimeLeft; bool hasTakenDamage; float invincibleCooldown; diff --git a/Code/Game/GameProtocols/ObjectProtocols.h b/Code/Game/GameProtocols/ObjectProtocols.h index cae7c7f5..234a5301 100644 --- a/Code/Game/GameProtocols/ObjectProtocols.h +++ b/Code/Game/GameProtocols/ObjectProtocols.h @@ -75,13 +75,15 @@ namespace GameLogic } Protocol_ObjectDamage(Oyster::Network::CustomNetProtocol& p) { - + this->object_ID = p[1].value.netInt; + this->healthLost = p[2].value.netFloat; } Protocol_ObjectDamage(int id, float hp) { this->protocol[0].value = protocol_Gameplay_ObjectDamage; this->protocol[0].type = Oyster::Network::NetAttributeType_Short; - + + this->protocol[1].type = Oyster::Network::NetAttributeType_Int; this->protocol[2].type = Oyster::Network::NetAttributeType_Float; object_ID = id; @@ -292,6 +294,7 @@ namespace GameLogic Oyster::Network::CustomNetProtocol protocol; }; + //#define protocol_Gameplay_ObjectEnabled 356 struct Protocol_ObjectPositionRotation :public Oyster::Network::CustomProtocolObject { short object_ID; @@ -366,7 +369,7 @@ namespace GameLogic Oyster::Network::CustomNetProtocol protocol; }; - //#define protocol_Gameplay_ObjectEnabled 356 + //#define protocol_Gameplay_ObjectEnabled 357 struct Protocol_ObjectEnable :public Oyster::Network::CustomProtocolObject { int objectID; @@ -399,7 +402,7 @@ namespace GameLogic Oyster::Network::CustomNetProtocol protocol; }; - //#define protocol_Gameplay_ObjectDisabled 357 + //#define protocol_Gameplay_ObjectDisabled 358 struct Protocol_ObjectDisable :public Oyster::Network::CustomProtocolObject { int objectID; @@ -439,7 +442,7 @@ namespace GameLogic Oyster::Network::CustomNetProtocol protocol; }; - //#define protocol_Gameplay_ObjectCreate 358 + //#define protocol_Gameplay_ObjectCreate 359 struct Protocol_ObjectCreate :public Oyster::Network::CustomProtocolObject { //ObjectType type; //ie player, box or whatever @@ -543,7 +546,7 @@ namespace GameLogic Oyster::Network::CustomNetProtocol protocol; }; - //#define protocol_Gameplay_ObjectCreatePlayer 359 + //#define protocol_Gameplay_ObjectCreatePlayer 360 struct Protocol_ObjectCreatePlayer :public Oyster::Network::CustomProtocolObject { /*1*/ int object_ID; @@ -673,7 +676,7 @@ namespace GameLogic Oyster::Network::CustomNetProtocol protocol; }; - //#define protocol_Gameplay_ObjectJoinTeam 360 + //#define protocol_Gameplay_ObjectJoinTeam 361 struct Protocol_ObjectJoinTeam :public Oyster::Network::CustomProtocolObject { int objectID; @@ -713,7 +716,7 @@ namespace GameLogic Oyster::Network::CustomNetProtocol protocol; }; - //#define protocol_Gameplay_ObjectLeaveTeam 361 + //#define protocol_Gameplay_ObjectLeaveTeam 362 struct Protocol_ObjectLeaveTeam :public Oyster::Network::CustomProtocolObject { int objectID; @@ -745,7 +748,7 @@ namespace GameLogic Oyster::Network::CustomNetProtocol protocol; }; - //#define protocol_Gameplay_ObjectWeaponCooldown 362 + //#define protocol_Gameplay_ObjectWeaponCooldown 363 struct Protocol_ObjectWeaponCooldown :public Oyster::Network::CustomProtocolObject { float seconds; @@ -777,7 +780,7 @@ namespace GameLogic Oyster::Network::CustomNetProtocol protocol; }; - //#define protocol_Gameplay_ObjectWeaponEnergy 363 + //#define protocol_Gameplay_ObjectWeaponEnergy 364 struct Protocol_ObjectWeaponEnergy :public Oyster::Network::CustomProtocolObject { float energy; @@ -809,42 +812,51 @@ namespace GameLogic Oyster::Network::CustomNetProtocol protocol; }; - //#define protocol_Gameplay_ObjectRespawn 364 + //#define protocol_Gameplay_ObjectRespawn 365 struct Protocol_ObjectRespawn :public Oyster::Network::CustomProtocolObject { + int objectID; float position[3]; Protocol_ObjectRespawn() { this->protocol[0].type = Oyster::Network::NetAttributeType_Short; this->protocol[0].value.netShort = protocol_Gameplay_ObjectRespawn; - - this->protocol[1].type = Oyster::Network::NetAttributeType_Float; + // ID + this->protocol[1].type = Oyster::Network::NetAttributeType_Int; + // POSITION this->protocol[2].type = Oyster::Network::NetAttributeType_Float; this->protocol[3].type = Oyster::Network::NetAttributeType_Float; + this->protocol[4].type = Oyster::Network::NetAttributeType_Float; + this->objectID = 0; memset(&this->position[0], 0, sizeof(float) * 3); } - Protocol_ObjectRespawn(float position[3]) + Protocol_ObjectRespawn(int id, float position[3]) { this->protocol[0].type = Oyster::Network::NetAttributeType_Short; this->protocol[0].value.netShort = protocol_Gameplay_ObjectRespawn; - this->protocol[1].type = Oyster::Network::NetAttributeType_Float; + // ID + this->protocol[1].type = Oyster::Network::NetAttributeType_Int; + // POSITION this->protocol[2].type = Oyster::Network::NetAttributeType_Float; this->protocol[3].type = Oyster::Network::NetAttributeType_Float; - + this->protocol[4].type = Oyster::Network::NetAttributeType_Float; + this->objectID = id; memcpy(&this->position[0], &position[0], sizeof(float) * 3); } Protocol_ObjectRespawn(Oyster::Network::CustomNetProtocol& p) { - this->position[0] = p[1].value.netFloat; - this->position[1] = p[2].value.netFloat; - this->position[2] = p[3].value.netFloat; + this->objectID = p[1].value.netInt; + this->position[0] = p[2].value.netFloat; + this->position[1] = p[3].value.netFloat; + this->position[2] = p[4].value.netFloat; } Oyster::Network::CustomNetProtocol GetProtocol() override { - this->protocol[1].value = this->position[0]; - this->protocol[2].value = this->position[1]; - this->protocol[3].value = this->position[2]; + this->protocol[1].value = this->objectID; + this->protocol[2].value = this->position[0]; + this->protocol[3].value = this->position[1]; + this->protocol[4].value = this->position[2]; return protocol; } @@ -852,7 +864,7 @@ namespace GameLogic Oyster::Network::CustomNetProtocol protocol; }; - //#define protocol_Gameplay_ObjectDie 365 + //#define protocol_Gameplay_ObjectDie 366 struct Protocol_ObjectDie :public Oyster::Network::CustomProtocolObject { int objectID; @@ -925,5 +937,45 @@ namespace GameLogic Oyster::Network::CustomNetProtocol protocol; }; } +//#define protocol_Gameplay_ObjectAction 368 + struct Protocol_ObjectAction :public Oyster::Network::CustomProtocolObject + { + short objectID; + float animationID; + + Protocol_ObjectAction() + { + this->protocol[0].value = protocol_Gameplay_ObjectAction; + this->protocol[0].type = Oyster::Network::NetAttributeType_Short; + this->protocol[1].type = Oyster::Network::NetAttributeType_Short; + this->protocol[2].type = Oyster::Network::NetAttributeType_Float; + + objectID = 0; + animationID = -1; + } + Protocol_ObjectAction(Oyster::Network::CustomNetProtocol& p) + { + objectID = p[1].value.netShort; + animationID = p[2].value.netFloat; + } + Protocol_ObjectAction(float animID, int id) + { + this->protocol[0].value = protocol_Gameplay_ObjectAction; + this->protocol[0].type = Oyster::Network::NetAttributeType_Short; + this->protocol[1].type = Oyster::Network::NetAttributeType_Short; + this->protocol[2].type = Oyster::Network::NetAttributeType_Float; + objectID = id; + animationID = animID; + } + Oyster::Network::CustomNetProtocol GetProtocol() override + { + this->protocol[1].value = objectID; + this->protocol[2].value = animationID; + return protocol; + } + + private: + Oyster::Network::CustomNetProtocol protocol; + }; #endif // !GAMELOGIC_PLAYER_PROTOCOLS_H \ No newline at end of file diff --git a/Code/Game/GameProtocols/PlayerProtocols.h b/Code/Game/GameProtocols/PlayerProtocols.h index 350c2cf6..eb34c07c 100644 --- a/Code/Game/GameProtocols/PlayerProtocols.h +++ b/Code/Game/GameProtocols/PlayerProtocols.h @@ -79,6 +79,7 @@ namespace GameLogic { public: float deltaRadian; + float lookdir[3]; Protocol_PlayerLeftTurn() { @@ -86,25 +87,40 @@ namespace GameLogic this->protocol[0].type = ::Oyster::Network::NetAttributeType_Short; // deltaRadian this->protocol[1].type = ::Oyster::Network::NetAttributeType_Float; + this->protocol[2].type = Oyster::Network::NetAttributeType_Float; + this->protocol[3].type = Oyster::Network::NetAttributeType_Float; + this->protocol[4].type = Oyster::Network::NetAttributeType_Float; + deltaRadian = 0.0f; + memset(&lookdir[0], 0, sizeof(float) * 3); } Protocol_PlayerLeftTurn( const ::Oyster::Network::CustomNetProtocol &p ) { this->deltaRadian = p[1].value.netFloat; + lookdir[0] = p[2].value.netFloat; + lookdir[1] = p[3].value.netFloat; + lookdir[2] = p[4].value.netFloat; } - Protocol_PlayerLeftTurn( float deltaRadian ) + Protocol_PlayerLeftTurn( float deltaRadian,float v[3] ) { this->protocol[0].value = protocol_Gameplay_PlayerLeftTurn; this->protocol[0].type = ::Oyster::Network::NetAttributeType_Short; - // deltaRadian this->protocol[1].type = ::Oyster::Network::NetAttributeType_Float; + this->protocol[2].type = Oyster::Network::NetAttributeType_Float; + this->protocol[3].type = Oyster::Network::NetAttributeType_Float; + this->protocol[4].type = Oyster::Network::NetAttributeType_Float; this->deltaRadian = deltaRadian; + memcpy(&lookdir[0], &v[0], sizeof(float) * 3); + } ::Oyster::Network::CustomNetProtocol GetProtocol() override { this->protocol[1].value = this->deltaRadian; + this->protocol[2].value = this->lookdir[0]; + this->protocol[3].value = this->lookdir[1]; + this->protocol[4].value = this->lookdir[2]; return protocol; } diff --git a/Code/Game/GameProtocols/ProtocolIdentificationID.h b/Code/Game/GameProtocols/ProtocolIdentificationID.h index cb630012..7aaf2eee 100644 --- a/Code/Game/GameProtocols/ProtocolIdentificationID.h +++ b/Code/Game/GameProtocols/ProtocolIdentificationID.h @@ -69,8 +69,8 @@ #define protocol_Gameplay_ObjectWeaponEnergy 364 #define protocol_Gameplay_ObjectRespawn 365 #define protocol_Gameplay_ObjectDie 366 -//Disconnect #define protocol_Gameplay_ObjectDisconnectPlayer 367 +#define protocol_Gameplay_ObjectAction 368 #define protocol_GameplayMAX 399 diff --git a/Code/Game/GameServer/GameClient.h b/Code/Game/GameServer/GameClient.h index 497e6c2e..aace26c7 100644 --- a/Code/Game/GameServer/GameClient.h +++ b/Code/Game/GameServer/GameClient.h @@ -55,6 +55,7 @@ namespace DanBias GameLogic::IPlayerData* ReleasePlayer(); Oyster::Network::NetClient ReleaseClient(); + bool IsInvalid(); void Invalidate(); int IncrementFailedProtocol(); void ResetFailedProtocolCount(); diff --git a/Code/Game/GameServer/GameSession.h b/Code/Game/GameServer/GameSession.h index ad9440e9..12067c2b 100644 --- a/Code/Game/GameServer/GameSession.h +++ b/Code/Game/GameServer/GameSession.h @@ -99,7 +99,10 @@ namespace DanBias //Callback method recieving from gamelogic static void ObjectMove ( GameLogic::IObjectData* movedObject ); static void ObjectDisabled ( GameLogic::IObjectData* movedObject, float seconds ); - + static void ObjectDamaged ( GameLogic::IObjectData* movedObject, float hp ); + static void ObjectRespawned ( GameLogic::IObjectData* movedObject, Oyster::Math::Float3 spawnPos ); + static void ObjectDead ( GameLogic::IObjectData* movedObject, float seconds ); + //Private member variables private: Utility::DynamicMemory::DynamicArray gClients; diff --git a/Code/Game/GameServer/Implementation/GameClient.cpp b/Code/Game/GameServer/Implementation/GameClient.cpp index 3293a383..90b412ef 100644 --- a/Code/Game/GameServer/Implementation/GameClient.cpp +++ b/Code/Game/GameServer/Implementation/GameClient.cpp @@ -19,18 +19,21 @@ GameClient::GameClient(Utility::DynamicMemory::SmartPointerclient = nwClient; this->player = 0; isReady = false; - this->character = L"crate_colonists.dan"; + this->character = L"char_orca.dan"; this->alias = L"Unknown"; this->secondsSinceLastResponse = 0.0f; } GameClient::~GameClient() { - this->client = 0; - this->player = 0; + if(this->player) + this->player->Inactivate(); + this->isReady = false; - this->character = L"crate_colonists.dan"; + this->character = L"char_orca.dan"; this->alias = L"Unknown"; this->secondsSinceLastResponse = 0.0f; + this->client = 0; + this->player = 0; } void GameClient::SetPlayer(GameLogic::IPlayerData* player) @@ -58,8 +61,14 @@ void GameClient::SetState(ClientState state) this->state = state; } +bool GameClient::IsInvalid() +{ + return this->isInvalid; +} void GameClient::Invalidate() { + this->player->Release(); + this->player = 0; this->isInvalid = true; this->isReady = false; this->state = ClientState_Invalid; diff --git a/Code/Game/GameServer/Implementation/GameSession_Gameplay.cpp b/Code/Game/GameServer/Implementation/GameSession_Gameplay.cpp index 0c52dfff..8cc47dcc 100644 --- a/Code/Game/GameServer/Implementation/GameSession_Gameplay.cpp +++ b/Code/Game/GameServer/Implementation/GameSession_Gameplay.cpp @@ -29,10 +29,10 @@ using namespace DanBias; float dt = (float)this->logicTimer.getElapsedSeconds(); if( dt >= this->logicFrameTime ) { + this->logicTimer.reset(); + this->ProcessClients(); this->gameInstance.NewFrame(); - - this->logicTimer.reset(); } } @@ -90,7 +90,7 @@ using namespace DanBias; { for (unsigned int i = 0; i < this->gClients.Size(); i++) { - if(this->gClients[i] ) + if(this->gClients[i] && !this->gClients[i]->IsInvalid()) { this->gClients[i]->UpdateClient(); } @@ -101,7 +101,7 @@ using namespace DanBias; bool returnValue = false; for (unsigned int i = 0; i < this->gClients.Size(); i++) { - if(this->gClients[i]) + if(this->gClients[i] && !this->gClients[i]->IsInvalid()) { this->gClients[i]->GetClient()->Send(message); returnValue = true; @@ -115,7 +115,7 @@ using namespace DanBias; { for (unsigned int i = 0; i < this->gClients.Size(); i++) { - if(this->gClients[i] && this->gClients[i]->GetClient()->GetID() == ID) + if(this->gClients[i] && !this->gClients[i]->IsInvalid() && this->gClients[i]->GetClient()->GetID() == ID) { this->gClients[i]->GetClient()->Send(protocol); return true; @@ -143,9 +143,6 @@ using namespace DanBias; Oyster::Math::Float3 temp = movedObject->GetPosition(); - if(temp.x < -300) - id = 0; - GameSession::gameSession->Send(p.GetProtocol()); //} } @@ -153,7 +150,18 @@ using namespace DanBias; { GameSession::gameSession->Send(Protocol_ObjectDisable(movedObject->GetID(), seconds).GetProtocol()); } - + void GameSession::ObjectDamaged( GameLogic::IObjectData* movedObject, float hp ) + { + GameSession::gameSession->Send(Protocol_ObjectDamage(movedObject->GetID(), hp).GetProtocol()); + } + void GameSession::ObjectRespawned( GameLogic::IObjectData* movedObject, Oyster::Math::Float3 spawnPos ) + { + GameSession::gameSession->Send(Protocol_ObjectRespawn(movedObject->GetID(), spawnPos).GetProtocol()); + } + void GameSession::ObjectDead( GameLogic::IObjectData* movedObject, float seconds ) + { + GameSession::gameSession->Send(Protocol_ObjectDie(movedObject->GetID(), seconds).GetProtocol()); + } //*****************************************************// //****************** Protocol methods *****************// //******************************************************************************************************************// @@ -224,6 +232,7 @@ using namespace DanBias; void GameSession::Gameplay_PlayerLeftTurn ( Protocol_PlayerLeftTurn& p, DanBias::GameClient* c ) { c->GetPlayer()->TurnLeft( p.deltaRadian ); + c->GetPlayer()->SetLookDir( p.lookdir ) ; } void GameSession::Gameplay_PlayerChangeWeapon ( Protocol_PlayerChangeWeapon& p, DanBias::GameClient* c ) { diff --git a/Code/Game/GameServer/Implementation/GameSession_General.cpp b/Code/Game/GameServer/Implementation/GameSession_General.cpp index 2b8a7d5c..0ad12987 100644 --- a/Code/Game/GameServer/Implementation/GameSession_General.cpp +++ b/Code/Game/GameServer/Implementation/GameSession_General.cpp @@ -36,8 +36,8 @@ GameSession::GameSession() this->isCreated = false; this->isRunning = false; this->gameSession = this; - this->logicFrameTime = DELTA_TIME_20; - this->networkFrameTime = DELTA_TIME_20; + this->logicFrameTime = DELTA_TIME_60; + this->networkFrameTime = DELTA_TIME_60; this->networkTimer.reset(); this->logicTimer.reset(); @@ -108,6 +108,9 @@ bool GameSession::Create(GameDescription& desc, bool forceStart) /* Set some game instance data options */ this->gameInstance.SetSubscription(GameSession::ObjectMove); this->gameInstance.SetSubscription(GameSession::ObjectDisabled); + this->gameInstance.SetHpSubscription(GameSession::ObjectDamaged); + this->gameInstance.SetRespawnSubscription(GameSession::ObjectRespawned); + this->gameInstance.SetDeadSubscription(GameSession::ObjectDead); this->gameInstance.SetFPS(60); this->description.clients.Clear(); @@ -214,14 +217,21 @@ bool GameSession::Join(gClient gameClient) { for (unsigned int i = 0; i < this->gClients.Size(); i++) { - if(this->gClients[i]) + if(this->gClients[i] && !this->gClients[i]->IsInvalid()) { IPlayerData* temp = this->gClients[i]->GetPlayer(); - Protocol_ObjectCreatePlayer oc( temp->GetPosition(), temp->GetRotation(), temp->GetScale(), + Protocol_ObjectCreatePlayer p1( temp->GetPosition(), temp->GetRotation(), temp->GetScale(), temp->GetID(), false, temp->GetTeamID(), Utility::String::WStringToString(this->gClients[i]->GetAlias(), std::string()), Utility::String::WStringToString(this->gClients[i]->GetCharacter(), std::string())); - nwClient->Send(oc); + nwClient->Send(p1); + + temp = playerData; + Protocol_ObjectCreatePlayer p2( temp->GetPosition(), temp->GetRotation(), temp->GetScale(), + temp->GetID(), false, temp->GetTeamID(), + Utility::String::WStringToString(gameClient->GetAlias(), std::string()), + Utility::String::WStringToString(gameClient->GetCharacter(), std::string())); + this->gClients[i]->GetClient()->Send(p2); } } } diff --git a/Code/Game/LanServer/GameServerDebugEnvironment/Source.cpp b/Code/Game/LanServer/GameServerDebugEnvironment/Source.cpp index 62332541..3357f52c 100644 --- a/Code/Game/LanServer/GameServerDebugEnvironment/Source.cpp +++ b/Code/Game/LanServer/GameServerDebugEnvironment/Source.cpp @@ -32,7 +32,7 @@ int WINAPI WinMain( HINSTANCE hinst, HINSTANCE prevInst, PSTR cmdLine, int cmdSh GameServerAPI::GameSetGameMode(L"free-for-all"); GameServerAPI::GameSetGameName(L"DebugServer"); GameServerAPI::GameSetGameTime(15); - GameServerAPI::GameSetMapName(L"2ofAll.bias"); + GameServerAPI::GameSetMapName(L"erik_250.bias"); GameServerAPI::GameSetMaxClients(10); if(GameServerAPI::GameStart(true)) diff --git a/Code/Game/LevelLoader/LevelParser.cpp b/Code/Game/LevelLoader/LevelParser.cpp index 5f5a5341..fe349988 100644 --- a/Code/Game/LevelLoader/LevelParser.cpp +++ b/Code/Game/LevelLoader/LevelParser.cpp @@ -166,16 +166,17 @@ std::vector> LevelParser::Parse(std::string filen case ObjectType_Light: { - LightType lightType; + //LightType lightType; //Get Light type - ParseObject(&buffer[counter+4], &lightType, sizeof(lightType)); + //ParseObject(&buffer[counter+4], &lightType, sizeof(lightType)); //We only support PointLight for now. BasicLight* header = new BasicLight; - ParseObject(&buffer[counter], header, sizeof(*header)); - counter += sizeof(*header); + + ParseLight(&buffer[counter], *header, counter); objects.push_back(header); + /*switch(lightType) { case LightType_PointLight: @@ -208,6 +209,7 @@ std::vector> LevelParser::Parse(std::string filen } break;*/ } + break; default: //Couldn't find typeID. FAIL!!!!!! break; diff --git a/Code/Game/LevelLoader/ObjectDefines.h b/Code/Game/LevelLoader/ObjectDefines.h index 918fb4e6..52f0e088 100644 --- a/Code/Game/LevelLoader/ObjectDefines.h +++ b/Code/Game/LevelLoader/ObjectDefines.h @@ -52,6 +52,7 @@ namespace GameLogic CollisionGeometryType_Box, CollisionGeometryType_Sphere, CollisionGeometryType_Cylinder, + CollisionGeometryType_CG_MESH, CollisionGeometryType_Count, CollisionGeometryType_Unknown = -1 @@ -161,6 +162,11 @@ namespace GameLogic float radius; }; + struct BoundingVolumeCGMesh : public BoundingVolumeBase + { + wchar_t filename[128]; + }; + struct BoundingVolume { CollisionGeometryType geoType; @@ -169,9 +175,9 @@ namespace GameLogic LevelLoaderInternal::BoundingVolumeBox box; LevelLoaderInternal::BoundingVolumeSphere sphere; LevelLoaderInternal::BoundingVolumeCylinder cylinder; + LevelLoaderInternal::BoundingVolumeCGMesh cgMesh; }; }; - } struct LevelMetaData : public ObjectTypeHeader @@ -253,8 +259,10 @@ namespace GameLogic LightType lightType; //Is not used right now float color[3]; float position[3]; - float raduis; + float radius; float intensity; + + virtual ~BasicLight(){} }; /* We only support pointlight right now. struct PointLight : public BasicLight diff --git a/Code/Game/LevelLoader/ParseFunctions.cpp b/Code/Game/LevelLoader/ParseFunctions.cpp index 09adb298..ac361c46 100644 --- a/Code/Game/LevelLoader/ParseFunctions.cpp +++ b/Code/Game/LevelLoader/ParseFunctions.cpp @@ -20,6 +20,32 @@ namespace GameLogic memcpy(header, buffer, size); } + void ParseLight(char* buffer, BasicLight& header, int& size) + { + int start = 0; + memcpy(&header.typeID, &buffer[start], 40); + start += 40; + /* + memcpy(&header.lightType, &buffer[start], 4); + start += 4; + + memcpy(&header.color, &buffer[start], 12); + start += 12; + + memcpy(&header.position, &buffer[start], 12); + start += 12; + + memcpy(&header.radius, &buffer[start], 4); + start += 4; + + memcpy(&header.intensity, &buffer[start], 4); + start += 4;*/ + + size += start; + + //memcpy(&header, buffer, size); + } + void ParseObject(char* buffer, ObjectHeader& header, int& size, bool loadCgf) { char tempName[128]; @@ -173,6 +199,22 @@ namespace GameLogic start += sizeof(volume.cylinder); break; + case CollisionGeometryType_CG_MESH: + { + memcpy(&volume.cgMesh, &buf[start], sizeof(float)*12); + start += sizeof(float)*12; + memcpy(&tempSize, &buf[start], sizeof(tempSize)); + start += 4; + memcpy(&tempName, &buf[start], tempSize); + tempName[tempSize] = '\0'; + + //convert from char[] to wchar_t[] + mbstowcs_s(NULL, volume.cgMesh.filename, tempSize+1, tempName, _TRUNCATE); + + start += tempSize; + } + break; + default: break; } diff --git a/Code/Game/LevelLoader/ParseFunctions.h b/Code/Game/LevelLoader/ParseFunctions.h index 0fc6dbc6..21e43858 100644 --- a/Code/Game/LevelLoader/ParseFunctions.h +++ b/Code/Game/LevelLoader/ParseFunctions.h @@ -18,6 +18,7 @@ namespace GameLogic */ void ParseObject(char* buffer, void *header, int size); + void ParseLight(char* buffer, BasicLight& header, int& size); void ParseObject(char* buffer, ObjectHeader& header, int& size , bool loadCgf); void ParseLevelMetaData(char* buffer, LevelMetaData &header, int &size); void ParseBoundingVolume(char* buffer, LevelLoaderInternal::BoundingVolume& volume, int &size); diff --git a/Code/Misc/OysterMath/LinearMath.h b/Code/Misc/OysterMath/LinearMath.h index 25b65331..5b87d83d 100644 --- a/Code/Misc/OysterMath/LinearMath.h +++ b/Code/Misc/OysterMath/LinearMath.h @@ -376,9 +376,13 @@ namespace LinearAlgebra3D template inline ::LinearAlgebra::Vector3 AngularAxis( const ::LinearAlgebra::Quaternion &rotation ) { // see http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm - ScalarType angle = ScalarType(2) * (ScalarType)::std::acos( rotation.real ), - multiplier = angle / (ScalarType)::std::sqrt( ScalarType(1) - rotation.real * rotation.real ); - return multiplier * rotation.imaginary; + if( rotation.real < ScalarType(1) ) + { + ScalarType angle = ScalarType(2) * ScalarType( ::std::acos(rotation.real) ), + multiplier = angle / ScalarType( ::std::sqrt(ScalarType(1) - rotation.real * rotation.real) ); + return multiplier * rotation.imaginary; + } + else return ::LinearAlgebra::Vector3::null; } // All Matrix to AngularAxis conversions here is incorrect @@ -838,7 +842,7 @@ namespace LinearAlgebra3D template ::LinearAlgebra::Vector3 & SnapAngularAxis( const ::LinearAlgebra::Vector3 &startAngularAxis, const ::LinearAlgebra::Vector3 &localStartNormal, const ::LinearAlgebra::Vector3 &worldEndNormal, ::LinearAlgebra::Vector3 &targetMem = ::LinearAlgebra::Vector3() ) - { + { //! @todo TODO: This code is broken and do not work! ::LinearAlgebra::Vector3 worldStartNormal( WorldAxisOf(Rotation(startAngularAxis), localStartNormal) ); targetMem = worldStartNormal.Cross( worldEndNormal ); targetMem *= (ScalarType)::std::acos( ::Utility::Value::Clamp(worldStartNormal.Dot(worldEndNormal), (ScalarType)0, (ScalarType)1) ); diff --git a/Code/Misc/Utilities/Resource/ResourceManager.cpp b/Code/Misc/Utilities/Resource/ResourceManager.cpp index 04c03a6f..e23ff398 100644 --- a/Code/Misc/Utilities/Resource/ResourceManager.cpp +++ b/Code/Misc/Utilities/Resource/ResourceManager.cpp @@ -437,6 +437,38 @@ int ResourceManager::GetResourceId(const wchar_t c[]) return -1; } +int ResourceManager::GetResourceCount(const wchar_t filename[]) +{ + ResourceData *t = FindResource(this->resources, filename); + + if(t) return t->referenceCount; + + return 0; +} +int ResourceManager::GetResourceCount(const HRESOURCE& resource) +{ + ResourceData *t = FindResource(this->resources, resource); + + if(t) return t->referenceCount; + + return 0; +} +int ResourceManager::GetResourceSize(const wchar_t filename[]) +{ + ResourceData *t = FindResource(this->resources, filename); + + if(t) return t->resourceSize; + + return 0; +} +int ResourceManager::GetResourceSize(const HRESOURCE& resource) +{ + ResourceData *t = FindResource(this->resources, resource); + + if(t) return t->resourceSize; + + return 0; +} diff --git a/Code/Misc/Utilities/Resource/ResourceManager.h b/Code/Misc/Utilities/Resource/ResourceManager.h index d5684538..b3de6af5 100644 --- a/Code/Misc/Utilities/Resource/ResourceManager.h +++ b/Code/Misc/Utilities/Resource/ResourceManager.h @@ -148,6 +148,14 @@ namespace Oyster * @return Returns the accociated ID */ int GetResourceId(const wchar_t filename[]); + + int GetResourceCount(const wchar_t filename[]); + + int GetResourceCount(const HRESOURCE& resource); + + int GetResourceSize(const wchar_t filename[]); + + int GetResourceSize(const HRESOURCE& resource); private: ResourceManager(const ResourceManager& obj); diff --git a/Code/Misc/Utilities/Utilities.h b/Code/Misc/Utilities/Utilities.h index b97d62d7..bf9bb65c 100644 --- a/Code/Misc/Utilities/Utilities.h +++ b/Code/Misc/Utilities/Utilities.h @@ -44,6 +44,7 @@ namespace Utility ReferenceCount() :count(0) { } ReferenceCount(const ReferenceCount& o) { count = o.count; } inline const ReferenceCount& operator=(const ReferenceCount& o) { count = o.count; return *this;} + operator int() { return this->count; } inline void Incref() { this->count++; } inline void Incref(int c) { this->count += c; } inline int Decref() { return --this->count;} diff --git a/Code/Network/NetworkAPI/NetworkClient.cpp b/Code/Network/NetworkAPI/NetworkClient.cpp index 3463ed8a..56425109 100644 --- a/Code/Network/NetworkAPI/NetworkClient.cpp +++ b/Code/Network/NetworkAPI/NetworkClient.cpp @@ -56,6 +56,17 @@ struct NetworkClient::PrivateData : public IThreadObject ThreadSafeQueue sendQueue; ThreadSafeQueue> recieveQueue; + //Testing for eventSelect. + HANDLE socketEvents[2]; + HANDLE shutdownEvent; + + //The OysterByte each message is packed in. + OysterByte tempMessage; + + //Used to buffer messages + OysterByte bufferedSend; + int numPackages; + //ID static unsigned int currID; const unsigned int ID; @@ -65,14 +76,18 @@ struct NetworkClient::PrivateData : public IThreadObject , parent(0) , owner(0) , outputEvent(0) - { + { + numPackages = 0; + bufferedSend.Resize(MAX_NETWORK_MESSAGE_SIZE); + tempMessage.Resize(MAX_NETWORK_MESSAGE_SIZE); InitWinSock(); this->thread.Create(this, false); this->thread.SetPriority(Oyster::Thread::OYSTER_THREAD_PRIORITY_1); } ~PrivateData() { - this->thread.Terminate(); + SetEvent(shutdownEvent); + this->thread.Wait(); ShutdownWinSock(); this->connection.Disconnect(); @@ -80,15 +95,150 @@ struct NetworkClient::PrivateData : public IThreadObject this->parent = 0; } + void ThreadEntry() + { + //Create alla events used in the thread + shutdownEvent = CreateEvent(NULL, true, false, NULL); + socketEvents[0] = WSACreateEvent(); + socketEvents[1] = WSACreateEvent(); + + if(socketEvents[0] == WSA_INVALID_EVENT) + { + //Error + } + + if(WSAEventSelect(this->connection.GetSocket(), socketEvents[0], FD_READ) == SOCKET_ERROR) + { + //Error + } + } + + void ThreadExit() + { + WSACloseEvent(socketEvents[0]); + WSACloseEvent(socketEvents[1]); + CloseHandle(shutdownEvent); + } + bool DoWork() override { - if(!this->connection.IsConnected()) return false; + WSANETWORKEVENTS wsaEvents; - Send(); - Recv(); - - return true; + while(WaitForSingleObject(shutdownEvent, 0) != WAIT_OBJECT_0) + { + if(!this->connection.IsConnected()) return false; + + int result = WSAWaitForMultipleEvents(2, socketEvents, FALSE, 100, FALSE) - WSA_WAIT_EVENT_0; + if(result == 0) + { + WSAEnumNetworkEvents(this->connection.GetSocket(), socketEvents[0], &wsaEvents); + if((wsaEvents.lNetworkEvents & FD_READ) && (wsaEvents.iErrorCode[FD_READ_BIT] == 0)) + { + //Recieve a message + Recv(); + } + } + else if(result == 1) + { + //Send all messages in the sendQueue + int i = this->sendQueue.Size(); + WSAResetEvent(socketEvents[1]); + + if(i == 1) + { + Send(); + } + else if(i > 1) + { + for(int j = 0; j < i; j++) + BufferMessage(); + + SendBuffer(); + } + } + } + + return false; } + + void SendBuffer() + { + if(bufferedSend.GetSize() > 0) + { + this->connection.Send(bufferedSend); + //printf("2. %d, %d\n", numPackages, bufferedSend.GetSize()); + bufferedSend.Clear(); + + //Debug + numPackages = 0; + } + } + + void BufferMessage() + { + int errorCode = 0; + + if(!this->sendQueue.IsEmpty()) + { + CustomNetProtocol p = this->sendQueue.Pop(); + + this->translator.Pack(tempMessage, p); + + + if(tempMessage.GetSize() > MAX_NETWORK_MESSAGE_SIZE - bufferedSend.GetSize()) + { + //Send buffered message + errorCode = this->connection.Send(bufferedSend); + //printf("2. %d, %d\n", numPackages, bufferedSend.GetSize()); + bufferedSend.Clear(); + + //Debug + numPackages = 0; + } + + bufferedSend += tempMessage; + tempMessage.Clear(); + + //Debug + numPackages++; + + if(errorCode != 0 && errorCode != WSAEWOULDBLOCK) + { + if( errorCode == WSAECONNABORTED || errorCode == WSAENOTCONN) + { + CEA parg; + parg.type = CEA::EventType_Disconnect; + parg.data.protocol = p; + NetEvent e = { this->parent, parg }; + this->recieveQueue.Push(e); + + if(this->outputEvent) + { + printf("\t(ID: %i | IP: %s | Protocol: %i) - EventType_Disconnect && EventType_ProtocolFailedToSend \n", this->ID, this->connection.GetIpAddress().c_str(), p[0].value.netShort); + } + } + else + { + CEA parg; + parg.type = CEA::EventType_ProtocolFailedToSend; + parg.data.protocol = p; + NetEvent e = { this->parent, parg }; + this->recieveQueue.Push(e); + + if(this->outputEvent) + { + printf("\t(ID: %i | IP: %s | Protocol: %i) - EventType_ProtocolFailedToSend\n", this->ID, this->connection.GetIpAddress().c_str(), p[0].value.netShort); + } + } + } + + if(this->outputEvent) + { + printf("\t(ID: %i | IP: %s | Protocol: %i) Message sent!\n", this->ID, this->connection.GetIpAddress().c_str(), p[0].value.netShort); + } + } + } + int Send() { int errorCode = 0; @@ -96,11 +246,11 @@ struct NetworkClient::PrivateData : public IThreadObject if(!this->sendQueue.IsEmpty()) { //printf("\t(%i)\n", this->sendQueue.Size()); - OysterByte temp; CustomNetProtocol p = this->sendQueue.Pop(); - this->translator.Pack(temp, p); - errorCode = this->connection.Send(temp); + this->translator.Pack(tempMessage, p); + errorCode = this->connection.Send(tempMessage); + tempMessage.Clear(); if(errorCode != 0 && errorCode != WSAEWOULDBLOCK) { @@ -144,12 +294,12 @@ struct NetworkClient::PrivateData : public IThreadObject { int errorCode = -1; - OysterByte temp = OysterByte(); - errorCode = this->connection.Recieve(temp); + errorCode = this->connection.Recieve(tempMessage); - if(errorCode == 0 && temp.GetSize()) + if(errorCode == 0 && tempMessage.GetSize()) { - HandleRecievedData(temp); + HandleRecievedData(tempMessage); + tempMessage.Clear(); /* Replaced with EmptyOutbufferedQueue() and HandleRecievedData(OysterByte) @@ -312,7 +462,7 @@ bool NetworkClient::Connect(ConnectionInfo& socket) if(this->privateData) return false; if(!this->privateData) this->privateData = new PrivateData(); - int result = this->privateData->connection.Connect(socket, false); + int result = this->privateData->connection.Connect(socket, true); //Connect has succeeded if(result != 0) return false; @@ -333,7 +483,7 @@ bool NetworkClient::Connect(unsigned short port, const char serverIP[]) if(!this->privateData) this->privateData = new PrivateData(); - int result = this->privateData->connection.Connect(port, serverIP, false); + int result = this->privateData->connection.Connect(port, serverIP, true); //Connect has succeeded if(result != 0) return false; @@ -381,7 +531,9 @@ void NetworkClient::Disconnect() { if(!privateData) return; - privateData->thread.Stop(); + SetEvent(privateData->shutdownEvent); + privateData->thread.Wait(); + privateData->connection.Disconnect(); this->privateData->sendQueue.Clear(); this->privateData->recieveQueue.Clear(); @@ -390,11 +542,13 @@ void NetworkClient::Disconnect() void NetworkClient::Send(CustomProtocolObject& protocol) { this->privateData->sendQueue.Push(protocol.GetProtocol()); + WSASetEvent(this->privateData->socketEvents[1]); } void NetworkClient::Send(CustomNetProtocol& protocol) { this->privateData->sendQueue.Push(protocol); + WSASetEvent(this->privateData->socketEvents[1]); } void NetworkClient::SetOwner(NetworkSession* owner) diff --git a/Code/Network/NetworkAPI/NetworkServer.h b/Code/Network/NetworkAPI/NetworkServer.h index 593c3847..82693310 100644 --- a/Code/Network/NetworkAPI/NetworkServer.h +++ b/Code/Network/NetworkAPI/NetworkServer.h @@ -22,16 +22,16 @@ namespace Oyster { struct BroadcastOptions { - //bool broadcast; - //float broadcastInterval; - //std::wstring subnetToBroadcast; - //CustomNetProtocol broadcastMessage; - //BroadcastOptions() - //{ - // broadcast = true; - // broadcastInterval = 1.0f; - // subnetToBroadcast = L"192.168.0.1"; - //} + bool broadcast; + float broadcastInterval; + std::wstring subnetToBroadcast; + CustomNetProtocol broadcastMessage; + BroadcastOptions() + { + broadcast = true; + broadcastInterval = 1.0f; + subnetToBroadcast = L"192.168.0.1"; + } } broadcastOptions; struct MainOptions @@ -117,6 +117,23 @@ namespace Oyster */ int NetworkServer::GetPort(); + + + /*************************************** + Broadcast functions + ***************************************/ + //Set broadcast settings. + void SetBroadcast(CustomNetProtocol& broadcastMessage, float interval = 1.0f, bool enable = true); + + //Set broadcast settings. + void SetBroadcastMessage(CustomNetProtocol& broadcastMessage); + + //Enable/disable broadcast. + void SetBroadcast(bool enable); + + //Set interval between each broadcast message in seconds. + void SetBroadcastInterval(float interval); + private: struct PrivateData; PrivateData* privateData; diff --git a/Code/Network/NetworkDependencies/Connection.cpp b/Code/Network/NetworkDependencies/Connection.cpp index 2cd992a2..0b0a6a3d 100644 --- a/Code/Network/NetworkDependencies/Connection.cpp +++ b/Code/Network/NetworkDependencies/Connection.cpp @@ -188,8 +188,8 @@ int Connection::Recieve(OysterByte &bytes) if(this->closed) return -1; int nBytes; - bytes.Resize(1000); - nBytes = recv(this->socket, bytes, 1000, 0); + bytes.Resize(MAX_NETWORK_MESSAGE_SIZE); + nBytes = recv(this->socket, bytes, MAX_NETWORK_MESSAGE_SIZE, 0); if(nBytes == SOCKET_ERROR) { bytes.SetSize(0); @@ -263,6 +263,11 @@ std::string Connection::GetIpAddress() return this->addr; } +int Connection::GetSocket() +{ + return socket; +} + /////////////////////////////////////// //Private functions /////////////////////////////////////// diff --git a/Code/Network/NetworkDependencies/Connection.h b/Code/Network/NetworkDependencies/Connection.h index 054537fc..e1c98a76 100644 --- a/Code/Network/NetworkDependencies/Connection.h +++ b/Code/Network/NetworkDependencies/Connection.h @@ -39,6 +39,8 @@ namespace Oyster int SetBlockingMode( bool blocking ); std::string GetIpAddress(); + int GetSocket(); + private: int InitiateSocket(); diff --git a/Code/Network/NetworkDependencies/ConnectionUDP.cpp b/Code/Network/NetworkDependencies/ConnectionUDP.cpp index e7d065a6..44a49d2d 100644 --- a/Code/Network/NetworkDependencies/ConnectionUDP.cpp +++ b/Code/Network/NetworkDependencies/ConnectionUDP.cpp @@ -135,10 +135,10 @@ int ConnectionUDP::Recieve(OysterByte &bytes) sockaddr_in from; int fromLength = sizeof( from ); - bytes.Resize(1000); + bytes.Resize(MAX_NETWORK_MESSAGE_SIZE); nBytes = recvfrom(this->socket, bytes, - 1000, + MAX_NETWORK_MESSAGE_SIZE, 0, (sockaddr*)&from, &fromLength diff --git a/Code/Network/NetworkDependencies/IConnection.h b/Code/Network/NetworkDependencies/IConnection.h index debdfe7b..b4c3627c 100644 --- a/Code/Network/NetworkDependencies/IConnection.h +++ b/Code/Network/NetworkDependencies/IConnection.h @@ -11,6 +11,8 @@ namespace Oyster { namespace Network { + const int MAX_NETWORK_MESSAGE_SIZE = 1400; + struct ConnectionInfo { int socket; @@ -44,6 +46,8 @@ namespace Oyster //Disconnects the client or server TODO: optimize! virtual int Disconnect() = 0; + + virtual int GetSocket() { return -1; }; }; } } diff --git a/Code/OysterGraphics/Definitions/GraphicalDefinition.h b/Code/OysterGraphics/Definitions/GraphicalDefinition.h index f6a6431c..77aecdc8 100644 --- a/Code/OysterGraphics/Definitions/GraphicalDefinition.h +++ b/Code/OysterGraphics/Definitions/GraphicalDefinition.h @@ -90,6 +90,14 @@ namespace Oyster Math::Float3 GlowTint; Math::Float PAD2; }; + + struct RenderInstanceData + { + Math::Matrix WV; + Math::Matrix WVP; + Math::Float3 Tint; + Math::Float3 GTint; + }; } } } \ No newline at end of file diff --git a/Code/OysterGraphics/DllInterfaces/GFXAPI.cpp b/Code/OysterGraphics/DllInterfaces/GFXAPI.cpp index 8f01bea4..ee3d9f8a 100644 --- a/Code/OysterGraphics/DllInterfaces/GFXAPI.cpp +++ b/Code/OysterGraphics/DllInterfaces/GFXAPI.cpp @@ -19,6 +19,7 @@ namespace Oyster Math::Float4x4 Projection; std::vector Lights; float deltaTime; + int MostModel; #ifdef _DEBUG Model::Model* cube; Model::Model* sphere; @@ -57,9 +58,11 @@ namespace Oyster debugSRV = (ID3D11ShaderResourceView*)API::CreateTexture(L"color_white.png"); cube = CreateModel(L"generic_cube.dan"); - cube->Tint = Math::Float3(0.0f,0.0f,1.0f); + cube->Tint = Math::Float3(1.0f,0.0f,0.0f); + cube->Instanced = false; sphere = CreateModel(L"generic_sphere.dan"); sphere->Tint = Math::Float3(1.0f,0.5f,182/255.0f); + sphere->Instanced = false; D3D11_RASTERIZER_DESC desc; @@ -133,6 +136,35 @@ namespace Oyster return API::Sucsess; } + void API::BeginLoadingModels() + { + } + + void API::EndLoadingModels() + { + //TODO finalize instance buffers and create rendering map; + int maxModels = 0; + for(auto i = Render::Resources::RenderData.begin(); i != Render::Resources::RenderData.end(); i++ ) + { + if((*i).second->Models > maxModels) + { + maxModels = (*i).second->Models; + } + (*i).second->rid = new Definitions::RenderInstanceData[(*i).second->Models+1]; + } + + Core::Buffer::BUFFER_INIT_DESC desc; + + + desc.ElementSize = sizeof(Definitions::RenderInstanceData); + desc.Type = Core::Buffer::VERTEX_BUFFER; + desc.Usage = Core::Buffer::BUFFER_CPU_WRITE_DISCARD; + desc.InitData = 0; + desc.NumElements = maxModels+1; + + Render::Resources::Gather::InstancedData.Init(desc); + } + //returns null for invalid filenames Model::Model* API::CreateModel(std::wstring filename) { @@ -142,6 +174,7 @@ namespace Oyster m->Animation.AnimationPlaying = NULL; m->Tint = Math::Float3(1); m->GlowTint = Math::Float3(1); + m->Instanced = true; m->info = (Model::ModelInfo*)Core::loader.LoadResource((Core::modelPath + filename).c_str(),Oyster::Graphics::Loading::LoadDAN, Oyster::Graphics::Loading::UnloadDAN); Model::ModelInfo* mi = (Model::ModelInfo*)m->info; @@ -152,6 +185,18 @@ namespace Oyster delete mi; return NULL; } + + if(!m->info->Animated) + { + if(Core::loader.GetResourceCount(m->info) == 1) + { + Render::Resources::RenderData[m->info] = new Render::Resources::ModelDataWrapper(); + } + else + { + Render::Resources::RenderData[m->info]->Models++; + } + } return m; } @@ -187,6 +232,12 @@ namespace Oyster SAFE_RELEASE(Core::deviceContext); SAFE_RELEASE(Core::device); + for(auto i = Render::Resources::RenderData.begin(); i != Render::Resources::RenderData.end(); i++ ) + { + SAFE_DELETE((*i).second->rid); + SAFE_DELETE((*i).second); + } + } void API::AddLight(Definitions::Pointlight light) @@ -208,9 +259,9 @@ namespace Oyster void API::StartRenderWireFrame() { - Core::deviceContext->OMSetRenderTargets((UINT)Render::Resources::Gather::Pass.RTV.size(),&Render::Resources::Gather::Pass.RTV[0],NULL); + //Core::deviceContext->OMSetRenderTargets((UINT)Render::Resources::Gather::AnimatedPass.RTV.size(),&Render::Resources::Gather::AnimatedPass.RTV[0],NULL); Core::deviceContext->RSSetState(wire); - Core::deviceContext->OMSetRenderTargets((UINT)Render::Resources::Gather::Pass.RTV.size(),&Render::Resources::Gather::Pass.RTV[0],NULL); + //Core::deviceContext->OMSetRenderTargets((UINT)Render::Resources::Gather::AnimatedPass.RTV.size(),&Render::Resources::Gather::AnimatedPass.RTV[0],NULL); } void API::RenderDebugCube(Math::Matrix world) diff --git a/Code/OysterGraphics/DllInterfaces/GFXAPI.h b/Code/OysterGraphics/DllInterfaces/GFXAPI.h index 795f649a..7f338cce 100644 --- a/Code/OysterGraphics/DllInterfaces/GFXAPI.h +++ b/Code/OysterGraphics/DllInterfaces/GFXAPI.h @@ -42,6 +42,10 @@ namespace Oyster static State Init(HWND Window, bool MSAA_Quality, bool Fullscreen, Option options); + static void BeginLoadingModels(); + + static void EndLoadingModels(); + static State ReloadShaders(); //should be called after rendered normal models, before GUI or Text rendering diff --git a/Code/OysterGraphics/Model/Model.h b/Code/OysterGraphics/Model/Model.h index 5985dbcd..6d4e96f2 100644 --- a/Code/OysterGraphics/Model/Model.h +++ b/Code/OysterGraphics/Model/Model.h @@ -26,6 +26,7 @@ namespace Oyster Oyster::Math::Float3 Tint; Oyster::Math::Float3 GlowTint; bool Visible; + bool Instanced; AnimationData Animation; }; } diff --git a/Code/OysterGraphics/OysterGraphics.vcxproj b/Code/OysterGraphics/OysterGraphics.vcxproj index 8faf4d0f..f4a3d130 100644 --- a/Code/OysterGraphics/OysterGraphics.vcxproj +++ b/Code/OysterGraphics/OysterGraphics.vcxproj @@ -239,13 +239,25 @@ Vertex Vertex + + Pixel + Pixel + Pixel + Pixel + + + Vertex + Vertex + Vertex + Vertex + Compute Compute Compute Compute - + Pixel Pixel Pixel @@ -281,7 +293,7 @@ Compute 5.0 - + Vertex Vertex Vertex @@ -328,8 +340,9 @@ + - + diff --git a/Code/OysterGraphics/OysterGraphics.vcxproj.filters b/Code/OysterGraphics/OysterGraphics.vcxproj.filters index d76a066f..83731090 100644 --- a/Code/OysterGraphics/OysterGraphics.vcxproj.filters +++ b/Code/OysterGraphics/OysterGraphics.vcxproj.filters @@ -100,8 +100,6 @@ - - @@ -109,6 +107,10 @@ + + + + @@ -117,8 +119,9 @@ - + + \ No newline at end of file diff --git a/Code/OysterGraphics/Render/DefaultRenderer.cpp b/Code/OysterGraphics/Render/DefaultRenderer.cpp index 7d0d987b..4b979be8 100644 --- a/Code/OysterGraphics/Render/DefaultRenderer.cpp +++ b/Code/OysterGraphics/Render/DefaultRenderer.cpp @@ -19,7 +19,6 @@ namespace Oyster Preparations::Basic::ClearBackBuffer(Oyster::Math::Float4(0,0,0,0)); Preparations::Basic::ClearDepthStencil(Resources::Gui::depth); Preparations::Basic::ClearRTV(Resources::GBufferRTV,Resources::GBufferSize,Math::Float4(0,0,0,0)); - Core::PipelineManager::SetRenderPass(Graphics::Render::Resources::Gather::Pass); Lights[1]; void* data; @@ -39,15 +38,39 @@ namespace Oyster data = Resources::Light::PointLightsData.Map(); memcpy(data, Lights, sizeof(Definitions::Pointlight) * numLights); Resources::Light::PointLightsData.Unmap(); + + for(auto i = Render::Resources::RenderData.begin(); i != Render::Resources::RenderData.end(); i++ ) + { + (*i).second->Models=0; + } + + Core::PipelineManager::SetRenderPass(Resources::Gather::AnimatedPass); } void DefaultRenderer::RenderScene(Model::Model* models, int count, Math::Matrix View, Math::Matrix Projection, float deltaTime) { for(int i = 0; i < count; ++i) { - if(&models[i] == NULL) + if(&models[i] == NULL || !models[i].Visible) continue; - if(models[i].Visible) + + Model::ModelInfo* info = models[i].info; + if(!info->Animated && models[i].Instanced) + { + Definitions::RenderInstanceData rid; + Math::Float3x3 normalTransform; + normalTransform = Math::Float3x3(models[i].WorldMatrix.v[0].xyz, models[i].WorldMatrix.v[1].xyz, models[i].WorldMatrix.v[2].xyz); + normalTransform.Transpose().Invert(); + Math::Matrix m = Math::Matrix(Math::Vector4(normalTransform.v[0],0.0f), Math::Vector4(normalTransform.v[1],0.0f), Math::Vector4(normalTransform.v[2],0.0f), Math::Vector4(0.0f)); + rid.WV = View * m; + rid.WVP = Projection * View * models[i].WorldMatrix; + + rid.Tint = models[i].Tint; + rid.GTint = models[i].GlowTint; + + Resources::RenderData[info]->rid[Resources::RenderData[info]->Models++] = rid; + } + else { Definitions::PerModel pm; Math::Float3x3 normalTransform; @@ -55,7 +78,6 @@ namespace Oyster normalTransform.Transpose().Invert(); Math::Matrix m = Math::Matrix(Math::Vector4(normalTransform.v[0],0.0f), Math::Vector4(normalTransform.v[1],0.0f), Math::Vector4(normalTransform.v[2],0.0f), Math::Vector4(0.0f)); pm.WV = View * m; - //pm.WV = models[i].WorldMatrix.GetTranspose().GetInverse(); pm.WVP = Projection * View * models[i].WorldMatrix; Model::ModelInfo* info = models[i].info; @@ -207,9 +229,47 @@ namespace Oyster Core::deviceContext->Dispatch((UINT)(Core::resolution.x/2), (UINT)((Core::resolution.y/2 + 127U) / 128U), 1); } + void RenderModel(Model::ModelInfo* info, Definitions::RenderInstanceData* rid , int count) + { + if(count < 1) + return; + if(info->Material.size()) + { + Core::deviceContext->PSSetShaderResources(0,(UINT)info->Material.size(),&(info->Material[0])); + } + info->Vertices->Apply(); + if(info->Indexed) + { + info->Indecies->Apply(); + } + + void* data = Resources::Gather::InstancedData.Map(); + memcpy(data, rid, sizeof(Definitions::RenderInstanceData)*count); + Resources::Gather::InstancedData.Unmap(); + + if(info->Indexed) + { + Core::deviceContext->DrawIndexedInstanced(info->IndexCount,count,0,0,0); + //Core::deviceContext->DrawIndexed(info->IndexCount,0,0); + } + else + { + Core::deviceContext->DrawInstanced(info->VertexCount,count,0,0); + //Core::deviceContext->Draw(info->VertexCount,0); + } + } + void DefaultRenderer::EndFrame() { + Core::PipelineManager::SetRenderPass(Graphics::Render::Resources::Gather::InstancedPass); + Resources::Gather::InstancedData.Apply(1); + + for(auto i = Render::Resources::RenderData.begin(); i != Render::Resources::RenderData.end(); i++ ) + { + RenderModel((*i).first,(*i).second->rid, (*i).second->Models); + } + Core::PipelineManager::SetRenderPass(Resources::Light::Pass); Core::deviceContext->Dispatch((UINT)((Core::resolution.x + 15U) / 16U), (UINT)((Core::resolution.y + 15U) / 16U), 1); diff --git a/Code/OysterGraphics/Render/Resources.cpp b/Code/OysterGraphics/Render/Resources.cpp index 2e693472..cced13e9 100644 --- a/Code/OysterGraphics/Render/Resources.cpp +++ b/Code/OysterGraphics/Render/Resources.cpp @@ -33,7 +33,8 @@ namespace Oyster ID3D11UnorderedAccessView* Resources::Blur::BufferUAV = {0}; ID3D11ShaderResourceView* Resources::Blur::BufferSRV = {0}; - Shader::RenderPass Resources::Gather::Pass; + Shader::RenderPass Resources::Gather::AnimatedPass; + Shader::RenderPass Resources::Gather::InstancedPass; Shader::RenderPass Resources::Light::Pass; Shader::RenderPass Resources::Post::Pass; Shader::RenderPass Resources::Gui::Pass; @@ -43,6 +44,7 @@ namespace Oyster Buffer Resources::Gather::ModelData = Buffer(); Buffer Resources::Gather::AnimationData = Buffer(); + Buffer Resources::Gather::InstancedData = Buffer(); Buffer Resources::Light::LightConstantsData = Buffer(); Buffer Resources::Gui::Data = Buffer(); Buffer Resources::Color = Buffer(); @@ -63,6 +65,8 @@ namespace Oyster ID3D11ShaderResourceView* Resources::Gui::Text::Font = NULL; ID3D11DepthStencilView* Resources::Gui::depth = NULL; + + std::map Resources::RenderData = std::map(); #pragma endregion @@ -76,8 +80,12 @@ namespace Oyster std::wstring end = L".cso"; #endif //Load Shaders - Core::PipelineManager::Init(path + L"GatherPixel" + end, ShaderType::Pixel, L"Gather"); - Core::PipelineManager::Init(path + L"GatherVertex" + end, ShaderType::Vertex, L"Gather"); + Core::PipelineManager::Init(path + L"GatherAnimPixel" + end, ShaderType::Pixel, L"AGather"); + Core::PipelineManager::Init(path + L"GatherAnimVertex" + end, ShaderType::Vertex, L"AGather"); + + + Core::PipelineManager::Init(path + L"GatherInstPixel" + end, ShaderType::Pixel, L"IGather"); + Core::PipelineManager::Init(path + L"GatherInstVertex" + end, ShaderType::Vertex, L"IGather"); #ifdef _DEBUG path = PathToHLSL+L"Light\\"; #endif @@ -151,6 +159,7 @@ namespace Oyster desc.NumElements = MAX_LETTER_COUNT; Gui::Text::Vertex.Init(desc); + return Core::Init::Success; } @@ -356,10 +365,11 @@ namespace Oyster { ////---------------- Geometry Pass Setup ---------------------------- - Gather::Pass.Shaders.Pixel = GetShader::Pixel(L"Gather"); - Gather::Pass.Shaders.Vertex = GetShader::Vertex(L"Gather"); +#pragma region Animated Pass + Gather::AnimatedPass.Shaders.Pixel = GetShader::Pixel(L"AGather"); + Gather::AnimatedPass.Shaders.Vertex = GetShader::Vertex(L"AGather"); - D3D11_INPUT_ELEMENT_DESC indesc[] = + D3D11_INPUT_ELEMENT_DESC AnimInDesc[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, @@ -368,20 +378,163 @@ namespace Oyster { "BONEWEIGHT", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 48, D3D11_INPUT_PER_VERTEX_DATA, 0 } }; - Shader::CreateInputLayout(indesc,5,GetShader::Vertex(L"Gather"),Gather::Pass.IAStage.Layout); - Gather::Pass.IAStage.Topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; - Gather::Pass.CBuffers.Vertex.push_back(Gather::AnimationData); - Gather::Pass.CBuffers.Vertex.push_back(Gather::ModelData); - Gather::Pass.CBuffers.Pixel.push_back(Color); - Gather::Pass.RenderStates.Rasterizer = RenderStates::rs; - Gather::Pass.RenderStates.SampleCount = 1; - Gather::Pass.RenderStates.SampleState = RenderStates::ss; - Gather::Pass.RenderStates.DepthStencil = RenderStates::dsState; + Shader::CreateInputLayout(AnimInDesc,5,GetShader::Vertex(L"AGather"),Gather::AnimatedPass.IAStage.Layout); + Gather::AnimatedPass.IAStage.Topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + Gather::AnimatedPass.CBuffers.Vertex.push_back(Gather::AnimationData); + Gather::AnimatedPass.CBuffers.Vertex.push_back(Gather::ModelData); + Gather::AnimatedPass.CBuffers.Pixel.push_back(Color); + Gather::AnimatedPass.RenderStates.Rasterizer = RenderStates::rs; + Gather::AnimatedPass.RenderStates.SampleCount = 1; + Gather::AnimatedPass.RenderStates.SampleState = RenderStates::ss; + Gather::AnimatedPass.RenderStates.DepthStencil = RenderStates::dsState; for(int i = 0; i RenderData; static const int GBufferSize = 3; static const int LBufferSize = 3; @@ -44,9 +54,11 @@ namespace Oyster struct Gather { - static Core::PipelineManager::RenderPass Pass; + static Core::PipelineManager::RenderPass AnimatedPass; + static Core::PipelineManager::RenderPass InstancedPass; static Core::Buffer ModelData; static Core::Buffer AnimationData; + static Core::Buffer InstancedData; }; struct Light diff --git a/Code/OysterGraphics/Shader/Passes/Gather/Header.hlsli b/Code/OysterGraphics/Shader/Passes/Gather/AnimHeader.hlsli similarity index 97% rename from Code/OysterGraphics/Shader/Passes/Gather/Header.hlsli rename to Code/OysterGraphics/Shader/Passes/Gather/AnimHeader.hlsli index 75a297bb..6f69bfca 100644 --- a/Code/OysterGraphics/Shader/Passes/Gather/Header.hlsli +++ b/Code/OysterGraphics/Shader/Passes/Gather/AnimHeader.hlsli @@ -1,4 +1,4 @@ -struct VertexIn +struct AnimVertexIn { float3 pos : POSITION; float2 UV : TEXCOORD; diff --git a/Code/OysterGraphics/Shader/Passes/Gather/GatherPixel.hlsl b/Code/OysterGraphics/Shader/Passes/Gather/GatherAnimPixel.hlsl similarity index 95% rename from Code/OysterGraphics/Shader/Passes/Gather/GatherPixel.hlsl rename to Code/OysterGraphics/Shader/Passes/Gather/GatherAnimPixel.hlsl index 11447238..dede36c2 100644 --- a/Code/OysterGraphics/Shader/Passes/Gather/GatherPixel.hlsl +++ b/Code/OysterGraphics/Shader/Passes/Gather/GatherAnimPixel.hlsl @@ -1,4 +1,4 @@ -#include "Header.hlsli" +#include "AnimHeader.hlsli" @@ -42,7 +42,7 @@ PixelOut main(VertexOut input) PixelOut output; float4 DiffGlow = Diffuse.Sample(S1, input.UV); float3 tint = Color*(1-DiffGlow.w) + GlowColor * DiffGlow.w; - tint = Color*(1-DiffGlow.w) + GlowColor * DiffGlow.w; + //tint = Color*(1-DiffGlow.w) + GlowColor * DiffGlow.w; output.DiffuseGlow = DiffGlow * float4(tint,1); //NORMALIZE diff --git a/Code/OysterGraphics/Shader/Passes/Gather/GatherVertex.hlsl b/Code/OysterGraphics/Shader/Passes/Gather/GatherAnimVertex.hlsl similarity index 90% rename from Code/OysterGraphics/Shader/Passes/Gather/GatherVertex.hlsl rename to Code/OysterGraphics/Shader/Passes/Gather/GatherAnimVertex.hlsl index 79c21eec..7e7a803f 100644 --- a/Code/OysterGraphics/Shader/Passes/Gather/GatherVertex.hlsl +++ b/Code/OysterGraphics/Shader/Passes/Gather/GatherAnimVertex.hlsl @@ -1,6 +1,6 @@ -#include "Header.hlsli" +#include "AnimHeader.hlsli" -VertexOut main( VertexIn input ) +VertexOut main( AnimVertexIn input ) { VertexOut output; diff --git a/Code/OysterGraphics/Shader/Passes/Gather/GatherInstPixel.hlsl b/Code/OysterGraphics/Shader/Passes/Gather/GatherInstPixel.hlsl new file mode 100644 index 00000000..72fce8c5 --- /dev/null +++ b/Code/OysterGraphics/Shader/Passes/Gather/GatherInstPixel.hlsl @@ -0,0 +1,63 @@ +#include "InstHeader.hlsli" + + + +float3x3 cotangent_frame( float3 N, float3 p, float2 uv ) +{ + // get edge vectors of the pixel triangle + float3 dp1 = ddx( p ); + float3 dp2 = ddy( p ); + float2 duv1 = ddx( uv ); + float2 duv2 = ddy( uv ); + + // solve the linear system + float3 dp2perp = cross( dp2, N ); + float3 dp1perp = cross( N, dp1 ); + float3 T = dp2perp * duv1.x + dp1perp * duv2.x; + float3 B = dp2perp * duv1.y + dp1perp * duv2.y; + + // construct a scale-invariant frame + float invmax = rsqrt( max( dot(T,T), dot(B,B) ) ); + return transpose(float3x3( T * invmax, B * invmax, N )); +} + +float3 perturb_normal( float3 N, float3 V, float2 texcoord ) +{ + // assume N, the interpolated vertex normal and + // V, the view vector (vertex to eye) + float3 map = Normal.Sample(S1,texcoord).xyz; + map = map * 255./127. - 128./127.; +#ifdef WITH_NORMALMAP_2CHANNEL + map.z = sqrt( 1. - dot( map.xy, map.xy ) ); +#endif +#ifdef WITH_NORMALMAP_GREEN_UP + map.y = -map.y; +#endif + float3x3 TBN = cotangent_frame( N, -V, texcoord ); + return normalize( mul(transpose(TBN), map) ); +} + +PixelOut main(VertexOut input) +{ + PixelOut output; + float4 DiffGlow = Diffuse.Sample(S1, input.UV); + float3 tint = input.tint * (1-DiffGlow.w) + input.gtint * DiffGlow.w; + //tint = Color*(1-DiffGlow.w) + GlowColor * DiffGlow.w; + output.DiffuseGlow = DiffGlow * float4(tint,1); + + //NORMALIZE + float3x3 CoTangentFrame = cotangent_frame(input.normal, normalize(input.ViewPos), input.UV); + + float3 map = Normal.Sample(S1,input.UV).xyz; + //map = normalize((map * 2) -1); + map = map * 255./127. - 128./127.; + //map = map * 255; + float3 normal = normalize(mul(CoTangentFrame, map)); + //normal = perturb_normal( normal, normalize(-input.ViewPos), input.UV ); + + output.NormalSpec = float4(normal, Normal.Sample(S1, input.UV).w*255); + + //output.NormalSpec = float4(input.normal, Normal.Sample(S1, input.UV).w * 0); + //output.NormalSpec = float4(map,0); + return output; +} \ No newline at end of file diff --git a/Code/OysterGraphics/Shader/Passes/Gather/GatherInstVertex.hlsl b/Code/OysterGraphics/Shader/Passes/Gather/GatherInstVertex.hlsl new file mode 100644 index 00000000..525ff982 --- /dev/null +++ b/Code/OysterGraphics/Shader/Passes/Gather/GatherInstVertex.hlsl @@ -0,0 +1,18 @@ +#include "InstHeader.hlsli" + +VertexOut main( InstVertexIn input ) +{ + VertexOut output; + + matrix WV = transpose(matrix(input.wv1, input.wv2, input.wv3, input.wv4)); + matrix WVP = transpose(matrix(input.wvp1, input.wvp2, input.wvp3, input.wvp4)); + + output.pos = mul(WVP, float4(input.pos,1)); + output.ViewPos = mul(WV, float4(input.pos,1)); + output.normal = mul(WV, float4(input.normal,0)).xyz; + output.UV = input.UV; + output.tint = input.Tint; + output.gtint = input.GlowTint; + + return output; +} \ No newline at end of file diff --git a/Code/OysterGraphics/Shader/Passes/Gather/InstHeader.hlsli b/Code/OysterGraphics/Shader/Passes/Gather/InstHeader.hlsli new file mode 100644 index 00000000..497374b4 --- /dev/null +++ b/Code/OysterGraphics/Shader/Passes/Gather/InstHeader.hlsli @@ -0,0 +1,44 @@ +struct InstVertexIn +{ + float3 pos : POSITION; + float2 UV : TEXCOORD; + float3 normal : NORMAL; + float4 boneIndex : BONEINDEX; + float4 boneWeight : BONEWEIGHT; + //instance Data + //WV MATRIX + float4 wv1 : WV0; + float4 wv2 : WV1; + float4 wv3 : WV2; + float4 wv4 : WV3; + + //WVP MATRIX + float4 wvp1 : WVP0; + float4 wvp2 : WVP1; + float4 wvp3 : WVP2; + float4 wvp4 : WVP3; + + float3 Tint : TINT; + float3 GlowTint : GTINT; +}; + +struct VertexOut +{ + float4 pos : SV_POSITION; + float4 ViewPos : POSITION; + float2 UV : TEXCOORD; + float3 normal : NORMAL; + float3 tint : TINT; + float3 gtint : GTINT; +}; + +struct PixelOut +{ + float4 DiffuseGlow : SV_TARGET0; + float4 NormalSpec : SV_TARGET1; +}; + +Texture2D Diffuse : register(t0); +Texture2D Normal : register(t1); + +SamplerState S1 : register(s0); \ No newline at end of file diff --git a/Code/OysterGraphics/Shader/Passes/Light/Defines.hlsli b/Code/OysterGraphics/Shader/Passes/Light/Defines.hlsli index adf01e9d..fb125b12 100644 --- a/Code/OysterGraphics/Shader/Passes/Light/Defines.hlsli +++ b/Code/OysterGraphics/Shader/Passes/Light/Defines.hlsli @@ -25,6 +25,16 @@ cbuffer LightConstants : register(b0) float4x4 View; } +struct FrustrumPoints +{ + float3 v0; + float3 v1; + float3 v2; + float3 v3; + float3 v4; + float3 v5; +}; + Texture2D DiffuseGlow : register(t0); Texture2D NormalSpec : register(t1); Texture2D GUI : register(t2); diff --git a/Code/OysterGraphics/Shader/Passes/Light/LightCalc.hlsli b/Code/OysterGraphics/Shader/Passes/Light/LightCalc.hlsli index 3dc2b45e..81fa2fa1 100644 --- a/Code/OysterGraphics/Shader/Passes/Light/LightCalc.hlsli +++ b/Code/OysterGraphics/Shader/Passes/Light/LightCalc.hlsli @@ -27,4 +27,9 @@ DiffSpec LightCalc(PointLight pl, float3 pos, int2 texCoord) float SpecCo = normalSpec.w < 1 ? 0.0f : 1.0f; output.Specular = output.Specular * SpecCo; return output; +} + +bool intersects(FrustrumPoints box, int Index) +{ + return true; } \ No newline at end of file diff --git a/Code/OysterGraphics/Shader/Passes/Light/LightPass.hlsl b/Code/OysterGraphics/Shader/Passes/Light/LightPass.hlsl index 89ed06d3..ddaed99e 100644 --- a/Code/OysterGraphics/Shader/Passes/Light/LightPass.hlsl +++ b/Code/OysterGraphics/Shader/Passes/Light/LightPass.hlsl @@ -8,13 +8,85 @@ //Calc Ambience Done //Write Glow +#define EXPAND 1024.0f +#define SHRINK 1.0f/EXPAND +#define UINT_MAX 0xFFFFFFFF +#define FLOAT_MAX 3.402823466e+38 +#define BLOCKSIZE 16 +#define NUMTHREADS BLOCKSIZE * BLOCKSIZE +#define MAXLIGHTS 100 -[numthreads(16, 16, 1)] -void main( uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID ) + +// -- Shared Memory ------------------------------------------------- // + +groupshared uint iMinDepth = UINT_MAX, + iMaxDepth = 0; +groupshared uint numVisiblePointLights = 0, + visiblePointlightIndex[MAXLIGHTS]; + +// ------------------------------------------------------------------ // + +[numthreads(BLOCKSIZE, BLOCKSIZE, 1)] +void main( uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID, uint3 Gid : SV_GroupID, uint GI : SV_GroupIndex ) { float2 UV = DTid.xy / Pixels; UV.x = UV.x * 2 - 1; UV.y = 1 - 2 * UV.y; + + float3 posN = float3(UV, DepthTexture[DTid.xy].x); + + // store and load shared minDepth and maxDepth + float minDepth = 0.0f, maxDepth = 0.0f, + depth = posN.z; + { + uint uidepth = (uint)( depth * EXPAND); + InterlockedMin( iMinDepth, uidepth ); + InterlockedMax( iMaxDepth, uidepth ); + + GroupMemoryBarrierWithGroupSync(); + minDepth = (float)( iMinDepth ) * SHRINK; + maxDepth = (float)( iMaxDepth ) * SHRINK; + } + + + // -- Switching to LightCulling ------------------------------------- // + + //define collision volume + float2 size = BLOCKSIZE / Pixels; + FrustrumPoints tile; + tile.v0 = float3(size * Gid,minDepth); + tile.v1 = float3(tile.v0.xy+size,maxDepth); + tile.v2 = float3(tile.v1.xy, minDepth); + tile.v3 = float3(tile.v0.x,tile.v1.y,minDepth); + tile.v4 = float3(tile.v1.x, tile.v0.y, minDepth); + tile.v5 = float3(tile.v0.xy, maxDepth); + + + + // culling the tile's near and far to minDepth & maxDepth ( with tolerance ) + + + uint numPass = (Lights + NUMTHREADS - 1) / NUMTHREADS; + numPass = min( numPass, MAXLIGHTS / NUMTHREADS ); + + for( uint passI = 0; passI < numPass; ++passI ) + { + uint lightIndex = (passI * NUMTHREADS) + GI; + lightIndex = min( lightIndex, Lights ); + + if( lightIndex < Lights ) + if( intersects(tile, lightIndex) ) + { + uint offset; + InterlockedAdd( numVisiblePointLights, 1, offset ); + visiblePointlightIndex[offset] = lightIndex; + } + } + + GroupMemoryBarrierWithGroupSync(); + + + float3 ViewPos = ToVpos(DTid.xy, UV); DiffSpec Shaded; Shaded.Diffuse = float3(0,0,0); @@ -47,7 +119,7 @@ void main( uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID ) DepthBase = DepthBase /4; Ambient[DTid.xy/2] = float4(DiffBase.xyz, AmbValue); Ambient[DTid.xy/2 + float2(Pixels.x/2, 0)] = GUI[DTid.xy]; - Ambient[DTid.xy/2 + float2(0, Pixels.y/2)] = float4(DiffBase.xyz * DiffBase.w /* * (2-DepthBase) */,DiffBase.w); + Ambient[DTid.xy/2 + float2(0, Pixels.y/2)] = float4(DiffBase.xyz * DiffBase.w ,DiffBase.w); Ambient[DTid.xy/2 + Pixels/2] = float4(NormalSpec[DTid.xy].xyz * float3(1,1,-1),1); } diff --git a/Code/Physics/GamePhysics/Implementation/PhysicsAPI_Impl.cpp b/Code/Physics/GamePhysics/Implementation/PhysicsAPI_Impl.cpp index df66bc12..b86f3821 100644 --- a/Code/Physics/GamePhysics/Implementation/PhysicsAPI_Impl.cpp +++ b/Code/Physics/GamePhysics/Implementation/PhysicsAPI_Impl.cpp @@ -287,10 +287,11 @@ void API_Impl::UpdateWorld() if(simpleBody->GetRigidBody()->getActivationState() == ACTIVE_TAG) { this->customBodies[i]->CallSubscription_Move(); - } + } + simpleBody->SetPreviousVelocity(simpleBody->GetLinearVelocity()); } - this->dynamicsWorld->stepSimulation(this->timeStep, 1, this->timeStep); + this->dynamicsWorld->stepSimulation(this->timeStep, 10, this->timeStep); ICustomBody::State state; @@ -312,9 +313,34 @@ void API_Impl::UpdateWorld() ICustomBody* bodyA = (ICustomBody*)obA->getUserPointer(); ICustomBody* bodyB = (ICustomBody*)obB->getUserPointer(); + + - bodyA->CallSubscription_AfterCollisionResponse(bodyA, bodyB, 0.0f); - bodyB->CallSubscription_AfterCollisionResponse(bodyB, bodyA, 0.0f); + int numContacts = contactManifold->getNumContacts(); + for (int j=0;jgetContactPoint(j); + if (pt.getDistance()<0.f) + { + if(bodyA->GetState().mass == 40 && bodyB->GetState().centerPos == Float3::null) + { + const char* breakPoint = "STOP"; + } + if(bodyB->GetState().mass == 40 && bodyA->GetState().centerPos == Float3::null) + { + const char* breakPoint = "STOP"; + } + + const btVector3& ptA = pt.getPositionWorldOnA(); + const btVector3& ptB = pt.getPositionWorldOnB(); + const btVector3& normalOnB = pt.m_normalWorldOnB; + + bodyA->CallSubscription_AfterCollisionResponse(bodyA, bodyB, 0.0f); + bodyB->CallSubscription_AfterCollisionResponse(bodyB, bodyA, 0.0f); + } + } + + } } diff --git a/Code/Physics/GamePhysics/Implementation/SimpleRigidBody.cpp b/Code/Physics/GamePhysics/Implementation/SimpleRigidBody.cpp index e2d87ce7..25c57e3b 100644 --- a/Code/Physics/GamePhysics/Implementation/SimpleRigidBody.cpp +++ b/Code/Physics/GamePhysics/Implementation/SimpleRigidBody.cpp @@ -22,6 +22,8 @@ SimpleRigidBody::SimpleRigidBody() this->state.restitutionCoeff = 0.0f; this->state.reach = Float3(0.0f, 0.0f, 0.0f); + this->collisionFlags = 0; + this->afterCollision = NULL; this->onMovement = NULL; @@ -85,7 +87,7 @@ void SimpleRigidBody::SetMotionState(btDefaultMotionState* motionState) void SimpleRigidBody::SetRigidBody(btRigidBody* rigidBody) { this->rigidBody = rigidBody; - + this->collisionFlags = rigidBody->getCollisionFlags(); } void SimpleRigidBody::SetSubscription(EventAction_AfterCollisionResponse function) @@ -421,5 +423,10 @@ void SimpleRigidBody::MoveToLimbo() void SimpleRigidBody::ReleaseFromLimbo() { - this->rigidBody->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); + this->rigidBody->setCollisionFlags(this->collisionFlags); +} + +void SimpleRigidBody::SetPreviousVelocity(::Oyster::Math::Float3 velocity) +{ + this->state.previousVelocity = velocity; } \ No newline at end of file diff --git a/Code/Physics/GamePhysics/Implementation/SimpleRigidBody.h b/Code/Physics/GamePhysics/Implementation/SimpleRigidBody.h index 4290b540..f3e7e0c6 100644 --- a/Code/Physics/GamePhysics/Implementation/SimpleRigidBody.h +++ b/Code/Physics/GamePhysics/Implementation/SimpleRigidBody.h @@ -64,6 +64,7 @@ namespace Oyster void SetCollisionShape(btCollisionShape* shape); void SetMotionState(btDefaultMotionState* motionState); void SetRigidBody(btRigidBody* rigidBody); + void SetPreviousVelocity(Math::Float3 velocity); void PreStep(const btCollisionWorld* collisionWorld); @@ -72,6 +73,8 @@ namespace Oyster void MoveToLimbo(); void ReleaseFromLimbo(); + + private: btCollisionShape* collisionShape; @@ -90,6 +93,8 @@ namespace Oyster btVector3 raySource[2]; btVector3 rayTarget[2]; btScalar rayLambda[2]; + + int collisionFlags; }; } } diff --git a/Code/Physics/GamePhysics/PhysicsStructs-Impl.h b/Code/Physics/GamePhysics/PhysicsStructs-Impl.h index 87cfcb17..56d5c4e8 100644 --- a/Code/Physics/GamePhysics/PhysicsStructs-Impl.h +++ b/Code/Physics/GamePhysics/PhysicsStructs-Impl.h @@ -10,7 +10,7 @@ namespace Oyster { namespace Struct { - inline CustomBodyState::CustomBodyState( ::Oyster::Math::Float mass, ::Oyster::Math::Float3 reach, ::Oyster::Math::Float restitutionCoeff, ::Oyster::Math::Float staticFrictionCoeff, ::Oyster::Math::Float dynamicFrictionCoeff, const ::Oyster::Math::Float3 ¢erPos, const ::Oyster::Math::Quaternion& quaternion) + inline CustomBodyState::CustomBodyState( ::Oyster::Math::Float mass, ::Oyster::Math::Float3 reach, ::Oyster::Math::Float restitutionCoeff, ::Oyster::Math::Float staticFrictionCoeff, ::Oyster::Math::Float dynamicFrictionCoeff, const ::Oyster::Math::Float3 ¢erPos, const ::Oyster::Math::Quaternion& quaternion, ::Oyster::Math::Float3 previousVelocity) { this->mass = mass; this->reach = reach; @@ -19,6 +19,7 @@ namespace Oyster this->dynamicFrictionCoeff = dynamicFrictionCoeff; this->centerPos = centerPos; this->quaternion = quaternion; + this->previousVelocity = ::Oyster::Math::Float3::null; } inline CustomBodyState & CustomBodyState::operator = ( const CustomBodyState &state ) @@ -30,6 +31,7 @@ namespace Oyster this->dynamicFrictionCoeff = state.dynamicFrictionCoeff; this->centerPos = state.centerPos; this->quaternion = state.quaternion; + this->previousVelocity = state.previousVelocity; return *this; } diff --git a/Code/Physics/GamePhysics/PhysicsStructs.h b/Code/Physics/GamePhysics/PhysicsStructs.h index 2f369b90..2ee7a59e 100644 --- a/Code/Physics/GamePhysics/PhysicsStructs.h +++ b/Code/Physics/GamePhysics/PhysicsStructs.h @@ -16,12 +16,13 @@ namespace Oyster public: // Default constructor CustomBodyState( ::Oyster::Math::Float mass = 1.0f, - ::Oyster::Math::Float3 reach = ::Oyster::Math::Float3(0,0,0), + ::Oyster::Math::Float3 reach = ::Oyster::Math::Float3::null, ::Oyster::Math::Float restitutionCoeff = 0.5f, ::Oyster::Math::Float staticFrictionCoeff = 1.0f, ::Oyster::Math::Float dynamicFrictionCoeff = 1.0f, const ::Oyster::Math::Float3 ¢erPos = ::Oyster::Math::Float3::null, - const ::Oyster::Math::Quaternion &quaternion = ::Oyster::Math::Quaternion(::Oyster::Math::Float3(0, 0, 0), 1)); + const ::Oyster::Math::Quaternion &quaternion = ::Oyster::Math::Quaternion(::Oyster::Math::Float3(0, 0, 0), 1), + ::Oyster::Math::Float3 previousVelocity = ::Oyster::Math::Float3::null); // Assignment operator CustomBodyState & operator = ( const CustomBodyState &state ); @@ -34,7 +35,7 @@ namespace Oyster // Variables for state ::Oyster::Math::Float mass, restitutionCoeff, staticFrictionCoeff, dynamicFrictionCoeff; - ::Oyster::Math::Float3 reach, centerPos; + ::Oyster::Math::Float3 reach, centerPos, previousVelocity; ::Oyster::Math::Quaternion quaternion; }; }