From 23aeb2fa85b5132d2bd590433416c74478a1288b Mon Sep 17 00:00:00 2001 From: huixiong806 <806680943@qq.com> Date: Sun, 23 Dec 2018 19:21:38 +0800 Subject: [PATCH 1/7] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E4=BA=86=E5=B8=A7?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Src/2DOBB.hpp | 203 ++----- Src/GameConnection.hpp | 60 +- Src/GameConnectionTH10.cpp | 159 +++-- Src/GameManager.cpp | 546 +++++++++++++----- Src/GameManager.hpp | 75 ++- Src/KeyboardManager.cpp | 41 +- Src/KeyboardManager.hpp | 5 +- Src/Object.hpp | 17 +- Src/Vec2.hpp | 4 +- Src/bmpCreater.cpp | 48 +- Src/bmpCreater.hpp | 95 ++- Src/main.cpp | 67 ++- .../TH10_Collision_Points.vcxproj | 1 - .../TH10_Collision_Points.vcxproj.filters | 3 - 14 files changed, 877 insertions(+), 447 deletions(-) diff --git a/Src/2DOBB.hpp b/Src/2DOBB.hpp index 4606a7b..94c910b 100644 --- a/Src/2DOBB.hpp +++ b/Src/2DOBB.hpp @@ -1,161 +1,50 @@ #pragma once #include "Vec2.hpp" -/*-------------------------------------------------------------------- -本文件来自 -http://www.flipcode.com/archives/2D_OBB_Intersection.shtml -2D OBB Intersection - -For 2D graphics or movement of 3D objects on a 2D ground plane it is often -useful to discover if the 2D oriented bounding boxes of two objects overlap -(have a non - empty intersection).One motivating example is the placement of -a new building in a Real - Time Strategy game.The UI needs to continuously -check whether the footprint of the new building overlaps the footprint of -any existing building.If there is any overlap, the UI should indicate that -is an illegal placement. - -Stefan Gottschalk's thesis (Collision Queries using Oriented Bounding -Boxes, Ph.D.Thesis, Department of Computer Science, University of North -Carolina at Chapel Hill, 1999) introduces the separating - axis method -for performing the equivalent test on 3D oriented bounding boxes. -This method depends on the observation that -for two boxes to be disjoint(i.e. * not* intersecting), there must be some axis -along which their projections are disjoint.The 3D case considers each of 15 -axes as a potential -separating axis.These axes are the three edge axes of box 1, the three edge -axes of box 2, and the nine cross products formed by taking some edge of box 1 -and some edge of box 2. - -In 2D this simplifies dramatically and only four axes need be considered. -These are -the orthogonal edges of each bounding box.If a few values are precomputed -every time a box moves, we end up performing only 16 dot products and some -comparisons in the worst case for each overlap test.One nice property of the -separating - axis method is that it can be -structured in an early out fashion, so that many fewer operations are needed in -the case where the boxes do not intersect.In general, the first test is -extremely -likely to fail(and return "no overlap") when there is no overlap.If it -passes, -the second test is even more likely to fail if there is no overlap, and so on. -Only when the boxes are in extremely close proximity is there even a 50 % chance -of -executing more than 2 tests. - -The C++ code sample provided efficiently computes this fast 2D oriented -bounding box -overlap.I augmented the OBB2D class with some methods for rendering and -construction to help visualize the result.OBB2D::overlaps1Way performs the -real work.It tests to see whether the box passed as an argument overlaps the -current box along either of the current box's dimensions. Note that this test -must be performed for each box on the other to determine whether there is truly -any overlap.To make the tests extremely efficient, OBB2D::origin stores the -projection of corner number zero onto a box's axes and the axes are stored -explicitly in OBB2D::axis.The magnitude of these stored axes is the inverse -of the corresponding edge length so that all overlap tests can be performed on -the interval[0, 1] without normalization, and square roots are avoided -throughout the entire class. - -Morgan McGuire morgan@cs.brown.edu - - -*/ -class OBB2D { -private: - /** Corners of the box, where 0 is the lower left. */ - Vec2d corner[4]; - - /** Two edges of the box extended away from corner[0]. */ - Vec2d axis[2]; - - /** origin[a] = corner[0].dot(axis[a]); */ - double origin[2]; - - /** Returns true if other overlaps one dimension of this. */ - bool overlaps1Way(const OBB2D& other) const { - for (int a = 0; a < 2; ++a) { - - double t = other.corner[0].dot(axis[a]); - - // Find the extent of box 2 on axis a - double tMin = t; - double tMax = t; - - for (int c = 1; c < 4; ++c) { - t = other.corner[c].dot(axis[a]); - - if (t < tMin) { - tMin = t; - } - else if (t > tMax) { - tMax = t; - } - } - - // We have to subtract off the origin - - // See if [tMin, tMax] intersects [0, 1] - if ((tMin > 1 + origin[a]) || (tMax < origin[a])) { - // There was no intersection along this dimension; - // the boxes cannot possibly overlap. - return false; - } - } - - // There was no dimension along which there is no intersection. - // Therefore the boxes overlap. - return true; - } - - - /** Updates the axes after the corners move. Assumes the - corners actually form a rectangle. */ - void computeAxes() { - axis[0] = corner[1] - corner[0]; - axis[1] = corner[3] - corner[0]; - - // Make the length of each axis 1/edge length so we know any - // dot product must be less than 1 to fall within the edge. - - for (int a = 0; a < 2; ++a) { - axis[a] /= axis[a].lengthSqr(); - origin[a] = corner[0].dot(axis[a]); - } - } +class Obb2D { public: - - OBB2D(const Vec2d& center, const double w, const double h, double angle) - { - Vec2d X(cos(angle), sin(angle)); - Vec2d Y(-sin(angle), cos(angle)); - - X *= w / 2; - Y *= h / 2; - - corner[0] = center - X - Y; - corner[1] = center + X - Y; - corner[2] = center + X + Y; - corner[3] = center - X + Y; - - computeAxes(); - } - - - /** For testing purposes. */ - void moveTo(const Vec2d& center) { - Vec2d centroid = (corner[0] + corner[1] + corner[2] + corner[3]) / 4; - - Vec2d translation = center - centroid; - - for (int c = 0; c < 4; ++c) { - corner[c] += translation; - } - - computeAxes(); - } - - /** Returns true if the intersection of the boxes is non-empty. */ - bool overlaps(const OBB2D& other) const { - return overlaps1Way(other) && other.overlaps1Way(*this); - } -}; \ No newline at end of file + Obb2D(const Vec2d& center, const Vec2d& size, const double angle) noexcept { + const auto x = Vec2d(cos(angle), sin(angle)) * size.x / 2, y = Vec2d(-sin(angle), cos(angle)) * size.y / 2; + corner[0] = center - x - y; + corner[1] = center + x - y; + corner[2] = center + x + y; + corner[3] = center - x + y; + computeAxes(); + } + + void moveTo(const Vec2d& center) noexcept { + const auto centroid = (corner[0] + corner[1] + corner[2] + corner[3]) / 4; + const auto translation = center - centroid; + for (auto c = 0; c < 4; ++c) { corner[c] += translation; } + computeAxes(); + } + + bool overlaps(const Obb2D& other) const noexcept { return overlaps1Way(other) && other.overlaps1Way(*this); } +private: + Vec2d corner[4]{}, axis[2]{}; + double origin[2]{}; + + bool overlaps1Way(const Obb2D& other) const noexcept { + for (auto a = 0; a < 2; ++a) { + auto t = other.corner[0].dot(axis[a]); + auto tMin = t, tMax = t; + for (auto c = 1; c < 4; ++c) { + t = other.corner[c].dot(axis[a]); + if (t < tMin) tMin = t; + else if (t > tMax) tMax = t; + } + if ((tMin > 1 + origin[a]) || (tMax < origin[a])) return false; + } + return true; + } + + void computeAxes() noexcept { + axis[0] = corner[1] - corner[0]; + axis[1] = corner[3] - corner[0]; + for (auto a = 0; a < 2; ++a) { + axis[a] /= axis[a].lengthSqr(); + origin[a] = corner[0].dot(axis[a]); + } + } + +}; diff --git a/Src/GameConnection.hpp b/Src/GameConnection.hpp index 5473a5b..dbc9ea7 100644 --- a/Src/GameConnection.hpp +++ b/Src/GameConnection.hpp @@ -3,15 +3,61 @@ #include #include #include "Object.hpp" - +#include "Windows.hpp" +enum class PlayerState:int +{ + NOTCREATED=0, + NORMAL=1, + INVINCIBLE =2, + DYING=4 +}; struct GameConnection { virtual ~GameConnection() noexcept = default; - virtual void GetPowers(std::vector &powers) noexcept = 0; - virtual void GetEnemyData(std::vector &enemy) noexcept = 0; - virtual void GetEnemyBulletData(std::vector &bullet, const Player &player, double maxRange) noexcept = 0; - virtual void GetPlayerData(Player &self) noexcept = 0; - virtual void GetEnemyLaserData(std::vector &laser) noexcept = 0; +<<<<<<< HEAD + virtual int getTimeline() noexcept = 0; + virtual void getPowers(std::vector &powers) noexcept = 0; + virtual void getEnemyData(std::vector &enemy) noexcept = 0; + virtual void getEnemyBulletData(std::vector &bullet, const Player &player, double maxRange) noexcept = 0; + virtual void getPlayerData(Player &self) noexcept = 0; + virtual void getEnemyLaserData(std::vector &laser) noexcept = 0; virtual void sendKeyInfo(int dir,bool shift,bool z,bool x) noexcept = 0; + virtual void getMousePosition(Vec2d& pos)noexcept = 0; + virtual PlayerState GetPlayerStateInformation()noexcept = 0; +}; +class GameConnectionTH10 : public GameConnection { +public: + GameConnectionTH10(); + ~GameConnectionTH10() noexcept override; + void getPowers(std::vector &powers) noexcept override; + void getEnemyData(std::vector &enemy) noexcept override; + void getEnemyBulletData(std::vector &bullet, const Player &player, double maxRange) noexcept override; + void getPlayerData(Player &self) noexcept override; + void getEnemyLaserData(std::vector &laser) noexcept override; + void sendKeyInfo(int dir, bool shift, bool z, bool x) noexcept override; + void getMousePosition(Vec2d& pos)noexcept override; + int getTimeline() noexcept override; + PlayerState GetPlayerStateInformation()noexcept override; +private: + HWND mWindow{ nullptr }; + HANDLE mHProcess{ nullptr }; + static bool GetProcessIdByName(const char *exeFileName, DWORD &pid) noexcept; + void readProcessRaw(intptr_t offset, size_t length, void *target) const noexcept { + static thread_local SIZE_T nbr; + ReadProcessMemory(mHProcess, reinterpret_cast(offset), target, length, &nbr); + } + template + T readProcess(intptr_t offset) const noexcept { + T result; + readProcessRaw(offset, sizeof(T), &result); + return result; + } +======= + virtual void getPowers(std::vector& powers) noexcept = 0; + virtual void getEnemyData(std::vector& enemy) noexcept = 0; + virtual void getEnemyBulletData(std::vector& bullet, const Player& player, double maxRange) noexcept = 0; + virtual void getPlayerData(Player& self) noexcept = 0; + virtual void getEnemyLaserData(std::vector& laser) noexcept = 0; + virtual void sendKeyInfo(int dir, bool shift, bool z, bool x) noexcept = 0; +>>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 }; - std::unique_ptr createGameConnection(); diff --git a/Src/GameConnectionTH10.cpp b/Src/GameConnectionTH10.cpp index 1d79262..4b9c6b1 100644 --- a/Src/GameConnectionTH10.cpp +++ b/Src/GameConnectionTH10.cpp @@ -1,40 +1,50 @@ #include "GameConnection.hpp" #include "KeyboardManager.hpp" -#include "Windows.hpp" + #include -class GameConnectionTH10 : public GameConnection { +<<<<<<< HEAD +======= +class GameConnectionTh10 : public GameConnection { public: - GameConnectionTH10(); - ~GameConnectionTH10() noexcept override; - void GetPowers(std::vector &powers) noexcept override; - void GetEnemyData(std::vector &enemy) noexcept override; - void GetEnemyBulletData(std::vector &bullet, const Player &player, double maxRange) noexcept override; - void GetPlayerData(Player &self) noexcept override; - void GetEnemyLaserData(std::vector &laser) noexcept override; + GameConnectionTh10(); + ~GameConnectionTh10() noexcept override; + void getPowers(std::vector& powers) noexcept override; + void getEnemyData(std::vector& enemy) noexcept override; + void getEnemyBulletData(std::vector& bullet, const Player& player, double maxRange) noexcept override; + void getPlayerData(Player& self) noexcept override; + void getEnemyLaserData(std::vector& laser) noexcept override; void sendKeyInfo(int dir, bool shift, bool z, bool x) noexcept override; private: HANDLE mHProcess{nullptr}; - static bool GetProcessIdByName(const char *exeFileName, DWORD &pid) noexcept; - void readProcessRaw(intptr_t offset, size_t length, void *target) const noexcept { + static bool getProcessIdByName(const char* exeFileName, DWORD& pid) noexcept; + + void readProcessRaw(const intptr_t offset, const size_t length, void* target) const noexcept { static thread_local SIZE_T nbr; ReadProcessMemory(mHProcess, reinterpret_cast(offset), target, length, &nbr); } - template - T readProcess(intptr_t offset) const noexcept { + + template + T readProcess(const intptr_t offset) const noexcept { T result; readProcessRaw(offset, sizeof(T), &result); return result; } }; +>>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 namespace { char staticBuffer[0x7F0 * 2001]; - template - T read(void *buffer) noexcept { return *reinterpret_cast(buffer); } + + template + T read(void* buffer) noexcept { return *reinterpret_cast(buffer); } } -void GameConnectionTH10::GetPowers(std::vector &powers) noexcept { +<<<<<<< HEAD +void GameConnectionTH10::getPowers(std::vector &powers) noexcept { +======= +void GameConnectionTh10::getPowers(std::vector& powers) noexcept { +>>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 powers.clear(); auto ebp = staticBuffer; const auto base = readProcess(0x00477818); @@ -44,35 +54,53 @@ void GameConnectionTH10::GetPowers(std::vector &powers) noexcept { const auto eax = read(ebp + 0x30); if (eax == 1) { const auto x = read(ebp), y = read(ebp + 0x4); - powers.emplace_back(x, y, 6, 6); + powers.emplace_back(Vec2d{x, y}, Vec2d{6, 6}); } ebp += 0x3F0; } } -void GameConnectionTH10::GetEnemyData(std::vector &enemy) noexcept { +<<<<<<< HEAD +void GameConnectionTH10::getEnemyData(std::vector &enemy) noexcept { +======= +void GameConnectionTh10::getEnemyData(std::vector& enemy) noexcept { +>>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 enemy.clear(); const auto base = readProcess(0x00477704); if (!base) return; - auto obj_base = readProcess(base + 0x58); - if (obj_base) { + auto objBase = readProcess(base + 0x58); + if (objBase) { while (true) { - const auto obj_address = readProcess(obj_base) + 0x103C; - const auto obj_next = readProcess(obj_base + 4); - const auto t = readProcess(obj_address + 0x1444); + const auto objAddress = readProcess(objBase) + 0x103C; + const auto objNext = readProcess(objBase + 4); + const auto t = readProcess(objAddress + 0x1444); if (!(t & 0x40u) && !(t & 0x12u)) { - const auto x = readProcess(obj_address + 0x2C), y = readProcess(obj_address + 0x30), - w = readProcess(obj_address + 0xB8), h = readProcess(obj_address + 0xBC); - enemy.emplace_back(x, y, w, h); + const auto x = readProcess(objAddress + 0x2C), y = readProcess(objAddress + 0x30), + w = readProcess(objAddress + 0xB8), h = readProcess(objAddress + 0xBC); + enemy.emplace_back(Vec2d{x, y}, Vec2d{w, h}); } - if (!obj_next) break; - obj_base = obj_next; + if (!objNext) break; + objBase = objNext; } } } - +<<<<<<< HEAD +void GameConnectionTH10::getMousePosition(Vec2d& pos)noexcept{ + const Vec2d orgdelta = Vec2d(28, 45); + POINT m; + GetCursorPos(&m); + RECT rect; + GetWindowRect(mWindow, &rect); + Vec2d org = Vec2d(rect.left + orgdelta.x + 200.0, rect.top + orgdelta.y); + pos = Vec2d(m.x - org.x, m.y - org.y); +} void -GameConnectionTH10::GetEnemyBulletData(std::vector &bullet, const Player &player, double maxRange) noexcept { +GameConnectionTH10::getEnemyBulletData(std::vector &bullet, const Player &player, double maxRange) noexcept { +======= + +void GameConnectionTh10::getEnemyBulletData(std::vector& bullet, const Player& player, + const double maxRange) noexcept { +>>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 bullet.clear(); auto ebx = staticBuffer; const auto base = readProcess(0x004776F0); @@ -87,24 +115,44 @@ GameConnectionTH10::GetEnemyBulletData(std::vector &bullet, const Player const auto bp = read(ebx + 0x446) & 0x0000FFFFu; if (bp) { const auto x = read(ebx + 0x3B4), y = read(ebx + 0x3B8), +<<<<<<< HEAD w = read(ebx + 0x3F0), h = read(ebx + 0x3F4), dx = read(ebx + 0x3C0), dy = read(ebx + 0x3C4); + if (distanceSqr(Vec2d(x, y), player.pos) <= maxRange * maxRange) + bullet.emplace_back(x, y, w, h, dx, dy); +======= + w = read(ebx + 0x3F0), h = read(ebx + 0x3F4), + dx = read(ebx + 0x3C0), dy = read(ebx + 0x3C4); //涓轰簡鏁堢巼锛屽彧鑰冭檻鍙兘浼氱鍒扮殑瀛愬脊 if (distanceSqr(Vec2d(x, y), player.pos) <= maxRange * maxRange) - bullet.emplace_back(x, y, w, h, dx / 2.0f, dy / 2.0f); + bullet.emplace_back(Vec2d{x, y}, Vec2d{w, h}, Vec2d{dx / 2.0f, dy / 2.0f}); +>>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 } ebx += 0x7F0; } } -void GameConnectionTH10::GetPlayerData(Player &self) noexcept { +<<<<<<< HEAD +void GameConnectionTH10::getPlayerData(Player &self) noexcept { const auto obj_base = readProcess(0x00477834); if (!obj_base) return; self.pos.x = readProcess(obj_base + 0x3C0); self.pos.y = readProcess(obj_base + 0x3C4); + self.size.x = 2.0; + self.size.y = 2.0; } -void GameConnectionTH10::GetEnemyLaserData(std::vector &laser) noexcept { +void GameConnectionTH10::getEnemyLaserData(std::vector &laser) noexcept { +======= +void GameConnectionTh10::getPlayerData(Player& self) noexcept { + const auto objBase = readProcess(0x00477834); + if (!objBase) return; + self.pos.x = readProcess(objBase + 0x3C0); + self.pos.y = readProcess(objBase + 0x3C4); +} + +void GameConnectionTh10::getEnemyLaserData(std::vector& laser) noexcept { +>>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 laser.clear(); const auto base = readProcess(0x0047781C); if (!base) return; @@ -113,34 +161,58 @@ void GameConnectionTH10::GetEnemyLaserData(std::vector &laser) noexcept { while (true) { const auto ebx = readProcess(esi + 0x8); const auto x = readProcess(esi + 0x24), y = readProcess(esi + 0x28), +<<<<<<< HEAD w = readProcess(esi + 0x44), h = readProcess(esi + 0x40), arc = readProcess(esi + 0x3C); - laser.emplace_back(x, y, w / 2.0f, h, arc); + laser.emplace_back(x, y, w, h, arc); +======= + w = readProcess(esi + 0x44), h = readProcess(esi + 0x40), + arc = readProcess(esi + 0x3C); + laser.emplace_back(Vec2d{x, y}, Vec2d{w / 2.0f, h}, arc); +>>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 if (!ebx) break; esi = ebx; } } } - +<<<<<<< HEAD +PlayerState GameConnectionTH10::GetPlayerStateInformation()noexcept { + int base_addr = readProcess(0x00477834); + if (!base_addr) + { + return (PlayerState)0; + } + return (PlayerState)readProcess(base_addr + 0x458); +} +int GameConnectionTH10::getTimeline() noexcept { + return readProcess(0x00474C88); +} void GameConnectionTH10::sendKeyInfo(int32_t dir, bool shift, bool z, bool x) noexcept { +======= + +void GameConnectionTh10::sendKeyInfo(const int32_t dir, const bool shift, const bool z, const bool x) noexcept { +>>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 KeyboardManager::sendKeyInfo(dir, shift, z, x); } -GameConnectionTH10::~GameConnectionTH10() noexcept { - GameConnectionTH10::sendKeyInfo(0, false, false, false); +GameConnectionTh10::~GameConnectionTh10() noexcept { + GameConnectionTh10::sendKeyInfo(0, false, false, false); CloseHandle(mHProcess); } -GameConnectionTH10::GameConnectionTH10() { +GameConnectionTh10::GameConnectionTh10() { DWORD pid = 1; - if (!GetProcessIdByName("th10.exe", pid)) + if (!getProcessIdByName("th10.exe", pid)) throw std::runtime_error("th10.exe not running!"); mHProcess = OpenProcess(PROCESS_VM_READ, true, pid); if (!mHProcess) throw std::runtime_error("cannot open th10 process!"); + mWindow = FindWindow(0, "搶曽晽恄榐丂乣 Mountain of Faith. ver 1.00a"); + if (!mWindow) + throw std::runtime_error("cannot open th10 window!"); } -bool GameConnectionTH10::GetProcessIdByName(const char *exeFileName, DWORD &pid) noexcept { +bool GameConnectionTh10::getProcessIdByName(const char* exeFileName, DWORD& pid) noexcept { pid = 0; PROCESSENTRY32 pe; pe.dwSize = sizeof(pe); @@ -151,10 +223,9 @@ bool GameConnectionTH10::GetProcessIdByName(const char *exeFileName, DWORD &pid) pid = pe.th32ProcessID; break; } - } while (Process32Next(hSnapshot, &pe)); + } + while (Process32Next(hSnapshot, &pe)); return static_cast(pid); } -std::unique_ptr createGameConnection() { - return std::make_unique(); -} +std::unique_ptr createGameConnection() { return std::make_unique(); } diff --git a/Src/GameManager.cpp b/Src/GameManager.cpp index d0f688b..72cc357 100644 --- a/Src/GameManager.cpp +++ b/Src/GameManager.cpp @@ -1,116 +1,173 @@ #include "GameManager.hpp" #include "bmpCreater.hpp" +<<<<<<< HEAD #include +Vec2d pointRotate(Vec2d target, Vec2d center, double arc) { + float _x, _y; + _x = (target.x - center.x) * cos(arc) - (target.y - center.y) * sin(arc); + _y = (target.x - center.x) * sin(arc) + (target.y - center.y) * cos(arc); + return center + Vec2d(_x, _y); +} +void GameManager::outputValueMap(const char* path) { + updateBoardInformation(99999.0); +======= +#include namespace { + // 6 : 1048576 2: 128 constexpr uint64_t compress(const Node& in) noexcept { return static_cast(in.time) << 60 | static_cast(in.pos.x * 1048576) << 30 | static_cast(in.pos.y * 1048576); } + + constexpr const auto maxInvincibleTime = 240; + + constexpr const auto maxDepth = 4; + + constexpr const auto s2D2 = 0.70710678118654752440084436; + + constexpr const Vec2d direction[] = { + {0.0, 0.0}, {1.0, 0.0}, {s2D2, -s2D2}, {0.0, -1.0}, {-s2D2, -s2D2}, {-1.0, 0.0}, {-s2D2, s2D2}, {0.0, 1.0}, + {s2D2, s2D2} + }; + + constexpr double playerSpeed[2] = {4.5, 2.0}; + + constexpr Vec2d ulCorner{-200, 0}, drCorner{200, 480}; + + const double eps = 1e-7; + + //浠庨珮浣嶅埌浣庝綅鍒嗗埆涓轰笂涓嬪乏鍙 + const int keyinfo[9] = {0x0, 0x1, 0x9, 0x8, 0xa, 0x2, 0x6, 0x4, 0x5}; } -GameManager::GameManager(): mState(GameState::NORMAL), mConnection(createGameConnection()) { +GameManager::GameManager(): mConnection(createGameConnection()) { valueMap.set_empty_key(compress(Node(0, {0.0, 0.0}))); valueMap.set_deleted_key(compress(Node(-1, {0.0, 0.0}))); } -Vec2d pointRotate(const Vec2d target, const Vec2d center, const double arc) noexcept { +Vec2d pointRotate(const Vec2d& target, const Vec2d& center, const double arc) noexcept { const auto x = (target.x - center.x) * cos(arc) - (target.y - center.y) * sin(arc); const auto y = (target.x - center.x) * sin(arc) + (target.y - center.y) * cos(arc); return center + Vec2d(x, y); } -void GameManager::updateEnemyLaserBoxes() { +void GameManager::updateEnemyLaserBoxes() noexcept { //灏嗘縺鍏夌殑鍒ゅ畾璁句负鐢ˋABB鍖呰捣鏉ラ偅涔堝ぇ(gg,鍏堣繖涔堝啓鍐嶆參鎱㈡敼鍚) - for (Laser& laser : mLaser) { - Vec2d ul = Vec2d(laser.pos.x - laser.size.x / 2.0, laser.pos.y); - Vec2d ur = Vec2d(laser.pos.x + laser.size.x / 2.0, laser.pos.y); - Vec2d dl = Vec2d(laser.pos.x - laser.size.x / 2.0, laser.pos.y + laser.size.y); - Vec2d dr = Vec2d(laser.pos.x + laser.size.x / 2.0, laser.pos.y + laser.size.y); - double arc = laser.arc - 3.1415926 * 5.0 / 2.0; - ul = pointRotate(ul, laser.pos, arc); - ur = pointRotate(ur, laser.pos, arc); - dl = pointRotate(dl, laser.pos, arc); - dr = pointRotate(dr, laser.pos, arc); + for (auto& laser : mLaser) { + const auto arc = laser.arc - 3.1415926 * 5.0 / 2.0; + const auto ul = pointRotate(Vec2d(laser.pos.x - laser.size.x / 2.0, laser.pos.y), laser.pos, arc), + ur = pointRotate(Vec2d(laser.pos.x + laser.size.x / 2.0, laser.pos.y), laser.pos, arc), + dl = pointRotate(Vec2d(laser.pos.x - laser.size.x / 2.0, laser.pos.y + laser.size.y), laser.pos, + arc), + dr = pointRotate(Vec2d(laser.pos.x + laser.size.x / 2.0, laser.pos.y + laser.size.y), laser.pos, + arc); laser.pos = (ul + ur + dl + dr) / 4.0; - double sizeX = std::max(std::max(ul.x, ur.x), std::max(dl.x, dr.x)) - std::min( + const auto sizeX = std::max(std::max(ul.x, ur.x), std::max(dl.x, dr.x)) - std::min( std::min(ul.x, ur.x), std::min(dl.x, dr.x)); - double sizeY = std::max(std::max(ul.y, ur.y), std::max(dl.y, dr.y)) - std::min( + const auto sizeY = std::max(std::max(ul.y, ur.y), std::max(dl.y, dr.y)) - std::min( std::min(ul.y, ur.y), std::min(dl.y, dr.y)); laser.size = Vec2d(sizeX, sizeY); } } -void GameManager::outputValueMap(const char* path) { - updateBoardInformation(1000.0); +void GameManager::doValueMapOutput(const char* path) const noexcept { +>>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 static Pixel map[480][400]; memset(map, 0, sizeof(map)); // 璁剧疆鑳屾櫙涓洪粦鑹 - double total = 400 * 480; double now = 0; - for (int i = 0; i < 400; ++i) { - for (int j = 0; j < 480; ++j) { + for (auto i = 0; i < 400; ++i) { + for (auto j = 0; j < 480; ++j) { now++; - Node state = Node(0, Vec2d(i - 200, j)); + const Node state{0, Vec2d(i - 200, j)}; if (legalState(state)) { +<<<<<<< HEAD double value = getValue(state); double k = 255.0 / 600.0, b = 140.0 * k; value = k * value + b; - map[479 - j][i].g = std::min(255, std::max(0, (int)value)); - map[479 - j][i].r = std::min(255, std::max(0, 255 - (int)value)); + map[479 - j][i].g = std::min(255, std::max(0,(int)value)); + map[479 - j][i].r = std::min(255, std::max(0, 255-(int)value)); +======= + constexpr auto k = 255.0 / 600.0, b = 140.0 * k; + const auto value = k * getValue(state) + b; + map[479 - j][i].g = std::min(255, std::max(0, static_cast(value))); + map[479 - j][i].r = std::min(255, std::max(0, 255 - static_cast(value))); +>>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 } } - //if (i % 100 == 0)std::cout << now / total * 100.0<<"%" << std::endl; } - generateBmp(map, 400, 480, path); +<<<<<<< HEAD + generateBmp((BYTE*)map, 400, 480, path); } - -static int invincibleTime = 0; - -void GameManager::updateBoardInformation(const double ratio) { - mConnection->GetPlayerData(mPlayer); - mConnection->GetEnemyData(mEnemy); - mConnection->GetEnemyBulletData(mBullet, mPlayer, ratio); - mConnection->GetEnemyLaserData(mLaser); - mConnection->GetPowers(mPowers); - updateEnemyLaserBoxes(); +void GameManager::updateEnemyLaserBoxes() noexcept { + //灏嗘縺鍏夌殑鍒ゅ畾璁句负鐢ˋABB鍖呰捣鏉ラ偅涔堝ぇ(gg,鍏堣繖涔堝啓鍐嶆參鎱㈡敼鍚) + for (auto& laser : mLaser) { + const auto arc = laser.arc - 3.1415926 * 5.0 / 2.0; + const auto ul = pointRotate(Vec2d(laser.pos.x - laser.size.x / 2.0, laser.pos.y), laser.pos, arc), + ur = pointRotate(Vec2d(laser.pos.x + laser.size.x / 2.0, laser.pos.y), laser.pos, arc), + dl = pointRotate(Vec2d(laser.pos.x - laser.size.x / 2.0, laser.pos.y + laser.size.y), laser.pos, + arc), + dr = pointRotate(Vec2d(laser.pos.x + laser.size.x / 2.0, laser.pos.y + laser.size.y), laser.pos, + arc); + laser.pos = (ul + ur + dl + dr) / 4.0; + const auto sizeX = std::max(std::max(ul.x, ur.x), std::max(dl.x, dr.x)) - std::min( + std::min(ul.x, ur.x), std::min(dl.x, dr.x)); + const auto sizeY = std::max(std::max(ul.y, ur.y), std::max(dl.y, dr.y)) - std::min( + std::min(ul.y, ur.y), std::min(dl.y, dr.y)); + laser.size = Vec2d(sizeX, sizeY); + } } - -void GameManager::update(unsigned long long frameCount) { - const int maxInvincibleTime = 240; - const int maxDepth = 4; - updateBoardInformation(static_cast(maxDepth) * playerSpeed[0] + 15.0); - if (invincibleTime == maxInvincibleTime - 60 && mPowers.empty()) { invincibleTime = 0; } - if (invincibleTime > 0)invincibleTime--; +void GameManager::updateBoardInformation(const double ratio) noexcept { + mConnection->getPlayerData(mPlayer); + mConnection->getEnemyData(mEnemy); + mConnection->getEnemyBulletData(mBullet, mPlayer, ratio); + mConnection->getEnemyLaserData(mLaser); + mConnection->getPowers(mPowers); + updateEnemyLaserBoxes(); +} +int invincibleTime=0; +void GameManager::update(unsigned long long frameCount,bool enabledMouse) { + mouseMode = enabledMouse; + const int maxDepth = 7; + const int maxInvincibleTime=240; + updateBoardInformation((double)maxDepth * playerSpeed[0] + 15.0); + mConnection->getMousePosition(mMousePos); + mMousePos = fixupPos(mMousePos); + if (invincibleTime == maxInvincibleTime-60 && mPowers.size() == 0) + { + invincibleTime = 0; + } + if (invincibleTime > 0)invincibleTime--; //纭畾褰撳墠鐘舵 mState = GameState::NORMAL; switch (mState) { case GameState::NORMAL: { - //BFS鎼滅储maxDepth姝ワ紝鎵惧埌maxDepth姝ュ唴浠峰兼渶楂樼殑鍙埌杈句綅缃 - valueMap.clear_no_resize(); + //BFS鎼滅储maxDepth姝ワ紝鎵惧埌maxDepth姝ュ唴浠峰兼渶楂樼殑鍙埌杈句綅缃 + valueMap.erase(valueMap.begin(), valueMap.end()); Node startState = Node(0, fixupPos(mPlayer.pos)); - valueMap[compress(startState)] = NodeSave(0, false, getValue(startState)); + valueMap[startState] = NodeSave(0, false, getValue(startState)); bfsQueue.push(startState); while (!bfsQueue.empty()) { - const auto now = bfsQueue.front(); - const auto nowData = valueMap[compress(now)]; + Node now = bfsQueue.front(); + NodeSave nowData = valueMap[now]; bfsQueue.pop(); if (now.time >= maxDepth)continue; for (int i = 0; i < 9; ++i) { for (int j = 0; j <= 1; ++j) { - const Node nex{now.time + 1, fixupPos(now.pos + Vec2d{dx[i], dy[i]} * playerSpeed[j])}; - if (!legalState(nex))continue; - if (auto&& [node, success] = valueMap.insert({compress(nex), NodeSave()}); success) { + if (now.time > 0&&nowData.shift != j)continue; + Node nex = Node(now.time + 1, fixupPos( + Vec2d(now.pos.x + dx[i] * playerSpeed[j], now.pos.y + dy[i] * playerSpeed[j]))); + if (valueMap.find(nex) == valueMap.end()) { + if (!legalState(nex))continue; if (now.time == 0) - node->second = NodeSave(i, static_cast(j), getValue(nex)); + valueMap[nex] = NodeSave(i, static_cast(j), getValue(nex)); else - node->second = NodeSave(nowData.from, nowData.shift, getValue(nex)); + valueMap[nex] = NodeSave(nowData.from, nowData.shift, getValue(nex)); bfsQueue.push(nex); } } } } - std::cout << "ValueMap:" << valueMap.size() << std::endl; - //閫夋嫨鏈楂樹及浠 bool haveNoChoice = true; double maxValue = -99999999999.0; @@ -118,8 +175,9 @@ void GameManager::update(unsigned long long frameCount) { bool useShift = false; bool useBomb = false; NodeSave movement; + //std::cout << valueMap.size() << std::endl; for (auto&& item : valueMap) { - if (item.first >> 60 == 0)continue; + if (item.first.time == 0)continue; if (item.second.value - maxValue > eps) { haveNoChoice = false; maxValue = item.second.value; @@ -130,176 +188,350 @@ void GameManager::update(unsigned long long frameCount) { } //鎵旈浄鍒ゆ柇 useBomb = false; - Object newPlayer = Object(mPlayer.pos.x, mPlayer.pos.y, mPlayer.size.x, mPlayer.size.y); - //1.琚瓙寮规墦涓 - if (invincibleTime > 0)useBomb = false; - else { - for (auto bullet : mBullet) { - if (hitTestBombChoice(bullet, newPlayer)) { - useBomb = true; - invincibleTime = maxInvincibleTime; - break; - } - } - //2.琚綋鏈 - for (auto enemy : mEnemy) { - if (hitTestBombChoice(enemy, newPlayer)) { - useBomb = true; - invincibleTime = maxInvincibleTime; - break; - } - } - //3.琚縺鍏夋墦涓 - for (auto laser : mLaser) { - if (hitTestBombChoice(laser, newPlayer)) { - useBomb = true; - invincibleTime = maxInvincibleTime; - break; - } - } - } - //if (!mLaser.empty())useBomb = true; - //鍙戦佸喅绛 + if (mConnection->GetPlayerStateInformation() == PlayerState::DYING) + { + invincibleTime = maxInvincibleTime; + useBomb = true; + } + //鍙戦佸喅绛 if (mEnemy.size() <= 1 && mBullet.empty()) - //璺宠繃瀵硅瘽锛岄棿闅斿抚鎸塟 + //璺宠繃瀵硅瘽锛岄棿闅斿抚鎸塟 mConnection->sendKeyInfo(moveKeyChoice, useShift, frameCount % 2, useBomb); else - //姝e父杩涜娓告垙 + //姝e父杩涜娓告垙 mConnection->sendKeyInfo(moveKeyChoice, useShift, true, useBomb); break; +======= + generateBmp(map, {400, 480}, path); +} + +void GameManager::outputValueMap(const char* path) noexcept { + updateBoardInformation(1000.0); + auto fork = *this; + auto res = std::async(std::launch::async, [fork = std::move(fork), path]() { fork.doValueMapOutput(path); }); +} + +static int invincibleTime = 0; + +void GameManager::updateBoardInformation(const double ratio) noexcept { + mConnection->getPlayerData(mPlayer); + mConnection->getEnemyData(mEnemy); + mConnection->getEnemyBulletData(mBullet, mPlayer, ratio); + mConnection->getEnemyLaserData(mLaser); + mConnection->getPowers(mPowers); + updateEnemyLaserBoxes(); +} + +void GameManager::pathEnumeration() noexcept { + //BFS鎼滅储maxDepth姝ワ紝鎵惧埌maxDepth姝ュ唴浠峰兼渶楂樼殑鍙埌杈句綅缃 + valueMap.clear_no_resize(); + bfsQueue.emplace(0, fixupPos(mPlayer.pos)); + while (!bfsQueue.empty()) { + const auto now = bfsQueue.front(); + const auto nowData = valueMap[compress(now)]; + bfsQueue.pop(); + for (auto i = 0; i < 9; ++i) { + for (auto j = 0; j <= 1; ++j) { + const Node nex{now.time + 1, fixupPos(now.pos + direction[i] * playerSpeed[j])}; + if (!legalState(nex))continue; + if (auto&& [node, success] = valueMap.insert({compress(nex), NodeSave()}); success) { + if (now.time == 0) + node->second = NodeSave(i, static_cast(j), getValue(nex)); + else + node->second = NodeSave(nowData.from, nowData.shift, getValue(nex)); + if (nex.time == maxDepth) bfsQueue.push(nex); + } + } + } } - default: - break; +} + +bool GameManager::evaluateBombUse() noexcept { + auto useBomb = false; + if (invincibleTime <= 0) { + //1.琚瓙寮规墦涓 + for (const auto& bullet : mBullet) { + if (hitTestBombChoice(bullet, mPlayer)) { + useBomb = true; + invincibleTime = maxInvincibleTime; + break; + } + } + //2.琚綋鏈 + for (const auto& enemy : mEnemy) { + if (hitTestBombChoice(enemy, mPlayer)) { + useBomb = true; + invincibleTime = maxInvincibleTime; + break; + } + } + //3.琚縺鍏夋墦涓 + for (const auto& laser : mLaser) { + if (hitTestBombChoice(laser, mPlayer)) { + useBomb = true; + invincibleTime = maxInvincibleTime; + break; + } + } +>>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 } + return useBomb; +} + +void GameManager::selectBestPath(int& moveKeyChoice, bool& useShift) noexcept { + auto maxValue = -99999999999.0; + for (auto&& item : valueMap) { + if (item.first >> 60 == 0)continue; + if (item.second.value - maxValue > eps) { + maxValue = item.second.value; + useShift = item.second.shift; + moveKeyChoice = keyinfo[item.second.from]; + } + } +} + +void GameManager::update(const unsigned long long frameCount) noexcept { + updateBoardInformation(static_cast(maxDepth) * playerSpeed[0] + 15.0); + if (invincibleTime == maxInvincibleTime - 60 && mPowers.empty()) { invincibleTime = 0; } + if (invincibleTime > 0)invincibleTime--; + + pathEnumeration(); + //閫夋嫨鏈楂樹及浠 + auto moveKeyChoice = -1; + auto useShift = false; + selectBestPath(moveKeyChoice, useShift); + + const auto useBomb = evaluateBombUse(); + //鍙戦佸喅绛 + if (mEnemy.size() <= 1 && mBullet.empty()) + //璺宠繃瀵硅瘽锛岄棿闅斿抚鎸塟 + mConnection->sendKeyInfo(moveKeyChoice, useShift, frameCount % 2, useBomb); + else + //姝e父杩涜娓告垙 + mConnection->sendKeyInfo(moveKeyChoice, useShift, true, useBomb); } //鍒ゆ柇鐘舵佹槸鍚﹀悎娉(鏌愪釜浣嶇疆鑳藉惁鍒拌揪) +<<<<<<< HEAD bool GameManager::legalState(Node state) const noexcept { - if (invincibleTime > 0)return true; + if (invincibleTime > 0)return true; Object newPlayer = Object(state.pos.x, state.pos.y, mPlayer.size.x, mPlayer.size.y); +======= +bool GameManager::legalState(const Node& state) const noexcept { + if (invincibleTime > 0)return true; +>>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 for (auto bullet : mBullet) { bullet.pos += bullet.delta * state.time; - if (hitTest(bullet, newPlayer)) { return false; } + if (hitTest(bullet, mPlayer)) { return false; } } for (auto enemy : mEnemy) { enemy.pos += enemy.delta * state.time; - if (hitTest(enemy, newPlayer)) { return false; } + if (hitTest(enemy, mPlayer)) { return false; } } - //for (auto laser : mLaser) { - // if (hitTest(laser, newPlayer)) { return false; } - //} + //for (auto laser : mLaser) { + // if (hitTest(laser, newPlayer)) { return false; } + //} return true; } - +<<<<<<< HEAD //瀵圭姸鎬佽繘琛屼及浠 double GameManager::getValue(Node state) const noexcept { double value = 0.0; double minEnemyDis = 400.0; Vec2d newPos = state.pos; Object newPlayer = Object(newPos.x, newPos.y, mPlayer.size.x, mPlayer.size.y); + //榧犳爣寮曞妯″紡浼颁环 + if (mouseMode) + { + double dis = distance(mMousePos, newPos); + value += 150.0 * (sqrt(390400.0) - dis) / sqrt(390400.0); + value -= 0.1 * state.time; + return value; + } minEnemyDis = 400.0; //鏀剁偣浼颁环锛岀鐐硅秺杩戯紝浠峰艰秺楂 double minPowerDis = 390400.0; for (auto& power : mPowers) { Vec2d newPowerPos = power.pos + power.delta * state.time; double dis = distanceSqr(newPowerPos, newPos); - if (dis < minPowerDis) { minPowerDis = dis; } + if (dis < minPowerDis) { + minPowerDis = dis; + } } - if (invincibleTime > 0)value += 400 * (390400.0 - minPowerDis) / 390400.0; - else value += 180 * (390400.0 - minPowerDis) / 390400.0; - + if (invincibleTime>0)value += 400 * (390400.0 - minPowerDis) / 390400.0; + else value += 180 * (390400.0 - minPowerDis) / 390400.0; + //鍦板浘浣嶇疆浼颁环(绔欏湪鍦板浘鍋忎笅鐨勪綅缃姞鍒) value += 80.0 * getMapValue(newPos); //鍑荤牬鏁屾満浼颁环(绔欏湪鏁屾満姝d笅鏂瑰姞鍒) - if (invincibleTime == 0) { - for (auto& enemy : mEnemy) { - double dis = abs(enemy.pos.x + enemy.delta.x * state.time - newPos.x); - minEnemyDis = std::min(minEnemyDis, dis); - } - value += 80.0 * (400 - minEnemyDis) / 400; - } + if (invincibleTime == 0) + { + for (auto& enemy : mEnemy) { + double dis = abs(enemy.pos.x + enemy.delta.x * state.time - newPos.x); + minEnemyDis = std::min(minEnemyDis, dis); + } + value += 80.0 * (400 - minEnemyDis) / 400; + } //瀛愬脊浼颁环(鍜屽瓙寮硅繍鍔ㄦ柟鍚戝す瑙掕秺澶у噺鍒嗚秺灏) - double avgScore = 0; - double count = 0; - for (auto bullet : mBullet) { - bullet.pos += bullet.delta * state.time; - if (distanceSqr(bullet.pos, newPos) <= 900) { - count++; - Vec2d selfDir = (newPos - bullet.pos).unit(); - Vec2d bulletDir = bullet.delta.unit(); - //璇ヤ綅缃殑浠峰间笌璇ヤ綅缃埌瀛愬脊鐨勮繛绾垮拰瀛愬脊杩愬姩鏂瑰悜鐨勫す瑙掓湁鍏筹紝澶硅瓒婂ぇ锛屽噺鍒嗚秺灏 - double dirvalue = selfDir.dot(bulletDir); - dirvalue += 1; - avgScore -= dirvalue; - } - } - if (invincibleTime == 0 && count > 0) { - avgScore /= count; - value += 70.0 * avgScore; - } + double avgScore = 0; + double count = 0; + for (auto bullet : mBullet) { + bullet.pos += bullet.delta * state.time; + if (distanceSqr(bullet.pos, newPos) <= 900) { + count++; + Vec2d selfDir = (newPos - bullet.pos).unit(); + Vec2d bulletDir = bullet.delta.unit(); + //璇ヤ綅缃殑浠峰间笌璇ヤ綅缃埌瀛愬脊鐨勮繛绾垮拰瀛愬脊杩愬姩鏂瑰悜鐨勫す瑙掓湁鍏筹紝澶硅瓒婂ぇ锛屽噺鍒嗚秺灏 + double dirvalue = selfDir.dot(bulletDir); + dirvalue += 1; + avgScore -= dirvalue; + } + } + if (invincibleTime == 0 && count > 0) { + avgScore /= count; + value += 70.0 * avgScore; + } avgScore = 0; count = 0; - double count2 = 0; - double avgScore2 = 0; + double count2 = 0; + double avgScore2 = 0; + //鏁屾満浼颁环 + for (auto& enemy : mEnemy) { + double dis = distanceSqr(enemy.pos, newPos); + Vec2d selfDir = (newPos - enemy.pos).unit(); + Vec2d up(0, -1); + double dirvalue = selfDir.dot(up); + //绔欑殑浣嶇疆鍋忛珮锛屽鏄撹寮瑰箷灏佹銆傗滀粠鏁屾満鎸囧悜鑷満鐨勫悜閲忊濆拰鈥滀粠鏁屾満鎸囧悜姝d笂鏂圭殑鍚戦噺鈥濈殑澶硅瓒婂ぇ瓒婂畨鍏紝鍑忓垎瓒婂皯銆 + if (enemy.pos.y <= 240) { + dirvalue += 1; + avgScore -= dirvalue; + count++; + } + //绂绘晫鏈鸿繃杩涘鏄撹鍙戝嚭鐨勫脊骞曟墦姝伙紝涔熷彲鑳借浣撴湳銆傚洜姝よ窛绂昏秺杩戝噺鍒嗚秺澶氥 + if (dis <= 20000.0) { + avgScore2 -= 1.0 - (dis / 20000.0); + count2++; + } + } + if (count > 0) { + avgScore /= count; + value += 80.0 * avgScore; + } + if (count2 > 0) { + avgScore2 /= count2; + value += 80.0 * avgScore2; + } + //value += rand() % 10/100.00; + value -= 0.1 * state.time; + return value; +} +======= + +double GameManager::getThreatValue(const Vec2d& newPos) const noexcept { + auto avgScore = 0.0, count = 0.0, avgScore2 = 0.0, count2 = 0.0; //鏁屾満浼颁环 for (auto& enemy : mEnemy) { - double dis = distanceSqr(enemy.pos, newPos); - Vec2d selfDir = (newPos - enemy.pos).unit(); - Vec2d up(0, -1); - double dirvalue = selfDir.dot(up); + constexpr const Vec2d up(0, -1); + const auto dis = distanceSqr(enemy.pos, newPos); + auto selfDir = (newPos - enemy.pos).unit(); //绔欑殑浣嶇疆鍋忛珮锛屽鏄撹寮瑰箷灏佹銆傗滀粠鏁屾満鎸囧悜鑷満鐨勫悜閲忊濆拰鈥滀粠鏁屾満鎸囧悜姝d笂鏂圭殑鍚戦噺鈥濈殑澶硅瓒婂ぇ瓒婂畨鍏紝鍑忓垎瓒婂皯銆 if (enemy.pos.y <= 240) { - dirvalue += 1; - avgScore -= dirvalue; + avgScore -= selfDir.dot(up) + 1.0; count++; } //绂绘晫鏈鸿繃杩涘鏄撹鍙戝嚭鐨勫脊骞曟墦姝伙紝涔熷彲鑳借浣撴湳銆傚洜姝よ窛绂昏秺杩戝噺鍒嗚秺澶氥 if (dis <= 20000.0) { - avgScore2 -= 1.0 - (dis / 20000.0); + avgScore2 -= 1.0 - dis / 20000.0; count2++; } } - if (count > 0) { - avgScore /= count; - value += 80.0 * avgScore; + if (count > 0) avgScore /= count; + if (count2 > 0) avgScore2 /= count2; + return 80.0 * avgScore + 80.0 * avgScore2; +} + +double GameManager::getAttackValue(const Node& state) const noexcept { + //瀛愬脊浼颁环(鍜屽瓙寮硅繍鍔ㄦ柟鍚戝す瑙掕秺澶у噺鍒嗚秺灏) + if (invincibleTime > 0) return 0.0; + auto avgScore = 0.0, count = 0.0; + for (auto bullet : mBullet) { + bullet.pos += bullet.delta * state.time; + if (distanceSqr(bullet.pos, state.pos) <= 900) { + count++; + auto selfDir = (state.pos - bullet.pos).unit(); + const auto bulletDir = bullet.delta.unit(); + avgScore -= selfDir.dot(bulletDir) + 1.0; + } } - if (count2 > 0) { - avgScore2 /= count2; - value += 80.0 * avgScore2; + if (count > 0) avgScore /= count; + return 70.0 * avgScore; +} + +double GameManager::getKillValue(const Node& state) const noexcept { + //鍑荤牬鏁屾満浼颁环(绔欏湪鏁屾満姝d笅鏂瑰姞鍒) + auto value = 0.0, minEnemyDis = 400.0; + if (invincibleTime == 0) { + for (auto& enemy : mEnemy) { + auto dis = abs(enemy.pos.x + enemy.delta.x * state.time - state.pos.x); + minEnemyDis = std::min(minEnemyDis, dis); + } + value += 80.0 * (400 - minEnemyDis) / 400; } - //value += rand() % 10/100.00; - value -= 0.1 * state.time; return value; } +double GameManager::getPowerValue(const Node& state) const noexcept { + //鏀剁偣浼颁环锛岀鐐硅秺杩戯紝浠峰艰秺楂 + auto minPowerDis = 390400.0; + for (auto& power : mPowers) { + const auto newPowerPos = power.pos + power.delta * state.time; + const auto dis = distanceSqr(newPowerPos, state.pos); + if (dis < minPowerDis) { minPowerDis = dis; } + } + return (invincibleTime > 0 ? 480 : 180) * (390400.0 - minPowerDis) / 390400.0; +} + +//瀵圭姸鎬佽繘琛屼及浠 +double GameManager::getValue(const Node& state) const noexcept { + return getPowerValue(state) + 80.0 * getMapValue(state.pos) + getKillValue(state) + getAttackValue(state) + + getThreatValue(state.pos) - 0.1 * state.time; +} + +>>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 //淇瓒呭嚭鍦板浘鐨勫潗鏍(涓昏鏄嚜鏈) Vec2d GameManager::fixupPos(const Vec2d& pos) noexcept { - Vec2d res = pos; + auto res = pos; if (res.x < ulCorner.x)res.x = ulCorner.x; if (res.y < ulCorner.y)res.y = ulCorner.y; if (res.x > drCorner.x)res.x = drCorner.x; if (res.y > drCorner.y)res.y = drCorner.y; return res; } - -//鎵旈浄鏃剁殑纰版挒妫娴嬶紝璇樊涓1.0 -bool GameManager::hitTestBombChoice(const Object& a, const Object& b) noexcept { - return abs(a.pos.x - b.pos.x) - ((a.size.x + b.size.x) / 2.0) <= 1.0 && - abs(a.pos.y - b.pos.y) - ((a.size.y + b.size.y) / 2.0) <= 1.0; -} - -//鍐崇瓥鏃剁殑纰版挒妫娴嬶紝灏嗗垽瀹氳寖鍥村鍔4.5鍚庢娴嬨傝涓嶈闅忔剰淇敼杩欎釜鍊笺 -//鍒ゅ畾杩囧ぇ锛孉I搴曞姏涓嬮檷銆傚垽瀹氳繃灏忥紝AI鏇村鏄撶Щ鍔ㄥ埌鏋佸叾鎺ヨ繎瀛愬脊鐨勫湴鏂癸紝鐢变簬瑙嗛噹鐨勫眬闄愭э紝瀹规槗鎾炲脊銆 +//鍐崇瓥鏃剁殑纰版挒妫娴 bool GameManager::hitTest(const Object& a, const Object& b) noexcept { - return abs(a.pos.x - b.pos.x) - ((a.size.x + b.size.x) / 2.0) <= 4.5 && - abs(a.pos.y - b.pos.y) - ((a.size.y + b.size.y) / 2.0) <= 4.5; + return abs(a.pos.x - b.pos.x) - ((a.size.x + b.size.x) / 2.0) <= eps+0.5 && + abs(a.pos.y - b.pos.y) - ((a.size.y + b.size.y) / 2.0) <= eps+0.5; } - +<<<<<<< HEAD //鍦板浘浣嶇疆浼颁环 double GameManager::getMapValue(Vec2d pos) noexcept { +======= + +//鍦板浘浣嶇疆浼颁环(绔欏湪鍦板浘鍋忎笅鐨勪綅缃姞鍒) +double GameManager::getMapValue(const Vec2d& pos) noexcept { +>>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 if (pos.y <= 100) return pos.y * 0.9 / 100; - double dis = (abs(390 - pos.y) * (-10.0 / 290.0) + 100.0) / 100.0; - double disx = (200 - abs(0 - pos.x)) / 200.0; + const auto dis = (abs(390 - pos.y) * (-10.0 / 290.0) + 100.0) / 100.0; + const auto disx = (200 - abs(0 - pos.x)) / 200.0; return dis * 0.95 + disx * 0.05; } + +bool operator<(const Node& lhs, const Node& rhs) { + if (lhs.time < rhs.time)return true; + if (lhs.time > rhs.time)return false; + if ((rhs.pos.x - lhs.pos.x) > eps)return true; + if ((lhs.pos.x - rhs.pos.x) > eps)return false; + if ((rhs.pos.y - lhs.pos.y) > eps)return true; + return false; +} diff --git a/Src/GameManager.hpp b/Src/GameManager.hpp index 4b5deac..0915c1a 100644 --- a/Src/GameManager.hpp +++ b/Src/GameManager.hpp @@ -1,63 +1,108 @@ #pragma once +#include #include -#include "sparsehash/dense_hash_map" #include "GameConnection.hpp" +<<<<<<< HEAD const double s2d2 = sqrt(2.0) / 2.0; const double dx[9] = {0, 1.0, s2d2, 0, -s2d2, -1.0, -s2d2, 0, s2d2}; const double dy[9] = {0, 0, -s2d2, -1.0, -s2d2, 0, s2d2, 1.0, s2d2}; +const double dx4[5] = { 0, 1.0, 0, -1.0, 0}; +const double dy4[5] = { 0, 0, -1.0, 0, 1.0 }; const double playerSpeed[2] = {4.5, 2.0}; -const Vec2d ulCorner = Vec2d(-200, 0); -const Vec2d drCorner = Vec2d(200, 480); -const double eps = 1e-7; +const Vec2d ulCorner = Vec2d(-184, 32); +const Vec2d drCorner = Vec2d(184, 432); +const double eps = 1e-2; //从高位到低位分别为上下左右 const int keyinfo[9] = {0x0, 0x1, 0x9, 0x8, 0xa, 0x2, 0x6, 0x4, 0x5}; - +const int keyinfo4[5] = { 0x0,0x1,0x8,0x2,0x4 }; enum class GameState { NORMAL, COLLECT, MOVE }; - struct Node { int8_t time; Vec2d pos; - Node() = default; constexpr Node(int8_t time_, Vec2d pos_) noexcept : time(time_), pos(pos_) {} +======= +struct Node { + int8_t time; + Vec2d pos; + Node() = default; + constexpr Node(const int8_t iTime, const Vec2d& iPos) noexcept : time(iTime), pos(iPos) {} +>>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 }; +bool operator<(const Node& lhs, const Node& rhs); struct NodeSave { bool shift; int from; double value; NodeSave() = default; - constexpr NodeSave(int from_, bool shift_, double value_) noexcept : shift(shift_), from(from_), value(value_) {} + constexpr NodeSave(const int iFrom, const bool iShift, const double iValue) noexcept : + shift(iShift), from(iFrom), value(iValue) {} }; - class GameManager { public: - GameManager(); +<<<<<<< HEAD + GameManager() : mState(GameState::NORMAL), mConnection(createGameConnection()) {} + void update(unsigned long long frameCount,bool enabledMouse); void outputValueMap(const char* path); - void update(unsigned long long frameCount); private: - google::dense_hash_map valueMap { 5500 }; + std::map valueMap; std::queue bfsQueue; GameState mState; + Player mPlayer {}; +======= + GameManager(); + void outputValueMap(const char* path) noexcept; + void update(unsigned long long frameCount) noexcept; +private: + google::dense_hash_map valueMap{5500}; + std::queue bfsQueue; Player mPlayer{}; +>>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 std::vector mEnemy; std::vector mBullet; std::vector mLaser; std::vector mPowers; +<<<<<<< HEAD + Vec2d mMousePos; + bool mouseMode; std::unique_ptr mConnection; - void updateEnemyLaserBoxes(); - void updateBoardInformation(const double ratio); bool legalState(Node state) const noexcept; //估价效率过低,待修改 double getValue(Node state) const noexcept; static Vec2d fixupPos(const Vec2d& pos) noexcept; static bool hitTest(const Object& a, const Object& b) noexcept; - static bool hitTestBombChoice(const Object& a, const Object& b) noexcept; + // Frame Advancing + void updateEnemyLaserBoxes() noexcept; + void updateBoardInformation(double ratio) noexcept; //地图位置估价 static double getMapValue(Vec2d pos) noexcept; +======= + std::shared_ptr mConnection; + // Frame Advancing + void updateEnemyLaserBoxes() noexcept; + void updateBoardInformation(double ratio) noexcept; + // ValueMap Capture + void doValueMapOutput(const char* path) const noexcept; + // Action Evaluation + void pathEnumeration() noexcept; + bool evaluateBombUse() noexcept; + bool legalState(const Node& state) const noexcept; + void selectBestPath(int& moveKeyChoice, bool& useShift) noexcept; + // Weight Evaluation + double getValue(const Node& state) const noexcept; + double getThreatValue(const Vec2d& newPos) const noexcept; + double getAttackValue(const Node& state) const noexcept; + double getKillValue(const Node& state) const noexcept; + double getPowerValue(const Node& state) const noexcept; + static Vec2d fixupPos(const Vec2d& pos) noexcept; + static bool hitTest(const Object& a, const Object& b) noexcept; + static bool hitTestBombChoice(const Object& a, const Object& b) noexcept; + static double getMapValue(const Vec2d& pos) noexcept; +>>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 }; diff --git a/Src/KeyboardManager.cpp b/Src/KeyboardManager.cpp index b52a109..68152fa 100644 --- a/Src/KeyboardManager.cpp +++ b/Src/KeyboardManager.cpp @@ -4,6 +4,7 @@ namespace { bool keystate[100]; +<<<<<<< HEAD constexpr const char KEY_SHIFT = 16; constexpr const char KEY_LEFT = 37; constexpr const char KEY_UP = 38; @@ -12,7 +13,19 @@ namespace { constexpr const char KEY_X = 88; constexpr const char KEY_Z = 90; constexpr const char KEY_ESCAPE = 90; - void sendKey(int key, bool down) noexcept { + void sendKey(int key, bool down) noexcept { +======= + constexpr const char keyShift = 16; + constexpr const char keyLeft = 37; + constexpr const char keyUp = 38; + constexpr const char keyRight = 39; + constexpr const char keyDown = 40; + constexpr const char keyX = 88; + constexpr const char keyZ = 90; + constexpr const char keyEscape = 90; + + void sendKey(const int key, const bool down) noexcept { +>>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 if (keystate[key] != down) { keystate[key] = down; if (down) keybd_event(key, MapVirtualKey(key, 0), 0, 0); @@ -21,23 +34,19 @@ namespace { } } -int isKeyDown(int id) { return GetAsyncKeyState(id) & 0x8000 ? 1 : 0; } +int isKeyDown(const int id) { return GetAsyncKeyState(id) & 0x8000 ? 1 : 0; } -void KeyboardManager::sendKeyInfo(int dir, bool shift, bool z, bool x) { - sendKey(KEY_UP, static_cast(dir & 0x8)); - sendKey(KEY_DOWN, static_cast(dir & 0x4)); - sendKey(KEY_LEFT, static_cast(dir & 0x2)); - sendKey(KEY_RIGHT, static_cast(dir & 0x1)); - sendKey(KEY_SHIFT, shift); - sendKey(KEY_Z, z); - sendKey(KEY_X, x); +void KeyboardManager::sendKeyInfo(const int dir, const bool shift, const bool z, const bool x) { + sendKey(keyUp, static_cast(dir & 0x8)); + sendKey(keyDown, static_cast(dir & 0x4)); + sendKey(keyLeft, static_cast(dir & 0x2)); + sendKey(keyRight, static_cast(dir & 0x1)); + sendKey(keyShift, shift); + sendKey(keyZ, z); + sendKey(keyX, x); } void KeyboardManager::init() { memset(keystate, 0, sizeof(keystate)); } -void KeyboardManager::pressEsc() { - keybd_event(KEY_ESCAPE, MapVirtualKey(KEY_ESCAPE, 0), 0, 0); -} -void KeyboardManager::releaseEsc() { - keybd_event(KEY_ESCAPE, MapVirtualKey(KEY_ESCAPE, 0), KEYEVENTF_KEYUP, 0); -} \ No newline at end of file +void KeyboardManager::pressEsc() { keybd_event(keyEscape, MapVirtualKey(keyEscape, 0), 0, 0); } +void KeyboardManager::releaseEsc() { keybd_event(keyEscape, MapVirtualKey(keyEscape, 0), KEYEVENTF_KEYUP, 0); } diff --git a/Src/KeyboardManager.hpp b/Src/KeyboardManager.hpp index 67cc51d..1979961 100644 --- a/Src/KeyboardManager.hpp +++ b/Src/KeyboardManager.hpp @@ -3,9 +3,8 @@ struct KeyboardManager { static void init(); static void sendKeyInfo(int dir, bool shift, bool z, bool x); - static void pressEsc(); - static void releaseEsc(); + static void pressEsc(); + static void releaseEsc(); }; int isKeyDown(int id); - diff --git a/Src/Object.hpp b/Src/Object.hpp index 5334c26..ced43d5 100644 --- a/Src/Object.hpp +++ b/Src/Object.hpp @@ -7,17 +7,24 @@ struct Object { Vec2d size; Vec2d delta; Object() = default; - constexpr Object(double x, double y, double w, double h) : pos(x, y), size(w, h), delta(0, 0) {} - constexpr Object(double x, double y, double w, double h, double dx, double dy): pos(x, y), size(w, h), delta(dx, dy) {} + constexpr Object(const Vec2d& iPos, const Vec2d& iSize) noexcept : pos(iPos), size(iSize), delta(0, 0) {} + + constexpr Object(const Vec2d& iPos, const Vec2d& iSize, const Vec2d& iDelta) noexcept : + pos(iPos), size(iSize), delta(iDelta) {} }; struct Laser : Object { double arc; - Laser() = default; - constexpr Laser(double x, double y, double w, double h, double arcIn) : Object(x, y, w, h), arc(arcIn) {} + Laser() noexcept = default; + constexpr Laser(const Vec2d& pos, const Vec2d& size, const double arcIn) noexcept : Object(pos, size), arc(arcIn) {} }; struct Player : Object { +<<<<<<< HEAD Player() = default; - constexpr Player(double x, double y, double w, double h) : Object(x, y, 2, 2) {} + constexpr Player(double x, double y, double w, double h) : Object(x, y, 4.0, 4.0) {} +======= + Player() noexcept = default; + constexpr Player(const Vec2d& pos, const Vec2d& size) noexcept : Object(pos, size) {} +>>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 }; diff --git a/Src/Vec2.hpp b/Src/Vec2.hpp index 8696b8f..365d262 100644 --- a/Src/Vec2.hpp +++ b/Src/Vec2.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include template struct Vec2 { @@ -42,7 +42,7 @@ struct Vec2 { auto length() const noexcept { return std::sqrt(lengthSqr()); } auto norm() const noexcept { return length(); } Vec2 unit() const noexcept { return (*this) / norm(); } - constexpr T dot(const Vec2& rhs) const noexcept { return x * rhs.x + y * rhs.y; } + constexpr T dot(const Vec2& rhs) const noexcept { return x * rhs.x + y * rhs.y; } }; template diff --git a/Src/bmpCreater.cpp b/Src/bmpCreater.cpp index 869479c..837873e 100644 --- a/Src/bmpCreater.cpp +++ b/Src/bmpCreater.cpp @@ -5,49 +5,49 @@ //浣嶅浘鏂囦欢澶存枃浠跺畾涔 //鍏朵腑涓嶅寘鎷枃浠剁被鍨嬩俊鎭紙鐢变簬缁撴瀯浣撶殑鍐呭瓨缁撴瀯鍐冲畾锛岃鏄姞浜嗙殑璇濆皢涓嶈兘姝g‘鐨勮鍙栨枃浠朵俊鎭級 -struct BMPFILEHEADER_T { +struct BmpFileHeader { uint16_t bfType = 0X4d42; //鏂囦欢绫诲瀷锛屽繀椤绘槸0x424D,鍗冲瓧绗︹淏M鈥 - uint32_t bfSize; //鏂囦欢澶у皬 + uint32_t bfSize{}; //鏂囦欢澶у皬 uint16_t bfReserved1 = 0; //淇濈暀瀛 uint16_t bfReserved2 = 0; //淇濈暀瀛 - uint32_t bfOffBits; //浠庢枃浠跺ご鍒板疄闄呬綅鍥炬暟鎹殑鍋忕Щ瀛楄妭鏁 + uint32_t bfOffBits{}; //浠庢枃浠跺ご鍒板疄闄呬綅鍥炬暟鎹殑鍋忕Щ瀛楄妭鏁 }; -struct BMPINFOHEADER_T { - uint32_t biSize; //淇℃伅澶村ぇ灏 - int32_t biWidth; //鍥惧儚瀹藉害 - int32_t biHeight; //鍥惧儚楂樺害 +struct BmpInfoHeader { + uint32_t biSize{}; //淇℃伅澶村ぇ灏 + int32_t biWidth{}; //鍥惧儚瀹藉害 + int32_t biHeight{}; //鍥惧儚楂樺害 uint16_t biPlanes = 1; //浣嶅钩闈㈡暟锛屽繀椤讳负1 uint16_t biBitCount = 24; //姣忓儚绱犱綅鏁 uint32_t biCompression = 0; //鍘嬬缉绫诲瀷 - uint32_t biSizeImage; //鍘嬬缉鍥惧儚澶у皬瀛楄妭鏁 + uint32_t biSizeImage{}; //鍘嬬缉鍥惧儚澶у皬瀛楄妭鏁 int32_t biXPelsPerMeter = 0; //姘村钩鍒嗚鲸鐜 int32_t biYPelsPerMeter = 0; //鍨傜洿鍒嗚鲸鐜 uint32_t biClrUsed = 0; //浣嶅浘瀹為檯鐢ㄥ埌鐨勮壊褰╂暟 uint32_t biClrImportant = 0; //鏈綅鍥句腑閲嶈鐨勮壊褰╂暟 }; //浣嶅浘淇℃伅澶村畾涔 -static_assert(alignof(BMPINFOHEADER_T) == 2 && alignof(BMPFILEHEADER_T) == 2, "pragma pack failure"); +static_assert(alignof(BmpInfoHeader) == 2 && alignof(BmpFileHeader) == 2, "pragma pack failure"); -void generateBmp(void* pData, int width, int height, const char* filename) { - int size = width * height * 3; // 姣忎釜鍍忕礌鐐3涓瓧鑺 +void generateBmp(void* pData, const Vec2i& size, const char* filename) { + const auto bmpSize = size.x * size.y * 3; // 姣忎釜鍍忕礌鐐3涓瓧鑺 // 浣嶅浘绗竴閮ㄥ垎锛屾枃浠朵俊鎭 - BMPFILEHEADER_T bfh; - bfh.bfSize = size // data size - + sizeof(BMPFILEHEADER_T) // first section size - + sizeof(BMPINFOHEADER_T) // second section size + BmpFileHeader bfh; + bfh.bfSize = bmpSize // data size + + sizeof(BmpFileHeader) // first section size + + sizeof(BmpInfoHeader) // second section size ; - bfh.bfOffBits = bfh.bfSize - size; + bfh.bfOffBits = bfh.bfSize - bmpSize; // 浣嶅浘绗簩閮ㄥ垎锛屾暟鎹俊鎭 - BMPINFOHEADER_T bih; - bih.biSize = sizeof(BMPINFOHEADER_T); - bih.biWidth = width; - bih.biHeight = height; - bih.biSizeImage = size; + BmpInfoHeader bih; + bih.biSize = sizeof(BmpInfoHeader); + bih.biWidth = size.x; + bih.biHeight = size.y; + bih.biSizeImage = bmpSize; if (std::ofstream file(filename, std::ios::binary); file.good()) { - file.write(reinterpret_cast(&bfh), sizeof(BMPFILEHEADER_T)); - file.write(reinterpret_cast(&bih), sizeof(BMPINFOHEADER_T)); - file.write(reinterpret_cast(pData), size); + file.write(reinterpret_cast(&bfh), sizeof(BmpFileHeader)); + file.write(reinterpret_cast(&bih), sizeof(BmpInfoHeader)); + file.write(reinterpret_cast(pData), bmpSize); } } diff --git a/Src/bmpCreater.hpp b/Src/bmpCreater.hpp index eb680b4..a026089 100644 --- a/Src/bmpCreater.hpp +++ b/Src/bmpCreater.hpp @@ -1,11 +1,98 @@ +<<<<<<< HEAD +#include +#include +#include +#include +#include +/* +typedef long BOOL; +typedef long LONG; +typedef unsigned char BYTE; +typedef unsigned long DWORD; +typedef unsigned short WORD; +*/ +//位图文件头文件定义 +//其中不包括文件类型信息(由于结构体的内存结构决定,要是加了的话将不能正确的读取文件信息) +typedef struct { + WORD bfType;//文件类型,必须是0x424D,即字符“BM” + DWORD bfSize;//文件大小 + WORD bfReserved1;//保留字 + WORD bfReserved2;//保留字 + DWORD bfOffBits;//从文件头到实际位图数据的偏移字节数 +} BMPFILEHEADER_T; + +struct BMPFILEHEADER_S { + WORD bfType; + DWORD bfSize; + WORD bfReserved1; + WORD bfReserved2; + DWORD bfOffBits; +======= #pragma once #include +#include "Vec2.hpp" -//生成Bmp图片,传递RGB值,传递图片像素大小,传递图片存储路径 -void generateBmp(void* pData, int width, int height, const char* filename); +void generateBmp(void* pData, const Vec2i& size, const char* filename); struct Pixel { uint8_t b, g, r; - constexpr Pixel(): b(0), g(0), r(0) {} - constexpr Pixel(uint8_t r_, uint8_t g_, uint8_t b_) : b(b_), g(g_), r(r_) {} + constexpr Pixel() noexcept : b(0), g(0), r(0) {} + constexpr Pixel(const uint8_t iR, const uint8_t iG, const uint8_t iB) noexcept : b(iB), g(iG), r(iR) {} +>>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 }; +typedef struct { + DWORD biSize;//信息头大小 + LONG biWidth;//图像宽度 + LONG biHeight;//图像高度 + WORD biPlanes;//位平面数,必须为1 + WORD biBitCount;//每像素位数 + DWORD biCompression;//压缩类型 + DWORD biSizeImage;//压缩图像大小字节数 + LONG biXPelsPerMeter;//水平分辨率 + LONG biYPelsPerMeter;//垂直分辨率 + DWORD biClrUsed;//位图实际用到的色彩数 + DWORD biClrImportant;//本位图中重要的色彩数 +} BMPINFOHEADER_T;//位图信息头定义 + +void generateBmp(BYTE * pData, int width, int height, const char * filename)//生成Bmp图片,传递RGB值,传递图片像素大小,传递图片存储路径 +{ + int size = width * height * 3; // 每个像素点3个字节 + // 位图第一部分,文件信息 + BMPFILEHEADER_T bfh; + bfh.bfType = 0X4d42; //bm + bfh.bfSize = size // data size + + sizeof(BMPFILEHEADER_T) // first section size + + sizeof(BMPINFOHEADER_T) // second section size + ; + bfh.bfReserved1 = 0; // reserved + bfh.bfReserved2 = 0; // reserved + bfh.bfOffBits = bfh.bfSize - size; + + // 位图第二部分,数据信息 + BMPINFOHEADER_T bih; + bih.biSize = sizeof(BMPINFOHEADER_T); + bih.biWidth = width; + bih.biHeight = height; + bih.biPlanes = 1; + bih.biBitCount = 24; + bih.biCompression = 0; + bih.biSizeImage = size; + bih.biXPelsPerMeter = 0; + bih.biYPelsPerMeter = 0; + bih.biClrUsed = 0; + bih.biClrImportant = 0; + FILE * fp = fopen(filename, "wb"); + if (!fp) return; + fwrite(&bfh, 1, sizeof(BMPFILEHEADER_T), fp); + fwrite(&bih, 1, sizeof(BMPINFOHEADER_T), fp); + fwrite(pData, 1, size, fp); + fclose(fp); +} +struct Pixel +{ + BYTE b; + BYTE g; + BYTE r; + Pixel() { r = g = b = 0; } + Pixel(BYTE r_, BYTE g_, BYTE b_) { r = r_; g = g_;b = b_; } +}; \ No newline at end of file diff --git a/Src/main.cpp b/Src/main.cpp index a4f568d..0364475 100644 --- a/Src/main.cpp +++ b/Src/main.cpp @@ -2,6 +2,7 @@ #include #include #include +#include "GameConnection.hpp" #include #include "KeyboardManager.hpp" #include "GameManager.hpp" @@ -15,33 +16,80 @@ class StopWatch { void stop() noexcept { mEndTime = steady_clock::now(); } void restart() noexcept { start(); } steady_clock::duration elapsed() const noexcept { return mEndTime - mBeginTime; } - int elapsed_ms() const noexcept { return static_cast(duration_cast(elapsed()).count()); } - int elapsed_s() const noexcept { return static_cast(duration_cast(elapsed()).count()); } + int elapsedMs() const noexcept { return static_cast(duration_cast(elapsed()).count()); } + int elapsedS() const noexcept { return static_cast(duration_cast(elapsed()).count()); } private: steady_clock::time_point mBeginTime, mEndTime; }; -void pauseUntilPress(const char* info, char key) { +void pauseUntilPress(const char* info, const char key) { std::cout << info << std::endl; while (true) { if (isKeyDown(key))return; std::this_thread::sleep_for(10ms); } } - +GameConnectionTH10 frameSyncer; int main() { try { KeyboardManager::init(); auto game = std::make_shared(); - bool quit = false; + const auto quit = false; std::cout << "准备完成" << std::endl; - pauseUntilPress("请将焦点放在风神录窗口上,开始游戏,然后按C开启AI", 'C'); - std::cout << "已开始游戏,按P键打印估价图,Q键退出" << std::endl; + pauseUntilPress("请将焦点放在风神录窗口上,开始游戏,按C开启AI", 'C'); + std::cout << "已开始游戏,按C键开启/关闭鼠标引导,Q键退出" << std::endl; unsigned long long frameCount = 0; StopWatch watch; +<<<<<<< HEAD int mapOutputCount = 0; - double cd = 0; + const double maxcd = 30; + double cd = 30; + bool mouseMode = false; + cout << "鼠标引导当前处于关闭状态" << endl; + int gameFrame = frameSyncer.getTimeline(); + unsigned long long loopCount = 0; + while (!quit) { + if (loopCount % 16 == 0) + { + if (cd > 0)cd -= 1.0; + if (isKeyDown('Q')) + break; + if (cd <= 0 && isKeyDown('C')) + { + cd = maxcd; + mouseMode ^= 1; + cout << (mouseMode ? "鼠标引导已开启" : "鼠标引导已关闭") << endl; + } + if (isKeyDown('P') && cd <= 0) { + cd = maxcd; + mapOutputCount++; + std::stringstream outputStream; + outputStream << "./value" << mapOutputCount << ".bmp"; + std::cout << outputStream.str() << std::endl; + game->outputValueMap(outputStream.str().c_str()); + continue; + } + } + int getGameFrame = frameSyncer.getTimeline(); + if (getGameFrame != gameFrame) + { + if (getGameFrame > gameFrame + 1) + { + cout << "Frame Lost!" << endl; + } + gameFrame = getGameFrame; + //watch.start(); + frameCount++; + game->update(frameCount, mouseMode); + //watch.stop(); + //cout << watch.elapsed_ms() / 16.0 * 100.0 << "%" << endl; + } + loopCount++; + std::this_thread::sleep_for(milliseconds(1)); +======= + auto mapOutputCount = 0; + auto cd = 0.0; const double maxcd = 10; while (!quit) { if (cd > 0)cd -= 1.0; @@ -60,7 +108,8 @@ int main() { frameCount++; game->update(frameCount); watch.stop(); - std::this_thread::sleep_for(milliseconds(std::max(0, 16 - watch.elapsed_ms()))); + std::this_thread::sleep_for(milliseconds(std::max(0, 16 - watch.elapsedMs()))); +>>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 } KeyboardManager::sendKeyInfo(0, false, false, false); } diff --git a/TH10_Collision_Points/TH10_Collision_Points.vcxproj b/TH10_Collision_Points/TH10_Collision_Points.vcxproj index 7f4e4fb..55326cd 100644 --- a/TH10_Collision_Points/TH10_Collision_Points.vcxproj +++ b/TH10_Collision_Points/TH10_Collision_Points.vcxproj @@ -19,7 +19,6 @@ - diff --git a/TH10_Collision_Points/TH10_Collision_Points.vcxproj.filters b/TH10_Collision_Points/TH10_Collision_Points.vcxproj.filters index 19f1608..f6d21e3 100644 --- a/TH10_Collision_Points/TH10_Collision_Points.vcxproj.filters +++ b/TH10_Collision_Points/TH10_Collision_Points.vcxproj.filters @@ -23,9 +23,6 @@ 婧愭枃浠 - - 婧愭枃浠 - From db418109baaaa4b31627c3bc09004f447f747553 Mon Sep 17 00:00:00 2001 From: huixiong806 <806680943@qq.com> Date: Sun, 23 Dec 2018 19:25:40 +0800 Subject: [PATCH 2/7] =?UTF-8?q?=E6=95=B4=E7=90=86=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Src/2DOBB.hpp | 203 ++++++++++++++++++++------ Src/GameConnection.hpp | 9 -- Src/GameConnectionTH10.cpp | 117 +++------------ Src/GameManager.cpp | 283 ++----------------------------------- Src/GameManager.hpp | 45 +----- Src/KeyboardManager.cpp | 39 ++--- Src/KeyboardManager.hpp | 5 +- Src/Object.hpp | 15 +- Src/Vec2.hpp | 4 +- Src/bmpCreater.cpp | 48 +++---- Src/bmpCreater.hpp | 13 -- Src/main.cpp | 32 +---- 12 files changed, 244 insertions(+), 569 deletions(-) diff --git a/Src/2DOBB.hpp b/Src/2DOBB.hpp index 94c910b..4606a7b 100644 --- a/Src/2DOBB.hpp +++ b/Src/2DOBB.hpp @@ -1,50 +1,161 @@ #pragma once #include "Vec2.hpp" +/*-------------------------------------------------------------------- +本文件来自 +http://www.flipcode.com/archives/2D_OBB_Intersection.shtml +2D OBB Intersection -class Obb2D { -public: - Obb2D(const Vec2d& center, const Vec2d& size, const double angle) noexcept { - const auto x = Vec2d(cos(angle), sin(angle)) * size.x / 2, y = Vec2d(-sin(angle), cos(angle)) * size.y / 2; - corner[0] = center - x - y; - corner[1] = center + x - y; - corner[2] = center + x + y; - corner[3] = center - x + y; - computeAxes(); - } - - void moveTo(const Vec2d& center) noexcept { - const auto centroid = (corner[0] + corner[1] + corner[2] + corner[3]) / 4; - const auto translation = center - centroid; - for (auto c = 0; c < 4; ++c) { corner[c] += translation; } - computeAxes(); - } - - bool overlaps(const Obb2D& other) const noexcept { return overlaps1Way(other) && other.overlaps1Way(*this); } +For 2D graphics or movement of 3D objects on a 2D ground plane it is often +useful to discover if the 2D oriented bounding boxes of two objects overlap +(have a non - empty intersection).One motivating example is the placement of +a new building in a Real - Time Strategy game.The UI needs to continuously +check whether the footprint of the new building overlaps the footprint of +any existing building.If there is any overlap, the UI should indicate that +is an illegal placement. + +Stefan Gottschalk's thesis (Collision Queries using Oriented Bounding +Boxes, Ph.D.Thesis, Department of Computer Science, University of North +Carolina at Chapel Hill, 1999) introduces the separating - axis method +for performing the equivalent test on 3D oriented bounding boxes. +This method depends on the observation that +for two boxes to be disjoint(i.e. * not* intersecting), there must be some axis +along which their projections are disjoint.The 3D case considers each of 15 +axes as a potential +separating axis.These axes are the three edge axes of box 1, the three edge +axes of box 2, and the nine cross products formed by taking some edge of box 1 +and some edge of box 2. + +In 2D this simplifies dramatically and only four axes need be considered. +These are +the orthogonal edges of each bounding box.If a few values are precomputed +every time a box moves, we end up performing only 16 dot products and some +comparisons in the worst case for each overlap test.One nice property of the +separating - axis method is that it can be +structured in an early out fashion, so that many fewer operations are needed in +the case where the boxes do not intersect.In general, the first test is +extremely +likely to fail(and return "no overlap") when there is no overlap.If it +passes, +the second test is even more likely to fail if there is no overlap, and so on. +Only when the boxes are in extremely close proximity is there even a 50 % chance +of +executing more than 2 tests. + +The C++ code sample provided efficiently computes this fast 2D oriented +bounding box +overlap.I augmented the OBB2D class with some methods for rendering and +construction to help visualize the result.OBB2D::overlaps1Way performs the +real work.It tests to see whether the box passed as an argument overlaps the +current box along either of the current box's dimensions. Note that this test +must be performed for each box on the other to determine whether there is truly +any overlap.To make the tests extremely efficient, OBB2D::origin stores the +projection of corner number zero onto a box's axes and the axes are stored +explicitly in OBB2D::axis.The magnitude of these stored axes is the inverse +of the corresponding edge length so that all overlap tests can be performed on +the interval[0, 1] without normalization, and square roots are avoided +throughout the entire class. + +Morgan McGuire morgan@cs.brown.edu + + +*/ +class OBB2D { private: - Vec2d corner[4]{}, axis[2]{}; - double origin[2]{}; - - bool overlaps1Way(const Obb2D& other) const noexcept { - for (auto a = 0; a < 2; ++a) { - auto t = other.corner[0].dot(axis[a]); - auto tMin = t, tMax = t; - for (auto c = 1; c < 4; ++c) { - t = other.corner[c].dot(axis[a]); - if (t < tMin) tMin = t; - else if (t > tMax) tMax = t; - } - if ((tMin > 1 + origin[a]) || (tMax < origin[a])) return false; - } - return true; - } - - void computeAxes() noexcept { - axis[0] = corner[1] - corner[0]; - axis[1] = corner[3] - corner[0]; - for (auto a = 0; a < 2; ++a) { - axis[a] /= axis[a].lengthSqr(); - origin[a] = corner[0].dot(axis[a]); - } - } - -}; + /** Corners of the box, where 0 is the lower left. */ + Vec2d corner[4]; + + /** Two edges of the box extended away from corner[0]. */ + Vec2d axis[2]; + + /** origin[a] = corner[0].dot(axis[a]); */ + double origin[2]; + + /** Returns true if other overlaps one dimension of this. */ + bool overlaps1Way(const OBB2D& other) const { + for (int a = 0; a < 2; ++a) { + + double t = other.corner[0].dot(axis[a]); + + // Find the extent of box 2 on axis a + double tMin = t; + double tMax = t; + + for (int c = 1; c < 4; ++c) { + t = other.corner[c].dot(axis[a]); + + if (t < tMin) { + tMin = t; + } + else if (t > tMax) { + tMax = t; + } + } + + // We have to subtract off the origin + + // See if [tMin, tMax] intersects [0, 1] + if ((tMin > 1 + origin[a]) || (tMax < origin[a])) { + // There was no intersection along this dimension; + // the boxes cannot possibly overlap. + return false; + } + } + + // There was no dimension along which there is no intersection. + // Therefore the boxes overlap. + return true; + } + + + /** Updates the axes after the corners move. Assumes the + corners actually form a rectangle. */ + void computeAxes() { + axis[0] = corner[1] - corner[0]; + axis[1] = corner[3] - corner[0]; + + // Make the length of each axis 1/edge length so we know any + // dot product must be less than 1 to fall within the edge. + + for (int a = 0; a < 2; ++a) { + axis[a] /= axis[a].lengthSqr(); + origin[a] = corner[0].dot(axis[a]); + } + } + +public: + + OBB2D(const Vec2d& center, const double w, const double h, double angle) + { + Vec2d X(cos(angle), sin(angle)); + Vec2d Y(-sin(angle), cos(angle)); + + X *= w / 2; + Y *= h / 2; + + corner[0] = center - X - Y; + corner[1] = center + X - Y; + corner[2] = center + X + Y; + corner[3] = center - X + Y; + + computeAxes(); + } + + + /** For testing purposes. */ + void moveTo(const Vec2d& center) { + Vec2d centroid = (corner[0] + corner[1] + corner[2] + corner[3]) / 4; + + Vec2d translation = center - centroid; + + for (int c = 0; c < 4; ++c) { + corner[c] += translation; + } + + computeAxes(); + } + + /** Returns true if the intersection of the boxes is non-empty. */ + bool overlaps(const OBB2D& other) const { + return overlaps1Way(other) && other.overlaps1Way(*this); + } +}; \ No newline at end of file diff --git a/Src/GameConnection.hpp b/Src/GameConnection.hpp index dbc9ea7..8fe5ef0 100644 --- a/Src/GameConnection.hpp +++ b/Src/GameConnection.hpp @@ -13,7 +13,6 @@ enum class PlayerState:int }; struct GameConnection { virtual ~GameConnection() noexcept = default; -<<<<<<< HEAD virtual int getTimeline() noexcept = 0; virtual void getPowers(std::vector &powers) noexcept = 0; virtual void getEnemyData(std::vector &enemy) noexcept = 0; @@ -51,13 +50,5 @@ class GameConnectionTH10 : public GameConnection { readProcessRaw(offset, sizeof(T), &result); return result; } -======= - virtual void getPowers(std::vector& powers) noexcept = 0; - virtual void getEnemyData(std::vector& enemy) noexcept = 0; - virtual void getEnemyBulletData(std::vector& bullet, const Player& player, double maxRange) noexcept = 0; - virtual void getPlayerData(Player& self) noexcept = 0; - virtual void getEnemyLaserData(std::vector& laser) noexcept = 0; - virtual void sendKeyInfo(int dir, bool shift, bool z, bool x) noexcept = 0; ->>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 }; std::unique_ptr createGameConnection(); diff --git a/Src/GameConnectionTH10.cpp b/Src/GameConnectionTH10.cpp index 4b9c6b1..1d61dce 100644 --- a/Src/GameConnectionTH10.cpp +++ b/Src/GameConnectionTH10.cpp @@ -3,48 +3,14 @@ #include -<<<<<<< HEAD -======= -class GameConnectionTh10 : public GameConnection { -public: - GameConnectionTh10(); - ~GameConnectionTh10() noexcept override; - void getPowers(std::vector& powers) noexcept override; - void getEnemyData(std::vector& enemy) noexcept override; - void getEnemyBulletData(std::vector& bullet, const Player& player, double maxRange) noexcept override; - void getPlayerData(Player& self) noexcept override; - void getEnemyLaserData(std::vector& laser) noexcept override; - void sendKeyInfo(int dir, bool shift, bool z, bool x) noexcept override; -private: - HANDLE mHProcess{nullptr}; - static bool getProcessIdByName(const char* exeFileName, DWORD& pid) noexcept; - - void readProcessRaw(const intptr_t offset, const size_t length, void* target) const noexcept { - static thread_local SIZE_T nbr; - ReadProcessMemory(mHProcess, reinterpret_cast(offset), target, length, &nbr); - } - - template - T readProcess(const intptr_t offset) const noexcept { - T result; - readProcessRaw(offset, sizeof(T), &result); - return result; - } -}; ->>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 namespace { char staticBuffer[0x7F0 * 2001]; - - template - T read(void* buffer) noexcept { return *reinterpret_cast(buffer); } + template + T read(void *buffer) noexcept { return *reinterpret_cast(buffer); } } -<<<<<<< HEAD void GameConnectionTH10::getPowers(std::vector &powers) noexcept { -======= -void GameConnectionTh10::getPowers(std::vector& powers) noexcept { ->>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 powers.clear(); auto ebp = staticBuffer; const auto base = readProcess(0x00477818); @@ -54,37 +20,32 @@ void GameConnectionTh10::getPowers(std::vector& powers) noexcept { const auto eax = read(ebp + 0x30); if (eax == 1) { const auto x = read(ebp), y = read(ebp + 0x4); - powers.emplace_back(Vec2d{x, y}, Vec2d{6, 6}); + powers.emplace_back(x, y, 6, 6); } ebp += 0x3F0; } } -<<<<<<< HEAD void GameConnectionTH10::getEnemyData(std::vector &enemy) noexcept { -======= -void GameConnectionTh10::getEnemyData(std::vector& enemy) noexcept { ->>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 enemy.clear(); const auto base = readProcess(0x00477704); if (!base) return; - auto objBase = readProcess(base + 0x58); - if (objBase) { + auto obj_base = readProcess(base + 0x58); + if (obj_base) { while (true) { - const auto objAddress = readProcess(objBase) + 0x103C; - const auto objNext = readProcess(objBase + 4); - const auto t = readProcess(objAddress + 0x1444); + const auto obj_address = readProcess(obj_base) + 0x103C; + const auto obj_next = readProcess(obj_base + 4); + const auto t = readProcess(obj_address + 0x1444); if (!(t & 0x40u) && !(t & 0x12u)) { - const auto x = readProcess(objAddress + 0x2C), y = readProcess(objAddress + 0x30), - w = readProcess(objAddress + 0xB8), h = readProcess(objAddress + 0xBC); - enemy.emplace_back(Vec2d{x, y}, Vec2d{w, h}); + const auto x = readProcess(obj_address + 0x2C), y = readProcess(obj_address + 0x30), + w = readProcess(obj_address + 0xB8), h = readProcess(obj_address + 0xBC); + enemy.emplace_back(x, y, w, h); } - if (!objNext) break; - objBase = objNext; + if (!obj_next) break; + obj_base = obj_next; } } } -<<<<<<< HEAD void GameConnectionTH10::getMousePosition(Vec2d& pos)noexcept{ const Vec2d orgdelta = Vec2d(28, 45); POINT m; @@ -96,11 +57,6 @@ void GameConnectionTH10::getMousePosition(Vec2d& pos)noexcept{ } void GameConnectionTH10::getEnemyBulletData(std::vector &bullet, const Player &player, double maxRange) noexcept { -======= - -void GameConnectionTh10::getEnemyBulletData(std::vector& bullet, const Player& player, - const double maxRange) noexcept { ->>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 bullet.clear(); auto ebx = staticBuffer; const auto base = readProcess(0x004776F0); @@ -115,24 +71,15 @@ void GameConnectionTh10::getEnemyBulletData(std::vector& bullet, const P const auto bp = read(ebx + 0x446) & 0x0000FFFFu; if (bp) { const auto x = read(ebx + 0x3B4), y = read(ebx + 0x3B8), -<<<<<<< HEAD w = read(ebx + 0x3F0), h = read(ebx + 0x3F4), dx = read(ebx + 0x3C0), dy = read(ebx + 0x3C4); if (distanceSqr(Vec2d(x, y), player.pos) <= maxRange * maxRange) bullet.emplace_back(x, y, w, h, dx, dy); -======= - w = read(ebx + 0x3F0), h = read(ebx + 0x3F4), - dx = read(ebx + 0x3C0), dy = read(ebx + 0x3C4); - //涓轰簡鏁堢巼锛屽彧鑰冭檻鍙兘浼氱鍒扮殑瀛愬脊 - if (distanceSqr(Vec2d(x, y), player.pos) <= maxRange * maxRange) - bullet.emplace_back(Vec2d{x, y}, Vec2d{w, h}, Vec2d{dx / 2.0f, dy / 2.0f}); ->>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 } ebx += 0x7F0; } } -<<<<<<< HEAD void GameConnectionTH10::getPlayerData(Player &self) noexcept { const auto obj_base = readProcess(0x00477834); if (!obj_base) return; @@ -143,16 +90,6 @@ void GameConnectionTH10::getPlayerData(Player &self) noexcept { } void GameConnectionTH10::getEnemyLaserData(std::vector &laser) noexcept { -======= -void GameConnectionTh10::getPlayerData(Player& self) noexcept { - const auto objBase = readProcess(0x00477834); - if (!objBase) return; - self.pos.x = readProcess(objBase + 0x3C0); - self.pos.y = readProcess(objBase + 0x3C4); -} - -void GameConnectionTh10::getEnemyLaserData(std::vector& laser) noexcept { ->>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 laser.clear(); const auto base = readProcess(0x0047781C); if (!base) return; @@ -161,21 +98,14 @@ void GameConnectionTh10::getEnemyLaserData(std::vector& laser) noexcept { while (true) { const auto ebx = readProcess(esi + 0x8); const auto x = readProcess(esi + 0x24), y = readProcess(esi + 0x28), -<<<<<<< HEAD w = readProcess(esi + 0x44), h = readProcess(esi + 0x40), arc = readProcess(esi + 0x3C); laser.emplace_back(x, y, w, h, arc); -======= - w = readProcess(esi + 0x44), h = readProcess(esi + 0x40), - arc = readProcess(esi + 0x3C); - laser.emplace_back(Vec2d{x, y}, Vec2d{w / 2.0f, h}, arc); ->>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 if (!ebx) break; esi = ebx; } } } -<<<<<<< HEAD PlayerState GameConnectionTH10::GetPlayerStateInformation()noexcept { int base_addr = readProcess(0x00477834); if (!base_addr) @@ -188,21 +118,17 @@ int GameConnectionTH10::getTimeline() noexcept { return readProcess(0x00474C88); } void GameConnectionTH10::sendKeyInfo(int32_t dir, bool shift, bool z, bool x) noexcept { -======= - -void GameConnectionTh10::sendKeyInfo(const int32_t dir, const bool shift, const bool z, const bool x) noexcept { ->>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 KeyboardManager::sendKeyInfo(dir, shift, z, x); } -GameConnectionTh10::~GameConnectionTh10() noexcept { - GameConnectionTh10::sendKeyInfo(0, false, false, false); +GameConnectionTH10::~GameConnectionTH10() noexcept { + GameConnectionTH10::sendKeyInfo(0, false, false, false); CloseHandle(mHProcess); } -GameConnectionTh10::GameConnectionTh10() { +GameConnectionTH10::GameConnectionTH10() { DWORD pid = 1; - if (!getProcessIdByName("th10.exe", pid)) + if (!GetProcessIdByName("th10.exe", pid)) throw std::runtime_error("th10.exe not running!"); mHProcess = OpenProcess(PROCESS_VM_READ, true, pid); if (!mHProcess) @@ -212,7 +138,7 @@ GameConnectionTh10::GameConnectionTh10() { throw std::runtime_error("cannot open th10 window!"); } -bool GameConnectionTh10::getProcessIdByName(const char* exeFileName, DWORD& pid) noexcept { +bool GameConnectionTH10::GetProcessIdByName(const char *exeFileName, DWORD &pid) noexcept { pid = 0; PROCESSENTRY32 pe; pe.dwSize = sizeof(pe); @@ -223,9 +149,10 @@ bool GameConnectionTh10::getProcessIdByName(const char* exeFileName, DWORD& pid) pid = pe.th32ProcessID; break; } - } - while (Process32Next(hSnapshot, &pe)); + } while (Process32Next(hSnapshot, &pe)); return static_cast(pid); } -std::unique_ptr createGameConnection() { return std::make_unique(); } +std::unique_ptr createGameConnection() { + return std::make_unique(); +} diff --git a/Src/GameManager.cpp b/Src/GameManager.cpp index 72cc357..785c9eb 100644 --- a/Src/GameManager.cpp +++ b/Src/GameManager.cpp @@ -1,6 +1,5 @@ #include "GameManager.hpp" #include "bmpCreater.hpp" -<<<<<<< HEAD #include Vec2d pointRotate(Vec2d target, Vec2d center, double arc) { float _x, _y; @@ -10,93 +9,24 @@ Vec2d pointRotate(Vec2d target, Vec2d center, double arc) { } void GameManager::outputValueMap(const char* path) { updateBoardInformation(99999.0); -======= -#include - -namespace { - // 6 : 1048576 2: 128 - constexpr uint64_t compress(const Node& in) noexcept { - return static_cast(in.time) << 60 | - static_cast(in.pos.x * 1048576) << 30 | static_cast(in.pos.y * 1048576); - } - - constexpr const auto maxInvincibleTime = 240; - - constexpr const auto maxDepth = 4; - - constexpr const auto s2D2 = 0.70710678118654752440084436; - - constexpr const Vec2d direction[] = { - {0.0, 0.0}, {1.0, 0.0}, {s2D2, -s2D2}, {0.0, -1.0}, {-s2D2, -s2D2}, {-1.0, 0.0}, {-s2D2, s2D2}, {0.0, 1.0}, - {s2D2, s2D2} - }; - - constexpr double playerSpeed[2] = {4.5, 2.0}; - - constexpr Vec2d ulCorner{-200, 0}, drCorner{200, 480}; - - const double eps = 1e-7; - - //浠庨珮浣嶅埌浣庝綅鍒嗗埆涓轰笂涓嬪乏鍙 - const int keyinfo[9] = {0x0, 0x1, 0x9, 0x8, 0xa, 0x2, 0x6, 0x4, 0x5}; -} - -GameManager::GameManager(): mConnection(createGameConnection()) { - valueMap.set_empty_key(compress(Node(0, {0.0, 0.0}))); - valueMap.set_deleted_key(compress(Node(-1, {0.0, 0.0}))); -} - -Vec2d pointRotate(const Vec2d& target, const Vec2d& center, const double arc) noexcept { - const auto x = (target.x - center.x) * cos(arc) - (target.y - center.y) * sin(arc); - const auto y = (target.x - center.x) * sin(arc) + (target.y - center.y) * cos(arc); - return center + Vec2d(x, y); -} - -void GameManager::updateEnemyLaserBoxes() noexcept { - //灏嗘縺鍏夌殑鍒ゅ畾璁句负鐢ˋABB鍖呰捣鏉ラ偅涔堝ぇ(gg,鍏堣繖涔堝啓鍐嶆參鎱㈡敼鍚) - for (auto& laser : mLaser) { - const auto arc = laser.arc - 3.1415926 * 5.0 / 2.0; - const auto ul = pointRotate(Vec2d(laser.pos.x - laser.size.x / 2.0, laser.pos.y), laser.pos, arc), - ur = pointRotate(Vec2d(laser.pos.x + laser.size.x / 2.0, laser.pos.y), laser.pos, arc), - dl = pointRotate(Vec2d(laser.pos.x - laser.size.x / 2.0, laser.pos.y + laser.size.y), laser.pos, - arc), - dr = pointRotate(Vec2d(laser.pos.x + laser.size.x / 2.0, laser.pos.y + laser.size.y), laser.pos, - arc); - laser.pos = (ul + ur + dl + dr) / 4.0; - const auto sizeX = std::max(std::max(ul.x, ur.x), std::max(dl.x, dr.x)) - std::min( - std::min(ul.x, ur.x), std::min(dl.x, dr.x)); - const auto sizeY = std::max(std::max(ul.y, ur.y), std::max(dl.y, dr.y)) - std::min( - std::min(ul.y, ur.y), std::min(dl.y, dr.y)); - laser.size = Vec2d(sizeX, sizeY); - } -} - -void GameManager::doValueMapOutput(const char* path) const noexcept { ->>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 static Pixel map[480][400]; memset(map, 0, sizeof(map)); // 璁剧疆鑳屾櫙涓洪粦鑹 + double total = 400 * 480; double now = 0; - for (auto i = 0; i < 400; ++i) { - for (auto j = 0; j < 480; ++j) { + for (int i = 0; i < 400; ++i) { + for (int j = 0; j < 480; ++j) { now++; - const Node state{0, Vec2d(i - 200, j)}; + Node state = Node(0, Vec2d(i - 200, j)); if (legalState(state)) { -<<<<<<< HEAD double value = getValue(state); double k = 255.0 / 600.0, b = 140.0 * k; value = k * value + b; map[479 - j][i].g = std::min(255, std::max(0,(int)value)); map[479 - j][i].r = std::min(255, std::max(0, 255-(int)value)); -======= - constexpr auto k = 255.0 / 600.0, b = 140.0 * k; - const auto value = k * getValue(state) + b; - map[479 - j][i].g = std::min(255, std::max(0, static_cast(value))); - map[479 - j][i].r = std::min(255, std::max(0, 255 - static_cast(value))); ->>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 } } + //if (i % 100 == 0)std::cout << now / total * 100.0<<"%" << std::endl; } -<<<<<<< HEAD generateBmp((BYTE*)map, 400, 480, path); } void GameManager::updateEnemyLaserBoxes() noexcept { @@ -201,139 +131,29 @@ void GameManager::update(unsigned long long frameCount,bool enabledMouse) { //姝e父杩涜娓告垙 mConnection->sendKeyInfo(moveKeyChoice, useShift, true, useBomb); break; -======= - generateBmp(map, {400, 480}, path); -} - -void GameManager::outputValueMap(const char* path) noexcept { - updateBoardInformation(1000.0); - auto fork = *this; - auto res = std::async(std::launch::async, [fork = std::move(fork), path]() { fork.doValueMapOutput(path); }); -} - -static int invincibleTime = 0; - -void GameManager::updateBoardInformation(const double ratio) noexcept { - mConnection->getPlayerData(mPlayer); - mConnection->getEnemyData(mEnemy); - mConnection->getEnemyBulletData(mBullet, mPlayer, ratio); - mConnection->getEnemyLaserData(mLaser); - mConnection->getPowers(mPowers); - updateEnemyLaserBoxes(); -} - -void GameManager::pathEnumeration() noexcept { - //BFS鎼滅储maxDepth姝ワ紝鎵惧埌maxDepth姝ュ唴浠峰兼渶楂樼殑鍙埌杈句綅缃 - valueMap.clear_no_resize(); - bfsQueue.emplace(0, fixupPos(mPlayer.pos)); - while (!bfsQueue.empty()) { - const auto now = bfsQueue.front(); - const auto nowData = valueMap[compress(now)]; - bfsQueue.pop(); - for (auto i = 0; i < 9; ++i) { - for (auto j = 0; j <= 1; ++j) { - const Node nex{now.time + 1, fixupPos(now.pos + direction[i] * playerSpeed[j])}; - if (!legalState(nex))continue; - if (auto&& [node, success] = valueMap.insert({compress(nex), NodeSave()}); success) { - if (now.time == 0) - node->second = NodeSave(i, static_cast(j), getValue(nex)); - else - node->second = NodeSave(nowData.from, nowData.shift, getValue(nex)); - if (nex.time == maxDepth) bfsQueue.push(nex); - } - } - } } -} - -bool GameManager::evaluateBombUse() noexcept { - auto useBomb = false; - if (invincibleTime <= 0) { - //1.琚瓙寮规墦涓 - for (const auto& bullet : mBullet) { - if (hitTestBombChoice(bullet, mPlayer)) { - useBomb = true; - invincibleTime = maxInvincibleTime; - break; - } - } - //2.琚綋鏈 - for (const auto& enemy : mEnemy) { - if (hitTestBombChoice(enemy, mPlayer)) { - useBomb = true; - invincibleTime = maxInvincibleTime; - break; - } - } - //3.琚縺鍏夋墦涓 - for (const auto& laser : mLaser) { - if (hitTestBombChoice(laser, mPlayer)) { - useBomb = true; - invincibleTime = maxInvincibleTime; - break; - } - } ->>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 - } - return useBomb; -} - -void GameManager::selectBestPath(int& moveKeyChoice, bool& useShift) noexcept { - auto maxValue = -99999999999.0; - for (auto&& item : valueMap) { - if (item.first >> 60 == 0)continue; - if (item.second.value - maxValue > eps) { - maxValue = item.second.value; - useShift = item.second.shift; - moveKeyChoice = keyinfo[item.second.from]; - } + default: + break; } } -void GameManager::update(const unsigned long long frameCount) noexcept { - updateBoardInformation(static_cast(maxDepth) * playerSpeed[0] + 15.0); - if (invincibleTime == maxInvincibleTime - 60 && mPowers.empty()) { invincibleTime = 0; } - if (invincibleTime > 0)invincibleTime--; - - pathEnumeration(); - //閫夋嫨鏈楂樹及浠 - auto moveKeyChoice = -1; - auto useShift = false; - selectBestPath(moveKeyChoice, useShift); - - const auto useBomb = evaluateBombUse(); - //鍙戦佸喅绛 - if (mEnemy.size() <= 1 && mBullet.empty()) - //璺宠繃瀵硅瘽锛岄棿闅斿抚鎸塟 - mConnection->sendKeyInfo(moveKeyChoice, useShift, frameCount % 2, useBomb); - else - //姝e父杩涜娓告垙 - mConnection->sendKeyInfo(moveKeyChoice, useShift, true, useBomb); -} - //鍒ゆ柇鐘舵佹槸鍚﹀悎娉(鏌愪釜浣嶇疆鑳藉惁鍒拌揪) -<<<<<<< HEAD bool GameManager::legalState(Node state) const noexcept { if (invincibleTime > 0)return true; Object newPlayer = Object(state.pos.x, state.pos.y, mPlayer.size.x, mPlayer.size.y); -======= -bool GameManager::legalState(const Node& state) const noexcept { - if (invincibleTime > 0)return true; ->>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 for (auto bullet : mBullet) { bullet.pos += bullet.delta * state.time; - if (hitTest(bullet, mPlayer)) { return false; } + if (hitTest(bullet, newPlayer)) { return false; } } for (auto enemy : mEnemy) { enemy.pos += enemy.delta * state.time; - if (hitTest(enemy, mPlayer)) { return false; } + if (hitTest(enemy, newPlayer)) { return false; } } //for (auto laser : mLaser) { // if (hitTest(laser, newPlayer)) { return false; } //} return true; } -<<<<<<< HEAD //瀵圭姸鎬佽繘琛屼及浠 double GameManager::getValue(Node state) const noexcept { double value = 0.0; @@ -425,82 +245,9 @@ double GameManager::getValue(Node state) const noexcept { value -= 0.1 * state.time; return value; } -======= - -double GameManager::getThreatValue(const Vec2d& newPos) const noexcept { - auto avgScore = 0.0, count = 0.0, avgScore2 = 0.0, count2 = 0.0; - //鏁屾満浼颁环 - for (auto& enemy : mEnemy) { - constexpr const Vec2d up(0, -1); - const auto dis = distanceSqr(enemy.pos, newPos); - auto selfDir = (newPos - enemy.pos).unit(); - //绔欑殑浣嶇疆鍋忛珮锛屽鏄撹寮瑰箷灏佹銆傗滀粠鏁屾満鎸囧悜鑷満鐨勫悜閲忊濆拰鈥滀粠鏁屾満鎸囧悜姝d笂鏂圭殑鍚戦噺鈥濈殑澶硅瓒婂ぇ瓒婂畨鍏紝鍑忓垎瓒婂皯銆 - if (enemy.pos.y <= 240) { - avgScore -= selfDir.dot(up) + 1.0; - count++; - } - //绂绘晫鏈鸿繃杩涘鏄撹鍙戝嚭鐨勫脊骞曟墦姝伙紝涔熷彲鑳借浣撴湳銆傚洜姝よ窛绂昏秺杩戝噺鍒嗚秺澶氥 - if (dis <= 20000.0) { - avgScore2 -= 1.0 - dis / 20000.0; - count2++; - } - } - if (count > 0) avgScore /= count; - if (count2 > 0) avgScore2 /= count2; - return 80.0 * avgScore + 80.0 * avgScore2; -} - -double GameManager::getAttackValue(const Node& state) const noexcept { - //瀛愬脊浼颁环(鍜屽瓙寮硅繍鍔ㄦ柟鍚戝す瑙掕秺澶у噺鍒嗚秺灏) - if (invincibleTime > 0) return 0.0; - auto avgScore = 0.0, count = 0.0; - for (auto bullet : mBullet) { - bullet.pos += bullet.delta * state.time; - if (distanceSqr(bullet.pos, state.pos) <= 900) { - count++; - auto selfDir = (state.pos - bullet.pos).unit(); - const auto bulletDir = bullet.delta.unit(); - avgScore -= selfDir.dot(bulletDir) + 1.0; - } - } - if (count > 0) avgScore /= count; - return 70.0 * avgScore; -} - -double GameManager::getKillValue(const Node& state) const noexcept { - //鍑荤牬鏁屾満浼颁环(绔欏湪鏁屾満姝d笅鏂瑰姞鍒) - auto value = 0.0, minEnemyDis = 400.0; - if (invincibleTime == 0) { - for (auto& enemy : mEnemy) { - auto dis = abs(enemy.pos.x + enemy.delta.x * state.time - state.pos.x); - minEnemyDis = std::min(minEnemyDis, dis); - } - value += 80.0 * (400 - minEnemyDis) / 400; - } - return value; -} - -double GameManager::getPowerValue(const Node& state) const noexcept { - //鏀剁偣浼颁环锛岀鐐硅秺杩戯紝浠峰艰秺楂 - auto minPowerDis = 390400.0; - for (auto& power : mPowers) { - const auto newPowerPos = power.pos + power.delta * state.time; - const auto dis = distanceSqr(newPowerPos, state.pos); - if (dis < minPowerDis) { minPowerDis = dis; } - } - return (invincibleTime > 0 ? 480 : 180) * (390400.0 - minPowerDis) / 390400.0; -} - -//瀵圭姸鎬佽繘琛屼及浠 -double GameManager::getValue(const Node& state) const noexcept { - return getPowerValue(state) + 80.0 * getMapValue(state.pos) + getKillValue(state) + getAttackValue(state) + - getThreatValue(state.pos) - 0.1 * state.time; -} - ->>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 //淇瓒呭嚭鍦板浘鐨勫潗鏍(涓昏鏄嚜鏈) Vec2d GameManager::fixupPos(const Vec2d& pos) noexcept { - auto res = pos; + Vec2d res = pos; if (res.x < ulCorner.x)res.x = ulCorner.x; if (res.y < ulCorner.y)res.y = ulCorner.y; if (res.x > drCorner.x)res.x = drCorner.x; @@ -512,18 +259,12 @@ bool GameManager::hitTest(const Object& a, const Object& b) noexcept { return abs(a.pos.x - b.pos.x) - ((a.size.x + b.size.x) / 2.0) <= eps+0.5 && abs(a.pos.y - b.pos.y) - ((a.size.y + b.size.y) / 2.0) <= eps+0.5; } -<<<<<<< HEAD //鍦板浘浣嶇疆浼颁环 double GameManager::getMapValue(Vec2d pos) noexcept { -======= - -//鍦板浘浣嶇疆浼颁环(绔欏湪鍦板浘鍋忎笅鐨勪綅缃姞鍒) -double GameManager::getMapValue(const Vec2d& pos) noexcept { ->>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 if (pos.y <= 100) return pos.y * 0.9 / 100; - const auto dis = (abs(390 - pos.y) * (-10.0 / 290.0) + 100.0) / 100.0; - const auto disx = (200 - abs(0 - pos.x)) / 200.0; + double dis = (abs(390 - pos.y) * (-10.0 / 290.0) + 100.0) / 100.0; + double disx = (200 - abs(0 - pos.x)) / 200.0; return dis * 0.95 + disx * 0.05; } diff --git a/Src/GameManager.hpp b/Src/GameManager.hpp index 0915c1a..b3d6163 100644 --- a/Src/GameManager.hpp +++ b/Src/GameManager.hpp @@ -4,7 +4,6 @@ #include #include "GameConnection.hpp" -<<<<<<< HEAD const double s2d2 = sqrt(2.0) / 2.0; const double dx[9] = {0, 1.0, s2d2, 0, -s2d2, -1.0, -s2d2, 0, s2d2}; const double dy[9] = {0, 0, -s2d2, -1.0, -s2d2, 0, s2d2, 1.0, s2d2}; @@ -26,13 +25,6 @@ struct Node { int8_t time; Vec2d pos; constexpr Node(int8_t time_, Vec2d pos_) noexcept : time(time_), pos(pos_) {} -======= -struct Node { - int8_t time; - Vec2d pos; - Node() = default; - constexpr Node(const int8_t iTime, const Vec2d& iPos) noexcept : time(iTime), pos(iPos) {} ->>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 }; bool operator<(const Node& lhs, const Node& rhs); @@ -41,12 +33,10 @@ struct NodeSave { int from; double value; NodeSave() = default; - constexpr NodeSave(const int iFrom, const bool iShift, const double iValue) noexcept : - shift(iShift), from(iFrom), value(iValue) {} + constexpr NodeSave(int from_, bool shift_, double value_) noexcept : shift(shift_), from(from_), value(value_) {} }; class GameManager { public: -<<<<<<< HEAD GameManager() : mState(GameState::NORMAL), mConnection(createGameConnection()) {} void update(unsigned long long frameCount,bool enabledMouse); void outputValueMap(const char* path); @@ -55,20 +45,10 @@ class GameManager { std::queue bfsQueue; GameState mState; Player mPlayer {}; -======= - GameManager(); - void outputValueMap(const char* path) noexcept; - void update(unsigned long long frameCount) noexcept; -private: - google::dense_hash_map valueMap{5500}; - std::queue bfsQueue; - Player mPlayer{}; ->>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 std::vector mEnemy; std::vector mBullet; std::vector mLaser; std::vector mPowers; -<<<<<<< HEAD Vec2d mMousePos; bool mouseMode; std::unique_ptr mConnection; @@ -82,27 +62,4 @@ class GameManager { void updateBoardInformation(double ratio) noexcept; //地图位置估价 static double getMapValue(Vec2d pos) noexcept; -======= - std::shared_ptr mConnection; - // Frame Advancing - void updateEnemyLaserBoxes() noexcept; - void updateBoardInformation(double ratio) noexcept; - // ValueMap Capture - void doValueMapOutput(const char* path) const noexcept; - // Action Evaluation - void pathEnumeration() noexcept; - bool evaluateBombUse() noexcept; - bool legalState(const Node& state) const noexcept; - void selectBestPath(int& moveKeyChoice, bool& useShift) noexcept; - // Weight Evaluation - double getValue(const Node& state) const noexcept; - double getThreatValue(const Vec2d& newPos) const noexcept; - double getAttackValue(const Node& state) const noexcept; - double getKillValue(const Node& state) const noexcept; - double getPowerValue(const Node& state) const noexcept; - static Vec2d fixupPos(const Vec2d& pos) noexcept; - static bool hitTest(const Object& a, const Object& b) noexcept; - static bool hitTestBombChoice(const Object& a, const Object& b) noexcept; - static double getMapValue(const Vec2d& pos) noexcept; ->>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 }; diff --git a/Src/KeyboardManager.cpp b/Src/KeyboardManager.cpp index 68152fa..3bbe7e3 100644 --- a/Src/KeyboardManager.cpp +++ b/Src/KeyboardManager.cpp @@ -4,7 +4,6 @@ namespace { bool keystate[100]; -<<<<<<< HEAD constexpr const char KEY_SHIFT = 16; constexpr const char KEY_LEFT = 37; constexpr const char KEY_UP = 38; @@ -14,18 +13,6 @@ namespace { constexpr const char KEY_Z = 90; constexpr const char KEY_ESCAPE = 90; void sendKey(int key, bool down) noexcept { -======= - constexpr const char keyShift = 16; - constexpr const char keyLeft = 37; - constexpr const char keyUp = 38; - constexpr const char keyRight = 39; - constexpr const char keyDown = 40; - constexpr const char keyX = 88; - constexpr const char keyZ = 90; - constexpr const char keyEscape = 90; - - void sendKey(const int key, const bool down) noexcept { ->>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 if (keystate[key] != down) { keystate[key] = down; if (down) keybd_event(key, MapVirtualKey(key, 0), 0, 0); @@ -34,19 +21,23 @@ namespace { } } -int isKeyDown(const int id) { return GetAsyncKeyState(id) & 0x8000 ? 1 : 0; } +int isKeyDown(int id) { return GetAsyncKeyState(id) & 0x8000 ? 1 : 0; } -void KeyboardManager::sendKeyInfo(const int dir, const bool shift, const bool z, const bool x) { - sendKey(keyUp, static_cast(dir & 0x8)); - sendKey(keyDown, static_cast(dir & 0x4)); - sendKey(keyLeft, static_cast(dir & 0x2)); - sendKey(keyRight, static_cast(dir & 0x1)); - sendKey(keyShift, shift); - sendKey(keyZ, z); - sendKey(keyX, x); +void KeyboardManager::sendKeyInfo(int dir, bool shift, bool z, bool x) { + sendKey(KEY_UP, static_cast(dir & 0x8)); + sendKey(KEY_DOWN, static_cast(dir & 0x4)); + sendKey(KEY_LEFT, static_cast(dir & 0x2)); + sendKey(KEY_RIGHT, static_cast(dir & 0x1)); + sendKey(KEY_SHIFT, shift); + sendKey(KEY_Z, z); + sendKey(KEY_X, x); } void KeyboardManager::init() { memset(keystate, 0, sizeof(keystate)); } -void KeyboardManager::pressEsc() { keybd_event(keyEscape, MapVirtualKey(keyEscape, 0), 0, 0); } -void KeyboardManager::releaseEsc() { keybd_event(keyEscape, MapVirtualKey(keyEscape, 0), KEYEVENTF_KEYUP, 0); } +void KeyboardManager::pressEsc() { + keybd_event(KEY_ESCAPE, MapVirtualKey(KEY_ESCAPE, 0), 0, 0); +} +void KeyboardManager::releaseEsc() { + keybd_event(KEY_ESCAPE, MapVirtualKey(KEY_ESCAPE, 0), KEYEVENTF_KEYUP, 0); +} \ No newline at end of file diff --git a/Src/KeyboardManager.hpp b/Src/KeyboardManager.hpp index 1979961..67cc51d 100644 --- a/Src/KeyboardManager.hpp +++ b/Src/KeyboardManager.hpp @@ -3,8 +3,9 @@ struct KeyboardManager { static void init(); static void sendKeyInfo(int dir, bool shift, bool z, bool x); - static void pressEsc(); - static void releaseEsc(); + static void pressEsc(); + static void releaseEsc(); }; int isKeyDown(int id); + diff --git a/Src/Object.hpp b/Src/Object.hpp index ced43d5..d9fa4c2 100644 --- a/Src/Object.hpp +++ b/Src/Object.hpp @@ -7,24 +7,17 @@ struct Object { Vec2d size; Vec2d delta; Object() = default; - constexpr Object(const Vec2d& iPos, const Vec2d& iSize) noexcept : pos(iPos), size(iSize), delta(0, 0) {} - - constexpr Object(const Vec2d& iPos, const Vec2d& iSize, const Vec2d& iDelta) noexcept : - pos(iPos), size(iSize), delta(iDelta) {} + constexpr Object(double x, double y, double w, double h) : pos(x, y), size(w, h), delta(0, 0) {} + constexpr Object(double x, double y, double w, double h, double dx, double dy): pos(x, y), size(w, h), delta(dx, dy) {} }; struct Laser : Object { double arc; - Laser() noexcept = default; - constexpr Laser(const Vec2d& pos, const Vec2d& size, const double arcIn) noexcept : Object(pos, size), arc(arcIn) {} + Laser() = default; + constexpr Laser(double x, double y, double w, double h, double arcIn) : Object(x, y, w, h), arc(arcIn) {} }; struct Player : Object { -<<<<<<< HEAD Player() = default; constexpr Player(double x, double y, double w, double h) : Object(x, y, 4.0, 4.0) {} -======= - Player() noexcept = default; - constexpr Player(const Vec2d& pos, const Vec2d& size) noexcept : Object(pos, size) {} ->>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 }; diff --git a/Src/Vec2.hpp b/Src/Vec2.hpp index 365d262..8696b8f 100644 --- a/Src/Vec2.hpp +++ b/Src/Vec2.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include template struct Vec2 { @@ -42,7 +42,7 @@ struct Vec2 { auto length() const noexcept { return std::sqrt(lengthSqr()); } auto norm() const noexcept { return length(); } Vec2 unit() const noexcept { return (*this) / norm(); } - constexpr T dot(const Vec2& rhs) const noexcept { return x * rhs.x + y * rhs.y; } + constexpr T dot(const Vec2& rhs) const noexcept { return x * rhs.x + y * rhs.y; } }; template diff --git a/Src/bmpCreater.cpp b/Src/bmpCreater.cpp index 837873e..869479c 100644 --- a/Src/bmpCreater.cpp +++ b/Src/bmpCreater.cpp @@ -5,49 +5,49 @@ //浣嶅浘鏂囦欢澶存枃浠跺畾涔 //鍏朵腑涓嶅寘鎷枃浠剁被鍨嬩俊鎭紙鐢变簬缁撴瀯浣撶殑鍐呭瓨缁撴瀯鍐冲畾锛岃鏄姞浜嗙殑璇濆皢涓嶈兘姝g‘鐨勮鍙栨枃浠朵俊鎭級 -struct BmpFileHeader { +struct BMPFILEHEADER_T { uint16_t bfType = 0X4d42; //鏂囦欢绫诲瀷锛屽繀椤绘槸0x424D,鍗冲瓧绗︹淏M鈥 - uint32_t bfSize{}; //鏂囦欢澶у皬 + uint32_t bfSize; //鏂囦欢澶у皬 uint16_t bfReserved1 = 0; //淇濈暀瀛 uint16_t bfReserved2 = 0; //淇濈暀瀛 - uint32_t bfOffBits{}; //浠庢枃浠跺ご鍒板疄闄呬綅鍥炬暟鎹殑鍋忕Щ瀛楄妭鏁 + uint32_t bfOffBits; //浠庢枃浠跺ご鍒板疄闄呬綅鍥炬暟鎹殑鍋忕Щ瀛楄妭鏁 }; -struct BmpInfoHeader { - uint32_t biSize{}; //淇℃伅澶村ぇ灏 - int32_t biWidth{}; //鍥惧儚瀹藉害 - int32_t biHeight{}; //鍥惧儚楂樺害 +struct BMPINFOHEADER_T { + uint32_t biSize; //淇℃伅澶村ぇ灏 + int32_t biWidth; //鍥惧儚瀹藉害 + int32_t biHeight; //鍥惧儚楂樺害 uint16_t biPlanes = 1; //浣嶅钩闈㈡暟锛屽繀椤讳负1 uint16_t biBitCount = 24; //姣忓儚绱犱綅鏁 uint32_t biCompression = 0; //鍘嬬缉绫诲瀷 - uint32_t biSizeImage{}; //鍘嬬缉鍥惧儚澶у皬瀛楄妭鏁 + uint32_t biSizeImage; //鍘嬬缉鍥惧儚澶у皬瀛楄妭鏁 int32_t biXPelsPerMeter = 0; //姘村钩鍒嗚鲸鐜 int32_t biYPelsPerMeter = 0; //鍨傜洿鍒嗚鲸鐜 uint32_t biClrUsed = 0; //浣嶅浘瀹為檯鐢ㄥ埌鐨勮壊褰╂暟 uint32_t biClrImportant = 0; //鏈綅鍥句腑閲嶈鐨勮壊褰╂暟 }; //浣嶅浘淇℃伅澶村畾涔 -static_assert(alignof(BmpInfoHeader) == 2 && alignof(BmpFileHeader) == 2, "pragma pack failure"); +static_assert(alignof(BMPINFOHEADER_T) == 2 && alignof(BMPFILEHEADER_T) == 2, "pragma pack failure"); -void generateBmp(void* pData, const Vec2i& size, const char* filename) { - const auto bmpSize = size.x * size.y * 3; // 姣忎釜鍍忕礌鐐3涓瓧鑺 +void generateBmp(void* pData, int width, int height, const char* filename) { + int size = width * height * 3; // 姣忎釜鍍忕礌鐐3涓瓧鑺 // 浣嶅浘绗竴閮ㄥ垎锛屾枃浠朵俊鎭 - BmpFileHeader bfh; - bfh.bfSize = bmpSize // data size - + sizeof(BmpFileHeader) // first section size - + sizeof(BmpInfoHeader) // second section size + BMPFILEHEADER_T bfh; + bfh.bfSize = size // data size + + sizeof(BMPFILEHEADER_T) // first section size + + sizeof(BMPINFOHEADER_T) // second section size ; - bfh.bfOffBits = bfh.bfSize - bmpSize; + bfh.bfOffBits = bfh.bfSize - size; // 浣嶅浘绗簩閮ㄥ垎锛屾暟鎹俊鎭 - BmpInfoHeader bih; - bih.biSize = sizeof(BmpInfoHeader); - bih.biWidth = size.x; - bih.biHeight = size.y; - bih.biSizeImage = bmpSize; + BMPINFOHEADER_T bih; + bih.biSize = sizeof(BMPINFOHEADER_T); + bih.biWidth = width; + bih.biHeight = height; + bih.biSizeImage = size; if (std::ofstream file(filename, std::ios::binary); file.good()) { - file.write(reinterpret_cast(&bfh), sizeof(BmpFileHeader)); - file.write(reinterpret_cast(&bih), sizeof(BmpInfoHeader)); - file.write(reinterpret_cast(pData), bmpSize); + file.write(reinterpret_cast(&bfh), sizeof(BMPFILEHEADER_T)); + file.write(reinterpret_cast(&bih), sizeof(BMPINFOHEADER_T)); + file.write(reinterpret_cast(pData), size); } } diff --git a/Src/bmpCreater.hpp b/Src/bmpCreater.hpp index a026089..3f1ba24 100644 --- a/Src/bmpCreater.hpp +++ b/Src/bmpCreater.hpp @@ -1,4 +1,3 @@ -<<<<<<< HEAD #include #include #include @@ -27,18 +26,6 @@ struct BMPFILEHEADER_S { WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; -======= -#pragma once -#include -#include "Vec2.hpp" - -void generateBmp(void* pData, const Vec2i& size, const char* filename); - -struct Pixel { - uint8_t b, g, r; - constexpr Pixel() noexcept : b(0), g(0), r(0) {} - constexpr Pixel(const uint8_t iR, const uint8_t iG, const uint8_t iB) noexcept : b(iB), g(iG), r(iR) {} ->>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 }; typedef struct { DWORD biSize;//信息头大小 diff --git a/Src/main.cpp b/Src/main.cpp index 0364475..e6764a2 100644 --- a/Src/main.cpp +++ b/Src/main.cpp @@ -16,14 +16,14 @@ class StopWatch { void stop() noexcept { mEndTime = steady_clock::now(); } void restart() noexcept { start(); } steady_clock::duration elapsed() const noexcept { return mEndTime - mBeginTime; } - int elapsedMs() const noexcept { return static_cast(duration_cast(elapsed()).count()); } - int elapsedS() const noexcept { return static_cast(duration_cast(elapsed()).count()); } + int elapsed_ms() const noexcept { return static_cast(duration_cast(elapsed()).count()); } + int elapsed_s() const noexcept { return static_cast(duration_cast(elapsed()).count()); } private: steady_clock::time_point mBeginTime, mEndTime; }; -void pauseUntilPress(const char* info, const char key) { +void pauseUntilPress(const char* info, char key) { std::cout << info << std::endl; while (true) { if (isKeyDown(key))return; @@ -35,13 +35,12 @@ int main() { try { KeyboardManager::init(); auto game = std::make_shared(); - const auto quit = false; + bool quit = false; std::cout << "准备完成" << std::endl; pauseUntilPress("请将焦点放在风神录窗口上,开始游戏,按C开启AI", 'C'); std::cout << "已开始游戏,按C键开启/关闭鼠标引导,Q键退出" << std::endl; unsigned long long frameCount = 0; StopWatch watch; -<<<<<<< HEAD int mapOutputCount = 0; const double maxcd = 30; double cd = 30; @@ -87,29 +86,6 @@ int main() { } loopCount++; std::this_thread::sleep_for(milliseconds(1)); -======= - auto mapOutputCount = 0; - auto cd = 0.0; - const double maxcd = 10; - while (!quit) { - if (cd > 0)cd -= 1.0; - if (isKeyDown('Q')) - break; - if (isKeyDown('P') && cd <= 0) { - cd = maxcd; - mapOutputCount++; - std::stringstream outputStream; - outputStream << "./value" << mapOutputCount << ".bmp"; - std::cout << outputStream.str() << std::endl; - game->outputValueMap(outputStream.str().c_str()); - continue; - } - watch.start(); - frameCount++; - game->update(frameCount); - watch.stop(); - std::this_thread::sleep_for(milliseconds(std::max(0, 16 - watch.elapsedMs()))); ->>>>>>> 9388c79051604a3fcb3dc29a2c558cf186aa0d56 } KeyboardManager::sendKeyInfo(0, false, false, false); } From 2a3e172005b8f4963ebab229a753f8456c7302ca Mon Sep 17 00:00:00 2001 From: renfei147 Date: Wed, 10 Jul 2019 23:04:43 +0800 Subject: [PATCH 3/7] fix the uncatched exception --- Src/GameManager.cpp | 4 ++++ Src/GameManager.hpp | 1 + Src/main.cpp | 5 ++--- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Src/GameManager.cpp b/Src/GameManager.cpp index 785c9eb..330e90c 100644 --- a/Src/GameManager.cpp +++ b/Src/GameManager.cpp @@ -276,3 +276,7 @@ bool operator<(const Node& lhs, const Node& rhs) { if ((rhs.pos.y - lhs.pos.y) > eps)return true; return false; } +int GameManager::getTimeline() noexcept +{ + return mConnection->getTimeline(); +} diff --git a/Src/GameManager.hpp b/Src/GameManager.hpp index b3d6163..7576ff8 100644 --- a/Src/GameManager.hpp +++ b/Src/GameManager.hpp @@ -40,6 +40,7 @@ class GameManager { GameManager() : mState(GameState::NORMAL), mConnection(createGameConnection()) {} void update(unsigned long long frameCount,bool enabledMouse); void outputValueMap(const char* path); + int getTimeline() noexcept; private: std::map valueMap; std::queue bfsQueue; diff --git a/Src/main.cpp b/Src/main.cpp index e6764a2..8e0bf03 100644 --- a/Src/main.cpp +++ b/Src/main.cpp @@ -30,7 +30,6 @@ void pauseUntilPress(const char* info, char key) { std::this_thread::sleep_for(10ms); } } -GameConnectionTH10 frameSyncer; int main() { try { KeyboardManager::init(); @@ -46,7 +45,7 @@ int main() { double cd = 30; bool mouseMode = false; cout << "鼠标引导当前处于关闭状态" << endl; - int gameFrame = frameSyncer.getTimeline(); + int gameFrame = game->getTimeline(); unsigned long long loopCount = 0; while (!quit) { if (loopCount % 16 == 0) @@ -70,7 +69,7 @@ int main() { continue; } } - int getGameFrame = frameSyncer.getTimeline(); + int getGameFrame = game->getTimeline(); if (getGameFrame != gameFrame) { if (getGameFrame > gameFrame + 1) From 1fca922c6e415a0a274ec3b17848261d78728f43 Mon Sep 17 00:00:00 2001 From: renfei147 Date: Thu, 11 Jul 2019 22:01:06 +0800 Subject: [PATCH 4/7] add basic laser support --- Src/GameManager.cpp | 233 +++++++++++++++++++++++--------------------- Src/GameManager.hpp | 2 +- 2 files changed, 121 insertions(+), 114 deletions(-) diff --git a/Src/GameManager.cpp b/Src/GameManager.cpp index 330e90c..257c07b 100644 --- a/Src/GameManager.cpp +++ b/Src/GameManager.cpp @@ -1,14 +1,15 @@ #include "GameManager.hpp" #include "bmpCreater.hpp" +#include "Vec2.hpp" #include Vec2d pointRotate(Vec2d target, Vec2d center, double arc) { - float _x, _y; - _x = (target.x - center.x) * cos(arc) - (target.y - center.y) * sin(arc); - _y = (target.x - center.x) * sin(arc) + (target.y - center.y) * cos(arc); - return center + Vec2d(_x, _y); + float _x, _y; + _x = (target.x - center.x) * cos(arc) - (target.y - center.y) * sin(arc); + _y = (target.x - center.x) * sin(arc) + (target.y - center.y) * cos(arc); + return center + Vec2d(_x, _y); } void GameManager::outputValueMap(const char* path) { - updateBoardInformation(99999.0); + updateBoardInformation(99999.0); static Pixel map[480][400]; memset(map, 0, sizeof(map)); // 璁剧疆鑳屾櫙涓洪粦鑹 double total = 400 * 480; @@ -29,31 +30,37 @@ void GameManager::outputValueMap(const char* path) { } generateBmp((BYTE*)map, 400, 480, path); } -void GameManager::updateEnemyLaserBoxes() noexcept { - //灏嗘縺鍏夌殑鍒ゅ畾璁句负鐢ˋABB鍖呰捣鏉ラ偅涔堝ぇ(gg,鍏堣繖涔堝啓鍐嶆參鎱㈡敼鍚) - for (auto& laser : mLaser) { - const auto arc = laser.arc - 3.1415926 * 5.0 / 2.0; - const auto ul = pointRotate(Vec2d(laser.pos.x - laser.size.x / 2.0, laser.pos.y), laser.pos, arc), - ur = pointRotate(Vec2d(laser.pos.x + laser.size.x / 2.0, laser.pos.y), laser.pos, arc), - dl = pointRotate(Vec2d(laser.pos.x - laser.size.x / 2.0, laser.pos.y + laser.size.y), laser.pos, - arc), - dr = pointRotate(Vec2d(laser.pos.x + laser.size.x / 2.0, laser.pos.y + laser.size.y), laser.pos, - arc); - laser.pos = (ul + ur + dl + dr) / 4.0; - const auto sizeX = std::max(std::max(ul.x, ur.x), std::max(dl.x, dr.x)) - std::min( - std::min(ul.x, ur.x), std::min(dl.x, dr.x)); - const auto sizeY = std::max(std::max(ul.y, ur.y), std::max(dl.y, dr.y)) - std::min( - std::min(ul.y, ur.y), std::min(dl.y, dr.y)); - laser.size = Vec2d(sizeX, sizeY); - } +void GameManager::updateEnemyLaserBoxes(const double ratio) noexcept { + for (auto& laser : mLaser) { + const auto arc = laser.arc - 3.1415926 * 5.0 / 2.0; + const auto ul = pointRotate(Vec2d(laser.pos.x - laser.size.x / 2.0, laser.pos.y), laser.pos, arc), + ur = pointRotate(Vec2d(laser.pos.x + laser.size.x / 2.0, laser.pos.y), laser.pos, arc), + dl = pointRotate(Vec2d(laser.pos.x - laser.size.x / 2.0, laser.pos.y + laser.size.y), laser.pos, + arc), + dr = pointRotate(Vec2d(laser.pos.x + laser.size.x / 2.0, laser.pos.y + laser.size.y), laser.pos, + arc); + const auto s = (ul + ur)*0.5; + const auto t = (dl + dr)*0.5; + const auto delta = (t - s).unit()*5.0; + double w = laser.size.x*0.5 + 2.0; + double add = w / laser.size.y; + for (double i = 0; i <= 1; i += add) + { + double x = i * s.x + (1.0 - i)*t.x; + double y = i * s.y + (1.0 - i)*t.y; + if (distanceSqr(Vec2d(x, y), mPlayer.pos) <= ratio * ratio) { + mBullet.emplace_back(x, y, w, w, delta.x, delta.y); + } + } + } } void GameManager::updateBoardInformation(const double ratio) noexcept { - mConnection->getPlayerData(mPlayer); - mConnection->getEnemyData(mEnemy); - mConnection->getEnemyBulletData(mBullet, mPlayer, ratio); - mConnection->getEnemyLaserData(mLaser); - mConnection->getPowers(mPowers); - updateEnemyLaserBoxes(); + mConnection->getPlayerData(mPlayer); + mConnection->getEnemyData(mEnemy); + mConnection->getEnemyBulletData(mBullet, mPlayer, ratio); + mConnection->getEnemyLaserData(mLaser); + mConnection->getPowers(mPowers); + updateEnemyLaserBoxes(ratio); } int invincibleTime=0; void GameManager::update(unsigned long long frameCount,bool enabledMouse) { @@ -64,15 +71,15 @@ void GameManager::update(unsigned long long frameCount,bool enabledMouse) { mConnection->getMousePosition(mMousePos); mMousePos = fixupPos(mMousePos); if (invincibleTime == maxInvincibleTime-60 && mPowers.size() == 0) - { - invincibleTime = 0; - } - if (invincibleTime > 0)invincibleTime--; + { + invincibleTime = 0; + } + if (invincibleTime > 0)invincibleTime--; //纭畾褰撳墠鐘舵 mState = GameState::NORMAL; switch (mState) { case GameState::NORMAL: { - //BFS鎼滅储maxDepth姝ワ紝鎵惧埌maxDepth姝ュ唴浠峰兼渶楂樼殑鍙埌杈句綅缃 + //BFS鎼滅储maxDepth姝ワ紝鎵惧埌maxDepth姝ュ唴浠峰兼渶楂樼殑鍙埌杈句綅缃 valueMap.erase(valueMap.begin(), valueMap.end()); Node startState = Node(0, fixupPos(mPlayer.pos)); valueMap[startState] = NodeSave(0, false, getValue(startState)); @@ -84,9 +91,9 @@ void GameManager::update(unsigned long long frameCount,bool enabledMouse) { if (now.time >= maxDepth)continue; for (int i = 0; i < 9; ++i) { for (int j = 0; j <= 1; ++j) { - if (now.time > 0&&nowData.shift != j)continue; + if (now.time > 0&&nowData.shift != j)continue; Node nex = Node(now.time + 1, fixupPos( - Vec2d(now.pos.x + dx[i] * playerSpeed[j], now.pos.y + dy[i] * playerSpeed[j]))); + Vec2d(now.pos.x + dx[i] * playerSpeed[j], now.pos.y + dy[i] * playerSpeed[j]))); if (valueMap.find(nex) == valueMap.end()) { if (!legalState(nex))continue; if (now.time == 0) @@ -105,7 +112,7 @@ void GameManager::update(unsigned long long frameCount,bool enabledMouse) { bool useShift = false; bool useBomb = false; NodeSave movement; - //std::cout << valueMap.size() << std::endl; + //std::cout << valueMap.size() << std::endl; for (auto&& item : valueMap) { if (item.first.time == 0)continue; if (item.second.value - maxValue > eps) { @@ -118,17 +125,17 @@ void GameManager::update(unsigned long long frameCount,bool enabledMouse) { } //鎵旈浄鍒ゆ柇 useBomb = false; - if (mConnection->GetPlayerStateInformation() == PlayerState::DYING) - { - invincibleTime = maxInvincibleTime; - useBomb = true; - } - //鍙戦佸喅绛 + if (mConnection->GetPlayerStateInformation() == PlayerState::DYING) + { + invincibleTime = maxInvincibleTime; + useBomb = true; + } + //鍙戦佸喅绛 if (mEnemy.size() <= 1 && mBullet.empty()) - //璺宠繃瀵硅瘽锛岄棿闅斿抚鎸塟 + //璺宠繃瀵硅瘽锛岄棿闅斿抚鎸塟 mConnection->sendKeyInfo(moveKeyChoice, useShift, frameCount % 2, useBomb); else - //姝e父杩涜娓告垙 + //姝e父杩涜娓告垙 mConnection->sendKeyInfo(moveKeyChoice, useShift, true, useBomb); break; } @@ -139,7 +146,7 @@ void GameManager::update(unsigned long long frameCount,bool enabledMouse) { //鍒ゆ柇鐘舵佹槸鍚﹀悎娉(鏌愪釜浣嶇疆鑳藉惁鍒拌揪) bool GameManager::legalState(Node state) const noexcept { - if (invincibleTime > 0)return true; + if (invincibleTime > 0)return true; Object newPlayer = Object(state.pos.x, state.pos.y, mPlayer.size.x, mPlayer.size.y); for (auto bullet : mBullet) { bullet.pos += bullet.delta * state.time; @@ -149,9 +156,9 @@ bool GameManager::legalState(Node state) const noexcept { enemy.pos += enemy.delta * state.time; if (hitTest(enemy, newPlayer)) { return false; } } - //for (auto laser : mLaser) { - // if (hitTest(laser, newPlayer)) { return false; } - //} + //for (auto laser : mLaser) { + // if (hitTest(laser, newPlayer)) { return false; } + //} return true; } //瀵圭姸鎬佽繘琛屼及浠 @@ -160,14 +167,14 @@ double GameManager::getValue(Node state) const noexcept { double minEnemyDis = 400.0; Vec2d newPos = state.pos; Object newPlayer = Object(newPos.x, newPos.y, mPlayer.size.x, mPlayer.size.y); - //榧犳爣寮曞妯″紡浼颁环 - if (mouseMode) - { - double dis = distance(mMousePos, newPos); - value += 150.0 * (sqrt(390400.0) - dis) / sqrt(390400.0); - value -= 0.1 * state.time; - return value; - } + //榧犳爣寮曞妯″紡浼颁环 + if (mouseMode) + { + double dis = distance(mMousePos, newPos); + value += 150.0 * (sqrt(390400.0) - dis) / sqrt(390400.0); + value -= 0.1 * state.time; + return value; + } minEnemyDis = 400.0; //鏀剁偣浼颁环锛岀鐐硅秺杩戯紝浠峰艰秺楂 double minPowerDis = 390400.0; @@ -178,71 +185,71 @@ double GameManager::getValue(Node state) const noexcept { minPowerDis = dis; } } - if (invincibleTime>0)value += 400 * (390400.0 - minPowerDis) / 390400.0; - else value += 180 * (390400.0 - minPowerDis) / 390400.0; - + if (invincibleTime>0)value += 400 * (390400.0 - minPowerDis) / 390400.0; + else value += 180 * (390400.0 - minPowerDis) / 390400.0; + //鍦板浘浣嶇疆浼颁环(绔欏湪鍦板浘鍋忎笅鐨勪綅缃姞鍒) value += 80.0 * getMapValue(newPos); //鍑荤牬鏁屾満浼颁环(绔欏湪鏁屾満姝d笅鏂瑰姞鍒) - if (invincibleTime == 0) - { - for (auto& enemy : mEnemy) { - double dis = abs(enemy.pos.x + enemy.delta.x * state.time - newPos.x); - minEnemyDis = std::min(minEnemyDis, dis); - } - value += 80.0 * (400 - minEnemyDis) / 400; - } + if (invincibleTime == 0) + { + for (auto& enemy : mEnemy) { + double dis = abs(enemy.pos.x + enemy.delta.x * state.time - newPos.x); + minEnemyDis = std::min(minEnemyDis, dis); + } + value += 80.0 * (400 - minEnemyDis) / 400; + } //瀛愬脊浼颁环(鍜屽瓙寮硅繍鍔ㄦ柟鍚戝す瑙掕秺澶у噺鍒嗚秺灏) - double avgScore = 0; - double count = 0; - for (auto bullet : mBullet) { - bullet.pos += bullet.delta * state.time; - if (distanceSqr(bullet.pos, newPos) <= 900) { - count++; - Vec2d selfDir = (newPos - bullet.pos).unit(); - Vec2d bulletDir = bullet.delta.unit(); - //璇ヤ綅缃殑浠峰间笌璇ヤ綅缃埌瀛愬脊鐨勮繛绾垮拰瀛愬脊杩愬姩鏂瑰悜鐨勫す瑙掓湁鍏筹紝澶硅瓒婂ぇ锛屽噺鍒嗚秺灏 - double dirvalue = selfDir.dot(bulletDir); - dirvalue += 1; - avgScore -= dirvalue; - } - } - if (invincibleTime == 0 && count > 0) { - avgScore /= count; - value += 70.0 * avgScore; - } + double avgScore = 0; + double count = 0; + for (auto bullet : mBullet) { + bullet.pos += bullet.delta * state.time; + if (distanceSqr(bullet.pos, newPos) <= 900) { + count++; + Vec2d selfDir = (newPos - bullet.pos).unit(); + Vec2d bulletDir = bullet.delta.unit(); + //璇ヤ綅缃殑浠峰间笌璇ヤ綅缃埌瀛愬脊鐨勮繛绾垮拰瀛愬脊杩愬姩鏂瑰悜鐨勫す瑙掓湁鍏筹紝澶硅瓒婂ぇ锛屽噺鍒嗚秺灏 + double dirvalue = selfDir.dot(bulletDir); + dirvalue += 1; + avgScore -= dirvalue; + } + } + if (invincibleTime == 0 && count > 0) { + avgScore /= count; + value += 70.0 * avgScore; + } avgScore = 0; count = 0; - double count2 = 0; - double avgScore2 = 0; + double count2 = 0; + double avgScore2 = 0; //鏁屾満浼颁环 - for (auto& enemy : mEnemy) { - double dis = distanceSqr(enemy.pos, newPos); - Vec2d selfDir = (newPos - enemy.pos).unit(); - Vec2d up(0, -1); - double dirvalue = selfDir.dot(up); - //绔欑殑浣嶇疆鍋忛珮锛屽鏄撹寮瑰箷灏佹銆傗滀粠鏁屾満鎸囧悜鑷満鐨勫悜閲忊濆拰鈥滀粠鏁屾満鎸囧悜姝d笂鏂圭殑鍚戦噺鈥濈殑澶硅瓒婂ぇ瓒婂畨鍏紝鍑忓垎瓒婂皯銆 - if (enemy.pos.y <= 240) { - dirvalue += 1; - avgScore -= dirvalue; - count++; - } - //绂绘晫鏈鸿繃杩涘鏄撹鍙戝嚭鐨勫脊骞曟墦姝伙紝涔熷彲鑳借浣撴湳銆傚洜姝よ窛绂昏秺杩戝噺鍒嗚秺澶氥 - if (dis <= 20000.0) { - avgScore2 -= 1.0 - (dis / 20000.0); - count2++; - } - } - if (count > 0) { - avgScore /= count; - value += 80.0 * avgScore; - } - if (count2 > 0) { - avgScore2 /= count2; - value += 80.0 * avgScore2; - } + for (auto& enemy : mEnemy) { + double dis = distanceSqr(enemy.pos, newPos); + Vec2d selfDir = (newPos - enemy.pos).unit(); + Vec2d up(0, -1); + double dirvalue = selfDir.dot(up); + //绔欑殑浣嶇疆鍋忛珮锛屽鏄撹寮瑰箷灏佹銆傗滀粠鏁屾満鎸囧悜鑷満鐨勫悜閲忊濆拰鈥滀粠鏁屾満鎸囧悜姝d笂鏂圭殑鍚戦噺鈥濈殑澶硅瓒婂ぇ瓒婂畨鍏紝鍑忓垎瓒婂皯銆 + if (enemy.pos.y <= 240) { + dirvalue += 1; + avgScore -= dirvalue; + count++; + } + //绂绘晫鏈鸿繃杩涘鏄撹鍙戝嚭鐨勫脊骞曟墦姝伙紝涔熷彲鑳借浣撴湳銆傚洜姝よ窛绂昏秺杩戝噺鍒嗚秺澶氥 + if (dis <= 20000.0) { + avgScore2 -= 1.0 - (dis / 20000.0); + count2++; + } + } + if (count > 0) { + avgScore /= count; + value += 80.0 * avgScore; + } + if (count2 > 0) { + avgScore2 /= count2; + value += 80.0 * avgScore2; + } //value += rand() % 10/100.00; - value -= 0.1 * state.time; + value -= 0.1 * state.time; return value; } //淇瓒呭嚭鍦板浘鐨勫潗鏍(涓昏鏄嚜鏈) diff --git a/Src/GameManager.hpp b/Src/GameManager.hpp index 7576ff8..246a400 100644 --- a/Src/GameManager.hpp +++ b/Src/GameManager.hpp @@ -59,7 +59,7 @@ class GameManager { static Vec2d fixupPos(const Vec2d& pos) noexcept; static bool hitTest(const Object& a, const Object& b) noexcept; // Frame Advancing - void updateEnemyLaserBoxes() noexcept; + void updateEnemyLaserBoxes(const double ratio) noexcept; void updateBoardInformation(double ratio) noexcept; //地图位置估价 static double getMapValue(Vec2d pos) noexcept; From 558764f34599225dc77f6f425f2f76879d5f4c19 Mon Sep 17 00:00:00 2001 From: orangebird <806680943@qq.com> Date: Wed, 18 Dec 2019 01:00:57 +0800 Subject: [PATCH 5/7] =?UTF-8?q?=E6=8F=90=E9=AB=98=E7=A2=B0=E6=92=9E?= =?UTF-8?q?=E5=88=A4=E5=AE=9A=E7=B2=BE=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Src/2DOBB.hpp | 161 ------------------ Src/GameConnectionTH10.cpp | 3 +- Src/GameManager.cpp | 10 +- Src/GameManager.hpp | 5 +- .../TH10_Collision_Points.vcxproj | 11 +- .../TH10_Collision_Points.vcxproj.filters | 3 - 6 files changed, 14 insertions(+), 179 deletions(-) delete mode 100644 Src/2DOBB.hpp diff --git a/Src/2DOBB.hpp b/Src/2DOBB.hpp deleted file mode 100644 index 4606a7b..0000000 --- a/Src/2DOBB.hpp +++ /dev/null @@ -1,161 +0,0 @@ -#pragma once -#include "Vec2.hpp" -/*-------------------------------------------------------------------- -本文件来自 -http://www.flipcode.com/archives/2D_OBB_Intersection.shtml -2D OBB Intersection - -For 2D graphics or movement of 3D objects on a 2D ground plane it is often -useful to discover if the 2D oriented bounding boxes of two objects overlap -(have a non - empty intersection).One motivating example is the placement of -a new building in a Real - Time Strategy game.The UI needs to continuously -check whether the footprint of the new building overlaps the footprint of -any existing building.If there is any overlap, the UI should indicate that -is an illegal placement. - -Stefan Gottschalk's thesis (Collision Queries using Oriented Bounding -Boxes, Ph.D.Thesis, Department of Computer Science, University of North -Carolina at Chapel Hill, 1999) introduces the separating - axis method -for performing the equivalent test on 3D oriented bounding boxes. -This method depends on the observation that -for two boxes to be disjoint(i.e. * not* intersecting), there must be some axis -along which their projections are disjoint.The 3D case considers each of 15 -axes as a potential -separating axis.These axes are the three edge axes of box 1, the three edge -axes of box 2, and the nine cross products formed by taking some edge of box 1 -and some edge of box 2. - -In 2D this simplifies dramatically and only four axes need be considered. -These are -the orthogonal edges of each bounding box.If a few values are precomputed -every time a box moves, we end up performing only 16 dot products and some -comparisons in the worst case for each overlap test.One nice property of the -separating - axis method is that it can be -structured in an early out fashion, so that many fewer operations are needed in -the case where the boxes do not intersect.In general, the first test is -extremely -likely to fail(and return "no overlap") when there is no overlap.If it -passes, -the second test is even more likely to fail if there is no overlap, and so on. -Only when the boxes are in extremely close proximity is there even a 50 % chance -of -executing more than 2 tests. - -The C++ code sample provided efficiently computes this fast 2D oriented -bounding box -overlap.I augmented the OBB2D class with some methods for rendering and -construction to help visualize the result.OBB2D::overlaps1Way performs the -real work.It tests to see whether the box passed as an argument overlaps the -current box along either of the current box's dimensions. Note that this test -must be performed for each box on the other to determine whether there is truly -any overlap.To make the tests extremely efficient, OBB2D::origin stores the -projection of corner number zero onto a box's axes and the axes are stored -explicitly in OBB2D::axis.The magnitude of these stored axes is the inverse -of the corresponding edge length so that all overlap tests can be performed on -the interval[0, 1] without normalization, and square roots are avoided -throughout the entire class. - -Morgan McGuire morgan@cs.brown.edu - - -*/ -class OBB2D { -private: - /** Corners of the box, where 0 is the lower left. */ - Vec2d corner[4]; - - /** Two edges of the box extended away from corner[0]. */ - Vec2d axis[2]; - - /** origin[a] = corner[0].dot(axis[a]); */ - double origin[2]; - - /** Returns true if other overlaps one dimension of this. */ - bool overlaps1Way(const OBB2D& other) const { - for (int a = 0; a < 2; ++a) { - - double t = other.corner[0].dot(axis[a]); - - // Find the extent of box 2 on axis a - double tMin = t; - double tMax = t; - - for (int c = 1; c < 4; ++c) { - t = other.corner[c].dot(axis[a]); - - if (t < tMin) { - tMin = t; - } - else if (t > tMax) { - tMax = t; - } - } - - // We have to subtract off the origin - - // See if [tMin, tMax] intersects [0, 1] - if ((tMin > 1 + origin[a]) || (tMax < origin[a])) { - // There was no intersection along this dimension; - // the boxes cannot possibly overlap. - return false; - } - } - - // There was no dimension along which there is no intersection. - // Therefore the boxes overlap. - return true; - } - - - /** Updates the axes after the corners move. Assumes the - corners actually form a rectangle. */ - void computeAxes() { - axis[0] = corner[1] - corner[0]; - axis[1] = corner[3] - corner[0]; - - // Make the length of each axis 1/edge length so we know any - // dot product must be less than 1 to fall within the edge. - - for (int a = 0; a < 2; ++a) { - axis[a] /= axis[a].lengthSqr(); - origin[a] = corner[0].dot(axis[a]); - } - } - -public: - - OBB2D(const Vec2d& center, const double w, const double h, double angle) - { - Vec2d X(cos(angle), sin(angle)); - Vec2d Y(-sin(angle), cos(angle)); - - X *= w / 2; - Y *= h / 2; - - corner[0] = center - X - Y; - corner[1] = center + X - Y; - corner[2] = center + X + Y; - corner[3] = center - X + Y; - - computeAxes(); - } - - - /** For testing purposes. */ - void moveTo(const Vec2d& center) { - Vec2d centroid = (corner[0] + corner[1] + corner[2] + corner[3]) / 4; - - Vec2d translation = center - centroid; - - for (int c = 0; c < 4; ++c) { - corner[c] += translation; - } - - computeAxes(); - } - - /** Returns true if the intersection of the boxes is non-empty. */ - bool overlaps(const OBB2D& other) const { - return overlaps1Way(other) && other.overlaps1Way(*this); - } -}; \ No newline at end of file diff --git a/Src/GameConnectionTH10.cpp b/Src/GameConnectionTH10.cpp index 1d61dce..9f30a65 100644 --- a/Src/GameConnectionTH10.cpp +++ b/Src/GameConnectionTH10.cpp @@ -1,8 +1,7 @@ #include "GameConnection.hpp" #include "KeyboardManager.hpp" - #include - +#include namespace { char staticBuffer[0x7F0 * 2001]; diff --git a/Src/GameManager.cpp b/Src/GameManager.cpp index 257c07b..27cb7f0 100644 --- a/Src/GameManager.cpp +++ b/Src/GameManager.cpp @@ -115,7 +115,7 @@ void GameManager::update(unsigned long long frameCount,bool enabledMouse) { //std::cout << valueMap.size() << std::endl; for (auto&& item : valueMap) { if (item.first.time == 0)continue; - if (item.second.value - maxValue > eps) { + if (item.second.value - maxValue > doubleEqualEps) { haveNoChoice = false; maxValue = item.second.value; useShift = item.second.shift; @@ -191,8 +191,7 @@ double GameManager::getValue(Node state) const noexcept { //鍦板浘浣嶇疆浼颁环(绔欏湪鍦板浘鍋忎笅鐨勪綅缃姞鍒) value += 80.0 * getMapValue(newPos); //鍑荤牬鏁屾満浼颁环(绔欏湪鏁屾満姝d笅鏂瑰姞鍒) - if (invincibleTime == 0) - { + if (invincibleTime == 0){ for (auto& enemy : mEnemy) { double dis = abs(enemy.pos.x + enemy.delta.x * state.time - newPos.x); minEnemyDis = std::min(minEnemyDis, dis); @@ -263,8 +262,9 @@ Vec2d GameManager::fixupPos(const Vec2d& pos) noexcept { } //鍐崇瓥鏃剁殑纰版挒妫娴 bool GameManager::hitTest(const Object& a, const Object& b) noexcept { - return abs(a.pos.x - b.pos.x) - ((a.size.x + b.size.x) / 2.0) <= eps+0.5 && - abs(a.pos.y - b.pos.y) - ((a.size.y + b.size.y) / 2.0) <= eps+0.5; + const double hitTestEps = 0.05;//濡傛灉缁忓父鍥犱负frame lost鑰屾挒寮癸紝璇烽傚綋鎻愰珮杩欎釜鍊,涓嶈楂樿繃0.5 + return abs(a.pos.x - b.pos.x) - ((a.size.x + b.size.x) / 2.0) <= hitTestEps && + abs(a.pos.y - b.pos.y) - ((a.size.y + b.size.y) / 2.0) <= hitTestEps; } //鍦板浘浣嶇疆浼颁环 double GameManager::getMapValue(Vec2d pos) noexcept { diff --git a/Src/GameManager.hpp b/Src/GameManager.hpp index 246a400..dc8bdba 100644 --- a/Src/GameManager.hpp +++ b/Src/GameManager.hpp @@ -9,10 +9,11 @@ const double dx[9] = {0, 1.0, s2d2, 0, -s2d2, -1.0, -s2d2, 0, s2d2}; const double dy[9] = {0, 0, -s2d2, -1.0, -s2d2, 0, s2d2, 1.0, s2d2}; const double dx4[5] = { 0, 1.0, 0, -1.0, 0}; const double dy4[5] = { 0, 0, -1.0, 0, 1.0 }; -const double playerSpeed[2] = {4.5, 2.0}; +const double playerSpeed[2] = {4.5, 2.0};//灵梦4.5/2.0 魔理沙5.0/2.0 const Vec2d ulCorner = Vec2d(-184, 32); const Vec2d drCorner = Vec2d(184, 432); -const double eps = 1e-2; +const double eps = 1e-1; +const double doubleEqualEps = 1e-9; //从高位到低位分别为上下左右 const int keyinfo[9] = {0x0, 0x1, 0x9, 0x8, 0xa, 0x2, 0x6, 0x4, 0x5}; const int keyinfo4[5] = { 0x0,0x1,0x8,0x2,0x4 }; diff --git a/TH10_Collision_Points/TH10_Collision_Points.vcxproj b/TH10_Collision_Points/TH10_Collision_Points.vcxproj index 55326cd..4bbc26a 100644 --- a/TH10_Collision_Points/TH10_Collision_Points.vcxproj +++ b/TH10_Collision_Points/TH10_Collision_Points.vcxproj @@ -25,7 +25,6 @@ - @@ -37,33 +36,33 @@ {CF610FEC-D7F3-4AAF-8661-23758D2EA736} TH10_Collision_Points - 10.0.16299.0 + 10.0 TH10_AI Application true - v141 + v142 MultiByte Application false - v141 + v142 true MultiByte Application true - v141 + v142 MultiByte Application false - v141 + v142 true MultiByte diff --git a/TH10_Collision_Points/TH10_Collision_Points.vcxproj.filters b/TH10_Collision_Points/TH10_Collision_Points.vcxproj.filters index f6d21e3..7d27810 100644 --- a/TH10_Collision_Points/TH10_Collision_Points.vcxproj.filters +++ b/TH10_Collision_Points/TH10_Collision_Points.vcxproj.filters @@ -46,8 +46,5 @@ 澶存枃浠 - - 澶存枃浠 - \ No newline at end of file From dee3c9a4db7c6f3fbe8fb53ab0e532ac9778e7a3 Mon Sep 17 00:00:00 2001 From: orangebird <806680943@qq.com> Date: Wed, 18 Dec 2019 01:11:52 +0800 Subject: [PATCH 6/7] Update GameManager.cpp --- Src/GameManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/GameManager.cpp b/Src/GameManager.cpp index 27cb7f0..83bd724 100644 --- a/Src/GameManager.cpp +++ b/Src/GameManager.cpp @@ -262,7 +262,7 @@ Vec2d GameManager::fixupPos(const Vec2d& pos) noexcept { } //鍐崇瓥鏃剁殑纰版挒妫娴 bool GameManager::hitTest(const Object& a, const Object& b) noexcept { - const double hitTestEps = 0.05;//濡傛灉缁忓父鍥犱负frame lost鑰屾挒寮癸紝璇烽傚綋鎻愰珮杩欎釜鍊,涓嶈楂樿繃0.5 + const double hitTestEps = 0.05;//姝ゅ艰繃灏忓彲鑳藉鑷碅I缁忓父鍐插お楂樻锛屼絾浠庣畻娉曚笂鏀硅繘姣旇皟澶ф鍊艰濂 return abs(a.pos.x - b.pos.x) - ((a.size.x + b.size.x) / 2.0) <= hitTestEps && abs(a.pos.y - b.pos.y) - ((a.size.y + b.size.y) / 2.0) <= hitTestEps; } From d2f531292802337ceae0f242380988856ba68448 Mon Sep 17 00:00:00 2001 From: orangebird <806680943@qq.com> Date: Sun, 22 Dec 2019 18:24:44 +0800 Subject: [PATCH 7/7] improve code quality --- Src/GameConnection.hpp | 31 +--------- Src/GameConnectionTH10.cpp | 35 +++++++++-- Src/GameManager.cpp | 59 +++++++++---------- Src/KeyboardManager.cpp | 2 +- Src/bmpCreater.hpp | 10 +--- Src/main.cpp | 29 ++++----- .../TH10_Collision_Points.vcxproj | 1 + 7 files changed, 75 insertions(+), 92 deletions(-) diff --git a/Src/GameConnection.hpp b/Src/GameConnection.hpp index 8fe5ef0..90c7e95 100644 --- a/Src/GameConnection.hpp +++ b/Src/GameConnection.hpp @@ -3,7 +3,6 @@ #include #include #include "Object.hpp" -#include "Windows.hpp" enum class PlayerState:int { NOTCREATED=0, @@ -21,34 +20,6 @@ struct GameConnection { virtual void getEnemyLaserData(std::vector &laser) noexcept = 0; virtual void sendKeyInfo(int dir,bool shift,bool z,bool x) noexcept = 0; virtual void getMousePosition(Vec2d& pos)noexcept = 0; - virtual PlayerState GetPlayerStateInformation()noexcept = 0; -}; -class GameConnectionTH10 : public GameConnection { -public: - GameConnectionTH10(); - ~GameConnectionTH10() noexcept override; - void getPowers(std::vector &powers) noexcept override; - void getEnemyData(std::vector &enemy) noexcept override; - void getEnemyBulletData(std::vector &bullet, const Player &player, double maxRange) noexcept override; - void getPlayerData(Player &self) noexcept override; - void getEnemyLaserData(std::vector &laser) noexcept override; - void sendKeyInfo(int dir, bool shift, bool z, bool x) noexcept override; - void getMousePosition(Vec2d& pos)noexcept override; - int getTimeline() noexcept override; - PlayerState GetPlayerStateInformation()noexcept override; -private: - HWND mWindow{ nullptr }; - HANDLE mHProcess{ nullptr }; - static bool GetProcessIdByName(const char *exeFileName, DWORD &pid) noexcept; - void readProcessRaw(intptr_t offset, size_t length, void *target) const noexcept { - static thread_local SIZE_T nbr; - ReadProcessMemory(mHProcess, reinterpret_cast(offset), target, length, &nbr); - } - template - T readProcess(intptr_t offset) const noexcept { - T result; - readProcessRaw(offset, sizeof(T), &result); - return result; - } + virtual PlayerState getPlayerStateInformation()noexcept = 0; }; std::unique_ptr createGameConnection(); diff --git a/Src/GameConnectionTH10.cpp b/Src/GameConnectionTH10.cpp index 9f30a65..455b0c8 100644 --- a/Src/GameConnectionTH10.cpp +++ b/Src/GameConnectionTH10.cpp @@ -1,5 +1,6 @@ #include "GameConnection.hpp" #include "KeyboardManager.hpp" +#include "Windows.hpp" #include #include @@ -8,7 +9,34 @@ namespace { template T read(void *buffer) noexcept { return *reinterpret_cast(buffer); } } - +class GameConnectionTH10 : public GameConnection { +public: + GameConnectionTH10(); + ~GameConnectionTH10() noexcept override; + void getPowers(std::vector& powers) noexcept override; + void getEnemyData(std::vector& enemy) noexcept override; + void getEnemyBulletData(std::vector& bullet, const Player& player, double maxRange) noexcept override; + void getPlayerData(Player& self) noexcept override; + void getEnemyLaserData(std::vector& laser) noexcept override; + void sendKeyInfo(int dir, bool shift, bool z, bool x) noexcept override; + void getMousePosition(Vec2d& pos)noexcept override; + int getTimeline() noexcept override; + PlayerState getPlayerStateInformation()noexcept override; +private: + HWND mWindow{ nullptr }; + HANDLE mHProcess{ nullptr }; + static bool GetProcessIdByName(const char* exeFileName, DWORD& pid) noexcept; + void readProcessRaw(intptr_t offset, size_t length, void* target) const noexcept { + static thread_local SIZE_T nbr; + ReadProcessMemory(mHProcess, reinterpret_cast(offset), target, length, &nbr); + } + template + T readProcess(intptr_t offset) const noexcept { + T result; + readProcessRaw(offset, sizeof(T), &result); + return result; + } +}; void GameConnectionTH10::getPowers(std::vector &powers) noexcept { powers.clear(); auto ebp = staticBuffer; @@ -105,10 +133,9 @@ void GameConnectionTH10::getEnemyLaserData(std::vector &laser) noexcept { } } } -PlayerState GameConnectionTH10::GetPlayerStateInformation()noexcept { +PlayerState GameConnectionTH10::getPlayerStateInformation()noexcept { int base_addr = readProcess(0x00477834); - if (!base_addr) - { + if (!base_addr){ return (PlayerState)0; } return (PlayerState)readProcess(base_addr + 0x458); diff --git a/Src/GameManager.cpp b/Src/GameManager.cpp index 83bd724..f5de797 100644 --- a/Src/GameManager.cpp +++ b/Src/GameManager.cpp @@ -1,3 +1,4 @@ +#include "Windows.hpp" #include "GameManager.hpp" #include "bmpCreater.hpp" #include "Vec2.hpp" @@ -11,7 +12,7 @@ Vec2d pointRotate(Vec2d target, Vec2d center, double arc) { void GameManager::outputValueMap(const char* path) { updateBoardInformation(99999.0); static Pixel map[480][400]; - memset(map, 0, sizeof(map)); // 璁剧疆鑳屾櫙涓洪粦鑹 + memset(map, 0, sizeof(map)); // 设置背景为黑色 double total = 400 * 480; double now = 0; for (int i = 0; i < 400; ++i) { @@ -44,8 +45,7 @@ void GameManager::updateEnemyLaserBoxes(const double ratio) noexcept { const auto delta = (t - s).unit()*5.0; double w = laser.size.x*0.5 + 2.0; double add = w / laser.size.y; - for (double i = 0; i <= 1; i += add) - { + for (double i = 0; i <= 1; i += add){ double x = i * s.x + (1.0 - i)*t.x; double y = i * s.y + (1.0 - i)*t.y; if (distanceSqr(Vec2d(x, y), mPlayer.pos) <= ratio * ratio) { @@ -70,16 +70,15 @@ void GameManager::update(unsigned long long frameCount,bool enabledMouse) { updateBoardInformation((double)maxDepth * playerSpeed[0] + 15.0); mConnection->getMousePosition(mMousePos); mMousePos = fixupPos(mMousePos); - if (invincibleTime == maxInvincibleTime-60 && mPowers.size() == 0) - { + if (invincibleTime == maxInvincibleTime-60 && mPowers.size() == 0){ invincibleTime = 0; } if (invincibleTime > 0)invincibleTime--; - //纭畾褰撳墠鐘舵 + //确定当前状态 mState = GameState::NORMAL; switch (mState) { case GameState::NORMAL: { - //BFS鎼滅储maxDepth姝ワ紝鎵惧埌maxDepth姝ュ唴浠峰兼渶楂樼殑鍙埌杈句綅缃 + //BFS搜索maxDepth步,找到maxDepth步内价值最高的可到达位置。 valueMap.erase(valueMap.begin(), valueMap.end()); Node startState = Node(0, fixupPos(mPlayer.pos)); valueMap[startState] = NodeSave(0, false, getValue(startState)); @@ -105,7 +104,7 @@ void GameManager::update(unsigned long long frameCount,bool enabledMouse) { } } } - //閫夋嫨鏈楂樹及浠 + //选择最高估价 bool haveNoChoice = true; double maxValue = -99999999999.0; int moveKeyChoice = -1; @@ -123,19 +122,18 @@ void GameManager::update(unsigned long long frameCount,bool enabledMouse) { movement = item.second; } } - //鎵旈浄鍒ゆ柇 + //扔雷判断 useBomb = false; - if (mConnection->GetPlayerStateInformation() == PlayerState::DYING) - { + if (mConnection->getPlayerStateInformation() == PlayerState::DYING){ invincibleTime = maxInvincibleTime; useBomb = true; } - //鍙戦佸喅绛 + //发送决策 if (mEnemy.size() <= 1 && mBullet.empty()) - //璺宠繃瀵硅瘽锛岄棿闅斿抚鎸塟 + //跳过对话,间隔帧按Z mConnection->sendKeyInfo(moveKeyChoice, useShift, frameCount % 2, useBomb); else - //姝e父杩涜娓告垙 + //正常进行游戏 mConnection->sendKeyInfo(moveKeyChoice, useShift, true, useBomb); break; } @@ -144,7 +142,7 @@ void GameManager::update(unsigned long long frameCount,bool enabledMouse) { } } -//鍒ゆ柇鐘舵佹槸鍚﹀悎娉(鏌愪釜浣嶇疆鑳藉惁鍒拌揪) +//判断状态是否合法(某个位置能否到达) bool GameManager::legalState(Node state) const noexcept { if (invincibleTime > 0)return true; Object newPlayer = Object(state.pos.x, state.pos.y, mPlayer.size.x, mPlayer.size.y); @@ -161,13 +159,13 @@ bool GameManager::legalState(Node state) const noexcept { //} return true; } -//瀵圭姸鎬佽繘琛屼及浠 +//对状态进行估价 double GameManager::getValue(Node state) const noexcept { double value = 0.0; double minEnemyDis = 400.0; Vec2d newPos = state.pos; Object newPlayer = Object(newPos.x, newPos.y, mPlayer.size.x, mPlayer.size.y); - //榧犳爣寮曞妯″紡浼颁环 + //鼠标引导模式估价 if (mouseMode) { double dis = distance(mMousePos, newPos); @@ -176,7 +174,7 @@ double GameManager::getValue(Node state) const noexcept { return value; } minEnemyDis = 400.0; - //鏀剁偣浼颁环锛岀鐐硅秺杩戯紝浠峰艰秺楂 + //收点估价,离点越近,价值越高 double minPowerDis = 390400.0; for (auto& power : mPowers) { Vec2d newPowerPos = power.pos + power.delta * state.time; @@ -188,9 +186,9 @@ double GameManager::getValue(Node state) const noexcept { if (invincibleTime>0)value += 400 * (390400.0 - minPowerDis) / 390400.0; else value += 180 * (390400.0 - minPowerDis) / 390400.0; - //鍦板浘浣嶇疆浼颁环(绔欏湪鍦板浘鍋忎笅鐨勪綅缃姞鍒) + //地图位置估价(站在地图偏下的位置加分) value += 80.0 * getMapValue(newPos); - //鍑荤牬鏁屾満浼颁环(绔欏湪鏁屾満姝d笅鏂瑰姞鍒) + //击破敌机估价(站在敌机正下方加分) if (invincibleTime == 0){ for (auto& enemy : mEnemy) { double dis = abs(enemy.pos.x + enemy.delta.x * state.time - newPos.x); @@ -198,7 +196,7 @@ double GameManager::getValue(Node state) const noexcept { } value += 80.0 * (400 - minEnemyDis) / 400; } - //瀛愬脊浼颁环(鍜屽瓙寮硅繍鍔ㄦ柟鍚戝す瑙掕秺澶у噺鍒嗚秺灏) + //子弹估价(和子弹运动方向夹角越大减分越少) double avgScore = 0; double count = 0; for (auto bullet : mBullet) { @@ -207,7 +205,7 @@ double GameManager::getValue(Node state) const noexcept { count++; Vec2d selfDir = (newPos - bullet.pos).unit(); Vec2d bulletDir = bullet.delta.unit(); - //璇ヤ綅缃殑浠峰间笌璇ヤ綅缃埌瀛愬脊鐨勮繛绾垮拰瀛愬脊杩愬姩鏂瑰悜鐨勫す瑙掓湁鍏筹紝澶硅瓒婂ぇ锛屽噺鍒嗚秺灏 + //该位置的价值与该位置到子弹的连线和子弹运动方向的夹角有关,夹角越大,减分越少 double dirvalue = selfDir.dot(bulletDir); dirvalue += 1; avgScore -= dirvalue; @@ -221,19 +219,19 @@ double GameManager::getValue(Node state) const noexcept { count = 0; double count2 = 0; double avgScore2 = 0; - //鏁屾満浼颁环 + //敌机估价 for (auto& enemy : mEnemy) { double dis = distanceSqr(enemy.pos, newPos); Vec2d selfDir = (newPos - enemy.pos).unit(); Vec2d up(0, -1); double dirvalue = selfDir.dot(up); - //绔欑殑浣嶇疆鍋忛珮锛屽鏄撹寮瑰箷灏佹銆傗滀粠鏁屾満鎸囧悜鑷満鐨勫悜閲忊濆拰鈥滀粠鏁屾満鎸囧悜姝d笂鏂圭殑鍚戦噺鈥濈殑澶硅瓒婂ぇ瓒婂畨鍏紝鍑忓垎瓒婂皯銆 + //站的位置偏高,容易被弹幕封死。“从敌机指向自机的向量”和“从敌机指向正上方的向量”的夹角越大越安全,减分越少。 if (enemy.pos.y <= 240) { dirvalue += 1; avgScore -= dirvalue; count++; } - //绂绘晫鏈鸿繃杩涘鏄撹鍙戝嚭鐨勫脊骞曟墦姝伙紝涔熷彲鑳借浣撴湳銆傚洜姝よ窛绂昏秺杩戝噺鍒嗚秺澶氥 + //离敌机过进容易被发出的弹幕打死,也可能被体术。因此距离越近减分越多。 if (dis <= 20000.0) { avgScore2 -= 1.0 - (dis / 20000.0); count2++; @@ -251,7 +249,7 @@ double GameManager::getValue(Node state) const noexcept { value -= 0.1 * state.time; return value; } -//淇瓒呭嚭鍦板浘鐨勫潗鏍(涓昏鏄嚜鏈) +//修正超出地图的坐标(主要是自机) Vec2d GameManager::fixupPos(const Vec2d& pos) noexcept { Vec2d res = pos; if (res.x < ulCorner.x)res.x = ulCorner.x; @@ -260,13 +258,13 @@ Vec2d GameManager::fixupPos(const Vec2d& pos) noexcept { if (res.y > drCorner.y)res.y = drCorner.y; return res; } -//鍐崇瓥鏃剁殑纰版挒妫娴 +//决策时的碰撞检测 bool GameManager::hitTest(const Object& a, const Object& b) noexcept { - const double hitTestEps = 0.05;//姝ゅ艰繃灏忓彲鑳藉鑷碅I缁忓父鍐插お楂樻锛屼絾浠庣畻娉曚笂鏀硅繘姣旇皟澶ф鍊艰濂 + const double hitTestEps = 0.05;//此值过小可能导致AI经常冲太高死,但从算法上改进比调大此值要好 return abs(a.pos.x - b.pos.x) - ((a.size.x + b.size.x) / 2.0) <= hitTestEps && abs(a.pos.y - b.pos.y) - ((a.size.y + b.size.y) / 2.0) <= hitTestEps; } -//鍦板浘浣嶇疆浼颁环 +//地图位置估价 double GameManager::getMapValue(Vec2d pos) noexcept { if (pos.y <= 100) return pos.y * 0.9 / 100; @@ -283,7 +281,6 @@ bool operator<(const Node& lhs, const Node& rhs) { if ((rhs.pos.y - lhs.pos.y) > eps)return true; return false; } -int GameManager::getTimeline() noexcept -{ +int GameManager::getTimeline() noexcept{ return mConnection->getTimeline(); } diff --git a/Src/KeyboardManager.cpp b/Src/KeyboardManager.cpp index 3bbe7e3..b52a109 100644 --- a/Src/KeyboardManager.cpp +++ b/Src/KeyboardManager.cpp @@ -12,7 +12,7 @@ namespace { constexpr const char KEY_X = 88; constexpr const char KEY_Z = 90; constexpr const char KEY_ESCAPE = 90; - void sendKey(int key, bool down) noexcept { + void sendKey(int key, bool down) noexcept { if (keystate[key] != down) { keystate[key] = down; if (down) keybd_event(key, MapVirtualKey(key, 0), 0, 0); diff --git a/Src/bmpCreater.hpp b/Src/bmpCreater.hpp index 3f1ba24..e5904eb 100644 --- a/Src/bmpCreater.hpp +++ b/Src/bmpCreater.hpp @@ -2,14 +2,10 @@ #include #include #include -#include -/* -typedef long BOOL; typedef long LONG; typedef unsigned char BYTE; typedef unsigned long DWORD; typedef unsigned short WORD; -*/ //位图文件头文件定义 //其中不包括文件类型信息(由于结构体的内存结构决定,要是加了的话将不能正确的读取文件信息) typedef struct { @@ -41,8 +37,7 @@ typedef struct { DWORD biClrImportant;//本位图中重要的色彩数 } BMPINFOHEADER_T;//位图信息头定义 -void generateBmp(BYTE * pData, int width, int height, const char * filename)//生成Bmp图片,传递RGB值,传递图片像素大小,传递图片存储路径 -{ +void generateBmp(BYTE * pData, int width, int height, const char * filename) {//生成Bmp图片,传递RGB值,传递图片像素大小,传递图片存储路径 int size = width * height * 3; // 每个像素点3个字节 // 位图第一部分,文件信息 BMPFILEHEADER_T bfh; @@ -75,8 +70,7 @@ typedef struct { fwrite(pData, 1, size, fp); fclose(fp); } -struct Pixel -{ +struct Pixel{ BYTE b; BYTE g; BYTE r; diff --git a/Src/main.cpp b/Src/main.cpp index 8e0bf03..334939f 100644 --- a/Src/main.cpp +++ b/Src/main.cpp @@ -2,12 +2,11 @@ #include #include #include -#include "GameConnection.hpp" #include +#include "GameConnection.hpp" #include "KeyboardManager.hpp" #include "GameManager.hpp" -using namespace std; using namespace std::chrono; class StopWatch { @@ -21,8 +20,6 @@ class StopWatch { private: steady_clock::time_point mBeginTime, mEndTime; }; - - void pauseUntilPress(const char* info, char key) { std::cout << info << std::endl; while (true) { @@ -41,26 +38,24 @@ int main() { unsigned long long frameCount = 0; StopWatch watch; int mapOutputCount = 0; - const double maxcd = 30; + const double maxCd = 30; double cd = 30; bool mouseMode = false; - cout << "鼠标引导当前处于关闭状态" << endl; + std::cout << "鼠标引导当前处于关闭状态" << std::endl; int gameFrame = game->getTimeline(); unsigned long long loopCount = 0; while (!quit) { - if (loopCount % 16 == 0) - { + if (loopCount % 16 == 0){ if (cd > 0)cd -= 1.0; if (isKeyDown('Q')) break; - if (cd <= 0 && isKeyDown('C')) - { - cd = maxcd; + if (cd <= 0 && isKeyDown('C')){ + cd = maxCd; mouseMode ^= 1; - cout << (mouseMode ? "鼠标引导已开启" : "鼠标引导已关闭") << endl; + std::cout << (mouseMode ? "鼠标引导已开启" : "鼠标引导已关闭") << std::endl; } if (isKeyDown('P') && cd <= 0) { - cd = maxcd; + cd = maxCd; mapOutputCount++; std::stringstream outputStream; outputStream << "./value" << mapOutputCount << ".bmp"; @@ -70,11 +65,9 @@ int main() { } } int getGameFrame = game->getTimeline(); - if (getGameFrame != gameFrame) - { - if (getGameFrame > gameFrame + 1) - { - cout << "Frame Lost!" << endl; + if (getGameFrame != gameFrame){ + if (getGameFrame > gameFrame + 1){ + std::cout << "Frame Lost!" << std::endl; } gameFrame = getGameFrame; //watch.start(); diff --git a/TH10_Collision_Points/TH10_Collision_Points.vcxproj b/TH10_Collision_Points/TH10_Collision_Points.vcxproj index 4bbc26a..566ad0e 100644 --- a/TH10_Collision_Points/TH10_Collision_Points.vcxproj +++ b/TH10_Collision_Points/TH10_Collision_Points.vcxproj @@ -136,6 +136,7 @@ true true stdcpplatest + %(PreprocessorDefinitions) true