From a034d3692a21bbf7218fc11f9df7d0df52fb47cc Mon Sep 17 00:00:00 2001 From: Nick Cano Date: Thu, 28 Jan 2016 09:38:12 -0800 Subject: [PATCH] Chapter 11 examples --- .../Chapter11_SearchAlgorithms.cpp | 143 ++++++++++ .../Chapter11_SearchAlgorithms.vcxproj | 74 ++++++ ...Chapter11_SearchAlgorithms.vcxproj.filters | 33 +++ Chapter11_SearchAlgorithms/DummyWindow.cpp | 120 +++++++++ Chapter11_SearchAlgorithms/DummyWindow.h | 46 ++++ Chapter11_SearchAlgorithms/WindowCode.h | 247 ++++++++++++++++++ .../Chapter11_StateMachines.cpp | 101 +++++++ .../Chapter11_StateMachines.vcxproj | 76 ++++++ .../Chapter11_StateMachines.vcxproj.filters | 27 ++ Chapter11_StateMachines/Game.h | 105 ++++++++ 10 files changed, 972 insertions(+) create mode 100644 Chapter11_SearchAlgorithms/Chapter11_SearchAlgorithms.cpp create mode 100644 Chapter11_SearchAlgorithms/Chapter11_SearchAlgorithms.vcxproj create mode 100644 Chapter11_SearchAlgorithms/Chapter11_SearchAlgorithms.vcxproj.filters create mode 100644 Chapter11_SearchAlgorithms/DummyWindow.cpp create mode 100644 Chapter11_SearchAlgorithms/DummyWindow.h create mode 100644 Chapter11_SearchAlgorithms/WindowCode.h create mode 100644 Chapter11_StateMachines/Chapter11_StateMachines.cpp create mode 100644 Chapter11_StateMachines/Chapter11_StateMachines.vcxproj create mode 100644 Chapter11_StateMachines/Chapter11_StateMachines.vcxproj.filters create mode 100644 Chapter11_StateMachines/Game.h diff --git a/Chapter11_SearchAlgorithms/Chapter11_SearchAlgorithms.cpp b/Chapter11_SearchAlgorithms/Chapter11_SearchAlgorithms.cpp new file mode 100644 index 0000000..78c4d7b --- /dev/null +++ b/Chapter11_SearchAlgorithms/Chapter11_SearchAlgorithms.cpp @@ -0,0 +1,143 @@ +#include +#include +#include +#include +#include +#include + +#include "WindowCode.h" + + +#define TILE_COST 1 + +class AStarNode; +typedef std::shared_ptr AStarNodePtr; + +class AStarNode +{ +public: + int x, y; + int g, score; + AStarNodePtr parent; + + AStarNode(int x, int y, int cost, AStarNodePtr p, int score = 0) + : x(x), y(y), g(cost), score(score), parent(p) + {} + static AStarNodePtr makePtr(int x, int y, int cost, AStarNodePtr p, int score = 0) + { + return AStarNodePtr(new AStarNode(x, y, cost, p, score)); + } + int heuristic(const int destx, int desty) const + { + int xd = destx - x; + int yd = desty - y; + return abs(xd) + abs(yd); + } + void updateScore(int endx, int endy) + { + this->score = g + heuristic(endx, endy) * TILE_COST; + } + AStarNodePtr getCopy() + { + return AStarNode::makePtr(x, y, g, parent, score); + } + std::vector getChildren(int width, int height) + { + std::vector ret; + auto copy = getCopy(); + if (x > 0) + ret.push_back(AStarNode::makePtr(x - 1, y, g + TILE_COST, copy)); + if (y > 0) + ret.push_back(AStarNode::makePtr(x, y - 1, g + TILE_COST, copy)); + if (x < width - 1) + ret.push_back(AStarNode::makePtr(x + 1, y, g + TILE_COST, copy)); + if (y < height - 1) + ret.push_back(AStarNode::makePtr(x, y + 1, g + TILE_COST, copy)); + return ret; + } +}; + +bool operator<(const AStarNodePtr &a, const AStarNodePtr &b) +{ + return a->score > b->score; +} +bool operator==(const AStarNodePtr &a, const AStarNodePtr &b) +{ + return a->x == b->x && a->y == b->y; +} + +template +void makeList(AStarNodePtr end, std::vector nodes, int path[WIDTH][HEIGHT]) +{ + for (auto n = nodes.begin(); n != nodes.end(); n++) + path[(*n)->x][(*n)->y] = 2; + + AStarNodePtr node = end; + while (node.get() != nullptr) + { + path[node->x][node->y] = 1; + node = node->parent; + } +} + +template +bool doAStarSearch( + int map[WIDTH][HEIGHT], + int startx, int starty, + int endx, int endy, + int path[WIDTH][HEIGHT]) +{ + std::priority_queue frontier; + std::vector allNodes; + + auto node = AStarNode::makePtr(startx, starty, 0, nullptr); + node->updateScore(endx, endy); + allNodes.push_back(node); + + while (true) + { + if (node->x == endx && node->y == endy) + { + makeList(node, allNodes, path); + return true; + } + + auto children = node->getChildren(WIDTH, HEIGHT); + for (auto c = children.begin(); c != children.end(); c++) + { + if (map[(*c)->x][(*c)->y] == BLOCKING) + continue; + auto found = std::find(allNodes.rbegin(), allNodes.rend(), *c); + if (found != allNodes.rend()) + { + if (*found > *c) + { + (*found)->g = (*c)->g; + (*found)->parent = (*c)->parent; + (*found)->updateScore(endx, endy); + } + } + else + { + (*c)->updateScore(endx, endy); + frontier.push(*c); + allNodes.push_back(*c); + } + } + + if (frontier.size() == 0) + return false; + + node = frontier.top(); + frontier.pop(); + } +} + + + +int main (int argc, char *argv[]) +{ + searchFunction = doAStarSearch; + showWindow(); + return 0; +} \ No newline at end of file diff --git a/Chapter11_SearchAlgorithms/Chapter11_SearchAlgorithms.vcxproj b/Chapter11_SearchAlgorithms/Chapter11_SearchAlgorithms.vcxproj new file mode 100644 index 0000000..c84198e --- /dev/null +++ b/Chapter11_SearchAlgorithms/Chapter11_SearchAlgorithms.vcxproj @@ -0,0 +1,74 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {35470A34-CBB0-41D1-A54B-E1CF3DE9A3B7} + Chapter11_SearchAlgorithms + + + + Application + true + MultiByte + + + Application + false + true + Unicode + + + + + + + + + + + + + + + Level3 + Disabled + + + true + + + + + Level3 + MaxSpeed + true + true + + + true + true + true + Console + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Chapter11_SearchAlgorithms/Chapter11_SearchAlgorithms.vcxproj.filters b/Chapter11_SearchAlgorithms/Chapter11_SearchAlgorithms.vcxproj.filters new file mode 100644 index 0000000..abc5ebf --- /dev/null +++ b/Chapter11_SearchAlgorithms/Chapter11_SearchAlgorithms.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/Chapter11_SearchAlgorithms/DummyWindow.cpp b/Chapter11_SearchAlgorithms/DummyWindow.cpp new file mode 100644 index 0000000..f18cffe --- /dev/null +++ b/Chapter11_SearchAlgorithms/DummyWindow.cpp @@ -0,0 +1,120 @@ +#include "DummyWindow.h" + +/* + THIS CODE EXISTS ONLY TO DISPLAY A WINDOW, + AND IS NOT RELEVANT TO THE EXAMPLE CODE +*/ + +std::map DummyWindow::windowMap; + +DummyWindow::DummyWindow(HINSTANCE _instance) : windowHandle(NULL), instance(_instance) +{} + +DummyWindow::~DummyWindow(void) +{ + DummyWindow::unregisterWindow(this, this->windowHandle); +} + +bool DummyWindow::initialize() +{ + WNDCLASSEX wcex; + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = WndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = this->instance; + wcex.hIcon = NULL; //LoadIcon(this->instance, MAKEINTRESOURCE(IDI_APPLICATION)); + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wcex.lpszMenuName = NULL; + wcex.lpszClassName = L"gamhakwind"; + wcex.hIconSm = NULL; //LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION)); + + if (!RegisterClassEx(&wcex)) + { + auto err = GetLastError(); + return false; + } + + this->windowHandle = CreateWindowA + ( + "gamhakwind", + "Game Hacking - Chapter 11 - SearchAlgorithms", + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, + 420, 490, + NULL, + NULL, + this->instance, + NULL + ); + if (this->windowHandle == NULL) + { + auto err = GetLastError(); + //return false; + } + + DummyWindow::registerWindow(this, this->windowHandle); + + SetTimer(this->windowHandle, NULL, 50, NULL); + + ShowWindow(this->windowHandle, SW_SHOW); + UpdateWindow(this->windowHandle); + return true; +} + +void DummyWindow::finalize() +{ + this->callbackMap.clear(); +} + +int32_t DummyWindow::doMessageLoop() +{ + MSG msg; + while (GetMessage(&msg, NULL, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return static_cast(msg.wParam); +} + +void DummyWindow::setMessageHandler(UINT message, windowMessageCallbackType callback) +{ + this->callbackMap[message] = callback; +} + +LRESULT DummyWindow::onMessageReceived(HWND window, UINT message, WPARAM wparam, LPARAM lparam) +{ + auto found = this->callbackMap.find(message); + if (found != this->callbackMap.end()) + return found->second(this, message, wparam, lparam); + return DefWindowProc(window, message, wparam, lparam); +} + +void DummyWindow::registerWindow(DummyWindow* dummy, HWND window) +{ + DummyWindow::windowMap[window] = dummy; +} +void DummyWindow::unregisterWindow(DummyWindow* dummy, HWND window) +{ + auto found = DummyWindow::windowMap.find(window); + if (found != DummyWindow::windowMap.end()) + DummyWindow::windowMap.erase(found); +} +DummyWindow* DummyWindow::findWindow(HWND window) +{ + auto found = DummyWindow::windowMap.find(window); + if (found != DummyWindow::windowMap.end()) + return found->second; + return nullptr; +} + +LRESULT DummyWindow::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + auto dummy = DummyWindow::findWindow(hWnd); + if (dummy) + return dummy->onMessageReceived(hWnd, uMsg, wParam, lParam); + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} \ No newline at end of file diff --git a/Chapter11_SearchAlgorithms/DummyWindow.h b/Chapter11_SearchAlgorithms/DummyWindow.h new file mode 100644 index 0000000..48747cd --- /dev/null +++ b/Chapter11_SearchAlgorithms/DummyWindow.h @@ -0,0 +1,46 @@ +#pragma once + +/* + THIS CODE EXISTS ONLY TO DISPLAY A WINDOW, + AND IS NOT RELEVANT TO THE EXAMPLE CODE +*/ + +#include +#include +#include +#include +#include + +class DummyWindow; +typedef std::function windowMessageCallbackType; + +class DummyWindow +{ +public: + DummyWindow(HINSTANCE _instance); + ~DummyWindow(void); + + bool initialize(); + void finalize(); + int32_t doMessageLoop(); + void setMessageHandler(UINT message, windowMessageCallbackType callback); + + HWND getHandle() { return this->windowHandle; } + +private: + static std::map windowMap; + + static void registerWindow(DummyWindow* dummy, HWND window); + static void unregisterWindow(DummyWindow* dummy, HWND window); + static DummyWindow* findWindow(HWND window); + static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + + +private: + std::map callbackMap; + HWND windowHandle; + HINSTANCE instance; + + LRESULT onMessageReceived(HWND window, UINT message, WPARAM wparam, LPARAM lparam); +}; + diff --git a/Chapter11_SearchAlgorithms/WindowCode.h b/Chapter11_SearchAlgorithms/WindowCode.h new file mode 100644 index 0000000..ec80560 --- /dev/null +++ b/Chapter11_SearchAlgorithms/WindowCode.h @@ -0,0 +1,247 @@ +#pragma once + +/* + THIS CODE EXISTS ONLY TO DISPLAY A WINDOW, + AND IS NOT RELEVANT TO THE EXAMPLE CODE +*/ + +#include "DummyWindow.h" +#include +#include +#include +#include + +const static int TILESIZE = 20; +const static int OFFSETX = 0; +const static int OFFSETY = 60; + +const static int YSIZE = 20; +const static int XSIZE = 20; + +const static int UNBLOCKING_TILE = 0; +const static int BLOCKING_TILE = 1; +const static int START_TILE = 2; +const static int END_TILE = 3; + + +int map[YSIZE][XSIZE] = {}; +int path[YSIZE][XSIZE] = {}; + +std::function searchFunction; + +#define DUMMY_SET_MESSAGE_HANDLER(dummy, message, callback) \ + do { dummy->setMessageHandler(message, callback); } while(0) + +typedef std::shared_ptr DummyWindowSharedPtr; + +DummyWindowSharedPtr dummyWindow; + + +void clearPath() +{ + memset((void*)&path, 0, sizeof(path)); +} + +LRESULT keyUpHandler(DummyWindow* dummy, UINT message, WPARAM wparam, LPARAM lparam) +{ + if (wparam == VK_RETURN) + { + clearPath(); + searchFunction(map, 0, 10, 19, 10, path); + } + return DefWindowProc(dummy->getHandle(), message, wparam, lparam); +} +LRESULT mouseUpHandler(DummyWindow* dummy, UINT message, WPARAM wparam, LPARAM lparam) +{ + POINT mousePoint; + mousePoint.x = GET_X_LPARAM(lparam) - OFFSETX; + mousePoint.y = GET_Y_LPARAM(lparam) - OFFSETY; + mousePoint.x /= TILESIZE; + mousePoint.y /= TILESIZE; + + mousePoint.x = mousePoint.x > XSIZE ? XSIZE : mousePoint.x; + mousePoint.y = mousePoint.y > YSIZE ? YSIZE : mousePoint.y; + mousePoint.x = mousePoint.x < 0 ? 0 : mousePoint.x; + mousePoint.y = mousePoint.y < 0 ? 0 : mousePoint.y; + + if (map[mousePoint.x][mousePoint.y] == BLOCKING_TILE) + map[mousePoint.x][mousePoint.y] = UNBLOCKING_TILE; + else if (map[mousePoint.x][mousePoint.y] == UNBLOCKING_TILE) + map[mousePoint.x][mousePoint.y] = BLOCKING_TILE; + + clearPath(); + return DefWindowProc(dummy->getHandle(), message, wparam, lparam); +} + +void paintString(HDC hdc, const wchar_t* string, int x, int y) +{ + TextOut(hdc, x, y, string, wcslen(string)); +} + +void paintMap(HDC hdc) +{ + static HBRUSH blackBrush = CreateSolidBrush(RGB(0, 0, 0)); + static HBRUSH redBrush = CreateSolidBrush(RGB(225, 40, 40)); + static HBRUSH greenBrush = CreateSolidBrush(RGB(40, 225, 40)); + static HBRUSH yellowBrush = CreateSolidBrush(RGB(255, 255, 0)); + static HBRUSH greyBrush = CreateSolidBrush(RGB(160, 160, 160)); + + paintString(hdc, L"Walls: Black ", 3, 3); + paintString(hdc, L"Start Pos: Green ", 113, 3); + paintString(hdc, L"End Pos: Red ", 253, 3); + + paintString(hdc, L"Path: Yellow Dots ", 3, 22); + paintString(hdc, L"Closed Nodes: Black Dots ", 203, 22); + + paintString(hdc, L"Toggle Wall: Click ", 3, 41); + paintString(hdc, L"Calculate Path: [enter] ", 203, 41); + + // draw tiles + for (int x = 0; x < XSIZE; x++) + { + int xStart = OFFSETX + x * TILESIZE; + for (int y = 0; y < YSIZE; y++) + { + auto tile = map[x][y]; + RECT location; + location.left = OFFSETX + x * TILESIZE; + location.top = OFFSETY + y * TILESIZE; + location.right = location.left + TILESIZE; + location.bottom = location.top + TILESIZE; + + switch (tile) + { + case UNBLOCKING_TILE: + FillRect(hdc, &location, greyBrush); + break; + case BLOCKING_TILE: + FillRect(hdc, &location, blackBrush); + break; + case START_TILE: + FillRect(hdc, &location, greenBrush); + break; + case END_TILE: + FillRect(hdc, &location, redBrush); + break; + default: + break; + } + + } + + } + + // draw path + for (int x = 0; x < XSIZE; x++) + { + int xStart = OFFSETX + x * TILESIZE; + for (int y = 0; y < YSIZE; y++) + { + auto tile = path[x][y]; + RECT location; + location.left = OFFSETX + x * TILESIZE; + location.top = OFFSETY + y * TILESIZE; + location.right = location.left + TILESIZE; + location.bottom = location.top + TILESIZE; + location.left += 6; + location.top += 6; + location.right -= 6; + location.bottom -= 6; + + if (tile == 1) + { + FillRect(hdc, &location, yellowBrush); + } + else if (tile == 2) + { + FillRect(hdc, &location, blackBrush); + } + } + + } + + // draw grid overlay + for (int x = 0; x < XSIZE; x++) + { + int xStart = OFFSETX + x * TILESIZE; + for (int y = 0; y < YSIZE; y++) + { + int yStart = OFFSETY + y * TILESIZE; + MoveToEx(hdc, OFFSETX, yStart, NULL); + LineTo(hdc, OFFSETX + XSIZE * TILESIZE, yStart); + } + MoveToEx(hdc, xStart + TILESIZE, OFFSETY, NULL); + LineTo(hdc, xStart + TILESIZE, OFFSETY + YSIZE * TILESIZE); + } +} + +LRESULT paintMessageHandler(DummyWindow* dummy, UINT message, WPARAM wparam, LPARAM lparam) +{ + RECT rect; + GetClientRect(dummy->getHandle(), &rect); + int width = rect.right - rect.left; + int height = rect.bottom + rect.left; + + PAINTSTRUCT ps; + auto hdc = BeginPaint(dummy->getHandle(), &ps); + auto secondhdc = CreateCompatibleDC(hdc); + auto buffer2 = CreateCompatibleBitmap(hdc, width, height); + SelectObject(secondhdc, buffer2); + + paintMap(secondhdc); + + BitBlt(hdc, 0, 0, width, height, secondhdc, 0, 0, SRCCOPY); + DeleteObject(buffer2); + DeleteDC(secondhdc); + DeleteDC(hdc); + EndPaint(dummy->getHandle(), &ps); + return 0; +} +LRESULT timerMessageHandler(DummyWindow* dummy, UINT message, WPARAM wparam, LPARAM lparam) +{ + RedrawWindow(dummy->getHandle(), NULL, NULL, RDW_INVALIDATE); + return 0; +} + +LRESULT closeMessageHandler(DummyWindow* dummy, UINT message, WPARAM wparam, LPARAM lparam) +{ + DestroyWindow(dummy->getHandle()); + return 0; +} +LRESULT destroyMessageHandler(DummyWindow* dummy, UINT message, WPARAM wparam, LPARAM lparam) +{ + PostQuitMessage(0); + return 0; +} + +LRESULT setCursorHandler(DummyWindow* dummy, UINT message, WPARAM wparam, LPARAM lparam) +{ + return DefWindowProc(dummy->getHandle(), message, wparam, lparam); +} + + +void showWindow() +{ + memset((void*)&map, 0, sizeof(map)); + memset((void*)&path, 0, sizeof(path)); + + map[0][10] = START_TILE; + map[19][10] = END_TILE; + + dummyWindow = DummyWindowSharedPtr(new DummyWindow(NULL)); + dummyWindow->initialize(); + + DUMMY_SET_MESSAGE_HANDLER(dummyWindow, WM_KEYUP, keyUpHandler); + DUMMY_SET_MESSAGE_HANDLER(dummyWindow, WM_LBUTTONUP, mouseUpHandler); + DUMMY_SET_MESSAGE_HANDLER(dummyWindow, WM_PAINT, paintMessageHandler); + DUMMY_SET_MESSAGE_HANDLER(dummyWindow, WM_TIMER, timerMessageHandler); + DUMMY_SET_MESSAGE_HANDLER(dummyWindow, WM_CLOSE, closeMessageHandler); + DUMMY_SET_MESSAGE_HANDLER(dummyWindow, WM_DESTROY, destroyMessageHandler); + DUMMY_SET_MESSAGE_HANDLER(dummyWindow, WM_SETCURSOR, setCursorHandler); + + dummyWindow->doMessageLoop(); +} \ No newline at end of file diff --git a/Chapter11_StateMachines/Chapter11_StateMachines.cpp b/Chapter11_StateMachines/Chapter11_StateMachines.cpp new file mode 100644 index 0000000..cf5e844 --- /dev/null +++ b/Chapter11_StateMachines/Chapter11_StateMachines.cpp @@ -0,0 +1,101 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "Game.h" + + +// this our our state definition +class StateDefinition +{ +public: + StateDefinition(){} + ~StateDefinition(){} + std::function condition; + std::function reach; +}; + +// set up the state machine +std::vector buildMachine() +{ + // build a machine with 10 state definitions + std::vector stateMachine(2); + + // get the current definition + auto curDef = stateMachine.begin(); + + // add a state for strong healing + curDef->condition = [](GameSensors* sensors) -> bool { + static float healAt = 50; + if (sensors->detectedStrongHeal()) + { + if (sensors->getStrongHealMaxed()) + { + healAt -= 1; + } + else + { + auto newHealAt = 100 - sensors->getStrongHealIncrease(); + healAt = (healAt + newHealAt) / 2.00f; + } + sensors->clearStrongHealInfo(); + } + return sensors->getHealthPercent() > healAt; + }; + curDef->reach = [](GameSensors* sensors, GameActuators* actuators) { + actuators->strongHeal(); + }; + curDef++; + + // add a state for weak healing + curDef->condition = [](GameSensors* sensors) -> bool { + static float healAt = 70; + static bool hasLearned = false; + if (!hasLearned && sensors->detectedWeakHeal()) + { + hasLearned = false; + healAt = 100 - sensors->getWeakHealIncrease(); + } + return sensors->getHealthPercent() > healAt; + }; + curDef->reach = [](GameSensors* sensors, GameActuators* actuators) { + actuators->weakHeal(); + }; + curDef++; + + return stateMachine; +} + +// do the feedback loop +void doFeedbackLoop(std::vector stateMachine) +{ + GameSensors sensors; + GameActuators actuators; + + while (true) + { + printf("Current Health %d/%d (%0.00f%%)\n", currentHealth, maximumHealth, sensors.getHealthPercent()); + for (auto state = stateMachine.begin(); state != stateMachine.end(); state++) + { + if (!state->condition(&sensors)) + { + state->reach(&sensors, &actuators); + break; + } + } + + getinput(); // since there's no actual game, this just allows you to change the state of the game to see how the feedback loop behaves + Sleep(1000); + } +} + +int main (int argc, char *argv[]) +{ + printf("Type a number to decrease health by that much. EG '2' dreaces health by 2. Press any other key to do nothing.\n"); + doFeedbackLoop(buildMachine()); + return 0; +} \ No newline at end of file diff --git a/Chapter11_StateMachines/Chapter11_StateMachines.vcxproj b/Chapter11_StateMachines/Chapter11_StateMachines.vcxproj new file mode 100644 index 0000000..bc7a4a8 --- /dev/null +++ b/Chapter11_StateMachines/Chapter11_StateMachines.vcxproj @@ -0,0 +1,76 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {F28D01D3-BDE9-4992-B3A9-9803D7294F05} + Chapter11_StateMachines + + + + Application + true + MultiByte + + + Application + false + true + MultiByte + + + + + + + + + + + + + $(SolutionDir)\BuildTemp\$(ProjectName)_$(Configuration)\ + + + $(SolutionDir)\BuildTemp\$(ProjectName)_$(Configuration)\ + + + + Level3 + Disabled + + + true + + + + + Level3 + MaxSpeed + true + true + + + true + true + true + + + + + + + + + + + + \ No newline at end of file diff --git a/Chapter11_StateMachines/Chapter11_StateMachines.vcxproj.filters b/Chapter11_StateMachines/Chapter11_StateMachines.vcxproj.filters new file mode 100644 index 0000000..9ed9f33 --- /dev/null +++ b/Chapter11_StateMachines/Chapter11_StateMachines.vcxproj.filters @@ -0,0 +1,27 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + + + Header Files + + + \ No newline at end of file diff --git a/Chapter11_StateMachines/Game.h b/Chapter11_StateMachines/Game.h new file mode 100644 index 0000000..fb5efa3 --- /dev/null +++ b/Chapter11_StateMachines/Game.h @@ -0,0 +1,105 @@ +#pragma once + + +/* + THIS CODE EXISTS ONLY TO SIMULATE THE PRESENCE OF A GAME, + GAME SENSORS, AND GAME ACTUATORS, AND IS NOT RELEVANT TO THE EXAMPLE CODE +*/ + + +// these variables simulate the memory of the game +int32_t currentHealth = 10; +int32_t maximumHealth = 10; + + +int32_t lastStrongHealAmount = 0; +bool lastStrongHealFull = false; +bool detectedStrongHeal = false; + +int32_t lastWeakHealAmount = 0; +bool detectedWeakHeal = false; + +// this emulates our game sensors +class GameSensors +{ +public: + GameSensors(){} + ~GameSensors(){} + + float getHealthPercent() + { + float ch = currentHealth; + float mh = maximumHealth; + return ((ch / mh) * 100.00f); + } + + bool detectedStrongHeal() + { + return ::detectedStrongHeal; + } + float getStrongHealIncrease() + { + float ch = lastStrongHealAmount; + float mh = maximumHealth; + return ((ch / mh) * 100.00f); + } + bool getStrongHealMaxed() + { + return lastStrongHealFull; + } + void clearStrongHealInfo() + { + ::detectedStrongHeal = false; + } + + bool detectedWeakHeal() + { + return ::detectedWeakHeal; + } + float getWeakHealIncrease() + { + float ch = lastWeakHealAmount; + float mh = maximumHealth; + return ((ch / mh) * 100.00f); + } +}; + +// this emulates our game actuators +class GameActuators +{ +public: + GameActuators(){} + ~GameActuators(){} + + void strongHeal() + { + auto startingHealth = currentHealth; + currentHealth = currentHealth + 4; + currentHealth = currentHealth > maximumHealth ? maximumHealth : currentHealth; + lastStrongHealAmount = currentHealth - startingHealth; + lastStrongHealFull = (currentHealth == maximumHealth); + detectedStrongHeal = true; + printf("Doing strong heal\n"); + } + void weakHeal() + { + auto startingHealth = currentHealth; + currentHealth = currentHealth + 2; + currentHealth = currentHealth > maximumHealth ? maximumHealth : currentHealth; + lastWeakHealAmount = currentHealth - startingHealth; + detectedWeakHeal = true; + printf("Doing weak heal\n"); + } + + +}; + +// since there's no actual game, this jsut allows you to change the state of the game to see how the feedback loop behaves +void getinput() +{ + printf("Your selection: "); + auto c = getch(); + if (c >= '1' && c <= '9') + currentHealth -= (c - '0'); + printf("%c\n", c); +} \ No newline at end of file