mirror of
https://github.com/GameHackingBook/GameHackingCode
synced 2026-06-08 11:08:54 +00:00
Chapter 11 examples
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
#include <stdio.h>
|
||||
#include <Windows.h>
|
||||
#include <math.h>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <memory>
|
||||
|
||||
#include "WindowCode.h"
|
||||
|
||||
|
||||
#define TILE_COST 1
|
||||
|
||||
class AStarNode;
|
||||
typedef std::shared_ptr<AStarNode> 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<AStarNodePtr> getChildren(int width, int height)
|
||||
{
|
||||
std::vector<AStarNodePtr> 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<int WIDTH, int HEIGHT>
|
||||
void makeList(AStarNodePtr end, std::vector<AStarNodePtr> 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<int WIDTH, int HEIGHT, int BLOCKING>
|
||||
bool doAStarSearch(
|
||||
int map[WIDTH][HEIGHT],
|
||||
int startx, int starty,
|
||||
int endx, int endy,
|
||||
int path[WIDTH][HEIGHT])
|
||||
{
|
||||
std::priority_queue<AStarNodePtr> frontier;
|
||||
std::vector<AStarNodePtr> 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<WIDTH, HEIGHT>(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<XSIZE, YSIZE, BLOCKING_TILE>;
|
||||
showWindow();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{35470A34-CBB0-41D1-A54B-E1CF3DE9A3B7}</ProjectGuid>
|
||||
<RootNamespace>Chapter11_SearchAlgorithms</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<SubSystem>Console</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Chapter11_SearchAlgorithms.cpp" />
|
||||
<ClCompile Include="DummyWindow.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="DummyWindow.h" />
|
||||
<ClInclude Include="WindowCode.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Chapter11_SearchAlgorithms.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DummyWindow.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="DummyWindow.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="WindowCode.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -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<HWND, DummyWindow*> 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<int32_t>(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);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
THIS CODE EXISTS ONLY TO DISPLAY A WINDOW,
|
||||
AND IS NOT RELEVANT TO THE EXAMPLE CODE
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
#include <map>
|
||||
#include <functional>
|
||||
#include <stdint.h>
|
||||
|
||||
class DummyWindow;
|
||||
typedef std::function<LRESULT(DummyWindow*, UINT, WPARAM, LPARAM)> 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<HWND, DummyWindow*> 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<UINT, windowMessageCallbackType> callbackMap;
|
||||
HWND windowHandle;
|
||||
HINSTANCE instance;
|
||||
|
||||
LRESULT onMessageReceived(HWND window, UINT message, WPARAM wparam, LPARAM lparam);
|
||||
};
|
||||
|
||||
@@ -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 <Windows.h>
|
||||
#include <windowsx.h>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
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<bool(
|
||||
int map[YSIZE][XSIZE],
|
||||
int startx, int starty,
|
||||
int endx, int endy,
|
||||
int path[YSIZE][XSIZE])> searchFunction;
|
||||
|
||||
#define DUMMY_SET_MESSAGE_HANDLER(dummy, message, callback) \
|
||||
do { dummy->setMessageHandler(message, callback); } while(0)
|
||||
|
||||
typedef std::shared_ptr<DummyWindow> 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();
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <Windows.h>
|
||||
#include <conio.h>
|
||||
#include <map>
|
||||
|
||||
#include "Game.h"
|
||||
|
||||
|
||||
// this our our state definition
|
||||
class StateDefinition
|
||||
{
|
||||
public:
|
||||
StateDefinition(){}
|
||||
~StateDefinition(){}
|
||||
std::function<bool(GameSensors*)> condition;
|
||||
std::function<void(GameSensors*, GameActuators*)> reach;
|
||||
};
|
||||
|
||||
// set up the state machine
|
||||
std::vector<StateDefinition> buildMachine()
|
||||
{
|
||||
// build a machine with 10 state definitions
|
||||
std::vector<StateDefinition> 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<StateDefinition> 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;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{F28D01D3-BDE9-4992-B3A9-9803D7294F05}</ProjectGuid>
|
||||
<RootNamespace>Chapter11_StateMachines</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<IntDir>$(SolutionDir)\BuildTemp\$(ProjectName)_$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<IntDir>$(SolutionDir)\BuildTemp\$(ProjectName)_$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Chapter11_StateMachines.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Game.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Chapter11_StateMachines.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Game.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user