From 4af5f4db61ce613c603ffa03daa3b7c38f0858ae Mon Sep 17 00:00:00 2001 From: desktopgame Date: Mon, 16 Sep 2019 20:34:11 +0900 Subject: [PATCH 01/57] fix WindowsSDK version --- Chapter01/Game.vcxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Chapter01/Game.vcxproj b/Chapter01/Game.vcxproj index e16204f8..4570ce44 100644 --- a/Chapter01/Game.vcxproj +++ b/Chapter01/Game.vcxproj @@ -21,7 +21,7 @@ {BC508D87-495F-4554-932D-DD68388B63CC} Win32Proj Game - 10.0.16299.0 + 10.0.17763.0 From 3632702eb714715a63bf5c88abb47d49b3539a70 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Mon, 16 Sep 2019 20:35:09 +0900 Subject: [PATCH 02/57] fix WindowsSDK version --- Chapter02/Game.vcxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Chapter02/Game.vcxproj b/Chapter02/Game.vcxproj index 35c39009..9aded0fc 100644 --- a/Chapter02/Game.vcxproj +++ b/Chapter02/Game.vcxproj @@ -35,7 +35,7 @@ {BC508D87-495F-4554-932D-DD68388B63CC} Win32Proj Game - 10.0.16299.0 + 10.0.17763.0 From abe8d56b50a3536e9ed6ecdf2dc1788e562ffa43 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Mon, 16 Sep 2019 20:36:02 +0900 Subject: [PATCH 03/57] fix WindowsSDK version --- Chapter03/Game.vcxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Chapter03/Game.vcxproj b/Chapter03/Game.vcxproj index fd6197c8..ccc20a14 100644 --- a/Chapter03/Game.vcxproj +++ b/Chapter03/Game.vcxproj @@ -43,7 +43,7 @@ {BC508D87-495F-4554-932D-DD68388B63CC} Win32Proj Game - 10.0.16299.0 + 10.0.17763.0 From dca6763ab0e6197fd3c2816a794fda3c263224f3 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Mon, 16 Sep 2019 20:36:56 +0900 Subject: [PATCH 04/57] fix WindowsSDK version --- Chapter04/Game.vcxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Chapter04/Game.vcxproj b/Chapter04/Game.vcxproj index 27b091d3..0f5ec651 100644 --- a/Chapter04/Game.vcxproj +++ b/Chapter04/Game.vcxproj @@ -50,7 +50,7 @@ {BC508D87-495F-4554-932D-DD68388B63CC} Win32Proj Game - 10.0.16299.0 + 10.0.17763.0 From 0c6a283255bd6bfb38d9f1d1fc1e25e727bb3f14 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Mon, 16 Sep 2019 20:37:52 +0900 Subject: [PATCH 05/57] fix WindowsSDK version --- Chapter05/Game.vcxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Chapter05/Game.vcxproj b/Chapter05/Game.vcxproj index b0bd2f45..d2e1546d 100644 --- a/Chapter05/Game.vcxproj +++ b/Chapter05/Game.vcxproj @@ -56,7 +56,7 @@ {BC508D87-495F-4554-932D-DD68388B63CC} Win32Proj Game - 10.0.16299.0 + 10.0.17763.0 From 38295229b7f59230888be5a9d0ed56563420c52e Mon Sep 17 00:00:00 2001 From: desktopgame Date: Mon, 16 Sep 2019 20:39:02 +0900 Subject: [PATCH 06/57] fix WindowsSDK version --- Chapter06/Game.vcxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Chapter06/Game.vcxproj b/Chapter06/Game.vcxproj index ff861c40..aca4c760 100644 --- a/Chapter06/Game.vcxproj +++ b/Chapter06/Game.vcxproj @@ -57,7 +57,7 @@ {BC508D87-495F-4554-932D-DD68388B63CC} Win32Proj Game - 10.0.16299.0 + 10.0.17763.0 From b450c2520d1079d80103f4fa019ea0208561e909 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Mon, 16 Sep 2019 20:47:48 +0900 Subject: [PATCH 07/57] fix WindowsSDK version --- Chapter07/Game.vcxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Chapter07/Game.vcxproj b/Chapter07/Game.vcxproj index e14fa8e5..36cd9aa1 100644 --- a/Chapter07/Game.vcxproj +++ b/Chapter07/Game.vcxproj @@ -63,7 +63,7 @@ {BC508D87-495F-4554-932D-DD68388B63CC} Win32Proj Game - 10.0.16299.0 + 10.0.17763.0 From ad953142bf8be1857a4472d58eb2ba0b268bc09a Mon Sep 17 00:00:00 2001 From: desktopgame Date: Mon, 16 Sep 2019 20:50:05 +0900 Subject: [PATCH 08/57] fix WindowsSDK version --- Chapter08/Game.vcxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Chapter08/Game.vcxproj b/Chapter08/Game.vcxproj index 5ab5ac24..96269189 100644 --- a/Chapter08/Game.vcxproj +++ b/Chapter08/Game.vcxproj @@ -58,7 +58,7 @@ {BC508D87-495F-4554-932D-DD68388B63CC} Win32Proj Game - 10.0.16299.0 + 10.0.17763.0 From 8682a4c4142c8cb03ba8de707c7706366383ab61 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Mon, 16 Sep 2019 20:51:29 +0900 Subject: [PATCH 09/57] fix WindowsSDK version --- Chapter09/Game.vcxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Chapter09/Game.vcxproj b/Chapter09/Game.vcxproj index ed68601d..05712db3 100644 --- a/Chapter09/Game.vcxproj +++ b/Chapter09/Game.vcxproj @@ -79,7 +79,7 @@ {BC508D87-495F-4554-932D-DD68388B63CC} Win32Proj Game - 10.0.16299.0 + 10.0.17763.0 From 62a785fb200229e1e3224a2cab5c6c8606af12b3 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Mon, 16 Sep 2019 20:53:11 +0900 Subject: [PATCH 10/57] fix WindowsSDK version --- Chapter10/Game.vcxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Chapter10/Game.vcxproj b/Chapter10/Game.vcxproj index e0ee7f3f..685fb39b 100644 --- a/Chapter10/Game.vcxproj +++ b/Chapter10/Game.vcxproj @@ -77,7 +77,7 @@ {BC508D87-495F-4554-932D-DD68388B63CC} Win32Proj Game - 10.0.16299.0 + 10.0.17763.0 From 094922e747b1ab7d6d332fb12fa4e1474bacabfb Mon Sep 17 00:00:00 2001 From: desktopgame Date: Mon, 16 Sep 2019 20:55:06 +0900 Subject: [PATCH 11/57] fix WindowsSDK version --- Chapter11/Game.vcxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Chapter11/Game.vcxproj b/Chapter11/Game.vcxproj index a49ef091..e3284cb3 100644 --- a/Chapter11/Game.vcxproj +++ b/Chapter11/Game.vcxproj @@ -89,7 +89,7 @@ {BC508D87-495F-4554-932D-DD68388B63CC} Win32Proj Game - 10.0.16299.0 + 10.0.17763.0 From f167fb74b8367a60ea724ade35835cb3421416c6 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Mon, 16 Sep 2019 20:56:38 +0900 Subject: [PATCH 12/57] fix WindowsSDK version --- Chapter12/Game.vcxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Chapter12/Game.vcxproj b/Chapter12/Game.vcxproj index 5ddbc62f..9fb179d5 100644 --- a/Chapter12/Game.vcxproj +++ b/Chapter12/Game.vcxproj @@ -98,7 +98,7 @@ {BC508D87-495F-4554-932D-DD68388B63CC} Win32Proj Game - 10.0.16299.0 + 10.0.17763.0 From 288e4e53e96a2f0e5975e9a367ee38f258688869 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Mon, 16 Sep 2019 20:58:15 +0900 Subject: [PATCH 13/57] fix WindowsSDK version --- Chapter13/Game.vcxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Chapter13/Game.vcxproj b/Chapter13/Game.vcxproj index aa3d84a1..1e5058d7 100644 --- a/Chapter13/Game.vcxproj +++ b/Chapter13/Game.vcxproj @@ -109,7 +109,7 @@ {BC508D87-495F-4554-932D-DD68388B63CC} Win32Proj Game - 10.0.16299.0 + 10.0.17763.0 From ef3851a1ba7f165390e7b882592b57e24411c5cf Mon Sep 17 00:00:00 2001 From: desktopgame Date: Mon, 16 Sep 2019 20:59:58 +0900 Subject: [PATCH 14/57] fix WindowsSDK version --- Chapter14/Game.vcxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Chapter14/Game.vcxproj b/Chapter14/Game.vcxproj index aef575d9..4281a08d 100644 --- a/Chapter14/Game.vcxproj +++ b/Chapter14/Game.vcxproj @@ -111,7 +111,7 @@ {BC508D87-495F-4554-932D-DD68388B63CC} Win32Proj Game - 10.0.16299.0 + 10.0.17763.0 From aaf5a1443ea89b80fa5b7ab451d96e724c92e60a Mon Sep 17 00:00:00 2001 From: desktopgame Date: Sat, 21 Sep 2019 14:15:06 +0900 Subject: [PATCH 15/57] add comment --- Chapter01/Game.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Chapter01/Game.cpp b/Chapter01/Game.cpp index 3b18199e..ab0da13f 100644 --- a/Chapter01/Game.cpp +++ b/Chapter01/Game.cpp @@ -167,27 +167,38 @@ void Game::UpdateGame() mBallVel.x *= -1.0f; } // Did the ball go off the screen? (if so, end game) + // 左の壁に当たった(プレイヤーの負け) else if (mBallPos.x <= 0.0f) { mIsRunning = false; } // Did the ball collide with the right wall? + // ボールが右に加速していて、ボールが右の壁に当たった else if (mBallPos.x >= (1024.0f - thickness) && mBallVel.x > 0.0f) { mBallVel.x *= -1.0f; } // Did the ball collide with the top wall? + // ボールが上に加速していて、ボールが上の壁に当たった if (mBallPos.y <= thickness && mBallVel.y < 0.0f) { mBallVel.y *= -1; } // Did the ball collide with the bottom wall? + // ボールが下に加速していて、ボールが下の壁に当たった else if (mBallPos.y >= (768 - thickness) && mBallVel.y > 0.0f) { mBallVel.y *= -1; } + /* + mBollPos.y ボールの上 + -y 上 + +y 下 + -x 左 + +x 右 + */ } void Game::GenerateOutput() From 2ff419df98959a78b451d42bdd04a2362cf1c3b4 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Sat, 21 Sep 2019 14:36:22 +0900 Subject: [PATCH 16/57] change object size --- Chapter01/Game.cpp | 45 ++++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/Chapter01/Game.cpp b/Chapter01/Game.cpp index ab0da13f..7ed548ba 100644 --- a/Chapter01/Game.cpp +++ b/Chapter01/Game.cpp @@ -8,7 +8,10 @@ #include "Game.h" -const int thickness = 15; +const float ballW = 30.0f; +const float ballH = 30.0f; +const float wallH = 15.0f; +const float paddleW = 25.0f; const float paddleH = 100.0f; Game::Game() @@ -137,13 +140,13 @@ void Game::UpdateGame() { mPaddlePos.y += mPaddleDir * 300.0f * deltaTime; // Make sure paddle doesn't move off screen! - if (mPaddlePos.y < (paddleH/2.0f + thickness)) + if (mPaddlePos.y < (paddleH/2.0f + wallH)) { - mPaddlePos.y = paddleH/2.0f + thickness; + mPaddlePos.y = paddleH/2.0f + wallH; } - else if (mPaddlePos.y > (768.0f - paddleH/2.0f - thickness)) + else if (mPaddlePos.y > (768.0f - paddleH/2.0f - wallH)) { - mPaddlePos.y = 768.0f - paddleH/2.0f - thickness; + mPaddlePos.y = 768.0f - paddleH/2.0f - wallH; } } @@ -160,7 +163,7 @@ void Game::UpdateGame() // Our y-difference is small enough diff <= paddleH / 2.0f && // We are in the correct x-position - mBallPos.x <= 25.0f && mBallPos.x >= 20.0f && + mBallPos.x - (ballW / 2.0f) <= mPaddlePos.x + paddleW && // The ball is moving to the left mBallVel.x < 0.0f) { @@ -174,20 +177,20 @@ void Game::UpdateGame() } // Did the ball collide with the right wall? // ボールが右に加速していて、ボールが右の壁に当たった - else if (mBallPos.x >= (1024.0f - thickness) && mBallVel.x > 0.0f) + else if (mBallPos.x + ballW >= 1024.0f && mBallVel.x > 0.0f) { mBallVel.x *= -1.0f; } // Did the ball collide with the top wall? // ボールが上に加速していて、ボールが上の壁に当たった - if (mBallPos.y <= thickness && mBallVel.y < 0.0f) + if (mBallPos.y - (ballH / 2) <= wallH && mBallVel.y < 0.0f) { mBallVel.y *= -1; } // Did the ball collide with the bottom wall? // ボールが下に加速していて、ボールが下の壁に当たった - else if (mBallPos.y >= (768 - thickness) && + else if (mBallPos.y + ballH >= 768 && mBallVel.y > 0.0f) { mBallVel.y *= -1; @@ -220,21 +223,21 @@ void Game::GenerateOutput() // Draw top wall SDL_Rect wall{ - 0, // Top left x - 0, // Top left y - 1024, // Width - thickness // Height + 0, // Top left x + 0, // Top left y + 1024, // Width + static_cast(wallH) // Height }; SDL_RenderFillRect(mRenderer, &wall); // Draw bottom wall - wall.y = 768 - thickness; + wall.y = 768 - static_cast(wallH); SDL_RenderFillRect(mRenderer, &wall); // Draw right wall - wall.x = 1024 - thickness; + wall.x = 1024 - static_cast(wallH); wall.y = 0; - wall.w = thickness; + wall.w = wallH; wall.h = 1024; SDL_RenderFillRect(mRenderer, &wall); @@ -242,17 +245,17 @@ void Game::GenerateOutput() SDL_Rect paddle{ static_cast(mPaddlePos.x), static_cast(mPaddlePos.y - paddleH/2), - thickness, + static_cast(paddleW), static_cast(paddleH) }; SDL_RenderFillRect(mRenderer, &paddle); // Draw ball SDL_Rect ball{ - static_cast(mBallPos.x - thickness/2), - static_cast(mBallPos.y - thickness/2), - thickness, - thickness + static_cast(mBallPos.x - ballW /2), + static_cast(mBallPos.y - ballH/2), + static_cast(ballW), + static_cast(ballH) }; SDL_RenderFillRect(mRenderer, &ball); From 4ded4e8921b6335eeee50df91c998f15986f7064 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Sat, 21 Sep 2019 18:41:25 +0900 Subject: [PATCH 17/57] add TileMapComponent --- Chapter02/CSV.h | 129 +++++++++++++++++++++++++++++++++ Chapter02/Game.cpp | 20 +++++ Chapter02/Game.vcxproj | 5 ++ Chapter02/Game.vcxproj.filters | 15 ++++ Chapter02/TileMapComponent.cpp | 60 +++++++++++++++ Chapter02/TileMapComponent.h | 14 ++++ Chapter02/TileMapTexture.cpp | 29 ++++++++ Chapter02/TileMapTexture.h | 20 +++++ 8 files changed, 292 insertions(+) create mode 100644 Chapter02/CSV.h create mode 100644 Chapter02/TileMapComponent.cpp create mode 100644 Chapter02/TileMapComponent.h create mode 100644 Chapter02/TileMapTexture.cpp create mode 100644 Chapter02/TileMapTexture.h diff --git a/Chapter02/CSV.h b/Chapter02/CSV.h new file mode 100644 index 00000000..62866395 --- /dev/null +++ b/Chapter02/CSV.h @@ -0,0 +1,129 @@ +#pragma once +#include +#include +#include +#include +#include + +template +class CSVRow { +public: + explicit CSVRow(); + + void AddElement(const T& elem); + void RemoveElement(int index); + const T& GetElementAt(int index) const; + size_t Count() const; +private: + std::vector elements; +}; + +template +class CSV { +public: + explicit CSV(); + void AddRow(const CSVRow& row); + void RemoveRow(int index); + const CSVRow& GetRowAt(int index) const; + size_t Count() const; +private: + std::vector > rows; +}; + +template +CSV readCSV(const std::string& filename, std::function func); + +template +CSV readCSV(const char* filename, std::function func); + + +// CSVRow +template +inline CSVRow::CSVRow() : elements() { +} + +template +inline void CSVRow::AddElement(const T & elem) { + elements.emplace_back(elem); +} + +template +inline void CSVRow::RemoveElement(int index) { + elements.erase(elements.begin() + index); +} + +template +inline const T & CSVRow::GetElementAt(int index) const { + return elements.at(index); +} + +template +inline size_t CSVRow::Count() const { + return elements.size(); +} + +// CSV +template +inline CSV::CSV() : rows() { +} + +template +inline void CSV::AddRow(const CSVRow& row) { + rows.emplace_back(row); +} + +template +inline void CSV::RemoveRow(int index) { + rows.erase(rows.begin() + index); +} + +template +inline const CSVRow& CSV::GetRowAt(int index) const { + return rows.at(index); +} + +template +inline size_t CSV::Count() const { + return rows.size(); +} + +// Function +template +inline CSV readCSV(const std::string & filename, std::function func) { + std::ifstream ifs(filename); + if (ifs.fail()) { + throw std::logic_error(filename + " is not found"); + } + CSV ret; + std::string line; + std::stringstream buf; + int width = 0; + while (getline(ifs, line)) { + buf.str(""); + buf.clear(std::stringstream::goodbit); + CSVRow row; + for (int i = 0; i < line.size(); i++) { + char c = line.at(i); + if (c == ',') { + T data = func(buf.str()); + row.AddElement(data); + buf.str(""); + buf.clear(std::stringstream::goodbit); + } else { + buf << c; + } + } + if (width == 0) { + width = row.Count(); + } else if (width != row.Count()) { + throw std::logic_error("invalid row: " + line); + } + ret.AddRow(row); + } + return ret; +} + +template +inline CSV readCSV(const char * filename, std::function func) { + return readCSV(std::string(filename), func); +} diff --git a/Chapter02/Game.cpp b/Chapter02/Game.cpp index 2bf0af03..ed630261 100644 --- a/Chapter02/Game.cpp +++ b/Chapter02/Game.cpp @@ -13,6 +13,7 @@ #include "SpriteComponent.h" #include "Ship.h" #include "BGSpriteComponent.h" +#include "TileMapComponent.h" Game::Game() :mWindow(nullptr) @@ -179,6 +180,25 @@ void Game::LoadData() }; bg->SetBGTextures(bgtexs); bg->SetScrollSpeed(-200.0f); + // タイルマップ読み込み + CSV layer1 = readCSV("Assets/MapLayer1.csv", [](const std::string& e) -> int { + return std::stoi(e); + }); + CSV layer2 = readCSV("Assets/MapLayer2.csv", [](const std::string& e) -> int { + return std::stoi(e); + }); + CSV layer3 = readCSV("Assets/MapLayer3.csv", [](const std::string& e) -> int { + return std::stoi(e); + }); + TileMapTexture tilemapTexture(24,8); + tilemapTexture.AddLayer(layer3); + tilemapTexture.AddLayer(layer2); + tilemapTexture.AddLayer(layer1); + temp = new Actor(this); + TileMapComponent* tilemapComp = new TileMapComponent(temp, tilemapTexture, 99); + tilemapComp->SetTexture(GetTexture("Assets/Tiles.png")); + + } void Game::UnloadData() diff --git a/Chapter02/Game.vcxproj b/Chapter02/Game.vcxproj index 9aded0fc..38c43e0d 100644 --- a/Chapter02/Game.vcxproj +++ b/Chapter02/Game.vcxproj @@ -20,16 +20,21 @@ + + + + + {BC508D87-495F-4554-932D-DD68388B63CC} diff --git a/Chapter02/Game.vcxproj.filters b/Chapter02/Game.vcxproj.filters index 760534ef..4a6301ab 100644 --- a/Chapter02/Game.vcxproj.filters +++ b/Chapter02/Game.vcxproj.filters @@ -34,6 +34,12 @@ Source Files + + Source Files + + + Source Files + @@ -60,5 +66,14 @@ Source Files + + Source Files + + + Source Files + + + Source Files + \ No newline at end of file diff --git a/Chapter02/TileMapComponent.cpp b/Chapter02/TileMapComponent.cpp new file mode 100644 index 00000000..3c0cf70b --- /dev/null +++ b/Chapter02/TileMapComponent.cpp @@ -0,0 +1,60 @@ +#include "TileMapComponent.h" +#include "Actor.h" + +TileMapComponent::TileMapComponent(Actor * owner, const TileMapTexture& tilemapTexture, int drawOrder) +: SpriteComponent(owner, drawOrder), tilemapTexture(tilemapTexture) { +} + +void TileMapComponent::Draw(SDL_Renderer * renderer) { + int tw = GetTexWidth(); + int th = GetTexHeight(); + int cw = tw / tilemapTexture.GetColumnCount(); + int ch = th / tilemapTexture.GetRowCount(); + int x = 0; + int y = 0; + for (int i = 0; i < tilemapTexture.GetLayerCount(); i++) { + const CSV& csv = tilemapTexture.GetLayer(i); + x = 0; + y = 0; + for (int j = 0; j < csv.Count(); j++) { + const CSVRow row = csv.GetRowAt(j); + for (int k = 0; k < row.Count(); k++) { + int index = row.GetElementAt(k); + drawCell(renderer, index, x, y, cw, ch); + x += cw; + } + y += ch; + x = 0; + } + } +} + +void TileMapComponent::SetTileMapTexture(const TileMapTexture & tilemapTexture) { + this->tilemapTexture = tilemapTexture; +} + +void TileMapComponent::drawCell(SDL_Renderer* renderer, int index, int x, int y, int cw, int ch) { + if (index == -1) { + return; + } + SDL_Rect r; + r.x = x; + r.y = y; + r.w = cw; + r.h = ch; + + SDL_Rect srcrect; + srcrect.w = cw; + srcrect.h = ch; + srcrect.x = (index % tilemapTexture.GetColumnCount()) * cw; + srcrect.y = (index / tilemapTexture.GetColumnCount()) * ch; + + // Draw (have to convert angle from radians to degrees, and clockwise to counter) + SDL_RenderCopyEx(renderer, + mTexture, + &srcrect, + &r, + -Math::ToDegrees(mOwner->GetRotation()), + nullptr, + SDL_FLIP_NONE); +} diff --git a/Chapter02/TileMapComponent.h b/Chapter02/TileMapComponent.h new file mode 100644 index 00000000..159e7514 --- /dev/null +++ b/Chapter02/TileMapComponent.h @@ -0,0 +1,14 @@ +#pragma once +#include "SpriteComponent.h" +#include "TileMapTexture.h" + +class TileMapComponent : public SpriteComponent { +public: + TileMapComponent(class Actor* owner, const TileMapTexture& tilemapTexture, int drawOrder = 100); + + void Draw(SDL_Renderer* renderer) override; + void SetTileMapTexture(const TileMapTexture& tilemapTexture); +private: + void drawCell(SDL_Renderer* renderer, int index, int x, int y, int cw, int ch); + TileMapTexture tilemapTexture; +}; \ No newline at end of file diff --git a/Chapter02/TileMapTexture.cpp b/Chapter02/TileMapTexture.cpp new file mode 100644 index 00000000..c03ea12b --- /dev/null +++ b/Chapter02/TileMapTexture.cpp @@ -0,0 +1,29 @@ +#include "TileMapTexture.h" + +TileMapTexture::TileMapTexture(int rowCount, int columnCount) + : layers(), rowCount(rowCount), columnCount(columnCount) { +} + +void TileMapTexture::AddLayer(const CSV& layer) { + layers.emplace_back(layer); +} + +void TileMapTexture::RemoveLayer(int index) { + layers.erase(layers.begin() + index); +} + +const CSV& TileMapTexture::GetLayer(int index) const { + return layers.at(index); +} + +size_t TileMapTexture::GetLayerCount() const { + return layers.size(); +} + +int TileMapTexture::GetRowCount() const { + return rowCount; +} + +int TileMapTexture::GetColumnCount() const { + return columnCount; +} diff --git a/Chapter02/TileMapTexture.h b/Chapter02/TileMapTexture.h new file mode 100644 index 00000000..5206fe37 --- /dev/null +++ b/Chapter02/TileMapTexture.h @@ -0,0 +1,20 @@ +#pragma once +#include "SDL/SDL.h" +#include +#include "CSV.h" + +class TileMapTexture { +public: + explicit TileMapTexture(int rowCount, int columnCount); + void AddLayer(const CSV& layer); + void RemoveLayer(int index); + const CSV& GetLayer(int index) const; + size_t GetLayerCount() const; + + int GetRowCount() const; + int GetColumnCount() const; +private: + int rowCount; + int columnCount; + std::vector > layers; +}; \ No newline at end of file From f6333a88e7ecd241e8cd48fb3e12cb08370b7474 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Sat, 21 Sep 2019 18:43:47 +0900 Subject: [PATCH 18/57] fix CSV --- Chapter02/CSV.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Chapter02/CSV.h b/Chapter02/CSV.h index 62866395..e3cf3408 100644 --- a/Chapter02/CSV.h +++ b/Chapter02/CSV.h @@ -113,6 +113,10 @@ inline CSV readCSV(const std::string & filename, std::function 0) { + row.AddElement(func(buf.str())); + } if (width == 0) { width = row.Count(); } else if (width != row.Count()) { From 45431627376bae8081d646da7e2fd80c767c8389 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Sun, 22 Sep 2019 13:28:34 +0900 Subject: [PATCH 19/57] implement respawn system --- Chapter03/Game.cpp | 2 ++ Chapter03/Ship.cpp | 60 ++++++++++++++++++++++++++++++++++++++++++++-- Chapter03/Ship.h | 13 ++++++++++ 3 files changed, 73 insertions(+), 2 deletions(-) diff --git a/Chapter03/Game.cpp b/Chapter03/Game.cpp index ed758b2a..21a63bf2 100644 --- a/Chapter03/Game.cpp +++ b/Chapter03/Game.cpp @@ -164,6 +164,8 @@ void Game::LoadData() mShip = new Ship(this); mShip->SetPosition(Vector2(512.0f, 384.0f)); mShip->SetRotation(Math::PiOver2); + mShip->SetRespawnPosition(Vector2(512.0f, 384.0f)); + mShip->SetRespawnRotation(Math::PiOver2); // Create asteroids const int numAsteroids = 20; diff --git a/Chapter03/Ship.cpp b/Chapter03/Ship.cpp index e5b236db..2fbded58 100644 --- a/Chapter03/Ship.cpp +++ b/Chapter03/Ship.cpp @@ -11,14 +11,19 @@ #include "InputComponent.h" #include "Game.h" #include "Laser.h" +#include "CircleComponent.h" +#include "Asteroid.h" Ship::Ship(Game* game) :Actor(game) ,mLaserCooldown(0.0f) + ,mElapsed(0.0f) + ,mIsDead(false) + ,mDeadTime(0.0f) { // Create a sprite component - SpriteComponent* sc = new SpriteComponent(this, 150); - sc->SetTexture(game->GetTexture("Assets/Ship.png")); + this->mSprite = new SpriteComponent(this, 150); + mSprite->SetTexture(game->GetTexture("Assets/Ship.png")); // Create an input component and set keys/speed InputComponent* ic = new InputComponent(this); @@ -28,15 +33,50 @@ Ship::Ship(Game* game) ic->SetCounterClockwiseKey(SDL_SCANCODE_D); ic->SetMaxForwardSpeed(300.0f); ic->SetMaxAngularSpeed(Math::TwoPi); + + this->mCircle = new CircleComponent(this); + mCircle->SetRadius(32.0f); } void Ship::UpdateActor(float deltaTime) { + if (mIsDead) { + mDeadTime += deltaTime; + if (mDeadTime > 1.0f) { + mSprite->SetTexture(GetGame()->GetTexture("Assets/Ship.png")); + SetPosition(GetRespawnPosition()); + SetRotation(GetRespawnRotation()); + this->mIsDead = false; + } + return; + } mLaserCooldown -= deltaTime; + if (mElapsed < 1.0f) { + this->mElapsed += deltaTime; + return; + } + // Do we intersect with an asteroid? + for (auto ast : GetGame()->GetAsteroids()) + { + if (Intersect(*mCircle, *(ast->GetCircle()))) + { + // The first asteroid we intersect with, + // set ourselves and the asteroid to dead + mSprite->SetTexture(nullptr); + ast->SetState(EDead); + this->mElapsed = 0.0f; + this->mDeadTime = 0.0f; + this->mIsDead = true; + break; + } + } } void Ship::ActorInput(const uint8_t* keyState) { + if (mIsDead) { + return; + } if (keyState[SDL_SCANCODE_SPACE] && mLaserCooldown <= 0.0f) { // Create a laser and set its position/rotation to mine @@ -48,3 +88,19 @@ void Ship::ActorInput(const uint8_t* keyState) mLaserCooldown = 0.5f; } } + +void Ship::SetRespawnPosition(const Vector2 respawnPosition) { + this->mRespawnPosition = respawnPosition; +} + +Vector2 Ship::GetRespawnPosition() const { + return mRespawnPosition; +} + +void Ship::SetRespawnRotation(const float rotation) { + this->mRespawnRotation = rotation; +} + +float Ship::GetRespawnRotation() const { + return mRespawnRotation; +} diff --git a/Chapter03/Ship.h b/Chapter03/Ship.h index 808639ff..642b16eb 100644 --- a/Chapter03/Ship.h +++ b/Chapter03/Ship.h @@ -15,6 +15,19 @@ class Ship : public Actor void UpdateActor(float deltaTime) override; void ActorInput(const uint8_t* keyState) override; + + void SetRespawnPosition(const Vector2 respawnPosition); + Vector2 GetRespawnPosition() const; + + void SetRespawnRotation(const float rotation); + float GetRespawnRotation() const; private: + float mElapsed; float mLaserCooldown; + bool mIsDead; + float mDeadTime; + Vector2 mRespawnPosition; + float mRespawnRotation; + class SpriteComponent* mSprite; + class CircleComponent* mCircle; }; \ No newline at end of file From 34d7beb43c02211cfe78bad05721959b8078ef7d Mon Sep 17 00:00:00 2001 From: desktopgame Date: Sun, 22 Sep 2019 14:03:24 +0900 Subject: [PATCH 20/57] update physics system --- Chapter03/Asteroid.cpp | 8 ++++++-- Chapter03/Asteroid.h | 2 ++ Chapter03/InputComponent.cpp | 1 + Chapter03/Laser.cpp | 6 ++++-- Chapter03/Laser.h | 1 + Chapter03/MoveComponent.cpp | 36 +++++++++++++++++++++++++++++++++++- Chapter03/MoveComponent.h | 13 +++++++++++++ 7 files changed, 62 insertions(+), 5 deletions(-) diff --git a/Chapter03/Asteroid.cpp b/Chapter03/Asteroid.cpp index c1dddb9e..5081444c 100644 --- a/Chapter03/Asteroid.cpp +++ b/Chapter03/Asteroid.cpp @@ -29,8 +29,8 @@ Asteroid::Asteroid(Game* game) sc->SetTexture(game->GetTexture("Assets/Asteroid.png")); // Create a move component, and set a forward speed - MoveComponent* mc = new MoveComponent(this); - mc->SetForwardSpeed(150.0f); + this->mMove = new MoveComponent(this); + mMove->SetForwardSpeed(150.0f); // Create a circle component (for collision) mCircle = new CircleComponent(this); @@ -44,3 +44,7 @@ Asteroid::~Asteroid() { GetGame()->RemoveAsteroid(this); } + +void Asteroid::UpdateActor(float deltaTime) { + mMove->AddForce(GetForward() * mMove->GetForwardSpeed()); +} diff --git a/Chapter03/Asteroid.h b/Chapter03/Asteroid.h index 45305770..0b0ccdfe 100644 --- a/Chapter03/Asteroid.h +++ b/Chapter03/Asteroid.h @@ -13,8 +13,10 @@ class Asteroid : public Actor public: Asteroid(class Game* game); ~Asteroid(); + void UpdateActor(float deltaTime); class CircleComponent* GetCircle() { return mCircle; } private: + class MoveComponent* mMove; class CircleComponent* mCircle; }; diff --git a/Chapter03/InputComponent.cpp b/Chapter03/InputComponent.cpp index 148ffc95..411b8b9e 100644 --- a/Chapter03/InputComponent.cpp +++ b/Chapter03/InputComponent.cpp @@ -32,6 +32,7 @@ void InputComponent::ProcessInput(const uint8_t* keyState) forwardSpeed -= mMaxForwardSpeed; } SetForwardSpeed(forwardSpeed); + AddForce(mOwner->GetForward() * forwardSpeed); // Calculate angular speed for MoveComponent float angularSpeed = 0.0f; diff --git a/Chapter03/Laser.cpp b/Chapter03/Laser.cpp index a03c1981..b63b0835 100644 --- a/Chapter03/Laser.cpp +++ b/Chapter03/Laser.cpp @@ -22,8 +22,9 @@ Laser::Laser(Game* game) sc->SetTexture(game->GetTexture("Assets/Laser.png")); // Create a move component, and set a forward speed - MoveComponent* mc = new MoveComponent(this); - mc->SetForwardSpeed(800.0f); + this->mMove = new MoveComponent(this); + mMove->SetForwardSpeed(800.0f); + mMove->SetMass(0.02f); // Create a circle component (for collision) mCircle = new CircleComponent(this); @@ -40,6 +41,7 @@ void Laser::UpdateActor(float deltaTime) } else { + mMove->AddForce(GetForward() * mMove->GetForwardSpeed()); // Do we intersect with an asteroid? for (auto ast : GetGame()->GetAsteroids()) { diff --git a/Chapter03/Laser.h b/Chapter03/Laser.h index f1afd638..6a89c36d 100644 --- a/Chapter03/Laser.h +++ b/Chapter03/Laser.h @@ -15,6 +15,7 @@ class Laser : public Actor void UpdateActor(float deltaTime) override; private: + class MoveComponent* mMove; class CircleComponent* mCircle; float mDeathTimer; }; diff --git a/Chapter03/MoveComponent.cpp b/Chapter03/MoveComponent.cpp index 2f0b8a6a..6fb52a8d 100644 --- a/Chapter03/MoveComponent.cpp +++ b/Chapter03/MoveComponent.cpp @@ -13,6 +13,9 @@ MoveComponent::MoveComponent(class Actor* owner, int updateOrder) :Component(owner, updateOrder) ,mAngularSpeed(0.0f) ,mForwardSpeed(0.0f) +,mForce(0.0f, 0.0f) +,mMass(0.1f) +,mVelocity(0.0f, 0.0f) { } @@ -28,9 +31,20 @@ void MoveComponent::Update(float deltaTime) if (!Math::NearZero(mForwardSpeed)) { + Vector2 pos = mOwner->GetPosition(); + // compute accel from sum of forces + Vector2 accel(mForce.x / mMass, mForce.y / mMass); + // compute velocity from accel + this->mVelocity = accel * deltaTime; + // compute position from velocity + pos += mVelocity * deltaTime; + this->mForce = Vector2(0.0f, 0.0f); + /* + Oridinal Code: Vector2 pos = mOwner->GetPosition(); pos += mOwner->GetForward() * mForwardSpeed * deltaTime; - + */ + // (Screen wrapping code only for asteroids) if (pos.x < 0.0f) { pos.x = 1022.0f; } else if (pos.x > 1024.0f) { pos.x = 2.0f; } @@ -41,3 +55,23 @@ void MoveComponent::Update(float deltaTime) mOwner->SetPosition(pos); } } + +void MoveComponent::AddForce(const Vector2 force) { + this->mForce += force; +} + +Vector2 MoveComponent::GetForce() const { + return mForce; +} + +void MoveComponent::SetMass(const float mass) { + this->mMass = mass; +} + +float MoveComponent::GetMass() const { + return mMass; +} + +Vector2 MoveComponent::GetVelocity() const { + return mVelocity; +} diff --git a/Chapter03/MoveComponent.h b/Chapter03/MoveComponent.h index 482c1e66..54df898f 100644 --- a/Chapter03/MoveComponent.h +++ b/Chapter03/MoveComponent.h @@ -8,6 +8,7 @@ #pragma once #include "Component.h" +#include "Math.h" class MoveComponent : public Component { @@ -21,9 +22,21 @@ class MoveComponent : public Component float GetForwardSpeed() const { return mForwardSpeed; } void SetAngularSpeed(float speed) { mAngularSpeed = speed; } void SetForwardSpeed(float speed) { mForwardSpeed = speed; } + + void AddForce(const Vector2 force); + Vector2 GetForce() const; + + void SetMass(const float mass); + float GetMass() const; + + Vector2 GetVelocity() const; private: // Controls rotation (radians/second) float mAngularSpeed; // Controls forward movement (units/second) float mForwardSpeed; + + Vector2 mForce; + float mMass; + Vector2 mVelocity; }; From 3640bdc644ec20bc5e73407735220872bd0ad5a4 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Sun, 22 Sep 2019 14:04:12 +0900 Subject: [PATCH 21/57] remove comment --- Chapter01/Game.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/Chapter01/Game.cpp b/Chapter01/Game.cpp index 7ed548ba..baa912c2 100644 --- a/Chapter01/Game.cpp +++ b/Chapter01/Game.cpp @@ -170,38 +170,27 @@ void Game::UpdateGame() mBallVel.x *= -1.0f; } // Did the ball go off the screen? (if so, end game) - // 左の壁に当たった(プレイヤーの負け) else if (mBallPos.x <= 0.0f) { mIsRunning = false; } // Did the ball collide with the right wall? - // ボールが右に加速していて、ボールが右の壁に当たった else if (mBallPos.x + ballW >= 1024.0f && mBallVel.x > 0.0f) { mBallVel.x *= -1.0f; } // Did the ball collide with the top wall? - // ボールが上に加速していて、ボールが上の壁に当たった if (mBallPos.y - (ballH / 2) <= wallH && mBallVel.y < 0.0f) { mBallVel.y *= -1; } // Did the ball collide with the bottom wall? - // ボールが下に加速していて、ボールが下の壁に当たった else if (mBallPos.y + ballH >= 768 && mBallVel.y > 0.0f) { mBallVel.y *= -1; } - /* - mBollPos.y ボールの上 - -y 上 - +y 下 - -x 左 - +x 右 - */ } void Game::GenerateOutput() From 826a34664285ddc5248b419d31e6cf4dea666aeb Mon Sep 17 00:00:00 2001 From: desktopgame Date: Sun, 22 Sep 2019 20:18:48 +0900 Subject: [PATCH 22/57] fix WindowsSDK version --- Exercises/4.2/Game.vcxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Exercises/4.2/Game.vcxproj b/Exercises/4.2/Game.vcxproj index 506ca23a..9168138c 100644 --- a/Exercises/4.2/Game.vcxproj +++ b/Exercises/4.2/Game.vcxproj @@ -37,7 +37,7 @@ {BC508D87-495F-4554-932D-DD68388B63CC} Win32Proj Game - 10.0.16299.0 + 10.0.17763.0 From 1d173ffcdd648e477b6389774ccded05b1a8f85a Mon Sep 17 00:00:00 2001 From: desktopgame Date: Sun, 22 Sep 2019 23:50:55 +0900 Subject: [PATCH 23/57] implement AI system --- Exercises/4.2/Board.cpp | 71 +++++++++++++++++++++++++----- Exercises/4.2/Board.h | 1 + Exercises/4.2/BoardNode.cpp | 46 +++++++++++++++++++ Exercises/4.2/BoardNode.h | 8 ++++ Exercises/4.2/Game.vcxproj | 2 + Exercises/4.2/Game.vcxproj.filters | 6 +++ 6 files changed, 124 insertions(+), 10 deletions(-) create mode 100644 Exercises/4.2/BoardNode.cpp create mode 100644 Exercises/4.2/BoardNode.h diff --git a/Exercises/4.2/Board.cpp b/Exercises/4.2/Board.cpp index 65d013aa..a42f78a8 100644 --- a/Exercises/4.2/Board.cpp +++ b/Exercises/4.2/Board.cpp @@ -8,6 +8,7 @@ #include "Board.h" #include "Random.h" +#include "BoardNode.h" BoardState::BoardState() { @@ -77,6 +78,17 @@ float BoardState::GetScore() const return CalculateHeuristic(); } +float BoardState::MatchesToScore(int matches) { + if (matches <= 1) { + return 0; + } else if (matches == 2) { + return 0.01f; + } else if (matches == 3) { + return 0.02f; + } + throw std::logic_error("invalid range"); +} + bool BoardState::IsFull() const { bool isFull = true; @@ -186,8 +198,53 @@ int BoardState::GetFourInARow() const float BoardState::CalculateHeuristic() const { + float score = 0.0f; // TODO: You could change this to calculate an actual heuristic - return 0.0f; + for (int i = 0; i < 6; i++) { + SquareState old = SquareState::Empty; + int matches = 0; + for (int j = 0; j < 7; j++) { + SquareState state = mBoard[i][j]; + if (j == 0) { + old = state; + matches = 1; + } else if (old == state) { + matches++; + } else if (old != state) { + if (old == SquareState::Red) { + score += MatchesToScore(matches); + } + old = state; + matches = 0; + } + } + if (old == SquareState::Red) { + score += MatchesToScore(matches); + } + } + for (int j = 0; j < 7; j++) { + SquareState old = SquareState::Empty; + int matches = 0; + for (int i = 0; i < 6; i++) { + SquareState state = mBoard[i][j]; + if (i == 0) { + old = state; + matches = 1; + } else if (old == state) { + matches++; + } else if (old != state) { + if (old == SquareState::Red) { + score += MatchesToScore(matches); + } + old = state; + matches = 0; + } + } + if (old == SquareState::Red) { + score += MatchesToScore(matches); + } + } + return score; } bool TryPlayerMove(BoardState* state, int column) @@ -209,15 +266,9 @@ bool TryPlayerMove(BoardState* state, int column) void CPUMove(BoardState* state) { // For now, this just randomly picks one of the possible moves - std::vector moves = state->GetPossibleMoves(BoardState::Red); - - int index = Random::GetIntRange(0, moves.size() - 1); + BoardState* stat = const_cast(AlphaBetaDecide(state, 8)); - *state = *moves[index]; + *state = *stat; - // Clear up memory from possible moves - for (auto state : moves) - { - delete state; - } + delete stat; } diff --git a/Exercises/4.2/Board.h b/Exercises/4.2/Board.h index eff8393a..fff11007 100644 --- a/Exercises/4.2/Board.h +++ b/Exercises/4.2/Board.h @@ -20,6 +20,7 @@ class BoardState SquareState mBoard[6][7]; protected: + static float MatchesToScore(int matches); bool IsFull() const; int GetFourInARow() const; float CalculateHeuristic() const; diff --git a/Exercises/4.2/BoardNode.cpp b/Exercises/4.2/BoardNode.cpp new file mode 100644 index 00000000..61616ce3 --- /dev/null +++ b/Exercises/4.2/BoardNode.cpp @@ -0,0 +1,46 @@ +#include "BoardNode.h" +#include + +const BoardState * AlphaBetaDecide(const BoardState * root, int maxDepth) { + const BoardState* choice = nullptr; + float maxValue = -std::numeric_limits::infinity(); + float beta = std::numeric_limits::infinity(); + for (const BoardState* child : root->GetPossibleMoves(BoardState::SquareState::Red)) { + float v = AlphaBetaMin(child, maxDepth - 1, maxValue, beta); + if (v > maxValue) { + maxValue = v; + choice = child; + } + } + return choice; +} + +float AlphaBetaMax(const BoardState * node, int depth, float alpha, float beta) { + if (depth == 0 || node->IsTerminal()) { + return node->GetScore(); + } + float maxValue = -std::numeric_limits::infinity(); + for (const BoardState* child : node->GetPossibleMoves(BoardState::SquareState::Red)) { + maxValue = std::max(maxValue, AlphaBetaMin(child, depth - 1, alpha, beta)); + if (maxValue >= beta) { + return maxValue; + } + alpha = std::max(maxValue, alpha); + } + return maxValue; +} + +float AlphaBetaMin(const BoardState * node, int depth, float alpha, float beta) { + if (depth == 0 || node->IsTerminal()) { + return node->GetScore(); + } + float minValue = std::numeric_limits::infinity(); + for (const BoardState* child : node->GetPossibleMoves(BoardState::SquareState::Yellow)) { + minValue = std::min(minValue, AlphaBetaMax(child, depth - 1, alpha, beta)); + if (minValue <= alpha) { + return minValue; + } + beta = std::min(minValue, beta); + } + return minValue; +} diff --git a/Exercises/4.2/BoardNode.h b/Exercises/4.2/BoardNode.h new file mode 100644 index 00000000..3dbe8740 --- /dev/null +++ b/Exercises/4.2/BoardNode.h @@ -0,0 +1,8 @@ +#pragma once +#include "Board.h" + +const BoardState* AlphaBetaDecide(const BoardState* root, int maxDepth); + +float AlphaBetaMax(const BoardState* node, int depth, float alpha, float beta); + +float AlphaBetaMin(const BoardState* node, int depth, float alpha, float beta); \ No newline at end of file diff --git a/Exercises/4.2/Game.vcxproj b/Exercises/4.2/Game.vcxproj index 9168138c..21b86e71 100644 --- a/Exercises/4.2/Game.vcxproj +++ b/Exercises/4.2/Game.vcxproj @@ -13,6 +13,7 @@ + @@ -25,6 +26,7 @@ + diff --git a/Exercises/4.2/Game.vcxproj.filters b/Exercises/4.2/Game.vcxproj.filters index 4321a926..25cad6e1 100644 --- a/Exercises/4.2/Game.vcxproj.filters +++ b/Exercises/4.2/Game.vcxproj.filters @@ -37,6 +37,9 @@ Source Files + + Source Files + @@ -66,5 +69,8 @@ Source Files + + Source Files + \ No newline at end of file From cc1d6fa17acd2d329958de5fb0e45e5e905ccb93 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Sun, 22 Sep 2019 23:54:00 +0900 Subject: [PATCH 24/57] fix AlphaBeta func --- Exercises/4.2/BoardNode.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Exercises/4.2/BoardNode.cpp b/Exercises/4.2/BoardNode.cpp index 61616ce3..695d568a 100644 --- a/Exercises/4.2/BoardNode.cpp +++ b/Exercises/4.2/BoardNode.cpp @@ -20,7 +20,7 @@ float AlphaBetaMax(const BoardState * node, int depth, float alpha, float beta) return node->GetScore(); } float maxValue = -std::numeric_limits::infinity(); - for (const BoardState* child : node->GetPossibleMoves(BoardState::SquareState::Red)) { + for (const BoardState* child : node->GetPossibleMoves(BoardState::SquareState::Yellow)) { maxValue = std::max(maxValue, AlphaBetaMin(child, depth - 1, alpha, beta)); if (maxValue >= beta) { return maxValue; @@ -35,7 +35,7 @@ float AlphaBetaMin(const BoardState * node, int depth, float alpha, float beta) return node->GetScore(); } float minValue = std::numeric_limits::infinity(); - for (const BoardState* child : node->GetPossibleMoves(BoardState::SquareState::Yellow)) { + for (const BoardState* child : node->GetPossibleMoves(BoardState::SquareState::Red)) { minValue = std::min(minValue, AlphaBetaMax(child, depth - 1, alpha, beta)); if (minValue <= alpha) { return minValue; From f8d6aad0af9965290c6c59649971ae96896fedbf Mon Sep 17 00:00:00 2001 From: desktopgame Date: Mon, 23 Sep 2019 14:01:15 +0900 Subject: [PATCH 25/57] implement color change system --- Chapter05/Game.cpp | 19 ++++++++++++++++++- Chapter05/Game.h | 5 +++++ Chapter05/Math.h | 19 +++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/Chapter05/Game.cpp b/Chapter05/Game.cpp index e18e90a3..1b51c3c5 100644 --- a/Chapter05/Game.cpp +++ b/Chapter05/Game.cpp @@ -24,6 +24,9 @@ Game::Game() ,mSpriteShader(nullptr) ,mIsRunning(true) ,mUpdatingActors(false) +,mStartColor(0.86f, 0.86f, 0.86f, 1.0f) +,mNextColor(1, 0, 0, 1.0f) +,mColorTime(0.0f) { } @@ -141,7 +144,21 @@ void Game::UpdateGame() { deltaTime = 0.05f; } + const float COLOR_LENGTH = 3.0f; mTicksCount = SDL_GetTicks(); + this->mColorTime += deltaTime; + if (mColorTime >= COLOR_LENGTH) { + this->mStartColor = this->mProgressColor = mNextColor; + this->mColorTime = 0; + this->mNextColor = Vector4( + Random::GetFloat(), + Random::GetFloat(), + Random::GetFloat(), + Random::GetFloat() + ); + } else { + this->mProgressColor = Vector4::Lerp(mStartColor, mNextColor, mColorTime / COLOR_LENGTH); + } // Update all actors mUpdatingActors = true; @@ -179,7 +196,7 @@ void Game::UpdateGame() void Game::GenerateOutput() { // Set the clear color to grey - glClearColor(0.86f, 0.86f, 0.86f, 1.0f); + glClearColor(mProgressColor.x, mProgressColor.y, mProgressColor.z, mProgressColor.w); // Clear the color buffer glClear(GL_COLOR_BUFFER_BIT); diff --git a/Chapter05/Game.h b/Chapter05/Game.h index d5c22637..23113a7b 100644 --- a/Chapter05/Game.h +++ b/Chapter05/Game.h @@ -58,6 +58,11 @@ class Game // Sprite vertex array class VertexArray* mSpriteVerts; + Vector4 mStartColor; + Vector4 mProgressColor; + Vector4 mNextColor; + float mColorTime; + SDL_Window* mWindow; SDL_GLContext mContext; Uint32 mTicksCount; diff --git a/Chapter05/Math.h b/Chapter05/Math.h index 752963f1..f720d0c8 100644 --- a/Chapter05/Math.h +++ b/Chapter05/Math.h @@ -412,6 +412,25 @@ class Vector3 static const Vector3 NegInfinity; }; +class Vector4 { +public: + Vector4() : x(0), y(0), z(0), w(1){ } + Vector4(float x, float y, float z) : x(x), y(y), z(z), w(1) { } + Vector4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {} + // Lerp from A to B by f + static Vector4 Lerp(const Vector4& a, const Vector4& b, float f) { + float nx = Math::Lerp(a.x, b.x, f); + float ny = Math::Lerp(a.y, b.y, f); + float nz = Math::Lerp(a.z, b.z, f); + float nw = Math::Lerp(a.w, b.w, f); + return Vector4(nx, ny, nz, nw); + } + float x; + float y; + float z; + float w; +}; + // 3x3 Matrix class Matrix3 { From 75703864b010e84949641daf080684df7b3dc15d Mon Sep 17 00:00:00 2001 From: desktopgame Date: Mon, 23 Sep 2019 15:02:38 +0900 Subject: [PATCH 26/57] implement vertex color --- Chapter05/Game.cpp | 8 ++++---- Chapter05/Shaders/Sprite.frag | 6 +++++- Chapter05/Shaders/Sprite.vert | 3 +++ Chapter05/VertexArray.cpp | 9 ++++++--- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/Chapter05/Game.cpp b/Chapter05/Game.cpp index 1b51c3c5..5057108b 100644 --- a/Chapter05/Game.cpp +++ b/Chapter05/Game.cpp @@ -235,10 +235,10 @@ bool Game::LoadShaders() void Game::CreateSpriteVerts() { float vertices[] = { - -0.5f, 0.5f, 0.f, 0.f, 0.f, // top left - 0.5f, 0.5f, 0.f, 1.f, 0.f, // top right - 0.5f, -0.5f, 0.f, 1.f, 1.f, // bottom right - -0.5f, -0.5f, 0.f, 0.f, 1.f // bottom left + -0.5f, 0.5f, 0.f, 0.f, 0.f, 1, 0, 0, // top left + 0.5f, 0.5f, 0.f, 1.f, 0.f, 1, 0, 0, // top right + 0.5f, -0.5f, 0.f, 1.f, 1.f, 1, 0, 0, // bottom right + -0.5f, -0.5f, 0.f, 0.f, 1.f, 1, 0, 0 // bottom left }; unsigned int indices[] = { diff --git a/Chapter05/Shaders/Sprite.frag b/Chapter05/Shaders/Sprite.frag index f48caf3d..9ca9ae0b 100644 --- a/Chapter05/Shaders/Sprite.frag +++ b/Chapter05/Shaders/Sprite.frag @@ -11,6 +11,7 @@ // Tex coord input from vertex shader in vec2 fragTexCoord; +in vec3 fragVerColor; // This corresponds to the output color to the color buffer out vec4 outColor; @@ -21,5 +22,8 @@ uniform sampler2D uTexture; void main() { // Sample color from texture - outColor = texture(uTexture, fragTexCoord); + vec4 tex = texture(uTexture, fragTexCoord); + vec4 vc = vec4(fragVerColor, 1); + vc.w = tex.w; + outColor = (vc + tex) / 2.0; } diff --git a/Chapter05/Shaders/Sprite.vert b/Chapter05/Shaders/Sprite.vert index ea0f396f..d4806d21 100644 --- a/Chapter05/Shaders/Sprite.vert +++ b/Chapter05/Shaders/Sprite.vert @@ -16,9 +16,11 @@ uniform mat4 uViewProj; // Attribute 0 is position, 1 is tex coords. layout(location = 0) in vec3 inPosition; layout(location = 1) in vec2 inTexCoord; +layout(location = 2) in vec3 inVerColor; // Add texture coordinate as output out vec2 fragTexCoord; +out vec3 fragVerColor; void main() { @@ -30,4 +32,5 @@ void main() // Transform // Pass along the texture coordinate to frag shader fragTexCoord = inTexCoord; + fragVerColor = inVerColor; } diff --git a/Chapter05/VertexArray.cpp b/Chapter05/VertexArray.cpp index c7bff446..f506e221 100644 --- a/Chapter05/VertexArray.cpp +++ b/Chapter05/VertexArray.cpp @@ -21,7 +21,7 @@ VertexArray::VertexArray(const float* verts, unsigned int numVerts, // Create vertex buffer glGenBuffers(1, &mVertexBuffer); glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer); - glBufferData(GL_ARRAY_BUFFER, numVerts * 5 * sizeof(float), verts, GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, numVerts * 8 * sizeof(float), verts, GL_STATIC_DRAW); // Create index buffer glGenBuffers(1, &mIndexBuffer); @@ -32,10 +32,13 @@ VertexArray::VertexArray(const float* verts, unsigned int numVerts, // (For now, assume one vertex format) // Position is 3 floats starting at offset 0 glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 5, 0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 8, 0); glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 5, + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 8, reinterpret_cast(sizeof(float) * 3)); + glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 8, + reinterpret_cast(sizeof(float) * 5)); + glEnableVertexAttribArray(2); } VertexArray::~VertexArray() From 58cb054a804e59f2c69afe69feb3d66d3eb20ff6 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Tue, 24 Sep 2019 13:32:03 +0900 Subject: [PATCH 27/57] implement shader switch system --- Chapter06/Assets/Sphere.gpmesh | 2 +- Chapter06/MeshComponent.h | 1 + Chapter06/Renderer.cpp | 67 +++++++++++++++++++++++++++------- Chapter06/Renderer.h | 3 +- 4 files changed, 58 insertions(+), 15 deletions(-) diff --git a/Chapter06/Assets/Sphere.gpmesh b/Chapter06/Assets/Sphere.gpmesh index 82ed952c..63140261 100644 --- a/Chapter06/Assets/Sphere.gpmesh +++ b/Chapter06/Assets/Sphere.gpmesh @@ -1,7 +1,7 @@ { "version":1, "vertexformat":"PosNormTex", - "shader":"BasicMesh", + "shader":"PhongMesh", "textures":[ "Assets/Sphere.png" ], diff --git a/Chapter06/MeshComponent.h b/Chapter06/MeshComponent.h index 48765568..1acd19a5 100644 --- a/Chapter06/MeshComponent.h +++ b/Chapter06/MeshComponent.h @@ -19,6 +19,7 @@ class MeshComponent : public Component virtual void Draw(class Shader* shader); // Set the mesh/texture index used by mesh component virtual void SetMesh(class Mesh* mesh) { mMesh = mesh; } + virtual class Mesh* GetMesh() const { return mMesh; } void SetTextureIndex(size_t index) { mTextureIndex = index; } protected: class Mesh* mMesh; diff --git a/Chapter06/Renderer.cpp b/Chapter06/Renderer.cpp index 43a25fe8..42e4aa0b 100644 --- a/Chapter06/Renderer.cpp +++ b/Chapter06/Renderer.cpp @@ -19,7 +19,7 @@ Renderer::Renderer(Game* game) :mGame(game) ,mSpriteShader(nullptr) - ,mMeshShader(nullptr) + ,mMeshShaderMap() { } @@ -90,8 +90,10 @@ void Renderer::Shutdown() delete mSpriteVerts; mSpriteShader->Unload(); delete mSpriteShader; - mMeshShader->Unload(); - delete mMeshShader; + for (auto kv : mMeshShaderMap) { + kv.second->Unload(); + } + mMeshShaderMap.clear(); SDL_GL_DeleteContext(mContext); SDL_DestroyWindow(mWindow); } @@ -126,15 +128,32 @@ void Renderer::Draw() // Enable depth buffering/disable alpha blend glEnable(GL_DEPTH_TEST); glDisable(GL_BLEND); - // Set the mesh shader active - mMeshShader->SetActive(); - // Update view-projection matrix - mMeshShader->SetMatrixUniform("uViewProj", mView * mProjection); - // Update lighting uniforms - SetLightUniforms(mMeshShader); + std::unordered_map > cache; for (auto mc : mMeshComps) { - mc->Draw(mMeshShader); + Mesh* msh = mc->GetMesh(); + std::string mshName = msh->GetShaderName(); + if (!cache.count(mshName)) { + std::vector v; + v.emplace_back(mc); + cache[mshName] = v; + } else { + std::vector& v = cache.at(mshName); + v.emplace_back(mc); + } + } + for (auto kv : cache) { + auto sh = mMeshShaderMap[kv.first]; + auto comps = kv.second; + // Set the mesh shader active + sh->SetActive(); + // Update view-projection matrix + sh->SetMatrixUniform("uViewProj", mView * mProjection); + // Update lighting uniforms + SetLightUniforms(sh); + for (auto comp : comps) { + comp->Draw(sh); + } } // Draw all sprite components @@ -256,10 +275,21 @@ bool Renderer::LoadShaders() Matrix4 viewProj = Matrix4::CreateSimpleViewProj(mScreenWidth, mScreenHeight); mSpriteShader->SetMatrixUniform("uViewProj", viewProj); + // Create phong mesh shader + Shader* mMeshShader = nullptr; + if ((mMeshShader = LoadShader("PhongMesh", "Shaders/Phong.vert", "Shaders/Phong.frag")) == nullptr) { + return false; + } + + mMeshShader->SetActive(); + // Set the view-projection matrix + mView = Matrix4::CreateLookAt(Vector3::Zero, Vector3::UnitX, Vector3::UnitZ); + mProjection = Matrix4::CreatePerspectiveFOV(Math::ToRadians(70.0f), + mScreenWidth, mScreenHeight, 25.0f, 10000.0f); + mMeshShader->SetMatrixUniform("uViewProj", mView * mProjection); + // Create basic mesh shader - mMeshShader = new Shader(); - if (!mMeshShader->Load("Shaders/Phong.vert", "Shaders/Phong.frag")) - { + if ((mMeshShader = LoadShader("BasicMesh", "Shaders/BasicMesh.vert", "Shaders/BasicMesh.frag")) == nullptr) { return false; } @@ -272,6 +302,17 @@ bool Renderer::LoadShaders() return true; } +Shader* Renderer::LoadShader(const std::string & name, const std::string & vertFile, const std::string & fragFile) { + Shader* sh = new Shader(); + if (sh->Load(vertFile, fragFile)) { + mMeshShaderMap[name] = sh; + return sh; + } + sh->Unload(); + delete sh; + return nullptr; +} + void Renderer::CreateSpriteVerts() { float vertices[] = { diff --git a/Chapter06/Renderer.h b/Chapter06/Renderer.h index 12746df2..270f9ad6 100644 --- a/Chapter06/Renderer.h +++ b/Chapter06/Renderer.h @@ -53,6 +53,7 @@ class Renderer float GetScreenHeight() const { return mScreenHeight; } private: bool LoadShaders(); + class Shader* LoadShader(const std::string& name, const std::string& vertFile, const std::string& fragFile); void CreateSpriteVerts(); void SetLightUniforms(class Shader* shader); @@ -76,7 +77,7 @@ class Renderer class VertexArray* mSpriteVerts; // Mesh shader - class Shader* mMeshShader; + std::unordered_map mMeshShaderMap; // View/projection for 3D shaders Matrix4 mView; From c5c8203245ef79cd05ec654ef77ae2d442c55aaa Mon Sep 17 00:00:00 2001 From: desktopgame Date: Tue, 24 Sep 2019 16:00:47 +0900 Subject: [PATCH 28/57] add `SetIntUniform` --- Chapter06/Shader.cpp | 7 +++++++ Chapter06/Shader.h | 1 + 2 files changed, 8 insertions(+) diff --git a/Chapter06/Shader.cpp b/Chapter06/Shader.cpp index cae3ac07..357b061c 100644 --- a/Chapter06/Shader.cpp +++ b/Chapter06/Shader.cpp @@ -90,6 +90,13 @@ void Shader::SetFloatUniform(const char* name, float value) glUniform1f(loc, value); } +void Shader::SetIntUniform(const char * name, int value) +{ + GLuint loc = glGetUniformLocation(mShaderProgram, name); + // Send the float data + glUniform1i(loc, value); +} + bool Shader::CompileShader(const std::string& fileName, GLenum shaderType, GLuint& outShader) diff --git a/Chapter06/Shader.h b/Chapter06/Shader.h index 929c9e41..66d73f2e 100644 --- a/Chapter06/Shader.h +++ b/Chapter06/Shader.h @@ -27,6 +27,7 @@ class Shader void SetVectorUniform(const char* name, const Vector3& vector); // Sets a float uniform void SetFloatUniform(const char* name, float value); + void SetIntUniform(const char* name, int value); private: // Tries to compile the specified shader bool CompileShader(const std::string& fileName, From 0cd653be635c7c3208023a7b44b1cb0ff5699613 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Tue, 24 Sep 2019 16:46:28 +0900 Subject: [PATCH 29/57] implement multiple lights --- Chapter06/Assets/Sphere.gpmesh | 2 +- Chapter06/Game.vcxproj | 2 +- Chapter06/Renderer.cpp | 67 ++++++++++++++++++ Chapter06/Shaders/PhongML.frag | 121 +++++++++++++++++++++++++++++++++ Chapter06/Shaders/PhongML.vert | 46 +++++++++++++ 5 files changed, 236 insertions(+), 2 deletions(-) create mode 100644 Chapter06/Shaders/PhongML.frag create mode 100644 Chapter06/Shaders/PhongML.vert diff --git a/Chapter06/Assets/Sphere.gpmesh b/Chapter06/Assets/Sphere.gpmesh index 63140261..2519d903 100644 --- a/Chapter06/Assets/Sphere.gpmesh +++ b/Chapter06/Assets/Sphere.gpmesh @@ -1,7 +1,7 @@ { "version":1, "vertexformat":"PosNormTex", - "shader":"PhongMesh", + "shader":"PhongMesh2", "textures":[ "Assets/Sphere.png" ], diff --git a/Chapter06/Game.vcxproj b/Chapter06/Game.vcxproj index aca4c760..64789e8d 100644 --- a/Chapter06/Game.vcxproj +++ b/Chapter06/Game.vcxproj @@ -94,7 +94,7 @@ NotUsing Level3 Disabled - WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) true ..\external\SDL\include;..\external\GLEW\include;..\external\SOIL\include;..\external\rapidjson\include;%(AdditionalIncludeDirectories) false diff --git a/Chapter06/Renderer.cpp b/Chapter06/Renderer.cpp index 42e4aa0b..755dea21 100644 --- a/Chapter06/Renderer.cpp +++ b/Chapter06/Renderer.cpp @@ -152,6 +152,10 @@ void Renderer::Draw() // Update lighting uniforms SetLightUniforms(sh); for (auto comp : comps) { + if (kv.first == "PhongMesh2") { + sh->SetIntUniform("uMaterial.mDiffuse", 0); + sh->SetIntUniform("uMaterial.mSpecular",0); + } comp->Draw(sh); } } @@ -288,6 +292,69 @@ bool Renderer::LoadShaders() mScreenWidth, mScreenHeight, 25.0f, 10000.0f); mMeshShader->SetMatrixUniform("uViewProj", mView * mProjection); + // Create phongML mesh shader + if ((mMeshShader = LoadShader("PhongMesh2", "Shaders/PhongML.vert", "Shaders/PhongML.frag")) == nullptr) { + return false; + } + + mMeshShader->SetActive(); + // Set the view-projection matrix + mView = Matrix4::CreateLookAt(Vector3::Zero, Vector3::UnitX, Vector3::UnitZ); + mProjection = Matrix4::CreatePerspectiveFOV(Math::ToRadians(70.0f), + mScreenWidth, mScreenHeight, 25.0f, 10000.0f); + mMeshShader->SetMatrixUniform("uViewProj", mView * mProjection); + const char* positionFmt = "pointLights[%d].mPosition"; + const char* constantFmt = "pointLights[%d].mConstant"; + const char* linearFmt = "pointLights[%d].mLinear"; + const char* quadraticFmt = "pointLights[%d].mQuadratic"; + const char* ambientFmt = "pointLights[%d].mAmbient"; + const char* diffuseFmt = "pointLights[%d].mDiffuse"; + const char* specularFmt = "pointLights[%d].mSpecular"; + const char* materialDiffuseFmt = "uMaterial.mDiffuse"; + const char* materialSpecularFmt = "uMaterial.mSpecular"; + const char* materialShininessFmt = "uMaterial.mShininess"; + mMeshShader->SetIntUniform(materialDiffuseFmt, 0); + mMeshShader->SetIntUniform(materialSpecularFmt, 1); + mMeshShader->SetFloatUniform(materialShininessFmt, 32); + const float UNIT = 200.0f; + Vector3 posTable[4] = { + Vector3(200.0f, -75.0f, 0.0f + UNIT), + Vector3(200.0f, -75.0f, 0.0f - UNIT), + Vector3(200.0f + UNIT, -75.0f, 0.0f + UNIT), + Vector3(200.0f - UNIT, -75.0f, 0.0f - UNIT), + }; + Vector3 colorTable[4] = { + Vector3(1, 0, 0), + Vector3(0, 1, 0), + Vector3(0, 0, 1), + Vector3(1, 0, 0), + }; + for (int i = 0; i < 4; i++) { + char buf[512]; + std::memset(buf, '\0', 512); + + std::sprintf(buf, positionFmt, i); + mMeshShader->SetVectorUniform(buf, posTable[i]); + + std::sprintf(buf, constantFmt, i); + mMeshShader->SetFloatUniform(buf, 1.0f); + + std::sprintf(buf, linearFmt, i); + mMeshShader->SetFloatUniform(buf, 1.0f); + + std::sprintf(buf, quadraticFmt, i); + mMeshShader->SetFloatUniform(buf, 1.0f); + + std::sprintf(buf, ambientFmt, i); + mMeshShader->SetVectorUniform(buf, colorTable[i]); + + std::sprintf(buf, diffuseFmt, i); + mMeshShader->SetVectorUniform(buf, colorTable[i]); + + std::sprintf(buf, specularFmt, i); + mMeshShader->SetVectorUniform(buf, colorTable[i]); + } + // Create basic mesh shader if ((mMeshShader = LoadShader("BasicMesh", "Shaders/BasicMesh.vert", "Shaders/BasicMesh.frag")) == nullptr) { return false; diff --git a/Chapter06/Shaders/PhongML.frag b/Chapter06/Shaders/PhongML.frag new file mode 100644 index 00000000..1dddd585 --- /dev/null +++ b/Chapter06/Shaders/PhongML.frag @@ -0,0 +1,121 @@ +// ---------------------------------------------------------------- +// From Game Programming in C++ by Sanjay Madhav +// Copyright (C) 2017 Sanjay Madhav. All rights reserved. +// +// Released under the BSD License +// See LICENSE in root directory for full details. +// ---------------------------------------------------------------- + +// Request GLSL 3.3 +#version 330 + +// Inputs from vertex shader +// Tex coord +in vec2 fragTexCoord; +// Normal (in world space) +in vec3 fragNormal; +// Position (in world space) +in vec3 fragWorldPos; +in mat4 fragWorldMat; + +// This corresponds to the output color to the color buffer +out vec4 outColor; + +// This is used for the texture sampling +uniform sampler2D uTexture; +struct Material { + sampler2D mDiffuse; + sampler2D mSpecular; + float mShininess; +}; +// Create a struct for directional light +struct DirectionalLight +{ + // Direction of light + vec3 mDirection; + // Diffuse color + vec3 mDiffuseColor; + // Specular color + vec3 mSpecColor; +}; +struct PointLight { + vec3 mPosition; + + float mConstant; + float mLinear; + float mQuadratic; + + vec3 mAmbient; + vec3 mDiffuse; + vec3 mSpecular; +}; +#define NR_POINT_LIGHTS 4 +uniform PointLight pointLights[NR_POINT_LIGHTS]; + +// Uniforms for lighting +// Camera position (in world space) +uniform vec3 uCameraPos; +// Specular power for this surface +uniform float uSpecPower; +// Ambient light level +uniform vec3 uAmbientLight; +uniform Material uMaterial; + +// Directional Light +uniform DirectionalLight uDirLight; + +vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir); + +void main() +{ + // Surface normal + vec3 N = normalize(fragNormal); + // Vector from surface to light + vec3 L = normalize(-uDirLight.mDirection); + // Vector from surface to camera + vec3 V = normalize(uCameraPos - fragWorldPos); + // Reflection of -L about N + vec3 R = normalize(reflect(-L, N)); + + // Compute phong reflection + vec3 Phong = uAmbientLight; + float NdotL = dot(N, L); + if (NdotL > 0) + { + vec3 Diffuse = uDirLight.mDiffuseColor * NdotL; + vec3 Specular = uDirLight.mSpecColor * pow(max(0.0, dot(R, V)), uSpecPower); + Phong += Diffuse + Specular; + } + + for(int i = 0; i < NR_POINT_LIGHTS; i++) { + Phong += CalcPointLight(pointLights[i], fragNormal, fragWorldPos, normalize(uCameraPos - fragWorldPos)); + } + // Final color is texture color times phong light (alpha = 1) + outColor = vec4(Phong, 1.0f); +} + +vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir) +{ + vec4 ltmp = vec4(light.mPosition, 1.0); + ltmp = ltmp * fragWorldMat; + vec3 ltmp3 = ltmp.xyz; + + vec3 lightDir = normalize(ltmp3 - fragPos); + // diffuse shading + float diff = max(dot(normal, lightDir), 0.0); + // specular shading + vec3 reflectDir = reflect(-lightDir, normal); + float spec = pow(max(dot(viewDir, reflectDir), 0.0), uMaterial.mShininess); + // attenuation + float distance = length(ltmp3 - fragPos); + float attenuation = 1.0 / (light.mConstant + light.mLinear * distance + + light.mQuadratic * (distance * distance)); + // combine results + vec3 ambient = light.mAmbient * vec3(texture(uMaterial.mDiffuse, fragTexCoord)); + vec3 diffuse = light.mDiffuse * diff * vec3(texture(uMaterial.mDiffuse, fragTexCoord)); + vec3 specular = light.mSpecular * spec * vec3(texture(uMaterial.mSpecular, fragTexCoord)); + ambient *= attenuation; + diffuse *= attenuation; + specular *= attenuation; + return (ambient + diffuse + specular); +} \ No newline at end of file diff --git a/Chapter06/Shaders/PhongML.vert b/Chapter06/Shaders/PhongML.vert new file mode 100644 index 00000000..b13f1fe5 --- /dev/null +++ b/Chapter06/Shaders/PhongML.vert @@ -0,0 +1,46 @@ +// ---------------------------------------------------------------- +// From Game Programming in C++ by Sanjay Madhav +// Copyright (C) 2017 Sanjay Madhav. All rights reserved. +// +// Released under the BSD License +// See LICENSE in root directory for full details. +// ---------------------------------------------------------------- + +// Request GLSL 3.3 +#version 330 + +// Uniforms for world transform and view-proj +uniform mat4 uWorldTransform; +uniform mat4 uViewProj; + +// Attribute 0 is position, 1 is normal, 2 is tex coords. +layout(location = 0) in vec3 inPosition; +layout(location = 1) in vec3 inNormal; +layout(location = 2) in vec2 inTexCoord; + +// Any vertex outputs (other than position) +out vec2 fragTexCoord; +// Normal (in world space) +out vec3 fragNormal; +// Position (in world space) +out vec3 fragWorldPos; +out mat4 fragWorldMat; + +void main() +{ + // Convert position to homogeneous coordinates + vec4 pos = vec4(inPosition, 1.0); + // Transform position to world space + pos = pos * uWorldTransform; + // Save world position + fragWorldPos = pos.xyz; + // Transform to clip space + gl_Position = pos * uViewProj; + + // Transform normal into world space (w = 0) + fragNormal = (vec4(inNormal, 0.0f) * uWorldTransform).xyz; + + // Pass along the texture coordinate to frag shader + fragTexCoord = inTexCoord; + fragWorldMat = uWorldTransform; +} From 2fa8965ebfd9272dda1f0e012640912a074d2c00 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Wed, 25 Sep 2019 12:26:55 +0900 Subject: [PATCH 30/57] add Set3DSettings --- Chapter07/AudioSystem.cpp | 5 +++++ Chapter07/AudioSystem.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/Chapter07/AudioSystem.cpp b/Chapter07/AudioSystem.cpp index 73c5feff..51154d6d 100644 --- a/Chapter07/AudioSystem.cpp +++ b/Chapter07/AudioSystem.cpp @@ -336,6 +336,11 @@ void AudioSystem::SetBusPaused(const std::string & name, bool pause) } } +void AudioSystem::Set3DSettings(float dopplerScale, float meter, float rollOfScale) +{ + mLowLevelSystem->set3DSettings(dopplerScale, meter, rollOfScale); +} + FMOD::Studio::EventInstance* AudioSystem::GetEventInstance(unsigned int id) { FMOD::Studio::EventInstance* event = nullptr; diff --git a/Chapter07/AudioSystem.h b/Chapter07/AudioSystem.h index 1e7398ef..84a8a3cd 100644 --- a/Chapter07/AudioSystem.h +++ b/Chapter07/AudioSystem.h @@ -51,6 +51,8 @@ class AudioSystem bool GetBusPaused(const std::string& name) const; void SetBusVolume(const std::string& name, float volume); void SetBusPaused(const std::string& name, bool pause); + + void Set3DSettings(float dopplerScale, float meter, float rollOfScale); protected: friend class SoundEvent; FMOD::Studio::EventInstance* GetEventInstance(unsigned int id); From 160f467986bd28160d50c01b579028336b6c83e4 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Wed, 25 Sep 2019 12:27:06 +0900 Subject: [PATCH 31/57] doppler effect test --- Chapter07/Game.cpp | 20 ++++++++++++++++++++ Chapter07/Game.h | 5 +++++ 2 files changed, 25 insertions(+) diff --git a/Chapter07/Game.cpp b/Chapter07/Game.cpp index e2715eb9..fc659712 100644 --- a/Chapter07/Game.cpp +++ b/Chapter07/Game.cpp @@ -179,6 +179,21 @@ void Game::UpdateGame() actor->Update(deltaTime); } mUpdatingActors = false; + const float WAIT = 2.0f; + const float DISTANCE = 1000; + this->mElapsed += deltaTime; + if (mElapsed >= WAIT) { + this->mToRight = !mToRight; + this->mElapsed = 0; + this->mBasePoint = mMoveSphere->GetPosition(); + } else { + float par = mElapsed / WAIT; + if (mToRight) { + mMoveSphere->SetPosition(mBasePoint + (Vector3(DISTANCE, 0, 0) * par)); + } else { + mMoveSphere->SetPosition(mBasePoint - (Vector3(DISTANCE, 0, 0) * par)); + } + } // Move any pending actors to mActors for (auto pending : mPendingActors) @@ -215,6 +230,7 @@ void Game::GenerateOutput() void Game::LoadData() { + mAudioSystem->Set3DSettings(1.0f, 50.0f, 1.0f); // Create actors Actor* a = new Actor(this); a->SetPosition(Vector3(200.0f, 75.0f, 0.0f)); @@ -295,6 +311,10 @@ void Game::LoadData() a = new Actor(this); a->SetPosition(Vector3(500.0f, -75.0f, 0.0f)); a->SetScale(1.0f); + this->mMoveSphere = a; + this->mBasePoint = a->GetPosition(); + this->mElapsed = 0.0f; + this->mToRight = true; mc = new MeshComponent(a); mc->SetMesh(mRenderer->GetMesh("Assets/Sphere.gpmesh")); AudioComponent* ac = new AudioComponent(a); diff --git a/Chapter07/Game.h b/Chapter07/Game.h index 12825f7c..e47bddd5 100644 --- a/Chapter07/Game.h +++ b/Chapter07/Game.h @@ -52,4 +52,9 @@ class Game class CameraActor* mCameraActor; SoundEvent mMusicEvent; SoundEvent mReverbSnap; + + class Actor* mMoveSphere; + Vector3 mBasePoint; + float mElapsed; + bool mToRight; }; From 9219b83d26a725404e99b9de45b70e1b2f44e1dc Mon Sep 17 00:00:00 2001 From: desktopgame Date: Wed, 25 Sep 2019 12:29:19 +0900 Subject: [PATCH 32/57] replace CameraActor --- Chapter07/CameraActor.cpp | 7 +++++-- Chapter07/CameraActor.h | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Chapter07/CameraActor.cpp b/Chapter07/CameraActor.cpp index ec43a95f..6099c612 100644 --- a/Chapter07/CameraActor.cpp +++ b/Chapter07/CameraActor.cpp @@ -13,12 +13,15 @@ #include "AudioSystem.h" #include "Game.h" #include "AudioComponent.h" +#include "MeshComponent.h" CameraActor::CameraActor(Game* game) :Actor(game) { mMoveComp = new MoveComponent(this); mAudioComp = new AudioComponent(this); + MeshComponent* mc = new MeshComponent(this); + mc->SetMesh(game->GetRenderer()->GetMesh("Assets/Sphere.gpmesh")); mLastFootstep = 0.0f; mFootstep = mAudioComp->PlayEvent("event:/Footstep"); mFootstep.SetPaused(true); @@ -38,10 +41,10 @@ void CameraActor::UpdateActor(float deltaTime) } // Compute new camera from this actor - Vector3 cameraPos = GetPosition(); + mCameraPos = GetPosition() - GetForward() * 200.0f + Vector3::UnitZ * 100.0f; Vector3 target = GetPosition() + GetForward() * 100.0f; Vector3 up = Vector3::UnitZ; - Matrix4 view = Matrix4::CreateLookAt(cameraPos, target, up); + Matrix4 view = Matrix4::CreateLookAt(mCameraPos, target, up); GetGame()->GetRenderer()->SetViewMatrix(view); GetGame()->GetAudioSystem()->SetListener(view); } diff --git a/Chapter07/CameraActor.h b/Chapter07/CameraActor.h index 7c95d106..9768de42 100644 --- a/Chapter07/CameraActor.h +++ b/Chapter07/CameraActor.h @@ -19,9 +19,11 @@ class CameraActor : public Actor void ActorInput(const uint8_t* keys) override; void SetFootstepSurface(float value); + const Vector3& GetCameraPosition() const { return mCameraPos; } private: class MoveComponent* mMoveComp; class AudioComponent* mAudioComp; + Vector3 mCameraPos; SoundEvent mFootstep; float mLastFootstep; }; \ No newline at end of file From 5f6f41327e18191aa1122a65e46e6b4736dd0e84 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Wed, 25 Sep 2019 13:16:20 +0900 Subject: [PATCH 33/57] implement virtual position --- Chapter07/AudioComponent.cpp | 24 +++++++++++++++++++++--- Chapter07/AudioComponent.h | 3 +++ Chapter07/Game.cpp | 1 + 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/Chapter07/AudioComponent.cpp b/Chapter07/AudioComponent.cpp index 3131b08b..f9f81741 100644 --- a/Chapter07/AudioComponent.cpp +++ b/Chapter07/AudioComponent.cpp @@ -10,9 +10,10 @@ #include "Actor.h" #include "Game.h" #include "AudioSystem.h" +#include "CameraActor.h" AudioComponent::AudioComponent(Actor* owner, int updateOrder) - :Component(owner, updateOrder) + :Component(owner, updateOrder), camera(nullptr) { } @@ -74,8 +75,20 @@ SoundEvent AudioComponent::PlayEvent(const std::string& name) if (e.Is3D()) { mEvents3D.emplace_back(e); - // Set initial 3D attributes - e.Set3DAttributes(mOwner->GetWorldTransform()); + if (camera) { + // Set initial 3D attributes + Vector3 realPos = mOwner->GetPosition(); + Vector3 playerToSound = realPos - camera->GetPosition(); + Vector3 cameraToSound = realPos - camera->GetCameraPosition(); + cameraToSound.Normalize(); + Vector3 virtualPos = cameraToSound * playerToSound.Length(); + mOwner->SetPosition(virtualPos); + mOwner->ComputeWorldTransform(); + e.Set3DAttributes(mOwner->GetWorldTransform()); + mOwner->SetPosition(realPos); + } else { + e.Set3DAttributes(mOwner->GetWorldTransform()); + } } else { @@ -99,3 +112,8 @@ void AudioComponent::StopAllEvents() mEvents2D.clear(); mEvents3D.clear(); } + +void AudioComponent::SetCamera(CameraActor * camera) +{ + this->camera = camera; +} diff --git a/Chapter07/AudioComponent.h b/Chapter07/AudioComponent.h index 8fdecd2d..29092a24 100644 --- a/Chapter07/AudioComponent.h +++ b/Chapter07/AudioComponent.h @@ -23,7 +23,10 @@ class AudioComponent : public Component SoundEvent PlayEvent(const std::string& name); void StopAllEvents(); + + void SetCamera(class CameraActor* camera); private: + class CameraActor* camera; std::vector mEvents2D; std::vector mEvents3D; }; \ No newline at end of file diff --git a/Chapter07/Game.cpp b/Chapter07/Game.cpp index fc659712..46a5f2a2 100644 --- a/Chapter07/Game.cpp +++ b/Chapter07/Game.cpp @@ -318,6 +318,7 @@ void Game::LoadData() mc = new MeshComponent(a); mc->SetMesh(mRenderer->GetMesh("Assets/Sphere.gpmesh")); AudioComponent* ac = new AudioComponent(a); + ac->SetCamera(mCameraActor); ac->PlayEvent("event:/FireLoop"); // Start music From 5c44a805ea33c6075472edcc48ebc17b15651bf4 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Wed, 25 Sep 2019 15:33:56 +0900 Subject: [PATCH 34/57] add InputDetector --- Chapter08/Assets/Input.txt | 3 + Chapter08/Game.cpp | 1 + Chapter08/Game.vcxproj | 2 + Chapter08/Game.vcxproj.filters | 6 ++ Chapter08/InputDetector.cpp | 130 +++++++++++++++++++++++++++++++++ Chapter08/InputDetector.h | 77 +++++++++++++++++++ Chapter08/InputSystem.cpp | 49 +++++++++++++ Chapter08/InputSystem.h | 10 +++ 8 files changed, 278 insertions(+) create mode 100644 Chapter08/Assets/Input.txt create mode 100644 Chapter08/InputDetector.cpp create mode 100644 Chapter08/InputDetector.h diff --git a/Chapter08/Assets/Input.txt b/Chapter08/Assets/Input.txt new file mode 100644 index 00000000..2955ee4c --- /dev/null +++ b/Chapter08/Assets/Input.txt @@ -0,0 +1,3 @@ +hoge +huga +jiso \ No newline at end of file diff --git a/Chapter08/Game.cpp b/Chapter08/Game.cpp index 6d86eda2..6f38a9ba 100644 --- a/Chapter08/Game.cpp +++ b/Chapter08/Game.cpp @@ -252,6 +252,7 @@ void Game::CreateSpriteVerts() void Game::LoadData() { + mInputSystem->ParseBindingFromFile("Assets/Input.txt"); // Create player's ship mShip = new Ship(this); mShip->SetRotation(Math::PiOver2); diff --git a/Chapter08/Game.vcxproj b/Chapter08/Game.vcxproj index 96269189..602c8474 100644 --- a/Chapter08/Game.vcxproj +++ b/Chapter08/Game.vcxproj @@ -17,6 +17,7 @@ + @@ -36,6 +37,7 @@ + diff --git a/Chapter08/Game.vcxproj.filters b/Chapter08/Game.vcxproj.filters index e78491fe..873a8bd5 100644 --- a/Chapter08/Game.vcxproj.filters +++ b/Chapter08/Game.vcxproj.filters @@ -61,6 +61,9 @@ Source Files + + Source Files + @@ -111,6 +114,9 @@ Source Files + + Source Files + diff --git a/Chapter08/InputDetector.cpp b/Chapter08/InputDetector.cpp new file mode 100644 index 00000000..010656b4 --- /dev/null +++ b/Chapter08/InputDetector.cpp @@ -0,0 +1,130 @@ +#include "InputDetector.h" +#include "InputSystem.h" +// KeyDetector +KeyDetector::KeyDetector(SDL_Scancode code) : code(code) +{ +} + +bool KeyDetector::GetBoolValue(InputState & state) const +{ + return state.Keyboard.GetKeyValue(code); +} + +ButtonState KeyDetector::GetButtonValue(InputState & state) const +{ + return state.Keyboard.GetKeyState(code); +} + +float KeyDetector::GetFloatValue(InputState & state) const +{ + return GetBoolValue(state) ? 1 : 0; +} + +Vector2 KeyDetector::GetAxisValue(InputState & state) const +{ + throw std::logic_error("unsupported operation"); +} +// MouseDetector +MouseDetector::MouseDetector(int button) : button(button) +{ +} + +bool MouseDetector::GetBoolValue(InputState & state) const +{ + return state.Mouse.GetButtonValue(button); +} + +ButtonState MouseDetector::GetButtonValue(InputState & state) const +{ + return state.Mouse.GetButtonState(button); +} + +float MouseDetector::GetFloatValue(InputState & state) const +{ + return GetBoolValue(state) ? 1 : 0; +} + +Vector2 MouseDetector::GetAxisValue(InputState & state) const +{ + throw std::logic_error("unsupported operation"); +} +// ControllerButtonDetector +ControllerButtonDetector::ControllerButtonDetector(SDL_GameControllerButton button) : button(button) +{ +} + +bool ControllerButtonDetector::GetBoolValue(InputState & state) const +{ + return state.Controller.GetButtonValue(button); +} + +ButtonState ControllerButtonDetector::GetButtonValue(InputState & state) const +{ + return state.Controller.GetButtonState(button); +} + +float ControllerButtonDetector::GetFloatValue(InputState & state) const +{ + return GetBoolValue(state) ? 1 : 0; +} + +Vector2 ControllerButtonDetector::GetAxisValue(InputState & state) const +{ + throw std::logic_error("unsupported operation"); +} +// ControllerStickDetector +ControllerStickDetector::ControllerStickDetector(ControllerDirection direction) : direction(direction) +{ +} + +bool ControllerStickDetector::GetBoolValue(InputState & state) const +{ + throw std::logic_error("unsupported operation"); +} + +ButtonState ControllerStickDetector::GetButtonValue(InputState & state) const +{ + throw std::logic_error("unsupported operation"); +} + +float ControllerStickDetector::GetFloatValue(InputState & state) const +{ + throw std::logic_error("unsupported operation"); +} + +Vector2 ControllerStickDetector::GetAxisValue(InputState & state) const +{ + if (direction == ControllerDirection::Left) { + return state.Controller.GetLeftStick(); + } else { + return state.Controller.GetRightStick(); + } +} + +ControllerTriggerDetector::ControllerTriggerDetector(ControllerDirection direction) : direction(direction) +{ +} + +bool ControllerTriggerDetector::GetBoolValue(InputState & state) const +{ + throw std::logic_error("unsupported operation"); +} + +ButtonState ControllerTriggerDetector::GetButtonValue(InputState & state) const +{ + throw std::logic_error("unsupported operation"); +} + +float ControllerTriggerDetector::GetFloatValue(InputState & state) const +{ + if (direction == ControllerDirection::Left) { + return state.Controller.GetLeftTrigger(); + } else { + return state.Controller.GetRightTrigger(); + } +} + +Vector2 ControllerTriggerDetector::GetAxisValue(InputState & state) const +{ + throw std::logic_error("unsupported operation"); +} diff --git a/Chapter08/InputDetector.h b/Chapter08/InputDetector.h new file mode 100644 index 00000000..68f49573 --- /dev/null +++ b/Chapter08/InputDetector.h @@ -0,0 +1,77 @@ +#pragma once +#include +#include +#include +#include + +class InputDetector { +public: + explicit InputDetector() = default; + virtual ~InputDetector() = default; + virtual bool GetBoolValue(class InputState& state) const = 0; + virtual enum ButtonState GetButtonValue(class InputState& state) const = 0; + virtual float GetFloatValue(class InputState& state) const = 0; + virtual struct Vector2 GetAxisValue(class InputState& state) const = 0; +private: +}; + +class KeyDetector : public InputDetector { +public: + explicit KeyDetector(SDL_Scancode code); + bool GetBoolValue(class InputState& state) const override; + enum ButtonState GetButtonValue(class InputState& state) const override; + float GetFloatValue(class InputState& state) const override; + struct Vector2 GetAxisValue(class InputState& state) const override; +private: + SDL_Scancode code; +}; + +class MouseDetector : public InputDetector { +public: + explicit MouseDetector(int button); + bool GetBoolValue(class InputState& state) const override; + enum ButtonState GetButtonValue(class InputState& state) const override; + float GetFloatValue(class InputState& state) const override; + struct Vector2 GetAxisValue(class InputState& state) const override; +private: + int button; +}; + +enum class ControllerDirection : int { + Left, + Right +}; + +class ControllerButtonDetector : public InputDetector { +public: + explicit ControllerButtonDetector(SDL_GameControllerButton button); + bool GetBoolValue(class InputState& state) const override; + enum ButtonState GetButtonValue(class InputState& state) const override; + float GetFloatValue(class InputState& state) const override; + struct Vector2 GetAxisValue(class InputState& state) const override; +private: + SDL_GameControllerButton button; +}; + +class ControllerStickDetector : public InputDetector { +public: + explicit ControllerStickDetector(ControllerDirection direction); + bool GetBoolValue(class InputState& state) const override; + enum ButtonState GetButtonValue(class InputState& state) const override; + float GetFloatValue(class InputState& state) const override; + struct Vector2 GetAxisValue(class InputState& state) const override; +private: + ControllerDirection direction; +}; + +class ControllerTriggerDetector : public InputDetector { +public: + explicit ControllerTriggerDetector(ControllerDirection direction); + bool GetBoolValue(class InputState& state) const override; + enum ButtonState GetButtonValue(class InputState& state) const override; + float GetFloatValue(class InputState& state) const override; + struct Vector2 GetAxisValue(class InputState& state) const override; +private: + ControllerDirection direction; + +}; \ No newline at end of file diff --git a/Chapter08/InputSystem.cpp b/Chapter08/InputSystem.cpp index da787cf9..e061e6e1 100644 --- a/Chapter08/InputSystem.cpp +++ b/Chapter08/InputSystem.cpp @@ -8,7 +8,10 @@ #include "InputSystem.h" #include +#include #include +#include +#include bool KeyboardState::GetKeyValue(SDL_Scancode keyCode) const { @@ -131,6 +134,10 @@ bool InputSystem::Initialize() void InputSystem::Shutdown() { + for (auto kv : bindings) { + delete kv.second; + } + ClearBinding(); } void InputSystem::PrepareForUpdate() @@ -223,6 +230,48 @@ void InputSystem::SetRelativeMouseMode(bool value) mState.Mouse.mIsRelative = value; } +void InputSystem::ParseBindingFromFile(const std::string & path) +{ + std::ifstream ifs(path); + std::string str((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); + ParseBindingFromString(str); +} + +void InputSystem::ParseBindingFromString(const std::string & source) +{ + ClearBinding(); + const char* sentence = source.c_str(); + std::stringstream ss(sentence); + std::string to; + + if (sentence != NULL) + { + while (std::getline(ss, to, '\n')) { + std::cout << to << std::endl; + } + } +} + +void InputSystem::PutBinding(const std::string & key, InputDetector * detector) +{ + bindings[key] = detector; +} + +void InputSystem::RemoveBinding(const std::string & key) +{ + bindings.erase(key); +} + +bool InputSystem::HasBinding(const std::string & key) const +{ + return bindings.count(key) > 0; +} + +void InputSystem::ClearBinding() +{ + bindings.clear(); +} + float InputSystem::Filter1D(int input) { // A value < dead zone is interpreted as 0% diff --git a/Chapter08/InputSystem.h b/Chapter08/InputSystem.h index a1eccc04..04c96515 100644 --- a/Chapter08/InputSystem.h +++ b/Chapter08/InputSystem.h @@ -10,6 +10,7 @@ #include #include #include +#include #include "Math.h" // The different button states @@ -100,6 +101,7 @@ struct InputState ControllerState Controller; }; +class InputDetector; class InputSystem { public: @@ -116,9 +118,17 @@ class InputSystem const InputState& GetState() const { return mState; } void SetRelativeMouseMode(bool value); + + void ParseBindingFromFile(const std::string& path); + void ParseBindingFromString(const std::string& source); + void PutBinding(const std::string& key, InputDetector* detector); + void RemoveBinding(const std::string& key); + bool HasBinding(const std::string& key) const; + void ClearBinding(); private: float Filter1D(int input); Vector2 Filter2D(int inputX, int inputY); InputState mState; SDL_GameController* mController; + std::unordered_map bindings; }; From 02f3bc366e5a353c71c0c77625b56c1d754e67b1 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Wed, 25 Sep 2019 15:35:33 +0900 Subject: [PATCH 35/57] add split --- Chapter08/InputSystem.cpp | 22 ++++++++++++++++++++++ Chapter08/InputSystem.h | 1 + 2 files changed, 23 insertions(+) diff --git a/Chapter08/InputSystem.cpp b/Chapter08/InputSystem.cpp index e061e6e1..ebcba37e 100644 --- a/Chapter08/InputSystem.cpp +++ b/Chapter08/InputSystem.cpp @@ -12,6 +12,7 @@ #include #include #include +#include bool KeyboardState::GetKeyValue(SDL_Scancode keyCode) const { @@ -272,6 +273,27 @@ void InputSystem::ClearBinding() bindings.clear(); } +size_t InputSystem::split(const std::string & txt, std::vector& strs, char ch) +{ + //https://stackoverflow.com/questions/5888022/split-string-by-single-spaces + size_t pos = txt.find(ch); + size_t initialPos = 0; + strs.clear(); + + // Decompose statement + while (pos != std::string::npos) { + strs.push_back(txt.substr(initialPos, pos - initialPos)); + initialPos = pos + 1; + + pos = txt.find(ch, initialPos); + } + + // Add the last one + strs.push_back(txt.substr(initialPos, std::min(pos, txt.size()) - initialPos + 1)); + + return strs.size(); +} + float InputSystem::Filter1D(int input) { // A value < dead zone is interpreted as 0% diff --git a/Chapter08/InputSystem.h b/Chapter08/InputSystem.h index 04c96515..68a74636 100644 --- a/Chapter08/InputSystem.h +++ b/Chapter08/InputSystem.h @@ -126,6 +126,7 @@ class InputSystem bool HasBinding(const std::string& key) const; void ClearBinding(); private: + static size_t split(const std::string &txt, std::vector &strs, char ch); float Filter1D(int input); Vector2 Filter2D(int inputX, int inputY); InputState mState; From 188a0e02b5cac7957a65e1835f2474ad813682cc Mon Sep 17 00:00:00 2001 From: desktopgame Date: Wed, 25 Sep 2019 15:51:29 +0900 Subject: [PATCH 36/57] fix parameter --- Chapter08/InputDetector.cpp | 40 +++++++++++++++---------------- Chapter08/InputDetector.h | 48 ++++++++++++++++++------------------- 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/Chapter08/InputDetector.cpp b/Chapter08/InputDetector.cpp index 010656b4..334b183d 100644 --- a/Chapter08/InputDetector.cpp +++ b/Chapter08/InputDetector.cpp @@ -5,22 +5,22 @@ KeyDetector::KeyDetector(SDL_Scancode code) : code(code) { } -bool KeyDetector::GetBoolValue(InputState & state) const +bool KeyDetector::GetBoolValue(const InputState & state) const { return state.Keyboard.GetKeyValue(code); } -ButtonState KeyDetector::GetButtonValue(InputState & state) const +ButtonState KeyDetector::GetButtonValue(const InputState & state) const { return state.Keyboard.GetKeyState(code); } -float KeyDetector::GetFloatValue(InputState & state) const +float KeyDetector::GetFloatValue(const InputState & state) const { return GetBoolValue(state) ? 1 : 0; } -Vector2 KeyDetector::GetAxisValue(InputState & state) const +Vector2 KeyDetector::GetAxisValue(const InputState & state) const { throw std::logic_error("unsupported operation"); } @@ -29,22 +29,22 @@ MouseDetector::MouseDetector(int button) : button(button) { } -bool MouseDetector::GetBoolValue(InputState & state) const +bool MouseDetector::GetBoolValue(const InputState & state) const { return state.Mouse.GetButtonValue(button); } -ButtonState MouseDetector::GetButtonValue(InputState & state) const +ButtonState MouseDetector::GetButtonValue(const InputState & state) const { return state.Mouse.GetButtonState(button); } -float MouseDetector::GetFloatValue(InputState & state) const +float MouseDetector::GetFloatValue(const InputState & state) const { return GetBoolValue(state) ? 1 : 0; } -Vector2 MouseDetector::GetAxisValue(InputState & state) const +Vector2 MouseDetector::GetAxisValue(const InputState & state) const { throw std::logic_error("unsupported operation"); } @@ -53,22 +53,22 @@ ControllerButtonDetector::ControllerButtonDetector(SDL_GameControllerButton butt { } -bool ControllerButtonDetector::GetBoolValue(InputState & state) const +bool ControllerButtonDetector::GetBoolValue(const InputState & state) const { return state.Controller.GetButtonValue(button); } -ButtonState ControllerButtonDetector::GetButtonValue(InputState & state) const +ButtonState ControllerButtonDetector::GetButtonValue(const InputState & state) const { return state.Controller.GetButtonState(button); } -float ControllerButtonDetector::GetFloatValue(InputState & state) const +float ControllerButtonDetector::GetFloatValue(const InputState & state) const { return GetBoolValue(state) ? 1 : 0; } -Vector2 ControllerButtonDetector::GetAxisValue(InputState & state) const +Vector2 ControllerButtonDetector::GetAxisValue(const InputState & state) const { throw std::logic_error("unsupported operation"); } @@ -77,22 +77,22 @@ ControllerStickDetector::ControllerStickDetector(ControllerDirection direction) { } -bool ControllerStickDetector::GetBoolValue(InputState & state) const +bool ControllerStickDetector::GetBoolValue(const InputState & state) const { throw std::logic_error("unsupported operation"); } -ButtonState ControllerStickDetector::GetButtonValue(InputState & state) const +ButtonState ControllerStickDetector::GetButtonValue(const InputState & state) const { throw std::logic_error("unsupported operation"); } -float ControllerStickDetector::GetFloatValue(InputState & state) const +float ControllerStickDetector::GetFloatValue(const InputState & state) const { throw std::logic_error("unsupported operation"); } -Vector2 ControllerStickDetector::GetAxisValue(InputState & state) const +Vector2 ControllerStickDetector::GetAxisValue(const InputState & state) const { if (direction == ControllerDirection::Left) { return state.Controller.GetLeftStick(); @@ -105,17 +105,17 @@ ControllerTriggerDetector::ControllerTriggerDetector(ControllerDirection directi { } -bool ControllerTriggerDetector::GetBoolValue(InputState & state) const +bool ControllerTriggerDetector::GetBoolValue(const InputState & state) const { throw std::logic_error("unsupported operation"); } -ButtonState ControllerTriggerDetector::GetButtonValue(InputState & state) const +ButtonState ControllerTriggerDetector::GetButtonValue(const InputState & state) const { throw std::logic_error("unsupported operation"); } -float ControllerTriggerDetector::GetFloatValue(InputState & state) const +float ControllerTriggerDetector::GetFloatValue(const InputState & state) const { if (direction == ControllerDirection::Left) { return state.Controller.GetLeftTrigger(); @@ -124,7 +124,7 @@ float ControllerTriggerDetector::GetFloatValue(InputState & state) const } } -Vector2 ControllerTriggerDetector::GetAxisValue(InputState & state) const +Vector2 ControllerTriggerDetector::GetAxisValue(const InputState & state) const { throw std::logic_error("unsupported operation"); } diff --git a/Chapter08/InputDetector.h b/Chapter08/InputDetector.h index 68f49573..557dcbd1 100644 --- a/Chapter08/InputDetector.h +++ b/Chapter08/InputDetector.h @@ -8,20 +8,20 @@ class InputDetector { public: explicit InputDetector() = default; virtual ~InputDetector() = default; - virtual bool GetBoolValue(class InputState& state) const = 0; - virtual enum ButtonState GetButtonValue(class InputState& state) const = 0; - virtual float GetFloatValue(class InputState& state) const = 0; - virtual struct Vector2 GetAxisValue(class InputState& state) const = 0; + virtual bool GetBoolValue(const class InputState& state) const = 0; + virtual enum ButtonState GetButtonValue(const class InputState& state) const = 0; + virtual float GetFloatValue(const class InputState& state) const = 0; + virtual struct Vector2 GetAxisValue(const class InputState& state) const = 0; private: }; class KeyDetector : public InputDetector { public: explicit KeyDetector(SDL_Scancode code); - bool GetBoolValue(class InputState& state) const override; - enum ButtonState GetButtonValue(class InputState& state) const override; - float GetFloatValue(class InputState& state) const override; - struct Vector2 GetAxisValue(class InputState& state) const override; + bool GetBoolValue(const class InputState& state) const override; + enum ButtonState GetButtonValue(const class InputState& state) const override; + float GetFloatValue(const class InputState& state) const override; + struct Vector2 GetAxisValue(const class InputState& state) const override; private: SDL_Scancode code; }; @@ -29,10 +29,10 @@ class KeyDetector : public InputDetector { class MouseDetector : public InputDetector { public: explicit MouseDetector(int button); - bool GetBoolValue(class InputState& state) const override; - enum ButtonState GetButtonValue(class InputState& state) const override; - float GetFloatValue(class InputState& state) const override; - struct Vector2 GetAxisValue(class InputState& state) const override; + bool GetBoolValue(const class InputState& state) const override; + enum ButtonState GetButtonValue(const class InputState& state) const override; + float GetFloatValue(const class InputState& state) const override; + struct Vector2 GetAxisValue(const class InputState& state) const override; private: int button; }; @@ -45,10 +45,10 @@ enum class ControllerDirection : int { class ControllerButtonDetector : public InputDetector { public: explicit ControllerButtonDetector(SDL_GameControllerButton button); - bool GetBoolValue(class InputState& state) const override; - enum ButtonState GetButtonValue(class InputState& state) const override; - float GetFloatValue(class InputState& state) const override; - struct Vector2 GetAxisValue(class InputState& state) const override; + bool GetBoolValue(const class InputState& state) const override; + enum ButtonState GetButtonValue(const class InputState& state) const override; + float GetFloatValue(const class InputState& state) const override; + struct Vector2 GetAxisValue(const class InputState& state) const override; private: SDL_GameControllerButton button; }; @@ -56,10 +56,10 @@ class ControllerButtonDetector : public InputDetector { class ControllerStickDetector : public InputDetector { public: explicit ControllerStickDetector(ControllerDirection direction); - bool GetBoolValue(class InputState& state) const override; - enum ButtonState GetButtonValue(class InputState& state) const override; - float GetFloatValue(class InputState& state) const override; - struct Vector2 GetAxisValue(class InputState& state) const override; + bool GetBoolValue(const class InputState& state) const override; + enum ButtonState GetButtonValue(const class InputState& state) const override; + float GetFloatValue(const class InputState& state) const override; + struct Vector2 GetAxisValue(const class InputState& state) const override; private: ControllerDirection direction; }; @@ -67,10 +67,10 @@ class ControllerStickDetector : public InputDetector { class ControllerTriggerDetector : public InputDetector { public: explicit ControllerTriggerDetector(ControllerDirection direction); - bool GetBoolValue(class InputState& state) const override; - enum ButtonState GetButtonValue(class InputState& state) const override; - float GetFloatValue(class InputState& state) const override; - struct Vector2 GetAxisValue(class InputState& state) const override; + bool GetBoolValue(const class InputState& state) const override; + enum ButtonState GetButtonValue(const class InputState& state) const override; + float GetFloatValue(const class InputState& state) const override; + struct Vector2 GetAxisValue(const class InputState& state) const override; private: ControllerDirection direction; From 380ed6792227abd340cf453c7e3854cc1e147639 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Wed, 25 Sep 2019 15:52:50 +0900 Subject: [PATCH 37/57] add utility method --- Chapter08/InputSystem.cpp | 80 ++++++++++++++++++++++++++++++++++++++- Chapter08/InputSystem.h | 7 ++++ 2 files changed, 85 insertions(+), 2 deletions(-) diff --git a/Chapter08/InputSystem.cpp b/Chapter08/InputSystem.cpp index ebcba37e..ce19eb64 100644 --- a/Chapter08/InputSystem.cpp +++ b/Chapter08/InputSystem.cpp @@ -13,6 +13,7 @@ #include #include #include +#include "InputDetector.h" bool KeyboardState::GetKeyValue(SDL_Scancode keyCode) const { @@ -129,7 +130,23 @@ bool InputSystem::Initialize() SDL_CONTROLLER_BUTTON_MAX); memset(mState.Controller.mPrevButtons, 0, SDL_CONTROLLER_BUTTON_MAX); - + cButtons[""] = SDL_CONTROLLER_BUTTON_INVALID; + cButtons["A"] = SDL_CONTROLLER_BUTTON_A; + cButtons["B"] = SDL_CONTROLLER_BUTTON_B; + cButtons["X"] = SDL_CONTROLLER_BUTTON_X; + cButtons["Y"] = SDL_CONTROLLER_BUTTON_Y; + cButtons["Back"] = SDL_CONTROLLER_BUTTON_BACK; + cButtons["Guide"] = SDL_CONTROLLER_BUTTON_GUIDE; + cButtons["Start"] = SDL_CONTROLLER_BUTTON_START; + cButtons["LeftStick"] = SDL_CONTROLLER_BUTTON_LEFTSTICK; + cButtons["RightStick"] = SDL_CONTROLLER_BUTTON_RIGHTSTICK; + cButtons["LeftShoulder"] = SDL_CONTROLLER_BUTTON_LEFTSHOULDER; + cButtons["RightShoulder"] = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER; + cButtons["DPadUp"] = SDL_CONTROLLER_BUTTON_DPAD_UP; + cButtons["DPadDown"] = SDL_CONTROLLER_BUTTON_DPAD_DOWN; + cButtons["DPadLeft"] = SDL_CONTROLLER_BUTTON_DPAD_LEFT; + cButtons["DPadRight"] = SDL_CONTROLLER_BUTTON_DPAD_RIGHT; + cButtons[""] = SDL_CONTROLLER_BUTTON_MAX; return true; } @@ -231,6 +248,26 @@ void InputSystem::SetRelativeMouseMode(bool value) mState.Mouse.mIsRelative = value; } +bool InputSystem::GetBoolValue(const std::string & name) const +{ + return bindings.at(name)->GetBoolValue(mState); +} + +ButtonState InputSystem::GetButtonValue(const std::string & name) const +{ + return bindings.at(name)->GetButtonValue(mState); +} + +float InputSystem::GetFloatValue(const std::string & name) const +{ + return bindings.at(name)->GetFloatValue(mState); +} + +Vector2 InputSystem::GetAxisValue(const std::string & name) const +{ + return bindings.at(name)->GetAxisValue(mState); +} + void InputSystem::ParseBindingFromFile(const std::string & path) { std::ifstream ifs(path); @@ -248,8 +285,47 @@ void InputSystem::ParseBindingFromString(const std::string & source) if (sentence != NULL) { while (std::getline(ss, to, '\n')) { - std::cout << to << std::endl; + AddBinding(to); + } + } +} + +void InputSystem::AddBinding(const std::string & oneline) +{ + std::vector words; + split(oneline, words, ' '); + std::string name = words[0]; + std::string type = words[1]; + if (type == "Key") { + PutBinding(name, new KeyDetector((SDL_Scancode)words[2].at(0))); + } else if (type == "Mouse") { + if (words[2] == "Left") { + PutBinding(name, new MouseDetector(SDL_BUTTON_LEFT)); + } else if (words[2] == "Right") { + PutBinding(name, new MouseDetector(SDL_BUTTON_RIGHT)); + } else { + throw std::logic_error("unknown mouse type: " + words[2]); + } + } else if (type == "ControllerButton") { + PutBinding(name, new ControllerButtonDetector(cButtons[words[2]])); + } else if (type == "ControllerStick") { + if (words[2] == "Left") { + PutBinding(name, new ControllerStickDetector(ControllerDirection::Left)); + } else if (words[2] == "Right") { + PutBinding(name, new ControllerStickDetector(ControllerDirection::Right)); + } else { + throw std::logic_error("unknown stick type: " + words[2]); + } + } else if (type == "ControllerTrigger") { + if (words[2] == "Left") { + PutBinding(name, new ControllerTriggerDetector(ControllerDirection::Left)); + } else if (words[2] == "Right") { + PutBinding(name, new ControllerTriggerDetector(ControllerDirection::Right)); + } else { + throw std::logic_error("unknown stick type: " + words[2]); } + } else { + throw std::logic_error("unsupported input type: " + type); } } diff --git a/Chapter08/InputSystem.h b/Chapter08/InputSystem.h index 68a74636..65a12894 100644 --- a/Chapter08/InputSystem.h +++ b/Chapter08/InputSystem.h @@ -119,8 +119,14 @@ class InputSystem void SetRelativeMouseMode(bool value); + bool GetBoolValue(const std::string& name) const; + ButtonState GetButtonValue(const std::string& name) const; + float GetFloatValue(const std::string& name) const; + Vector2 GetAxisValue(const std::string& name) const; + void ParseBindingFromFile(const std::string& path); void ParseBindingFromString(const std::string& source); + void AddBinding(const std::string& oneline); void PutBinding(const std::string& key, InputDetector* detector); void RemoveBinding(const std::string& key); bool HasBinding(const std::string& key) const; @@ -132,4 +138,5 @@ class InputSystem InputState mState; SDL_GameController* mController; std::unordered_map bindings; + std::unordered_map cButtons; }; From c3db2dd8d1d344f7709329695dfee307881de8e5 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Wed, 25 Sep 2019 15:52:55 +0900 Subject: [PATCH 38/57] add test file --- Chapter08/Assets/Input.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Chapter08/Assets/Input.txt b/Chapter08/Assets/Input.txt index 2955ee4c..9ff34ea5 100644 --- a/Chapter08/Assets/Input.txt +++ b/Chapter08/Assets/Input.txt @@ -1,3 +1 @@ -hoge -huga -jiso \ No newline at end of file +Fire ControllerButton A \ No newline at end of file From a7b0498f7f5b1fc39cb0e0eff7dd88d7d3034c21 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Wed, 25 Sep 2019 16:04:43 +0900 Subject: [PATCH 39/57] fix --- Chapter08/Game.cpp | 3 +- Chapter08/InputSystem.cpp | 309 ++++++++++++++++++++------------------ Chapter08/InputSystem.h | 41 ++--- 3 files changed, 192 insertions(+), 161 deletions(-) diff --git a/Chapter08/Game.cpp b/Chapter08/Game.cpp index 6f38a9ba..ed2d94df 100644 --- a/Chapter08/Game.cpp +++ b/Chapter08/Game.cpp @@ -62,7 +62,7 @@ bool Game::Initialize() // Initialize input system mInputSystem = new InputSystem(); - if (!mInputSystem->Initialize()) + if (!mInputSystem->Initialize("Assets/Input.txt")) { SDL_Log("Failed to initialize input system"); return false; @@ -252,7 +252,6 @@ void Game::CreateSpriteVerts() void Game::LoadData() { - mInputSystem->ParseBindingFromFile("Assets/Input.txt"); // Create player's ship mShip = new Ship(this); mShip->SetRotation(Math::PiOver2); diff --git a/Chapter08/InputSystem.cpp b/Chapter08/InputSystem.cpp index ce19eb64..919edda8 100644 --- a/Chapter08/InputSystem.cpp +++ b/Chapter08/InputSystem.cpp @@ -108,28 +108,8 @@ ButtonState ControllerState::GetButtonState(SDL_GameControllerButton button) con } } } - -bool InputSystem::Initialize() +InputState::InputState() { - // Keyboard - // Assign current state pointer - mState.Keyboard.mCurrState = SDL_GetKeyboardState(NULL); - // Clear previous state memory - memset(mState.Keyboard.mPrevState, 0, - SDL_NUM_SCANCODES); - - // Mouse (just set everything to 0) - mState.Mouse.mCurrButtons = 0; - mState.Mouse.mPrevButtons = 0; - - // Get the connected controller, if it exists - mController = SDL_GameControllerOpen(0); - // Initialize controller state - mState.Controller.mIsConnected = (mController != nullptr); - memset(mState.Controller.mCurrButtons, 0, - SDL_CONTROLLER_BUTTON_MAX); - memset(mState.Controller.mPrevButtons, 0, - SDL_CONTROLLER_BUTTON_MAX); cButtons[""] = SDL_CONTROLLER_BUTTON_INVALID; cButtons["A"] = SDL_CONTROLLER_BUTTON_A; cButtons["B"] = SDL_CONTROLLER_BUTTON_B; @@ -147,135 +127,43 @@ bool InputSystem::Initialize() cButtons["DPadLeft"] = SDL_CONTROLLER_BUTTON_DPAD_LEFT; cButtons["DPadRight"] = SDL_CONTROLLER_BUTTON_DPAD_RIGHT; cButtons[""] = SDL_CONTROLLER_BUTTON_MAX; - return true; } - -void InputSystem::Shutdown() +InputState::~InputState() { for (auto kv : bindings) { delete kv.second; } ClearBinding(); } - -void InputSystem::PrepareForUpdate() +// InputState +bool InputState::GetBoolValue(const std::string & name) const { - // Copy current state to previous - // Keyboard - memcpy(mState.Keyboard.mPrevState, - mState.Keyboard.mCurrState, - SDL_NUM_SCANCODES); - - // Mouse - mState.Mouse.mPrevButtons = mState.Mouse.mCurrButtons; - mState.Mouse.mIsRelative = false; - mState.Mouse.mScrollWheel = Vector2::Zero; - - // Controller - memcpy(mState.Controller.mPrevButtons, - mState.Controller.mCurrButtons, - SDL_CONTROLLER_BUTTON_MAX); + return bindings.at(name)->GetBoolValue(Self()); } -void InputSystem::Update() +ButtonState InputState::GetButtonValue(const std::string & name) const { - // Mouse - int x = 0, y = 0; - if (mState.Mouse.mIsRelative) - { - mState.Mouse.mCurrButtons = - SDL_GetRelativeMouseState(&x, &y); - } - else - { - mState.Mouse.mCurrButtons = - SDL_GetMouseState(&x, &y); - } - - mState.Mouse.mMousePos.x = static_cast(x); - mState.Mouse.mMousePos.y = static_cast(y); - - // Controller - // Buttons - for (int i = 0; i < SDL_CONTROLLER_BUTTON_MAX; i++) - { - mState.Controller.mCurrButtons[i] = - SDL_GameControllerGetButton(mController, - SDL_GameControllerButton(i)); - } - - // Triggers - mState.Controller.mLeftTrigger = - Filter1D(SDL_GameControllerGetAxis(mController, - SDL_CONTROLLER_AXIS_TRIGGERLEFT)); - mState.Controller.mRightTrigger = - Filter1D(SDL_GameControllerGetAxis(mController, - SDL_CONTROLLER_AXIS_TRIGGERRIGHT)); - - // Sticks - x = SDL_GameControllerGetAxis(mController, - SDL_CONTROLLER_AXIS_LEFTX); - y = -SDL_GameControllerGetAxis(mController, - SDL_CONTROLLER_AXIS_LEFTY); - mState.Controller.mLeftStick = Filter2D(x, y); - - x = SDL_GameControllerGetAxis(mController, - SDL_CONTROLLER_AXIS_RIGHTX); - y = -SDL_GameControllerGetAxis(mController, - SDL_CONTROLLER_AXIS_RIGHTY); - mState.Controller.mRightStick = Filter2D(x, y); + return bindings.at(name)->GetButtonValue(Self()); } -void InputSystem::ProcessEvent(SDL_Event& event) +float InputState::GetFloatValue(const std::string & name) const { - switch (event.type) - { - case SDL_MOUSEWHEEL: - mState.Mouse.mScrollWheel = Vector2( - static_cast(event.wheel.x), - static_cast(event.wheel.y)); - break; - default: - break; - } -} - -void InputSystem::SetRelativeMouseMode(bool value) -{ - SDL_bool set = value ? SDL_TRUE : SDL_FALSE; - SDL_SetRelativeMouseMode(set); - - mState.Mouse.mIsRelative = value; -} - -bool InputSystem::GetBoolValue(const std::string & name) const -{ - return bindings.at(name)->GetBoolValue(mState); + return bindings.at(name)->GetFloatValue(Self()); } -ButtonState InputSystem::GetButtonValue(const std::string & name) const +Vector2 InputState::GetAxisValue(const std::string & name) const { - return bindings.at(name)->GetButtonValue(mState); + return bindings.at(name)->GetAxisValue(Self()); } -float InputSystem::GetFloatValue(const std::string & name) const -{ - return bindings.at(name)->GetFloatValue(mState); -} - -Vector2 InputSystem::GetAxisValue(const std::string & name) const -{ - return bindings.at(name)->GetAxisValue(mState); -} - -void InputSystem::ParseBindingFromFile(const std::string & path) +void InputState::ParseBindingFromFile(const std::string & path) { std::ifstream ifs(path); std::string str((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); ParseBindingFromString(str); } -void InputSystem::ParseBindingFromString(const std::string & source) +void InputState::ParseBindingFromString(const std::string & source) { ClearBinding(); const char* sentence = source.c_str(); @@ -290,7 +178,7 @@ void InputSystem::ParseBindingFromString(const std::string & source) } } -void InputSystem::AddBinding(const std::string & oneline) +void InputState::AddBinding(const std::string & oneline) { std::vector words; split(oneline, words, ' '); @@ -298,58 +186,74 @@ void InputSystem::AddBinding(const std::string & oneline) std::string type = words[1]; if (type == "Key") { PutBinding(name, new KeyDetector((SDL_Scancode)words[2].at(0))); - } else if (type == "Mouse") { + } + else if (type == "Mouse") { if (words[2] == "Left") { PutBinding(name, new MouseDetector(SDL_BUTTON_LEFT)); - } else if (words[2] == "Right") { + } + else if (words[2] == "Right") { PutBinding(name, new MouseDetector(SDL_BUTTON_RIGHT)); - } else { + } + else { throw std::logic_error("unknown mouse type: " + words[2]); } - } else if (type == "ControllerButton") { + } + else if (type == "ControllerButton") { PutBinding(name, new ControllerButtonDetector(cButtons[words[2]])); - } else if (type == "ControllerStick") { + } + else if (type == "ControllerStick") { if (words[2] == "Left") { PutBinding(name, new ControllerStickDetector(ControllerDirection::Left)); - } else if (words[2] == "Right") { + } + else if (words[2] == "Right") { PutBinding(name, new ControllerStickDetector(ControllerDirection::Right)); - } else { + } + else { throw std::logic_error("unknown stick type: " + words[2]); } - } else if (type == "ControllerTrigger") { + } + else if (type == "ControllerTrigger") { if (words[2] == "Left") { PutBinding(name, new ControllerTriggerDetector(ControllerDirection::Left)); - } else if (words[2] == "Right") { + } + else if (words[2] == "Right") { PutBinding(name, new ControllerTriggerDetector(ControllerDirection::Right)); - } else { + } + else { throw std::logic_error("unknown stick type: " + words[2]); } - } else { + } + else { throw std::logic_error("unsupported input type: " + type); } } -void InputSystem::PutBinding(const std::string & key, InputDetector * detector) +void InputState::PutBinding(const std::string & key, InputDetector * detector) { bindings[key] = detector; } -void InputSystem::RemoveBinding(const std::string & key) +void InputState::RemoveBinding(const std::string & key) { bindings.erase(key); } -bool InputSystem::HasBinding(const std::string & key) const +bool InputState::HasBinding(const std::string & key) const { return bindings.count(key) > 0; } -void InputSystem::ClearBinding() +void InputState::ClearBinding() { bindings.clear(); } -size_t InputSystem::split(const std::string & txt, std::vector& strs, char ch) +const InputState & InputState::Self() const +{ + return *this; +} + +size_t InputState::split(const std::string & txt, std::vector& strs, char ch) { //https://stackoverflow.com/questions/5888022/split-string-by-single-spaces size_t pos = txt.find(ch); @@ -370,6 +274,127 @@ size_t InputSystem::split(const std::string & txt, std::vector& str return strs.size(); } + +// InputSystem +bool InputSystem::Initialize(const std::string& bindingFile) +{ + // Keyboard + // Assign current state pointer + mState.Keyboard.mCurrState = SDL_GetKeyboardState(NULL); + // Clear previous state memory + memset(mState.Keyboard.mPrevState, 0, + SDL_NUM_SCANCODES); + + // Mouse (just set everything to 0) + mState.Mouse.mCurrButtons = 0; + mState.Mouse.mPrevButtons = 0; + + // Get the connected controller, if it exists + mController = SDL_GameControllerOpen(0); + // Initialize controller state + mState.Controller.mIsConnected = (mController != nullptr); + memset(mState.Controller.mCurrButtons, 0, + SDL_CONTROLLER_BUTTON_MAX); + memset(mState.Controller.mPrevButtons, 0, + SDL_CONTROLLER_BUTTON_MAX); + mState.ParseBindingFromFile(bindingFile); + return true; +} + +void InputSystem::Shutdown() +{ +} + +void InputSystem::PrepareForUpdate() +{ + // Copy current state to previous + // Keyboard + memcpy(mState.Keyboard.mPrevState, + mState.Keyboard.mCurrState, + SDL_NUM_SCANCODES); + + // Mouse + mState.Mouse.mPrevButtons = mState.Mouse.mCurrButtons; + mState.Mouse.mIsRelative = false; + mState.Mouse.mScrollWheel = Vector2::Zero; + + // Controller + memcpy(mState.Controller.mPrevButtons, + mState.Controller.mCurrButtons, + SDL_CONTROLLER_BUTTON_MAX); +} + +void InputSystem::Update() +{ + // Mouse + int x = 0, y = 0; + if (mState.Mouse.mIsRelative) + { + mState.Mouse.mCurrButtons = + SDL_GetRelativeMouseState(&x, &y); + } + else + { + mState.Mouse.mCurrButtons = + SDL_GetMouseState(&x, &y); + } + + mState.Mouse.mMousePos.x = static_cast(x); + mState.Mouse.mMousePos.y = static_cast(y); + + // Controller + // Buttons + for (int i = 0; i < SDL_CONTROLLER_BUTTON_MAX; i++) + { + mState.Controller.mCurrButtons[i] = + SDL_GameControllerGetButton(mController, + SDL_GameControllerButton(i)); + } + + // Triggers + mState.Controller.mLeftTrigger = + Filter1D(SDL_GameControllerGetAxis(mController, + SDL_CONTROLLER_AXIS_TRIGGERLEFT)); + mState.Controller.mRightTrigger = + Filter1D(SDL_GameControllerGetAxis(mController, + SDL_CONTROLLER_AXIS_TRIGGERRIGHT)); + + // Sticks + x = SDL_GameControllerGetAxis(mController, + SDL_CONTROLLER_AXIS_LEFTX); + y = -SDL_GameControllerGetAxis(mController, + SDL_CONTROLLER_AXIS_LEFTY); + mState.Controller.mLeftStick = Filter2D(x, y); + + x = SDL_GameControllerGetAxis(mController, + SDL_CONTROLLER_AXIS_RIGHTX); + y = -SDL_GameControllerGetAxis(mController, + SDL_CONTROLLER_AXIS_RIGHTY); + mState.Controller.mRightStick = Filter2D(x, y); +} + +void InputSystem::ProcessEvent(SDL_Event& event) +{ + switch (event.type) + { + case SDL_MOUSEWHEEL: + mState.Mouse.mScrollWheel = Vector2( + static_cast(event.wheel.x), + static_cast(event.wheel.y)); + break; + default: + break; + } +} + +void InputSystem::SetRelativeMouseMode(bool value) +{ + SDL_bool set = value ? SDL_TRUE : SDL_FALSE; + SDL_SetRelativeMouseMode(set); + + mState.Mouse.mIsRelative = value; +} + float InputSystem::Filter1D(int input) { // A value < dead zone is interpreted as 0% diff --git a/Chapter08/InputSystem.h b/Chapter08/InputSystem.h index 65a12894..fddff39c 100644 --- a/Chapter08/InputSystem.h +++ b/Chapter08/InputSystem.h @@ -93,19 +93,40 @@ class ControllerState bool mIsConnected; }; +class InputDetector; // Wrapper that contains current state of input -struct InputState +class InputState { +public: + InputState(); + ~InputState(); KeyboardState Keyboard; MouseState Mouse; ControllerState Controller; + + bool GetBoolValue(const std::string& name) const; + ButtonState GetButtonValue(const std::string& name) const; + float GetFloatValue(const std::string& name) const; + Vector2 GetAxisValue(const std::string& name) const; + + void ParseBindingFromFile(const std::string& path); + void ParseBindingFromString(const std::string& source); + void AddBinding(const std::string& oneline); + void PutBinding(const std::string& key, InputDetector* detector); + void RemoveBinding(const std::string& key); + bool HasBinding(const std::string& key) const; + void ClearBinding(); +private: + const InputState& Self() const; + std::unordered_map bindings; + std::unordered_map cButtons; + static size_t split(const std::string &txt, std::vector &strs, char ch); }; -class InputDetector; class InputSystem { public: - bool Initialize(); + bool Initialize(const std::string& bindingFile); void Shutdown(); // Called right before SDL_PollEvents loop @@ -119,24 +140,10 @@ class InputSystem void SetRelativeMouseMode(bool value); - bool GetBoolValue(const std::string& name) const; - ButtonState GetButtonValue(const std::string& name) const; - float GetFloatValue(const std::string& name) const; - Vector2 GetAxisValue(const std::string& name) const; - void ParseBindingFromFile(const std::string& path); - void ParseBindingFromString(const std::string& source); - void AddBinding(const std::string& oneline); - void PutBinding(const std::string& key, InputDetector* detector); - void RemoveBinding(const std::string& key); - bool HasBinding(const std::string& key) const; - void ClearBinding(); private: - static size_t split(const std::string &txt, std::vector &strs, char ch); float Filter1D(int input); Vector2 Filter2D(int inputX, int inputY); InputState mState; SDL_GameController* mController; - std::unordered_map bindings; - std::unordered_map cButtons; }; From 23cb83f09be1448d80fb688bcb82d72979c4d8a3 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Wed, 25 Sep 2019 16:06:15 +0900 Subject: [PATCH 40/57] update Ship --- Chapter08/Assets/Input.txt | 2 +- Chapter08/Ship.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Chapter08/Assets/Input.txt b/Chapter08/Assets/Input.txt index 9ff34ea5..f7855c20 100644 --- a/Chapter08/Assets/Input.txt +++ b/Chapter08/Assets/Input.txt @@ -1 +1 @@ -Fire ControllerButton A \ No newline at end of file +Fire Mouse Left \ No newline at end of file diff --git a/Chapter08/Ship.cpp b/Chapter08/Ship.cpp index 86bb7b3d..3bcc5303 100644 --- a/Chapter08/Ship.cpp +++ b/Chapter08/Ship.cpp @@ -38,7 +38,7 @@ void Ship::UpdateActor(float deltaTime) void Ship::ActorInput(const InputState& state) { - if (state.Controller.GetRightTrigger() > 0.25f + if (state.GetBoolValue("Fire") > 0.25f && mLaserCooldown <= 0.0f) { // Create a laser and set its position/rotation to mine From 566ba2e8e35e6569cc0b791791c10a0093170e1f Mon Sep 17 00:00:00 2001 From: desktopgame Date: Wed, 25 Sep 2019 16:08:26 +0900 Subject: [PATCH 41/57] fix parser --- Chapter08/InputSystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Chapter08/InputSystem.cpp b/Chapter08/InputSystem.cpp index 919edda8..2c71426d 100644 --- a/Chapter08/InputSystem.cpp +++ b/Chapter08/InputSystem.cpp @@ -185,7 +185,7 @@ void InputState::AddBinding(const std::string & oneline) std::string name = words[0]; std::string type = words[1]; if (type == "Key") { - PutBinding(name, new KeyDetector((SDL_Scancode)words[2].at(0))); + PutBinding(name, new KeyDetector((SDL_Scancode)std::stoi(words[2]))); } else if (type == "Mouse") { if (words[2] == "Left") { From 777ff668863207c9a8394a23ad3bd883c8ad9bc9 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Wed, 25 Sep 2019 16:09:10 +0900 Subject: [PATCH 42/57] add comment syntax --- Chapter08/InputSystem.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Chapter08/InputSystem.cpp b/Chapter08/InputSystem.cpp index 2c71426d..13af2f9d 100644 --- a/Chapter08/InputSystem.cpp +++ b/Chapter08/InputSystem.cpp @@ -173,6 +173,9 @@ void InputState::ParseBindingFromString(const std::string & source) if (sentence != NULL) { while (std::getline(ss, to, '\n')) { + if (to[0] == '#') { + continue; + } AddBinding(to); } } From a654b5e3761811357901b15c61c14958e36e7358 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Wed, 25 Sep 2019 16:10:22 +0900 Subject: [PATCH 43/57] fix binding --- Chapter08/Assets/Input.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Chapter08/Assets/Input.txt b/Chapter08/Assets/Input.txt index f7855c20..ef8e79b6 100644 --- a/Chapter08/Assets/Input.txt +++ b/Chapter08/Assets/Input.txt @@ -1 +1,4 @@ -Fire Mouse Left \ No newline at end of file +Fire Mouse Left +#縺薙▲縺。繧呈怏蜉ケ縺ォ縺吶k縺ィA繧ュ繝シ縺梧怏蜉ケ縺ォ縺ェ繧 +#謨ー蟄励ョ隧ウ邏ー縺ッ SDL_scancode.h 縺ォ +#Fire Key 4 \ No newline at end of file From 46e5451e085c5e7b276bc567b168d16bbc463896 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Wed, 25 Sep 2019 16:28:35 +0900 Subject: [PATCH 44/57] fix --- Chapter08/Ship.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Chapter08/Ship.cpp b/Chapter08/Ship.cpp index 3bcc5303..a94e2854 100644 --- a/Chapter08/Ship.cpp +++ b/Chapter08/Ship.cpp @@ -38,7 +38,7 @@ void Ship::UpdateActor(float deltaTime) void Ship::ActorInput(const InputState& state) { - if (state.GetBoolValue("Fire") > 0.25f + if (state.GetFloatValue("Fire") > 0.25f && mLaserCooldown <= 0.0f) { // Create a laser and set its position/rotation to mine From ad3314e3cd14f2e77d19f6799f3687b0b740b232 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Thu, 26 Sep 2019 13:47:37 +0900 Subject: [PATCH 45/57] temp --- Chapter09/FollowCamera.cpp | 44 ++++++++++++++++++++++++++++++++++++-- Chapter09/FollowCamera.h | 9 ++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/Chapter09/FollowCamera.cpp b/Chapter09/FollowCamera.cpp index 274a5754..fb60bdbe 100644 --- a/Chapter09/FollowCamera.cpp +++ b/Chapter09/FollowCamera.cpp @@ -8,6 +8,7 @@ #include "FollowCamera.h" #include "Actor.h" +#include "Game.h" FollowCamera::FollowCamera(Actor* owner) :CameraComponent(owner) @@ -15,6 +16,10 @@ FollowCamera::FollowCamera(Actor* owner) ,mVertDist(150.0f) ,mTargetDist(100.0f) ,mSpringConstant(64.0f) + ,mOffset(-400.0f, 0.0f, 0.0f) + ,mUp(Vector3::UnitZ) + ,mPitchSpeed(0.0f) + ,mYawSpeed(0.0f) { } @@ -39,8 +44,43 @@ void FollowCamera::Update(float deltaTime) mOwner->GetForward() * mTargetDist; // Use actual position here, not ideal Matrix4 view = Matrix4::CreateLookAt(mActualPos, target, - Vector3::UnitZ); - SetViewMatrix(view); + mUp); + + int x, y; + Uint32 buttons = SDL_GetMouseState(&x, &y); + bool leftIsDown = (buttons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0; + if (leftIsDown) { + this->mYawSpeed = 1.0f; + this->mPitchSpeed = 1.0f; + // Create a quaternion for yaw about world up + Quaternion yaw(Vector3::UnitZ, mYawSpeed * deltaTime); + // Transform offset and up by yaw + mOffset = Vector3::Transform(mOffset, yaw); + mUp = Vector3::Transform(mUp, yaw); + + // Compute camera forward/right from these vectors + // Forward owner.position - (owner.position + offset) + // = -offset + Vector3 forward = -1.0f * mOffset; + forward.Normalize(); + Vector3 right = Vector3::Cross(mUp, forward); + right.Normalize(); + + // Create quaternion for pitch about camera right + Quaternion pitch(right, mPitchSpeed * deltaTime); + // Transform camera offset and up by pitch + mOffset = Vector3::Transform(mOffset, pitch); + mUp = Vector3::Transform(mUp, pitch); + + Matrix4 pm = Matrix4::CreateFromQuaternion(pitch); + Matrix4 ym = Matrix4::CreateFromQuaternion(yaw); + SetViewMatrix(view * pm * ym); + } else { + mOffset = Vector3(-400.0f, 0.0f, 0.0f); + mUp = (Vector3::UnitZ); + mPitchSpeed = (0.0f); + SetViewMatrix(view); + } } void FollowCamera::SnapToIdeal() diff --git a/Chapter09/FollowCamera.h b/Chapter09/FollowCamera.h index f821e408..5d894814 100644 --- a/Chapter09/FollowCamera.h +++ b/Chapter09/FollowCamera.h @@ -37,4 +37,13 @@ class FollowCamera : public CameraComponent float mTargetDist; // Spring constant (higher is more stiff) float mSpringConstant; + + // Offset from target + Vector3 mOffset; + // Up vector of camera + Vector3 mUp; + // Rotation/sec speed of pitch + float mPitchSpeed; + // Rotation/sec speed of yaw + float mYawSpeed; }; From 569a3e7198b1f58dbf14fd1772aa45adc0e822f3 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Thu, 26 Sep 2019 14:38:28 +0900 Subject: [PATCH 46/57] update SplineCamera --- Chapter09/SplineCamera.cpp | 25 ++++++++++++++++++++++++- Chapter09/SplineCamera.h | 1 + 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/Chapter09/SplineCamera.cpp b/Chapter09/SplineCamera.cpp index 7c542f83..371ae12a 100644 --- a/Chapter09/SplineCamera.cpp +++ b/Chapter09/SplineCamera.cpp @@ -43,6 +43,7 @@ SplineCamera::SplineCamera(Actor* owner) ,mT(0.0f) ,mSpeed(0.5f) ,mPaused(true) + ,mReturn(false) { } @@ -50,7 +51,7 @@ void SplineCamera::Update(float deltaTime) { CameraComponent::Update(deltaTime); // Update t value - if (!mPaused) + if (!mReturn && !mPaused) { mT += mSpeed * deltaTime; // Advance to the next control point if needed. @@ -65,9 +66,31 @@ void SplineCamera::Update(float deltaTime) mT = mT - 1.0f; } else + { + // Path's done, so pause + mPaused = false; + mReturn = true; + } + } + } + if (mReturn && !mPaused) { + mT += mSpeed * deltaTime; + // Advance to the next control point if needed. + // This assumes speed isn't so fast that you jump past + // multiple control points in one frame. + if (mT >= 1.0f) + { + // Make sure we have enough points to advance the path + if (mIndex > 1) + { + mIndex--; + mT = mT - 1.0f; + } + else { // Path's done, so pause mPaused = true; + mReturn = false; } } } diff --git a/Chapter09/SplineCamera.h b/Chapter09/SplineCamera.h index a76f4fe4..d5ee14c9 100644 --- a/Chapter09/SplineCamera.h +++ b/Chapter09/SplineCamera.h @@ -45,4 +45,5 @@ class SplineCamera : public CameraComponent float mSpeed; // Whether to move the camera long the path bool mPaused; + bool mReturn; }; From 1e94cf9abac684f07651447fae3faefb0c28e938 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Thu, 26 Sep 2019 18:06:53 +0900 Subject: [PATCH 47/57] add jump system --- Chapter10/FPSActor.cpp | 23 ++++++++++++++++++++++- Chapter10/FPSActor.h | 8 ++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/Chapter10/FPSActor.cpp b/Chapter10/FPSActor.cpp index d22170fd..b9404f57 100644 --- a/Chapter10/FPSActor.cpp +++ b/Chapter10/FPSActor.cpp @@ -21,6 +21,9 @@ FPSActor::FPSActor(Game* game) :Actor(game) + ,mState(FPSActorState::None) + ,mVelocityY(0) + ,mGravityY(0) { mMoveComp = new MoveComponent(this); mAudioComp = new AudioComponent(this); @@ -95,7 +98,16 @@ void FPSActor::ActorInput(const uint8_t* keys) { strafeSpeed += 400.0f; } - + if (this->mState == FPSActorState::None && keys[SDL_SCANCODE_SPACE]) { + this->mState = FPSActorState::Jump; + this->mVelocityY = 100; + this->mGravityY = 0; + } else if (this->mState == FPSActorState::Jump) { + // add gravity + const float GRAVITY_SCALE = 1.0f; + this->mGravityY -= GRAVITY_SCALE; + this->mVelocityY += mGravityY; + } mMoveComp->SetForwardSpeed(forwardSpeed); mMoveComp->SetStrafeSpeed(strafeSpeed); @@ -127,6 +139,15 @@ void FPSActor::ActorInput(const uint8_t* keys) pitchSpeed *= maxPitchSpeed; } mCameraComp->SetPitchSpeed(pitchSpeed); + if (this->mState == FPSActorState::Jump) { + Vector3 curPos = this->GetPosition(); + Vector3 newPos = curPos + (Vector3::UnitZ * mVelocityY); + if (newPos.z < 0) { + newPos.z = 0; + this->mState = FPSActorState::None; + } + this->SetPosition(newPos); + } } void FPSActor::Shoot() diff --git a/Chapter10/FPSActor.h b/Chapter10/FPSActor.h index b904f76c..44682640 100644 --- a/Chapter10/FPSActor.h +++ b/Chapter10/FPSActor.h @@ -10,6 +10,11 @@ #include "Actor.h" #include "SoundEvent.h" +enum class FPSActorState { + None, + Jump, + Fall, +}; class FPSActor : public Actor { public: @@ -34,4 +39,7 @@ class FPSActor : public Actor class Actor* mFPSModel; SoundEvent mFootstep; float mLastFootstep; + FPSActorState mState; + float mGravityY; + float mVelocityY; }; From 2c4ebc17908fcdb016873926dc259dd1122dbc69 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Thu, 26 Sep 2019 21:29:43 +0900 Subject: [PATCH 48/57] fix jump system --- Chapter10/FPSActor.cpp | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/Chapter10/FPSActor.cpp b/Chapter10/FPSActor.cpp index b9404f57..2ca2bda0 100644 --- a/Chapter10/FPSActor.cpp +++ b/Chapter10/FPSActor.cpp @@ -18,6 +18,7 @@ #include "BallActor.h" #include "BoxComponent.h" #include "PlaneActor.h" +#include "PhysWorld.h" FPSActor::FPSActor(Game* game) :Actor(game) @@ -49,6 +50,26 @@ FPSActor::FPSActor(Game* game) void FPSActor::UpdateActor(float deltaTime) { Actor::UpdateActor(deltaTime); + if (this->mState == FPSActorState::Jump) { + // add gravity + const float GRAVITY_SCALE = 1.0f; + this->mGravityY -= GRAVITY_SCALE; + this->mVelocityY += mGravityY; + // update position + Vector3 curPos = this->GetPosition() + (Vector3::NegUnitZ * (87.5f * 2.f)); + Vector3 newPos = curPos + (Vector3::UnitZ * mVelocityY); + LineSegment lineSeg(curPos, newPos); + PhysWorld::CollisionInfo cinfo; + if (GetGame()->GetPhysWorld()->SegmentCast(lineSeg, cinfo) && + mVelocityY < 0 && + this != cinfo.mActor) { + newPos.y = cinfo.mPoint.y; + this->mState = FPSActorState::None; + } + Vector3 tmp = this->GetPosition() + (Vector3::UnitZ * mVelocityY); + tmp.y = newPos.y; + this->SetPosition(tmp); + } FixCollisions(); @@ -99,14 +120,10 @@ void FPSActor::ActorInput(const uint8_t* keys) strafeSpeed += 400.0f; } if (this->mState == FPSActorState::None && keys[SDL_SCANCODE_SPACE]) { + const float JUMP_POWER = 100.0f; this->mState = FPSActorState::Jump; - this->mVelocityY = 100; + this->mVelocityY = JUMP_POWER; this->mGravityY = 0; - } else if (this->mState == FPSActorState::Jump) { - // add gravity - const float GRAVITY_SCALE = 1.0f; - this->mGravityY -= GRAVITY_SCALE; - this->mVelocityY += mGravityY; } mMoveComp->SetForwardSpeed(forwardSpeed); mMoveComp->SetStrafeSpeed(strafeSpeed); @@ -139,15 +156,6 @@ void FPSActor::ActorInput(const uint8_t* keys) pitchSpeed *= maxPitchSpeed; } mCameraComp->SetPitchSpeed(pitchSpeed); - if (this->mState == FPSActorState::Jump) { - Vector3 curPos = this->GetPosition(); - Vector3 newPos = curPos + (Vector3::UnitZ * mVelocityY); - if (newPos.z < 0) { - newPos.z = 0; - this->mState = FPSActorState::None; - } - this->SetPosition(newPos); - } } void FPSActor::Shoot() From fad5ebfd5f8cca6de829d6e8510cc0aca919bb6a Mon Sep 17 00:00:00 2001 From: desktopgame Date: Thu, 26 Sep 2019 22:20:28 +0900 Subject: [PATCH 49/57] update sweep & pron --- Chapter10/PhysWorld.cpp | 122 ++++++++++++++++++++++++++++++++++------ Chapter10/PhysWorld.h | 4 ++ 2 files changed, 110 insertions(+), 16 deletions(-) diff --git a/Chapter10/PhysWorld.cpp b/Chapter10/PhysWorld.cpp index 6db12580..c3b4d7b0 100644 --- a/Chapter10/PhysWorld.cpp +++ b/Chapter10/PhysWorld.cpp @@ -10,6 +10,8 @@ #include #include "BoxComponent.h" #include +#include +#include PhysWorld::PhysWorld(Game* game) :mGame(game) @@ -65,21 +67,20 @@ void PhysWorld::TestPairwise(std::function f) void PhysWorld::TestSweepAndPrune(std::function f) { - // Sort by min.x - std::sort(mBoxes.begin(), mBoxes.end(), - [](BoxComponent* a, BoxComponent* b) { - return a->GetWorldBox().mMin.x < - b->GetWorldBox().mMin.x; - }); - for (size_t i = 0; i < mBoxes.size(); i++) + std::unordered_map > xMap; + std::unordered_map > yMap; + std::unordered_map > zMap; + + for (size_t i = 0; i < mXBoxes.size(); i++) { // Get max.x for current box - BoxComponent* a = mBoxes[i]; + BoxComponent* a = mXBoxes[i]; float max = a->GetWorldBox().mMax.x; - for (size_t j = i + 1; j < mBoxes.size(); j++) + std::vector dest; + for (size_t j = i + 1; j < mXBoxes.size(); j++) { - BoxComponent* b = mBoxes[j]; + BoxComponent* b = mXBoxes[j]; // If AABB[j] min is past the max bounds of AABB[i], // then there aren't any other possible intersections // against AABB[i] @@ -89,24 +90,113 @@ void PhysWorld::TestSweepAndPrune(std::function f) } else if (Intersect(a->GetWorldBox(), b->GetWorldBox())) { - f(a->GetOwner(), b->GetOwner()); + dest.emplace_back(b); + } + } + xMap.insert_or_assign(a, dest); + } + for (size_t i = 0; i < mYBoxes.size(); i++) + { + // Get max.x for current box + BoxComponent* a = mYBoxes[i]; + float max = a->GetWorldBox().mMax.y; + std::vector dest; + for (size_t j = i + 1; j < mYBoxes.size(); j++) + { + BoxComponent* b = mYBoxes[j]; + // If AABB[j] min is past the max bounds of AABB[i], + // then there aren't any other possible intersections + // against AABB[i] + if (b->GetWorldBox().mMin.y > max) + { + break; + } + else if (Intersect(a->GetWorldBox(), b->GetWorldBox())) + { + dest.emplace_back(b); + } + } + yMap.insert_or_assign(a, dest); + } + for (size_t i = 0; i < mZBoxes.size(); i++) + { + // Get max.x for current box + BoxComponent* a = mZBoxes[i]; + float max = a->GetWorldBox().mMax.z; + std::vector dest; + for (size_t j = i + 1; j < mZBoxes.size(); j++) + { + BoxComponent* b = mZBoxes[j]; + // If AABB[j] min is past the max bounds of AABB[i], + // then there aren't any other possible intersections + // against AABB[i] + if (b->GetWorldBox().mMin.z > max) + { + break; + } + else if (Intersect(a->GetWorldBox(), b->GetWorldBox())) + { + dest.emplace_back(b); } } + zMap.insert_or_assign(a, dest); + } + std::unordered_set uniqueBoxes; + for (auto box : mBoxes) { + uniqueBoxes.clear(); + const std::vector& xv = xMap.at(box); + const std::vector& yv = yMap.at(box); + const std::vector& zv = zMap.at(box); + if (xv.empty() || yv.empty() || zv.empty()) { + continue; + } + for (auto v : xv) uniqueBoxes.emplace(v); + for (auto v : yv) uniqueBoxes.emplace(v); + for (auto v : zv) uniqueBoxes.emplace(v); + for (auto uniqueV : uniqueBoxes) { + f(box->GetOwner(), uniqueV->GetOwner()); + } } } void PhysWorld::AddBox(BoxComponent* box) { mBoxes.emplace_back(box); + mXBoxes.emplace_back(box); + mYBoxes.emplace_back(box); + mZBoxes.emplace_back(box); + std::sort(mXBoxes.begin(), mXBoxes.end(), + [](BoxComponent* a, BoxComponent* b) { + return a->GetWorldBox().mMin.x < + b->GetWorldBox().mMin.x; + }); + std::sort(mYBoxes.begin(), mYBoxes.end(), + [](BoxComponent* a, BoxComponent* b) { + return a->GetWorldBox().mMin.y < + b->GetWorldBox().mMin.y; + }); + std::sort(mZBoxes.begin(), mZBoxes.end(), + [](BoxComponent* a, BoxComponent* b) { + return a->GetWorldBox().mMin.z < + b->GetWorldBox().mMin.z; + }); } void PhysWorld::RemoveBox(BoxComponent* box) { - auto iter = std::find(mBoxes.begin(), mBoxes.end(), box); - if (iter != mBoxes.end()) + RemoveBox(mBoxes, box); + RemoveBox(mXBoxes, box); + RemoveBox(mYBoxes, box); + RemoveBox(mZBoxes, box); +} + +void PhysWorld::RemoveBox(std::vector src, BoxComponent * box) +{ + auto iter = std::find(src.begin(), src.end(), box); + if (iter != src.end()) { // Swap to end of vector and pop off (avoid erase copies) - std::iter_swap(iter, mBoxes.end() - 1); - mBoxes.pop_back(); + std::iter_swap(iter, src.end() - 1); + src.pop_back(); } -} +} \ No newline at end of file diff --git a/Chapter10/PhysWorld.h b/Chapter10/PhysWorld.h index db392cb6..741b51e8 100644 --- a/Chapter10/PhysWorld.h +++ b/Chapter10/PhysWorld.h @@ -44,5 +44,9 @@ class PhysWorld void RemoveBox(class BoxComponent* box); private: class Game* mGame; + static void RemoveBox(std::vector src, class BoxComponent* box); std::vector mBoxes; + std::vector mXBoxes; + std::vector mYBoxes; + std::vector mZBoxes; }; From 69d1e14e78fe565866d7221084312ca1b78e7aae Mon Sep 17 00:00:00 2001 From: desktopgame Date: Fri, 27 Sep 2019 13:17:21 +0900 Subject: [PATCH 50/57] temp --- Chapter10/Collision.cpp | 20 ++++++++++++++++++++ Chapter10/Collision.h | 1 + Chapter11/Assets/English.gptext | 2 ++ Chapter11/Assets/Russian.gptext | 2 ++ Chapter11/Game.cpp | 2 ++ Chapter11/Game.h | 1 + Chapter11/Game.vcxproj | 2 ++ Chapter11/Game.vcxproj.filters | 6 ++++++ Chapter11/MainMenu.cpp | 26 ++++++++++++++++++++++++++ Chapter11/MainMenu.h | 8 ++++++++ 10 files changed, 70 insertions(+) create mode 100644 Chapter11/MainMenu.cpp create mode 100644 Chapter11/MainMenu.h diff --git a/Chapter10/Collision.cpp b/Chapter10/Collision.cpp index 46ab3681..d96c5766 100644 --- a/Chapter10/Collision.cpp +++ b/Chapter10/Collision.cpp @@ -300,6 +300,26 @@ bool Intersect(const AABB& a, const AABB& b) return !no; } +bool Intersect(const OBB & a, const OBB & b) +{ + Vector3 aNAxisX = Vector3::Transform(Vector3::UnitX, a.mRotation); + Vector3 aNAxisY = Vector3::Transform(Vector3::UnitY, a.mRotation); + Vector3 aNAxisZ = Vector3::Transform(Vector3::UnitZ, a.mRotation); + Vector3 bNAxisX = Vector3::Transform(Vector3::UnitX, b.mRotation); + Vector3 bNAxisY = Vector3::Transform(Vector3::UnitY, b.mRotation); + Vector3 bNAxisZ = Vector3::Transform(Vector3::UnitZ, b.mRotation); + + + Vector3 aAxisX = aNAxisX * a.mExtents.x; + Vector3 aAxisY = aNAxisX * a.mExtents.y; + Vector3 aAxisZ = aNAxisX * a.mExtents.z; + Vector3 bAxisX = aNAxisX * a.mExtents.x; + Vector3 bAxisY = aNAxisX * a.mExtents.y; + Vector3 bAxisZ = aNAxisX * a.mExtents.z; + + return false; +} + bool Intersect(const Capsule& a, const Capsule& b) { float distSq = LineSegment::MinDistSq(a.mSegment, diff --git a/Chapter10/Collision.h b/Chapter10/Collision.h index 67c672f8..e1175750 100644 --- a/Chapter10/Collision.h +++ b/Chapter10/Collision.h @@ -88,6 +88,7 @@ struct ConvexPolygon // Intersection functions bool Intersect(const Sphere& a, const Sphere& b); bool Intersect(const AABB& a, const AABB& b); +bool Intersect(const OBB& a, const OBB& b); bool Intersect(const Capsule& a, const Capsule& b); bool Intersect(const Sphere& s, const AABB& box); diff --git a/Chapter11/Assets/English.gptext b/Chapter11/Assets/English.gptext index 17a2b8a4..2796a2fe 100644 --- a/Chapter11/Assets/English.gptext +++ b/Chapter11/Assets/English.gptext @@ -1,7 +1,9 @@ { "TextMap":{ "PauseTitle": "PAUSED", + "MainMenuTitle": "MAIN MENU", "ResumeButton": "Resume", + "StartButton": "Start", "QuitButton": "Quit", "QuitText": "Do you want to quit?", "OKButton": "OK", diff --git a/Chapter11/Assets/Russian.gptext b/Chapter11/Assets/Russian.gptext index 4011f9f3..24784ea7 100644 --- a/Chapter11/Assets/Russian.gptext +++ b/Chapter11/Assets/Russian.gptext @@ -1,7 +1,9 @@ { "TextMap":{ "PauseTitle": "ミ渙籍」ミ厘", + "MainMenuTitle": "MAIN MENU", "ResumeButton": "ミ湲ミセミエミセミサミカミクムび", + "StartButton": "Start", "QuitButton": "ミ」ミイミセミサミクムび袴ム", "QuitText": "ミ柘 ムミセムひクムひオ ミアムミセムミクムび ミコムτミクムび?", "OKButton": "ミ榧", diff --git a/Chapter11/Game.cpp b/Chapter11/Game.cpp index a4809788..96974f57 100644 --- a/Chapter11/Game.cpp +++ b/Chapter11/Game.cpp @@ -26,6 +26,7 @@ #include #include #include +#include "MainMenu.h" Game::Game() :mRenderer(nullptr) @@ -355,6 +356,7 @@ void Game::LoadData() SDL_SetRelativeMouseMode(SDL_TRUE); // Make an initial call to get relative to clear out SDL_GetRelativeMouseState(nullptr, nullptr); + new MainMenu(this); // Different camera actors mFPSActor = new FPSActor(this); diff --git a/Chapter11/Game.h b/Chapter11/Game.h index 1384784d..4592fb19 100644 --- a/Chapter11/Game.h +++ b/Chapter11/Game.h @@ -38,6 +38,7 @@ class Game enum GameState { + EMainMenu, EGameplay, EPaused, EQuit diff --git a/Chapter11/Game.vcxproj b/Chapter11/Game.vcxproj index e3284cb3..85e8ff17 100644 --- a/Chapter11/Game.vcxproj +++ b/Chapter11/Game.vcxproj @@ -27,6 +27,7 @@ + @@ -60,6 +61,7 @@ + diff --git a/Chapter11/Game.vcxproj.filters b/Chapter11/Game.vcxproj.filters index 93afbba1..5ab4b539 100644 --- a/Chapter11/Game.vcxproj.filters +++ b/Chapter11/Game.vcxproj.filters @@ -106,6 +106,9 @@ Source Files + + Source Files + @@ -201,6 +204,9 @@ Source Files + + Source Files + diff --git a/Chapter11/MainMenu.cpp b/Chapter11/MainMenu.cpp new file mode 100644 index 00000000..2022a690 --- /dev/null +++ b/Chapter11/MainMenu.cpp @@ -0,0 +1,26 @@ +#include "MainMenu.h" +#include "Game.h" +#include "DialogBox.h" +#include + +MainMenu::MainMenu(Game * game) : UIScreen(game) +{ + mGame->SetState(Game::EMainMenu); + SetRelativeMouseMode(false); + SetTitle("MainMenuTitle"); + AddButton("StartButton", [this]() { + Close(); + }); + AddButton("QuitButton", [this]() { + new DialogBox(mGame, "QuitText", + [this]() { + mGame->SetState(Game::EQuit); + }); + }); +} + +MainMenu::~MainMenu() +{ + SetRelativeMouseMode(true); + mGame->SetState(Game::EGameplay); +} diff --git a/Chapter11/MainMenu.h b/Chapter11/MainMenu.h new file mode 100644 index 00000000..17305201 --- /dev/null +++ b/Chapter11/MainMenu.h @@ -0,0 +1,8 @@ +#pragma once +#include "UIScreen.h" + +class MainMenu : public UIScreen { +public: + MainMenu(class Game* game); + ~MainMenu(); +}; \ No newline at end of file From 0ad663f98ab99d2be167431a1a003c0f7da4e0bc Mon Sep 17 00:00:00 2001 From: desktopgame Date: Fri, 27 Sep 2019 13:22:28 +0900 Subject: [PATCH 51/57] add MainMenu --- Chapter11/Game.cpp | 71 ++++++++++++++++++++++++++-------------------- Chapter11/Game.h | 2 ++ 2 files changed, 43 insertions(+), 30 deletions(-) diff --git a/Chapter11/Game.cpp b/Chapter11/Game.cpp index 96974f57..86bad4a8 100644 --- a/Chapter11/Game.cpp +++ b/Chapter11/Game.cpp @@ -34,6 +34,7 @@ Game::Game() ,mPhysWorld(nullptr) ,mGameState(EGameplay) ,mUpdatingActors(false) +,mGenActors(false) { } @@ -284,6 +285,9 @@ void Game::UpdateGame() ++iter; } } + if (this->mGameState == EGameplay) { + GenActors(); + } } void Game::GenerateOutput() @@ -296,6 +300,41 @@ void Game::LoadData() // Load English text LoadText("Assets/English.gptext"); + // Enable relative mouse mode for camera look + SDL_SetRelativeMouseMode(SDL_TRUE); + // Make an initial call to get relative to clear out + SDL_GetRelativeMouseState(nullptr, nullptr); + new MainMenu(this); +} + +void Game::UnloadData() +{ + // Delete actors + // Because ~Actor calls RemoveActor, have to use a different style loop + while (!mActors.empty()) + { + delete mActors.back(); + } + + // Clear the UI stack + while (!mUIStack.empty()) + { + delete mUIStack.back(); + mUIStack.pop_back(); + } + + if (mRenderer) + { + mRenderer->UnloadData(); + } +} + +void Game::GenActors() +{ + if (mGenActors) { + return; + } + this->mGenActors = true; // Create actors Actor* a = nullptr; Quaternion q; @@ -320,7 +359,7 @@ void Game::LoadData() a = new PlaneActor(this); a->SetPosition(Vector3(start + i * size, start - size, 0.0f)); a->SetRotation(q); - + a = new PlaneActor(this); a->SetPosition(Vector3(start + i * size, -start + size, 0.0f)); a->SetRotation(q); @@ -348,16 +387,10 @@ void Game::LoadData() // UI elements mHUD = new HUD(this); - + // Start music mMusicEvent = mAudioSystem->PlayEvent("event:/Music"); - // Enable relative mouse mode for camera look - SDL_SetRelativeMouseMode(SDL_TRUE); - // Make an initial call to get relative to clear out - SDL_GetRelativeMouseState(nullptr, nullptr); - new MainMenu(this); - // Different camera actors mFPSActor = new FPSActor(this); @@ -378,28 +411,6 @@ void Game::LoadData() a->SetRotation(Quaternion(Vector3::UnitZ, -Math::PiOver2)); } -void Game::UnloadData() -{ - // Delete actors - // Because ~Actor calls RemoveActor, have to use a different style loop - while (!mActors.empty()) - { - delete mActors.back(); - } - - // Clear the UI stack - while (!mUIStack.empty()) - { - delete mUIStack.back(); - mUIStack.pop_back(); - } - - if (mRenderer) - { - mRenderer->UnloadData(); - } -} - void Game::Shutdown() { UnloadData(); diff --git a/Chapter11/Game.h b/Chapter11/Game.h index 4592fb19..40f97d8f 100644 --- a/Chapter11/Game.h +++ b/Chapter11/Game.h @@ -62,6 +62,7 @@ class Game void GenerateOutput(); void LoadData(); void UnloadData(); + void GenActors(); // All the actors in the game std::vector mActors; @@ -88,4 +89,5 @@ class Game class FPSActor* mFPSActor; class SpriteComponent* mCrosshair; SoundEvent mMusicEvent; + bool mGenActors; }; From 7180732166331176b2adf0587784c7df433eb276 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Fri, 27 Sep 2019 13:33:04 +0900 Subject: [PATCH 52/57] add Icon --- Chapter11/HUD.cpp | 10 ++++++---- Chapter11/HUD.h | 7 ++++++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Chapter11/HUD.cpp b/Chapter11/HUD.cpp index 1b578937..e79fd501 100644 --- a/Chapter11/HUD.cpp +++ b/Chapter11/HUD.cpp @@ -53,9 +53,9 @@ void HUD::Draw(Shader* shader) const Vector2 cRadarPos(-390.0f, 275.0f); DrawTexture(shader, mRadar, cRadarPos, 1.0f); // Blips - for (Vector2& blip : mBlips) + for (Icon& icon : mBlips) { - DrawTexture(shader, mBlipTex, cRadarPos + blip, 1.0f); + DrawTexture(shader, icon.mTexture, cRadarPos + icon.mPosition, 1.0f); } // Radar arrow DrawTexture(shader, mRadarArrow, cRadarPos); @@ -117,7 +117,7 @@ void HUD::UpdateRadar(float deltaTime) float angle = Math::Atan2(playerForward2D.y, playerForward2D.x); // Make a 2D rotation matrix Matrix3 rotMat = Matrix3::CreateRotation(angle); - + Icon icon; // Get positions of blips for (auto tc : mTargetComps) { @@ -137,7 +137,9 @@ void HUD::UpdateRadar(float deltaTime) // Rotate blipPos blipPos = Vector2::Transform(blipPos, rotMat); - mBlips.emplace_back(blipPos); + icon.mPosition = blipPos; + icon.mTexture = mBlipTex; + mBlips.emplace_back(icon); } } } diff --git a/Chapter11/HUD.h b/Chapter11/HUD.h index 9f7f973a..d200e96f 100644 --- a/Chapter11/HUD.h +++ b/Chapter11/HUD.h @@ -10,6 +10,11 @@ #include "UIScreen.h" #include +struct Icon { + Vector2 mPosition; + class Texture* mTexture; +}; + class HUD : public UIScreen { public: @@ -36,7 +41,7 @@ class HUD : public UIScreen // All the target components in the game std::vector mTargetComps; // 2D offsets of blips relative to radar - std::vector mBlips; + std::vector mBlips; // Adjust range of radar and radius float mRadarRange; float mRadarRadius; From 2e2134936f1fb9924e4cbd67bec2dbdd8d5542d7 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Fri, 27 Sep 2019 13:36:04 +0900 Subject: [PATCH 53/57] change icon --- Chapter11/HUD.cpp | 7 +++++++ Chapter11/HUD.h | 2 ++ 2 files changed, 9 insertions(+) diff --git a/Chapter11/HUD.cpp b/Chapter11/HUD.cpp index e79fd501..5092342a 100644 --- a/Chapter11/HUD.cpp +++ b/Chapter11/HUD.cpp @@ -28,6 +28,8 @@ HUD::HUD(Game* game) mCrosshair = r->GetTexture("Assets/Crosshair.png"); mCrosshairEnemy = r->GetTexture("Assets/CrosshairRed.png"); mBlipTex = r->GetTexture("Assets/Blip.png"); + mHighBlipTex = r->GetTexture("Assets/BlipUp.png"); + mLowBlipTex = r->GetTexture("Assets/BlipDown.png"); mRadarArrow = r->GetTexture("Assets/RadarArrow.png"); } @@ -139,6 +141,11 @@ void HUD::UpdateRadar(float deltaTime) blipPos = Vector2::Transform(blipPos, rotMat); icon.mPosition = blipPos; icon.mTexture = mBlipTex; + if (targetPos.y > playerPos.y) { + icon.mTexture = mHighBlipTex; + } else if (targetPos.y < playerPos.y) { + icon.mTexture = mLowBlipTex; + } mBlips.emplace_back(icon); } } diff --git a/Chapter11/HUD.h b/Chapter11/HUD.h index d200e96f..51592253 100644 --- a/Chapter11/HUD.h +++ b/Chapter11/HUD.h @@ -36,6 +36,8 @@ class HUD : public UIScreen class Texture* mCrosshair; class Texture* mCrosshairEnemy; class Texture* mBlipTex; + class Texture* mHighBlipTex; + class Texture* mLowBlipTex; class Texture* mRadarArrow; // All the target components in the game From ca6e05efa7d72fb8249e565a81fd513cb7c876cb Mon Sep 17 00:00:00 2001 From: desktopgame Date: Fri, 27 Sep 2019 15:06:59 +0900 Subject: [PATCH 54/57] implement arrow target --- Chapter11/Game.cpp | 2 ++ Chapter11/Game.h | 2 ++ Chapter11/HUD.cpp | 9 +++++++++ Chapter11/HUD.h | 3 +++ Chapter11/UIScreen.cpp | 19 +++++++++++++++++++ Chapter11/UIScreen.h | 3 +++ 6 files changed, 38 insertions(+) diff --git a/Chapter11/Game.cpp b/Chapter11/Game.cpp index 86bad4a8..55db6ae8 100644 --- a/Chapter11/Game.cpp +++ b/Chapter11/Game.cpp @@ -35,6 +35,7 @@ Game::Game() ,mGameState(EGameplay) ,mUpdatingActors(false) ,mGenActors(false) +,mArrowTarget(nullptr) { } @@ -393,6 +394,7 @@ void Game::GenActors() // Different camera actors mFPSActor = new FPSActor(this); + mArrowTarget = new Actor(this); // Create target actors a = new TargetActor(this); diff --git a/Chapter11/Game.h b/Chapter11/Game.h index 40f97d8f..9064dd9a 100644 --- a/Chapter11/Game.h +++ b/Chapter11/Game.h @@ -55,6 +55,7 @@ class Game void AddPlane(class PlaneActor* plane); void RemovePlane(class PlaneActor* plane); std::vector& GetPlanes() { return mPlanes; } + class Actor* GetArrowTarget() const { return mArrowTarget; } private: void ProcessInput(); void HandleKeyPress(int key); @@ -87,6 +88,7 @@ class Game // Game-specific code std::vector mPlanes; class FPSActor* mFPSActor; + class Actor* mArrowTarget; class SpriteComponent* mCrosshair; SoundEvent mMusicEvent; bool mGenActors; diff --git a/Chapter11/HUD.cpp b/Chapter11/HUD.cpp index 5092342a..3ed94412 100644 --- a/Chapter11/HUD.cpp +++ b/Chapter11/HUD.cpp @@ -31,6 +31,7 @@ HUD::HUD(Game* game) mHighBlipTex = r->GetTexture("Assets/BlipUp.png"); mLowBlipTex = r->GetTexture("Assets/BlipDown.png"); mRadarArrow = r->GetTexture("Assets/RadarArrow.png"); + mTargetArrow = r->GetTexture("Assets/Arrow.png"); } HUD::~HUD() @@ -61,6 +62,7 @@ void HUD::Draw(Shader* shader) } // Radar arrow DrawTexture(shader, mRadarArrow, cRadarPos); + DrawTexture2(shader, mTargetArrow, mArrowPos, 1.0f, mAngle); //// Health bar //DrawTexture(shader, mHealthBar, Vector2(-350.0f, -350.0f)); @@ -114,6 +116,13 @@ void HUD::UpdateRadar(float deltaTime) // Ditto for player forward Vector3 playerForward = mGame->GetPlayer()->GetForward(); Vector2 playerForward2D(playerForward.x, playerForward.y); + + Vector3 arrowTargetPos = mGame->GetArrowTarget()->GetPosition(); + Vector2 arrowTargetPos2D(arrowTargetPos.y, arrowTargetPos.x); + Vector2 dirToArrow = playerPos2D - arrowTargetPos2D; + dirToArrow.Normalize(); + this->mAngle = Math::Atan2(-dirToArrow.x, dirToArrow.y); + this->mArrowPos = Vector2(); // Use atan2 to get rotation of radar float angle = Math::Atan2(playerForward2D.y, playerForward2D.x); diff --git a/Chapter11/HUD.h b/Chapter11/HUD.h index 51592253..969c8d25 100644 --- a/Chapter11/HUD.h +++ b/Chapter11/HUD.h @@ -39,6 +39,9 @@ class HUD : public UIScreen class Texture* mHighBlipTex; class Texture* mLowBlipTex; class Texture* mRadarArrow; + class Texture* mTargetArrow; + float mAngle; + Vector2 mArrowPos; // All the target components in the game std::vector mTargetComps; diff --git a/Chapter11/UIScreen.cpp b/Chapter11/UIScreen.cpp index a21d8580..84971d1e 100644 --- a/Chapter11/UIScreen.cpp +++ b/Chapter11/UIScreen.cpp @@ -174,6 +174,25 @@ void UIScreen::DrawTexture(class Shader* shader, class Texture* texture, glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr); } +void UIScreen::DrawTexture2(Shader * shader, Texture * texture, const Vector2 & offset, float scale, float angle) +{// Scale the quad by the width/height of texture + Matrix4 scaleMat = Matrix4::CreateScale( + static_cast(texture->GetWidth()) * scale, + static_cast(texture->GetHeight()) * scale, + 1.0f); + // Translate to position on screen + Matrix4 transMat = Matrix4::CreateTranslation( + Vector3(offset.x, offset.y, 0.0f)); + Matrix4 rotationMat = Matrix4::CreateRotationZ(angle); + // Set world transform + Matrix4 world = scaleMat * rotationMat * transMat; + shader->SetMatrixUniform("uWorldTransform", world); + // Set current texture + texture->SetActive(); + // Draw quad + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr); +} + void UIScreen::SetRelativeMouseMode(bool relative) { if (relative) diff --git a/Chapter11/UIScreen.h b/Chapter11/UIScreen.h index cb37007a..491d194d 100644 --- a/Chapter11/UIScreen.h +++ b/Chapter11/UIScreen.h @@ -75,6 +75,9 @@ class UIScreen void DrawTexture(class Shader* shader, class Texture* texture, const Vector2& offset = Vector2::Zero, float scale = 1.0f); + void DrawTexture2(class Shader* shader, class Texture* texture, + const Vector2& offset = Vector2::Zero, + float scale = 1.0f, float angle = 0.0f); // Sets the mouse mode to relative or not void SetRelativeMouseMode(bool relative); class Game* mGame; From bf194f6b1a77859666d244e57039885ebc334eee Mon Sep 17 00:00:00 2001 From: desktopgame Date: Fri, 27 Sep 2019 15:37:26 +0900 Subject: [PATCH 55/57] fix --- Chapter11/HUD.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Chapter11/HUD.cpp b/Chapter11/HUD.cpp index 3ed94412..c7fb39ba 100644 --- a/Chapter11/HUD.cpp +++ b/Chapter11/HUD.cpp @@ -150,9 +150,9 @@ void HUD::UpdateRadar(float deltaTime) blipPos = Vector2::Transform(blipPos, rotMat); icon.mPosition = blipPos; icon.mTexture = mBlipTex; - if (targetPos.y > playerPos.y) { + if (targetPos.z > playerPos.z) { icon.mTexture = mHighBlipTex; - } else if (targetPos.y < playerPos.y) { + } else if (targetPos.z < playerPos.z) { icon.mTexture = mLowBlipTex; } mBlips.emplace_back(icon); From 9add4771e7c25d66f35240a3902f5de9abd050ac Mon Sep 17 00:00:00 2001 From: desktopgame Date: Sat, 28 Sep 2019 12:56:38 +0900 Subject: [PATCH 56/57] add GetBonePosition --- Chapter12/SkeletalMeshComponent.cpp | 12 ++++++++++++ Chapter12/SkeletalMeshComponent.h | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/Chapter12/SkeletalMeshComponent.cpp b/Chapter12/SkeletalMeshComponent.cpp index 640c94c8..e7c58e0e 100644 --- a/Chapter12/SkeletalMeshComponent.cpp +++ b/Chapter12/SkeletalMeshComponent.cpp @@ -65,6 +65,17 @@ void SkeletalMeshComponent::Update(float deltaTime) } } +Vector3 SkeletalMeshComponent::GetBonePosition(const std::string & name) const { + for (size_t i = 0; i < mSkeleton->GetNumBones(); i++) { + const Skeleton::Bone& bone = mSkeleton->GetBone(i); + if (bone.mName != name) { + continue; + } + return Vector3::Transform(Vector3::Zero, mPose[i]); + } + throw std::logic_error("invalid name: " + name); +} + float SkeletalMeshComponent::PlayAnimation(const Animation* anim, float playRate) { mAnimation = anim; @@ -83,6 +94,7 @@ void SkeletalMeshComponent::ComputeMatrixPalette() const std::vector& globalInvBindPoses = mSkeleton->GetGlobalInvBindPoses(); std::vector currentPoses; mAnimation->GetGlobalPoseAtTime(currentPoses, mSkeleton, mAnimTime); + this->mPose = currentPoses; // Setup the palette for each bone for (size_t i = 0; i < mSkeleton->GetNumBones(); i++) diff --git a/Chapter12/SkeletalMeshComponent.h b/Chapter12/SkeletalMeshComponent.h index 2237f769..07e37086 100644 --- a/Chapter12/SkeletalMeshComponent.h +++ b/Chapter12/SkeletalMeshComponent.h @@ -9,6 +9,7 @@ #pragma once #include "MeshComponent.h" #include "MatrixPalette.h" +#include class SkeletalMeshComponent : public MeshComponent { @@ -22,6 +23,8 @@ class SkeletalMeshComponent : public MeshComponent // Setters void SetSkeleton(const class Skeleton* sk) { mSkeleton = sk; } + Vector3 GetBonePosition(const std::string& name) const; + // Play an animation. Returns the length of the animation float PlayAnimation(const class Animation* anim, float playRate = 1.0f); protected: @@ -32,4 +35,5 @@ class SkeletalMeshComponent : public MeshComponent const class Animation* mAnimation; float mAnimPlayRate; float mAnimTime; + std::vector mPose; }; From 2a8c6e20ff9814992158985d56e73630fef0cc57 Mon Sep 17 00:00:00 2001 From: desktopgame Date: Sat, 28 Sep 2019 21:47:29 +0900 Subject: [PATCH 57/57] performance tune --- Chapter14/LevelLoader.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Chapter14/LevelLoader.cpp b/Chapter14/LevelLoader.cpp index 0970b5c0..636017d5 100644 --- a/Chapter14/LevelLoader.cpp +++ b/Chapter14/LevelLoader.cpp @@ -287,6 +287,17 @@ void LevelLoader::SaveActors(rapidjson::Document::AllocatorType& alloc, rapidjson::Value props(rapidjson::kObjectType); // Save properties actor->SaveProperties(alloc, props); + + // Check default value + if (actor->GetType() == Actor::TypeID::TTargetActor) { + TargetActor tempActor(game); + rapidjson::Value tempJson(rapidjson::kObjectType); + tempActor.SaveProperties(alloc, tempJson); + if (props == tempJson) { + props.Clear(); + } + } + // Add the properties member obj.AddMember("properties", props, alloc);