From 76810f03e910c55ca48671f3c57fda680007e18a Mon Sep 17 00:00:00 2001 From: efool Date: Thu, 3 Jul 2025 12:57:06 -0400 Subject: [PATCH 01/17] Refactor repo layout and build config - removed unused files - lowercase file names - remade msvc solution and project --- .gitignore | 2 + BoardGame.sln | 30 - BoardGame/BoardGame.vcxproj.filters | 60 -- BoardGame/BoardGame.vcxproj.user | 4 - BoardGame/Entity.cpp | 2 - BoardGame/GodHelpMe.cpp | 547 ------------------ BoardGame/bitmap.png | Bin 151 -> 0 bytes BoardGame/bitmap.txt | 0 BoardGame/Board.cpp => src/board.cpp | 6 +- BoardGame/Board.h => src/board.h | 4 +- BoardGame/Entity.h => src/entity.h | 0 BoardGame/Fenetre.cpp => src/fenetre.cpp | 2 +- BoardGame/Fenetre.h => src/fenetre.h | 2 +- BoardGame/Fruit.h => src/fruit.h | 2 +- BoardGame/Main.cpp => src/main.cpp | 4 +- BoardGame/Point.cpp => src/point.cpp | 2 +- BoardGame/Point.h => src/point.h | 2 +- BoardGame/Snake.cpp => src/snake.cpp | 2 +- BoardGame/Snake.h => src/snake.h | 2 +- {BoardGame => src}/stdafx.h | 0 vc/snake.sln | 31 + .../BoardGame.vcxproj => vc/snake.vcxproj | 303 +++++----- vc/snake.vcxproj.filters | 48 ++ 23 files changed, 252 insertions(+), 803 deletions(-) create mode 100644 .gitignore delete mode 100644 BoardGame.sln delete mode 100644 BoardGame/BoardGame.vcxproj.filters delete mode 100644 BoardGame/BoardGame.vcxproj.user delete mode 100644 BoardGame/Entity.cpp delete mode 100644 BoardGame/GodHelpMe.cpp delete mode 100644 BoardGame/bitmap.png delete mode 100644 BoardGame/bitmap.txt rename BoardGame/Board.cpp => src/board.cpp (97%) rename BoardGame/Board.h => src/board.h (94%) rename BoardGame/Entity.h => src/entity.h (100%) rename BoardGame/Fenetre.cpp => src/fenetre.cpp (99%) rename BoardGame/Fenetre.h => src/fenetre.h (93%) rename BoardGame/Fruit.h => src/fruit.h (93%) rename BoardGame/Main.cpp => src/main.cpp (93%) rename BoardGame/Point.cpp => src/point.cpp (93%) rename BoardGame/Point.h => src/point.h (95%) rename BoardGame/Snake.cpp => src/snake.cpp (98%) rename BoardGame/Snake.h => src/snake.h (98%) rename {BoardGame => src}/stdafx.h (100%) create mode 100644 vc/snake.sln rename BoardGame/BoardGame.vcxproj => vc/snake.vcxproj (79%) create mode 100644 vc/snake.vcxproj.filters diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fa40bd9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/.vs/* +/vc/* diff --git a/BoardGame.sln b/BoardGame.sln deleted file mode 100644 index bcb90e0..0000000 --- a/BoardGame.sln +++ /dev/null @@ -1,30 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.14.36203.30 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BoardGame", "BoardGame\BoardGame.vcxproj", "{19A76AF3-0481-4CCC-B842-42AE45CA36FF}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {19A76AF3-0481-4CCC-B842-42AE45CA36FF}.Debug|x64.ActiveCfg = Debug|x64 - {19A76AF3-0481-4CCC-B842-42AE45CA36FF}.Debug|x86.ActiveCfg = Debug|Win32 - {19A76AF3-0481-4CCC-B842-42AE45CA36FF}.Debug|x86.Build.0 = Debug|Win32 - {19A76AF3-0481-4CCC-B842-42AE45CA36FF}.Release|x64.ActiveCfg = Release|x64 - {19A76AF3-0481-4CCC-B842-42AE45CA36FF}.Release|x64.Build.0 = Release|x64 - {19A76AF3-0481-4CCC-B842-42AE45CA36FF}.Release|x86.ActiveCfg = Release|Win32 - {19A76AF3-0481-4CCC-B842-42AE45CA36FF}.Release|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {24FAB3E0-8459-4EB5-8375-4B52435D172E} - EndGlobalSection -EndGlobal diff --git a/BoardGame/BoardGame.vcxproj.filters b/BoardGame/BoardGame.vcxproj.filters deleted file mode 100644 index 32a4aa1..0000000 --- a/BoardGame/BoardGame.vcxproj.filters +++ /dev/null @@ -1,60 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Fichiers sources - - - Fichiers sources - - - Fichiers sources - - - Fichiers sources - - - Fichiers sources - - - Fichiers sources - - - - - Fichiers d%27en-tête - - - Fichiers d%27en-tête - - - Fichiers d%27en-tête - - - Fichiers d%27en-tête - - - Fichiers d%27en-tête - - - Fichiers d%27en-tête - - - Fichiers d%27en-tête - - - \ No newline at end of file diff --git a/BoardGame/BoardGame.vcxproj.user b/BoardGame/BoardGame.vcxproj.user deleted file mode 100644 index 88a5509..0000000 --- a/BoardGame/BoardGame.vcxproj.user +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/BoardGame/Entity.cpp b/BoardGame/Entity.cpp deleted file mode 100644 index b0ae70b..0000000 --- a/BoardGame/Entity.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "Entity.h" - diff --git a/BoardGame/GodHelpMe.cpp b/BoardGame/GodHelpMe.cpp deleted file mode 100644 index bd427bd..0000000 --- a/BoardGame/GodHelpMe.cpp +++ /dev/null @@ -1,547 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include - -class Board; - -class Entity -{ -public: - virtual ~Entity() = default; - virtual void render() const = 0; - - int getPosition() const { return Position; } - void setPosition(int pos) { Position = pos; } - virtual bool isCollidable() { return false; }; - -protected: - int Position; -}; - -class Snake : public Entity -{ -public: - Snake(float speed, int score, int startPosition) - : m_Speed(speed), m_Score(score) - { - m_Body.push_back(startPosition); - Position = startPosition; - } - void addSegment(int count) - { - for (int i = 0; i < count; ++i) - { - m_Body.push_back(m_Body.back()); //rajout d'un segment dans la derniere position - } - } - - - void addSpeed(float speed); - - void removeSpeed(float speed); - - void move(int direction); - - void render() const override { - //system("color 0C"); - std::cout << "\033[34m~\033[0m"; //ANSI code color pour changement de la couleur dans terminal - } - - void setPosition(int pos) { position = pos; }; - - int getPosition() const { return m_Body[0]; } - - bool isCollidable() override { return true; }; - - void addScore(int score) { this->m_Score += score; }; - - int getScore() { return m_Score; }; - std::vector getBody() { return m_Body; }; - int wrap(int value, int max); - - -private: - - float m_Speed = 5.0f; - int m_Length = 1; - int position; - const int _OFFSET = 16; - int m_Score = 0; - int m_currentDirection = 1; - - - std::vector m_Body;//liste des segments du serpent - friend std::ostream& operator<<(std::ostream& os, const Snake& snake); - - - -}; - -class Fruit : public Entity -{ -public: - Fruit(int pos) { this->Position = pos; } - bool isCollidable() override { return true; }; - void render() const override { - std::cout << "%"; - } - int getPoints() { return points; }; - -private: - int points = 1000; - -}; -namespace Fenetre { - - LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); - - HWND CreateMainWindow(Board* board); - void WNDRenderBoard(HWND hwnd, HDC hdc, const Board& board); -} - - -class Board -{ - -public: - Board(); - void renderBoard(); - static int getBoardSize() { return m_BoardSize; }; - static void setBoardSize(int Size) { m_BoardSize = Size; } - std::shared_ptr getSnake() const; - void moveSnake(int direction); - const std::vector>& getEntities() const { return m_Board; } - - void setWindowHandle(HWND hwnd) { this->hwnd = hwnd; }; - std::shared_ptr spawnFruit(); - std::shared_ptr getEntityAt(int index) const - { - return m_Board[index]; - } - int getSnakeSegmentOrder(int index) const; - - -private: - std::vector>m_Board; - static int m_BoardSize; - HWND hwnd = nullptr; - -}; - -class Point : public Entity -{ -public: - Point(int x, int y); - - int getPosX() { return x; }; - int getPosY() { return y; }; - bool isCollidable() override { return false; }; - void render() const override { - //system("color 0A"); - std::cout << "\033[32mo\033[0m"; - } - -private: - int x, y; - int Position = 0; - - friend std::ostream& operator<<(std::ostream& os, const Point& point); -}; - -void Snake::addSpeed(float speed) -{ - m_Speed += speed; -} -void Snake::removeSpeed(float speed) -{ - m_Speed -= speed; -} -int Snake::wrap(int value, int max) { - return (value + max) % max; -} - -void Snake::move(int direction) -{ - //gros pavé pour check si le joueur fait demi tour direct* - //[TODO] rendre lisible et optimisé - if ((m_currentDirection == 1 && direction == 3) || - (m_currentDirection == 3 && direction == 1) || - (m_currentDirection == 2 && direction == 4) || - (m_currentDirection == 4 && direction == 2)) - { - direction = m_currentDirection; // on ignore si le joueur fait un 180° - } - else - { - m_currentDirection = direction; - int head = m_Body.front(); - int row = head / 16; - int col = head % 16; - - switch (direction) - { - case 1: col--; break; - case 2: row--; break; - case 3: col++; break; - case 4: row++; break; - } - - row = wrap(row, 16); - col = wrap(col, 16); - - int newHead = row * 16 + col; - - // check la collision on skip la tete sinon probleme - for (size_t i = 1; i < m_Body.size(); ++i) - { - if (newHead == m_Body[i]) - { - std::cout << "Parti fini" << "\n"; - exit(0); // on quitte pour l'instant - //[TODO] faire un menu et un écran de fin - } - } - - for (int i = m_Body.size() - 1; i > 0; --i) - { - m_Body[i] = m_Body[i - 1]; - } - - m_Body[0] = newHead; - Position = newHead; - } - - -} - - - -std::ostream& operator<<(std::ostream& os, const Snake& snake) -{ - os << "~"; - return os; -} -Point::Point(int x, int y) -{ - this->x = x; - this->y = y; - this->Position = y * 16 + x; -} -std::ostream& operator<<(std::ostream& os, const Point& point) -{ - //os << "Point(x: " << point.x << ", y: " << point.y << ", place: " << point.place << ")"; - os << 'o'; - return os; -} - -namespace Fenetre { - - - - - LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) - { - - switch (uMsg) - { - case WM_DESTROY: - PostQuitMessage(0); - return 0; - - case WM_PAINT: - { - PAINTSTRUCT ps; - HDC hdc = BeginPaint(hwnd, &ps); - - Board* board = (Board*)GetWindowLongPtr(hwnd, GWLP_USERDATA); - if (board) - { - WNDRenderBoard(hwnd, hdc, *board); - } - //HBRUSH CustomBrush = CreateSolidBrush(50);//def de la couleur du pinceau - //FillRect(hdc, &ps.rcPaint, CustomBrush);//application de la peinture sur le background - //DeleteObject(CustomBrush);//nettoyage du pinceau - - EndPaint(hwnd, &ps); - } - break; - case WM_CREATE: - { - LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam; - Board* board = (Board*)pcs->lpCreateParams; - SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)board); - } - break; - - case WM_KEYDOWN: - { - Board* board = (Board*)GetWindowLongPtr(hwnd, GWLP_USERDATA); - if (board) - { - switch (wParam) - { - case 'Q': board->moveSnake(1); break; - case 'Z': board->moveSnake(2); break; - case 'D': board->moveSnake(3); break; - case 'S': board->moveSnake(4); break; - } - } - } - break; - } - return DefWindowProc(hwnd, uMsg, wParam, lParam); - } - - HWND CreateMainWindow(Board* board) - { - const wchar_t CLASS_NAME[] = L"SnakeWindow"; - - WNDCLASS wc = {}; - wc.lpfnWndProc = Fenetre::WindowProc; - wc.hInstance = GetModuleHandle(NULL); - wc.lpszClassName = CLASS_NAME; - - RegisterClass(&wc); - - HWND hwnd = CreateWindowEx( - 0, CLASS_NAME, L"Snake", WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, GetModuleHandle(NULL), board - ); - - if (hwnd == NULL) { - std::cout << "debug: echec de creation de la fenetre\n"; - exit(1); - } - - ShowWindow(hwnd, SW_SHOW); - return hwnd; - } - - void Fenetre::WNDRenderBoard(HWND hwnd, HDC hdc, const Board& board) - { - RECT clientRect; - GetClientRect(hwnd, &clientRect); - - int squareWidth = clientRect.right / Board::getBoardSize(); - int squareHeight = clientRect.bottom / Board::getBoardSize(); - - for (int row = 0; row < Board::getBoardSize(); ++row) - { - for (int col = 0; col < Board::getBoardSize(); ++col) - { - RECT square = { - col * squareWidth, - row * squareHeight, - (col + 1) * squareWidth, - (row + 1) * squareHeight - }; - - int index = row * Board::getBoardSize() + col; - std::shared_ptr entity = board.getEntityAt(index); - - - HBRUSH brush = nullptr; - - if (std::dynamic_pointer_cast(entity)) - { - brush = CreateSolidBrush(RGB(0, 0, 255)); - - } - else if (std::dynamic_pointer_cast(entity)) - { - brush = CreateSolidBrush(RGB(255, 0, 0)); - } - else - { - brush = CreateSolidBrush(RGB(0, 255, 0)); - } - - FillRect(hdc, &square, brush); - DeleteObject(brush); - SetBkMode(hdc, TRANSPARENT); - - - int segmentOrder = board.getSnakeSegmentOrder(index); - if (segmentOrder != -1) { - std::wstring text = std::to_wstring(segmentOrder); - DrawText(hdc, text.c_str(), -1, &square, DT_CENTER | DT_VCENTER | DT_SINGLELINE); - } - - - } - } - } - -}int Board::m_BoardSize = 16; - - -Board::Board() -{ - for (int x = 0; x < m_BoardSize; x++) - { - for (int y = 0; y < m_BoardSize; y++) - { - int current = x * 16 + y; - - if (current == (m_BoardSize * m_BoardSize) / 2) - { - m_Board.push_back(std::make_shared(5.0f, 1, 128)); - } - else - { - m_Board.push_back(std::make_shared(y, x)); - } - } - } -} - -void Board::renderBoard() -{ - int TotalSize = m_BoardSize * m_BoardSize; - system("cls"); //clear le terminal à chaque nouveau render - - for (int i = 0; i < TotalSize; i++) - { - m_Board[i]->render(); - - if ((i + 1) % m_BoardSize == 0) - { - std::cout << std::endl; - } - } -} - - -std::shared_ptr Board::getSnake() const -{ - for (auto& entity : m_Board) - { - - std::shared_ptr snake = std::dynamic_pointer_cast(entity); - if (snake != nullptr) - { - return snake; - } - } - return nullptr; -} - -void Board::moveSnake(int direction) -{ - std::shared_ptr snake = getSnake(); - if (!snake) return; - - int oldHeadPosition = snake->getPosition(); - - std::vector oldBody = snake->getBody(); - - snake->move(direction); - - int newHeadPosition = snake->getPosition(); - - if (std::dynamic_pointer_cast(m_Board[newHeadPosition])) - { - auto fruit = spawnFruit(); - snake->addSegment(1); - snake->addScore(fruit->getPoints()); - } - - for (int pos : oldBody) - { - int oldY = pos / m_BoardSize; - int oldX = pos % m_BoardSize; - m_Board[pos] = std::make_shared(oldX, oldY); - } - - for (int pos : snake->getBody()) - { - m_Board[pos] = snake; - } - - InvalidateRect(hwnd, NULL, TRUE); -} - - -std::shared_ptr Board::spawnFruit() -{ - std::vector emptyPositions; - for (int i = 0; i < m_Board.size(); i++) - { - if (std::dynamic_pointer_cast(m_Board[i])) - { - emptyPositions.push_back(i); - } - } - - if (emptyPositions.empty()) return nullptr; - - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_int_distribution<> distrib(0, emptyPositions.size() - 1); - - int chosenIndex = emptyPositions[distrib(gen)]; - - m_Board[chosenIndex] = std::make_shared(chosenIndex); - return std::dynamic_pointer_cast(m_Board[chosenIndex]); -} -int Board::getSnakeSegmentOrder(int index) const { - auto snake = getSnake(); - - const auto& body = snake->getBody(); - - for (size_t i = 0; i < body.size(); ++i) { - if (body[i] == index) - return static_cast(i); - } - return -1; -} - - -int main() { - - Board board; - - HWND hwnd = Fenetre::CreateMainWindow(&board); - board.setWindowHandle(hwnd); - - std::shared_ptr snake = board.getSnake(); - if (!snake) - { - std::cout << "debug: snake pas trouvé\n\r"; - return 1; - } - - board.spawnFruit(); - - char input = ' '; - MSG msg = { }; - - while (input != 'x') - { - while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) - { - if (msg.message == WM_QUIT) - { - input = 'x'; - break; - } - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - board.renderBoard(); - - std::cout << "\ndeplace toi avec zqsd\n"; - std::cout << "Ton Score:" << snake->getScore(); - } - - std::cout << "partie fini" << std::endl; - return 0; -} diff --git a/BoardGame/bitmap.png b/BoardGame/bitmap.png deleted file mode 100644 index 1cfb2cc6b71152b6cb29dca3a0c3387a1b261e29..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 151 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|0zF+ELoEE0 zQ&Lm^o^N2U`CZE~--P+`3dX}qJaxu0$7l0JNa}oC&g{fiu<@4RpMQU)mn-(P@JLjM x2fShJ;$>)M)YjHM*Px;$;K #define TIMER_ID 1 diff --git a/BoardGame/Fenetre.h b/src/fenetre.h similarity index 93% rename from BoardGame/Fenetre.h rename to src/fenetre.h index e7c767f..212e6fc 100644 --- a/BoardGame/Fenetre.h +++ b/src/fenetre.h @@ -2,7 +2,7 @@ #include "stdafx.h" #include "board.h" -#include "Fruit.h" +#include "fruit.h" namespace Fenetre { LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); diff --git a/BoardGame/Fruit.h b/src/fruit.h similarity index 93% rename from BoardGame/Fruit.h rename to src/fruit.h index b212db0..1f34e57 100644 --- a/BoardGame/Fruit.h +++ b/src/fruit.h @@ -1,5 +1,5 @@ #pragma once -#include "Entity.h" +#include "entity.h" #include "stdafx.h" diff --git a/BoardGame/Main.cpp b/src/main.cpp similarity index 93% rename from BoardGame/Main.cpp rename to src/main.cpp index a413512..2c0e1bb 100644 --- a/BoardGame/Main.cpp +++ b/src/main.cpp @@ -1,7 +1,7 @@ -#include "Board.h" +#include "board.h" #include "stdafx.h" #include -#include "Fenetre.h" +#include "fenetre.h" int main() { diff --git a/BoardGame/Point.cpp b/src/point.cpp similarity index 93% rename from BoardGame/Point.cpp rename to src/point.cpp index b635728..db51d51 100644 --- a/BoardGame/Point.cpp +++ b/src/point.cpp @@ -1,4 +1,4 @@ -#include "Point.h" +#include "point.h" Point::Point(int x, int y) diff --git a/BoardGame/Point.h b/src/point.h similarity index 95% rename from BoardGame/Point.h rename to src/point.h index d3b13a2..7304837 100644 --- a/BoardGame/Point.h +++ b/src/point.h @@ -1,6 +1,6 @@ #pragma once #include "stdafx.h" -#include "Entity.h" +#include "entity.h" class Point : public Entity { public: diff --git a/BoardGame/Snake.cpp b/src/snake.cpp similarity index 98% rename from BoardGame/Snake.cpp rename to src/snake.cpp index 05e1ef4..5c87966 100644 --- a/BoardGame/Snake.cpp +++ b/src/snake.cpp @@ -1,4 +1,4 @@ -#include "Snake.h" +#include "snake.h" void Snake::addSpeed(float speed) { diff --git a/BoardGame/Snake.h b/src/snake.h similarity index 98% rename from BoardGame/Snake.h rename to src/snake.h index d7e610b..ed1b8b1 100644 --- a/BoardGame/Snake.h +++ b/src/snake.h @@ -1,6 +1,6 @@ #pragma once #include "stdafx.h" -#include "Entity.h" +#include "entity.h" class Snake : public Entity diff --git a/BoardGame/stdafx.h b/src/stdafx.h similarity index 100% rename from BoardGame/stdafx.h rename to src/stdafx.h diff --git a/vc/snake.sln b/vc/snake.sln new file mode 100644 index 0000000..1287059 --- /dev/null +++ b/vc/snake.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.14.36121.58 d17.14 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "snake", "snake.vcxproj", "{DE726747-E9F3-4EC5-AF95-079BE135692A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DE726747-E9F3-4EC5-AF95-079BE135692A}.Debug|x64.ActiveCfg = Debug|x64 + {DE726747-E9F3-4EC5-AF95-079BE135692A}.Debug|x64.Build.0 = Debug|x64 + {DE726747-E9F3-4EC5-AF95-079BE135692A}.Debug|x86.ActiveCfg = Debug|Win32 + {DE726747-E9F3-4EC5-AF95-079BE135692A}.Debug|x86.Build.0 = Debug|Win32 + {DE726747-E9F3-4EC5-AF95-079BE135692A}.Release|x64.ActiveCfg = Release|x64 + {DE726747-E9F3-4EC5-AF95-079BE135692A}.Release|x64.Build.0 = Release|x64 + {DE726747-E9F3-4EC5-AF95-079BE135692A}.Release|x86.ActiveCfg = Release|Win32 + {DE726747-E9F3-4EC5-AF95-079BE135692A}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A74185CC-97AC-4082-AB9A-6D0ED3A8EA51} + EndGlobalSection +EndGlobal diff --git a/BoardGame/BoardGame.vcxproj b/vc/snake.vcxproj similarity index 79% rename from BoardGame/BoardGame.vcxproj rename to vc/snake.vcxproj index f76742a..4106528 100644 --- a/BoardGame/BoardGame.vcxproj +++ b/vc/snake.vcxproj @@ -1,147 +1,158 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 17.0 - Win32Proj - {19a76af3-0481-4ccc-b842-42ae45ca36ff} - BoardGame - 10.0 - - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - Application - true - v143 - Unicode - - - Application - false - v143 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - Level3 - true - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - - - - - Level3 - true - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - - - - - Level3 - true - _DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - stdcpp17 - - - Console - true - - - - - Level3 - true - true - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - stdcpp17 - - - Console - true - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 17.0 + Win32Proj + {de726747-e9f3-4ec5-af95-079be135692a} + snake + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)x\$(Platform)\$(Configuration)\ + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)x\$(Platform)\$(Configuration)\ + + + $(SolutionDir)x\$(Platform)\$(Configuration)\ + + + $(SolutionDir)x\$(Platform)\$(Configuration)\ + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vc/snake.vcxproj.filters b/vc/snake.vcxproj.filters new file mode 100644 index 0000000..7f883c3 --- /dev/null +++ b/vc/snake.vcxproj.filters @@ -0,0 +1,48 @@ + + + + + {24f6694e-79e9-40c7-b160-1c97ee56c0ba} + + + + + src + + + src + + + src + + + src + + + src + + + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + \ No newline at end of file From c28226f45fa178f46006b4919d8ded5d28ec5db9 Mon Sep 17 00:00:00 2001 From: efool Date: Thu, 3 Jul 2025 13:07:10 -0400 Subject: [PATCH 02/17] Fix warnings --- src/board.cpp | 4 ++-- src/fenetre.cpp | 6 +++--- src/snake.cpp | 2 +- src/snake.h | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/board.cpp b/src/board.cpp index d891ac8..fb38a64 100644 --- a/src/board.cpp +++ b/src/board.cpp @@ -96,7 +96,7 @@ void Board::moveSnake(int direction) std::shared_ptr Board::spawnFruit() { std::vector emptyPositions; - for (int i = 0; i < m_Board.size(); i++) + for (int i = 0; i < int(m_Board.size()); i++) { if (std::dynamic_pointer_cast(m_Board[i])) { @@ -106,7 +106,7 @@ std::shared_ptr Board::spawnFruit() if (emptyPositions.empty()) return nullptr; - std::uniform_int_distribution<> distrib(0, emptyPositions.size() - 1); + std::uniform_int_distribution<> distrib(0, int(emptyPositions.size()) - 1); int chosenIndex = emptyPositions[distrib(gen)]; diff --git a/src/fenetre.cpp b/src/fenetre.cpp index b1ee009..30ab15f 100644 --- a/src/fenetre.cpp +++ b/src/fenetre.cpp @@ -44,7 +44,7 @@ namespace Fenetre { std::wstring fpsText = L"FPS: " + std::to_wstring(fps); std::wstring title = L"Snake - FPS: " + std::to_wstring(fps); SetWindowText(hwnd, title.c_str()); - TextOut(hdc, 10, 10, fpsText.c_str(), fpsText.length()); + TextOut(hdc, 10, 10, fpsText.c_str(), int(fpsText.length())); } } //HBRUSH CustomBrush = CreateSolidBrush(50);//def de la couleur du pinceau @@ -60,7 +60,7 @@ namespace Fenetre { Board* board = (Board*)pcs->lpCreateParams; SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)board); auto speed = board->getSnake()->getSpeed(); - SetTimer(hwnd, TIMER_ID, 50-speed, NULL); + SetTimer(hwnd, TIMER_ID, UINT(50 - speed), NULL); // todo: round? } break; @@ -165,7 +165,7 @@ namespace Fenetre { if (std::dynamic_pointer_cast(entity)) { int segmentOrder = board.getSnakeSegmentOrder(index); - int snakeLength = board.getSnake()->getBody().size(); + int snakeLength = int(board.getSnake()->getBody().size()); if (segmentOrder != -1 && snakeLength > 1) { diff --git a/src/snake.cpp b/src/snake.cpp index 5c87966..d4aaf88 100644 --- a/src/snake.cpp +++ b/src/snake.cpp @@ -46,7 +46,7 @@ void Snake::move(int direction) } } - for (int i = m_Body.size() - 1; i > 0; --i) + for (int i = int(m_Body.size()) - 1; i > 0; --i) { m_Body[i] = m_Body[i - 1]; } diff --git a/src/snake.h b/src/snake.h index ed1b8b1..73047d2 100644 --- a/src/snake.h +++ b/src/snake.h @@ -62,7 +62,7 @@ class Snake : public Entity private: - float m_Speed = 3.0f*(0.3*m_Length);//[TODO] rendre modulable si ajout difficulter + float m_Speed = 3.0f*(0.3f*m_Length);//[TODO] rendre modulable si ajout difficulter int m_Length = 1; int position; const int _OFFSET = 16; From 80c09d533774e60c1188ff38f1b523b54b67313c Mon Sep 17 00:00:00 2001 From: efool Date: Thu, 3 Jul 2025 13:10:41 -0400 Subject: [PATCH 03/17] Refactor warning level to 4 - fixed warnings --- src/board.cpp | 4 ---- src/board.h | 2 -- src/fenetre.cpp | 1 - src/main.cpp | 5 +---- vc/snake.vcxproj | 8 ++++---- 5 files changed, 5 insertions(+), 15 deletions(-) diff --git a/src/board.cpp b/src/board.cpp index fb38a64..74d9f11 100644 --- a/src/board.cpp +++ b/src/board.cpp @@ -62,8 +62,6 @@ void Board::moveSnake(int direction) std::shared_ptr snake = getSnake(); if (!snake) return; - int oldHeadPosition = snake->getPosition(); - std::vector oldBody = snake->getBody(); snake->move(direction); @@ -88,8 +86,6 @@ void Board::moveSnake(int direction) { m_Board[pos] = snake; } - - InvalidateRect(hwnd, NULL, TRUE); } diff --git a/src/board.h b/src/board.h index a8fdcb4..1e9d660 100644 --- a/src/board.h +++ b/src/board.h @@ -15,7 +15,6 @@ class Board std::shared_ptr getSnake() const; void moveSnake(int direction); const std::vector>& getEntities() const { return m_Board; } - void setWindowHandle(HWND hwnd) { this->hwnd = hwnd; }; std::shared_ptr spawnFruit(); std::shared_ptr getEntityAt(int index) const { @@ -27,7 +26,6 @@ class Board private: std::vector>m_Board; static int m_BoardSize; - HWND hwnd = nullptr; }; diff --git a/src/fenetre.cpp b/src/fenetre.cpp index 30ab15f..50f1fb1 100644 --- a/src/fenetre.cpp +++ b/src/fenetre.cpp @@ -161,7 +161,6 @@ namespace Fenetre { HBRUSH brush = nullptr; - auto snakeLength = board.getSnake()->getBody().size(); if (std::dynamic_pointer_cast(entity)) { int segmentOrder = board.getSnakeSegmentOrder(index); diff --git a/src/main.cpp b/src/main.cpp index 2c0e1bb..d6b8b2a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,8 +8,7 @@ int main() { Board board; - HWND hwnd = Fenetre::CreateMainWindow(&board); - board.setWindowHandle(hwnd); + Fenetre::CreateMainWindow(&board); std::shared_ptr snake = board.getSnake(); if (!snake) @@ -20,8 +19,6 @@ int main() { board.spawnFruit(); - char input = ' '; - MSG msg = {}; while (GetMessage(&msg, NULL, 0, 0)) { diff --git a/vc/snake.vcxproj b/vc/snake.vcxproj index 4106528..f5c6ee8 100644 --- a/vc/snake.vcxproj +++ b/vc/snake.vcxproj @@ -86,7 +86,7 @@ - Level3 + Level4 true WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true @@ -98,7 +98,7 @@ - Level3 + Level4 true true true @@ -112,7 +112,7 @@ - Level3 + Level4 true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true @@ -124,7 +124,7 @@ - Level3 + Level4 true true true From ed4ba7ff1c4d6f458dfacdb908f702a84b36be69 Mon Sep 17 00:00:00 2001 From: efool Date: Thu, 3 Jul 2025 13:16:10 -0400 Subject: [PATCH 04/17] convert to tabs and fix misc spaces --- src/board.cpp | 161 +++++++++---------- src/board.h | 6 +- src/entity.h | 12 +- src/fenetre.cpp | 406 ++++++++++++++++++++++++------------------------ src/fenetre.h | 11 +- src/fruit.h | 4 - src/main.cpp | 36 ++--- src/point.cpp | 12 +- src/point.h | 5 +- src/snake.cpp | 69 ++++---- src/snake.h | 19 +-- src/stdafx.h | 2 +- 12 files changed, 355 insertions(+), 388 deletions(-) diff --git a/src/board.cpp b/src/board.cpp index 74d9f11..af16f52 100644 --- a/src/board.cpp +++ b/src/board.cpp @@ -8,115 +8,116 @@ std::mt19937 gen(rd()); Board::Board() { - for (int x = 0; x < m_BoardSize; x++) - { - for (int y = 0; y < m_BoardSize; y++) - { - int current = x * 16 + y; - - if (current == (m_BoardSize * m_BoardSize) / 2) - { - m_Board.push_back(std::make_shared(5.0f, 1, 150)); - } - else - { - m_Board.push_back(std::make_shared(y, x)); - } - } - } + for (int x = 0; x < m_BoardSize; x++) + { + for (int y = 0; y < m_BoardSize; y++) + { + int current = x * 16 + y; + + if (current == (m_BoardSize * m_BoardSize) / 2) + { + m_Board.push_back(std::make_shared(5.0f, 1, 150)); + } + else + { + m_Board.push_back(std::make_shared(y, x)); + } + } + } } void Board::renderBoard() { - int TotalSize = m_BoardSize * m_BoardSize; - system("cls"); //clear le terminal à chaque nouveau render - - for (int i = 0; i < TotalSize; i++) - { - m_Board[i]->render(); - - if ((i + 1) % m_BoardSize == 0) - { - std::cout << std::endl; - } - } + int TotalSize = m_BoardSize * m_BoardSize; + system("cls"); //clear le terminal à chaque nouveau render + + for (int i = 0; i < TotalSize; i++) + { + m_Board[i]->render(); + + if ((i + 1) % m_BoardSize == 0) + { + std::cout << std::endl; + } + } } std::shared_ptr Board::getSnake() const { - for (auto& entity : m_Board) - { - - std::shared_ptr snake = std::dynamic_pointer_cast(entity); - if (snake != nullptr) - { - return snake; - } - } - return nullptr; + for (auto& entity : m_Board) + { + std::shared_ptr snake = std::dynamic_pointer_cast(entity); + if (snake != nullptr) + { + return snake; + } + } + return nullptr; } void Board::moveSnake(int direction) { - std::shared_ptr snake = getSnake(); - if (!snake) return; + std::shared_ptr snake = getSnake(); + if (!snake) return; - std::vector oldBody = snake->getBody(); + std::vector oldBody = snake->getBody(); - snake->move(direction); + snake->move(direction); - int newHeadPosition = snake->getPosition(); + int newHeadPosition = snake->getPosition(); - if (std::dynamic_pointer_cast(m_Board[newHeadPosition])) - { - auto fruit = spawnFruit(); - snake->addSegment(1); - snake->addScore(fruit->getPoints()); - } + if (std::dynamic_pointer_cast(m_Board[newHeadPosition])) + { + auto fruit = spawnFruit(); + snake->addSegment(1); + snake->addScore(fruit->getPoints()); + } - for (int pos : oldBody) - { - int oldY = pos / m_BoardSize; - int oldX = pos % m_BoardSize; - m_Board[pos] = std::make_shared(oldX, oldY); - } + for (int pos : oldBody) + { + int oldY = pos / m_BoardSize; + int oldX = pos % m_BoardSize; + m_Board[pos] = std::make_shared(oldX, oldY); + } - for (int pos : snake->getBody()) - { - m_Board[pos] = snake; - } + for (int pos : snake->getBody()) + { + m_Board[pos] = snake; + } } std::shared_ptr Board::spawnFruit() { - std::vector emptyPositions; - for (int i = 0; i < int(m_Board.size()); i++) - { - if (std::dynamic_pointer_cast(m_Board[i])) - { - emptyPositions.push_back(i); - } - } + std::vector emptyPositions; + for (int i = 0; i < int(m_Board.size()); i++) + { + if (std::dynamic_pointer_cast(m_Board[i])) + { + emptyPositions.push_back(i); + } + } - if (emptyPositions.empty()) return nullptr; + if (emptyPositions.empty()) return nullptr; - std::uniform_int_distribution<> distrib(0, int(emptyPositions.size()) - 1); + std::uniform_int_distribution<> distrib(0, int(emptyPositions.size()) - 1); - int chosenIndex = emptyPositions[distrib(gen)]; + int chosenIndex = emptyPositions[distrib(gen)]; - m_Board[chosenIndex] = std::make_shared(chosenIndex); - return std::dynamic_pointer_cast(m_Board[chosenIndex]); + m_Board[chosenIndex] = std::make_shared(chosenIndex); + return std::dynamic_pointer_cast(m_Board[chosenIndex]); } -int Board::getSnakeSegmentOrder(int index) const { - auto snake = getSnake(); - const auto& body = snake->getBody(); +int Board::getSnakeSegmentOrder(int index) const +{ + auto snake = getSnake(); + + const auto& body = snake->getBody(); - for (size_t i = 0; i < body.size(); ++i) { - if (body[i] == index) - return static_cast(i); - } - return -1; + for (size_t i = 0; i < body.size(); ++i) { + if (body[i] == index) + return static_cast(i); + } + return -1; } diff --git a/src/board.h b/src/board.h index 1e9d660..d0dcca3 100644 --- a/src/board.h +++ b/src/board.h @@ -6,7 +6,6 @@ class Board { - public: Board(); void renderBoard(); @@ -26,7 +25,4 @@ class Board private: std::vector>m_Board; static int m_BoardSize; - -}; - - +}; \ No newline at end of file diff --git a/src/entity.h b/src/entity.h index 2c46e0a..868391a 100644 --- a/src/entity.h +++ b/src/entity.h @@ -4,13 +4,13 @@ class Entity { public: - virtual ~Entity() = default; - virtual void render() const = 0; + virtual ~Entity() = default; + virtual void render() const = 0; - int getPosition() const { return Position; } - void setPosition(int pos) { Position = pos; } - virtual bool isCollidable() { return false; }; + int getPosition() const { return Position; } + void setPosition(int pos) { Position = pos; } + virtual bool isCollidable() { return false; }; protected: - int Position; + int Position; }; diff --git a/src/fenetre.cpp b/src/fenetre.cpp index 50f1fb1..49972c3 100644 --- a/src/fenetre.cpp +++ b/src/fenetre.cpp @@ -2,212 +2,206 @@ #include #define TIMER_ID 1 - using namespace std::chrono; -namespace Fenetre { - - int frames = 0; - int fps = 0; - auto lastTime = steady_clock::now(); - - LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) - { - - switch (uMsg) - { - case WM_DESTROY: - KillTimer(hwnd, TIMER_ID); - PostQuitMessage(0); - return 0; - - case WM_PAINT: - { - PAINTSTRUCT ps; - HDC hdc = BeginPaint(hwnd, &ps); - - Board* board = (Board*)GetWindowLongPtr(hwnd, GWLP_USERDATA); - if (board) - { - WNDRenderBoard(hwnd, hdc, *board); - frames++; - - auto currentTime = steady_clock::now(); - auto elapsed = duration_cast(currentTime - lastTime).count(); - - if (elapsed >= 1) { - fps = frames; - frames = 0; - lastTime = currentTime; - - - std::cout << "FPS: " << fps << std::endl; - std::wstring fpsText = L"FPS: " + std::to_wstring(fps); - std::wstring title = L"Snake - FPS: " + std::to_wstring(fps); - SetWindowText(hwnd, title.c_str()); - TextOut(hdc, 10, 10, fpsText.c_str(), int(fpsText.length())); - } - } - //HBRUSH CustomBrush = CreateSolidBrush(50);//def de la couleur du pinceau - //FillRect(hdc, &ps.rcPaint, CustomBrush);//application de la peinture sur le background - //DeleteObject(CustomBrush);//nettoyage du pinceau - - EndPaint(hwnd, &ps); - } - break; - case WM_CREATE: - { - LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam; - Board* board = (Board*)pcs->lpCreateParams; - SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)board); - auto speed = board->getSnake()->getSpeed(); - SetTimer(hwnd, TIMER_ID, UINT(50 - speed), NULL); // todo: round? - - } - break; - case WM_KEYDOWN: - { - Board* board = (Board*)GetWindowLongPtr(hwnd, GWLP_USERDATA); - auto snake = board->getSnake(); - - int desiredDirection = snake->getCurrentDirection(); - - switch (wParam) - { - case 'Q': desiredDirection = 1; break; - case 'Z': desiredDirection = 2; break; - case 'D': desiredDirection = 3; break; - case 'S': desiredDirection = 4; break; - } - - if (!snake->isOpposite(snake->getNextDirection(), desiredDirection)) - { - snake->setNextDirection(desiredDirection); - } - } - break; - - case WM_TIMER: - { - Board* board = (Board*)GetWindowLongPtr(hwnd, GWLP_USERDATA); - if (board) - { - auto snake = board->getSnake(); - if (snake->getAlive()) - { - board->moveSnake(snake->getNextDirection()); - - snake->setCurrentDirection(snake->getNextDirection()); - - InvalidateRect(hwnd, NULL, TRUE); - } - else - { - KillTimer(hwnd, TIMER_ID); - } - } - } - break; - - } - return DefWindowProc(hwnd, uMsg, wParam, lParam); - } - - HWND CreateMainWindow(Board *board) - { - const wchar_t CLASS_NAME[] = L"SnakeWindow"; - - WNDCLASS wc = {}; - wc.lpfnWndProc = Fenetre::WindowProc; - wc.hInstance = GetModuleHandle(NULL); - wc.lpszClassName = CLASS_NAME; - - RegisterClass(&wc); - - HWND hwnd = CreateWindowEx( - 0, CLASS_NAME, L"Snake", WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, GetModuleHandle(NULL), board - ); - - if (hwnd == NULL) { - std::cout << "debug: echec de creation de la fenetre\n"; - exit(1); - } - - ShowWindow(hwnd, SW_SHOW); - return hwnd; - } - - void Fenetre::WNDRenderBoard(HWND hwnd, HDC hdc, const Board& board) - { - RECT clientRect; - GetClientRect(hwnd, &clientRect); - - int squareWidth = clientRect.right / Board::getBoardSize(); - int squareHeight = clientRect.bottom / Board::getBoardSize(); - - for (int row = 0; row < Board::getBoardSize(); ++row) - { - for (int col = 0; col < Board::getBoardSize(); ++col) - { - RECT square = { - col * squareWidth, - row * squareHeight, - (col + 1) * squareWidth, - (row + 1) * squareHeight - }; - - int index = row * Board::getBoardSize() + col; - std::shared_ptr entity = board.getEntityAt(index); - - - HBRUSH brush = nullptr; - if (std::dynamic_pointer_cast(entity)) - { - int segmentOrder = board.getSnakeSegmentOrder(index); - int snakeLength = int(board.getSnake()->getBody().size()); - - if (segmentOrder != -1 && snakeLength > 1) - { - float ratio = static_cast(segmentOrder) / (snakeLength - 1); - - int brightness = static_cast(ratio * 200); - - int red = brightness; - int green = brightness; - int blue = 255; - - brush = CreateSolidBrush(RGB(red, green, blue)); - } - else - { - brush = CreateSolidBrush(RGB(0, 0, 255)); //bleu si ça bug - } - } - else if (std::dynamic_pointer_cast(entity)) - { - brush = CreateSolidBrush(RGB(255, 0, 0)); - } - else - { - brush = CreateSolidBrush(RGB(0, 255, 0)); - } - - FillRect(hdc, &square, brush); - DeleteObject(brush); - SetBkMode(hdc, TRANSPARENT); - - - int segmentOrder = board.getSnakeSegmentOrder(index); - if (segmentOrder != -1) { - std::wstring text = std::to_wstring(segmentOrder); - DrawText(hdc, text.c_str(), -1, &square, DT_CENTER | DT_VCENTER | DT_SINGLELINE); - } - - - } - } - } - - } +namespace Fenetre { +int frames = 0; +int fps = 0; +auto lastTime = steady_clock::now(); + +LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_DESTROY: + KillTimer(hwnd, TIMER_ID); + PostQuitMessage(0); + return 0; + + case WM_PAINT: + { + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hwnd, &ps); + + Board* board = (Board*)GetWindowLongPtr(hwnd, GWLP_USERDATA); + if (board) + { + WNDRenderBoard(hwnd, hdc, *board); + frames++; + + auto currentTime = steady_clock::now(); + auto elapsed = duration_cast(currentTime - lastTime).count(); + + if (elapsed >= 1) { + fps = frames; + frames = 0; + lastTime = currentTime; + + std::cout << "FPS: " << fps << std::endl; + std::wstring fpsText = L"FPS: " + std::to_wstring(fps); + std::wstring title = L"Snake - FPS: " + std::to_wstring(fps); + SetWindowText(hwnd, title.c_str()); + TextOut(hdc, 10, 10, fpsText.c_str(), int(fpsText.length())); + } + } + //HBRUSH CustomBrush = CreateSolidBrush(50);//def de la couleur du pinceau + //FillRect(hdc, &ps.rcPaint, CustomBrush);//application de la peinture sur le background + //DeleteObject(CustomBrush);//nettoyage du pinceau + + EndPaint(hwnd, &ps); + } + break; + case WM_CREATE: + { + LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam; + Board* board = (Board*)pcs->lpCreateParams; + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)board); + auto speed = board->getSnake()->getSpeed(); + SetTimer(hwnd, TIMER_ID, UINT(50 - speed), NULL); // todo: round? + + } + break; + case WM_KEYDOWN: + { + Board* board = (Board*)GetWindowLongPtr(hwnd, GWLP_USERDATA); + auto snake = board->getSnake(); + + int desiredDirection = snake->getCurrentDirection(); + + switch (wParam) + { + case 'Q': desiredDirection = 1; break; + case 'Z': desiredDirection = 2; break; + case 'D': desiredDirection = 3; break; + case 'S': desiredDirection = 4; break; + } + + if (!snake->isOpposite(snake->getNextDirection(), desiredDirection)) + { + snake->setNextDirection(desiredDirection); + } + } + break; + + case WM_TIMER: + { + Board* board = (Board*)GetWindowLongPtr(hwnd, GWLP_USERDATA); + if (board) + { + auto snake = board->getSnake(); + if (snake->getAlive()) + { + board->moveSnake(snake->getNextDirection()); + + snake->setCurrentDirection(snake->getNextDirection()); + + InvalidateRect(hwnd, NULL, TRUE); + } + else + { + KillTimer(hwnd, TIMER_ID); + } + } + } + break; + + } + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +HWND CreateMainWindow(Board *board) +{ + const wchar_t CLASS_NAME[] = L"SnakeWindow"; + + WNDCLASS wc = {}; + wc.lpfnWndProc = Fenetre::WindowProc; + wc.hInstance = GetModuleHandle(NULL); + wc.lpszClassName = CLASS_NAME; + + RegisterClass(&wc); + + HWND hwnd = CreateWindowEx( + 0, CLASS_NAME, L"Snake", WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, GetModuleHandle(NULL), board + ); + + if (hwnd == NULL) { + std::cout << "debug: echec de creation de la fenetre\n"; + exit(1); + } + + ShowWindow(hwnd, SW_SHOW); + return hwnd; +} + +void Fenetre::WNDRenderBoard(HWND hwnd, HDC hdc, const Board& board) +{ + RECT clientRect; + GetClientRect(hwnd, &clientRect); + + int squareWidth = clientRect.right / Board::getBoardSize(); + int squareHeight = clientRect.bottom / Board::getBoardSize(); + + for (int row = 0; row < Board::getBoardSize(); ++row) + { + for (int col = 0; col < Board::getBoardSize(); ++col) + { + RECT square = { + col * squareWidth, + row * squareHeight, + (col + 1) * squareWidth, + (row + 1) * squareHeight + }; + + int index = row * Board::getBoardSize() + col; + std::shared_ptr entity = board.getEntityAt(index); + + + HBRUSH brush = nullptr; + if (std::dynamic_pointer_cast(entity)) + { + int segmentOrder = board.getSnakeSegmentOrder(index); + int snakeLength = int(board.getSnake()->getBody().size()); + + if (segmentOrder != -1 && snakeLength > 1) + { + float ratio = static_cast(segmentOrder) / (snakeLength - 1); + + int brightness = static_cast(ratio * 200); + + int red = brightness; + int green = brightness; + int blue = 255; + + brush = CreateSolidBrush(RGB(red, green, blue)); + } + else + { + brush = CreateSolidBrush(RGB(0, 0, 255)); //bleu si ça bug + } + } + else if (std::dynamic_pointer_cast(entity)) + { + brush = CreateSolidBrush(RGB(255, 0, 0)); + } + else + { + brush = CreateSolidBrush(RGB(0, 255, 0)); + } + + FillRect(hdc, &square, brush); + DeleteObject(brush); + SetBkMode(hdc, TRANSPARENT); + + + int segmentOrder = board.getSnakeSegmentOrder(index); + if (segmentOrder != -1) { + std::wstring text = std::to_wstring(segmentOrder); + DrawText(hdc, text.c_str(), -1, &square, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + } + } + } +} + +} \ No newline at end of file diff --git a/src/fenetre.h b/src/fenetre.h index 212e6fc..db326c9 100644 --- a/src/fenetre.h +++ b/src/fenetre.h @@ -1,12 +1,13 @@ #pragma once #include "stdafx.h" #include "board.h" - #include "fruit.h" + namespace Fenetre { - LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + + HWND CreateMainWindow(Board* board); + void WNDRenderBoard(HWND hwnd, HDC hdc, const Board& board); - HWND CreateMainWindow(Board* board); - void WNDRenderBoard(HWND hwnd, HDC hdc, const Board& board); -} +} \ No newline at end of file diff --git a/src/fruit.h b/src/fruit.h index 1f34e57..69b2863 100644 --- a/src/fruit.h +++ b/src/fruit.h @@ -2,9 +2,6 @@ #include "entity.h" #include "stdafx.h" - - - class Fruit : public Entity { public: @@ -17,5 +14,4 @@ class Fruit : public Entity private: int points = 1000; - }; diff --git a/src/main.cpp b/src/main.cpp index d6b8b2a..38e4705 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,28 +5,26 @@ int main() { + Board board; - Board board; + Fenetre::CreateMainWindow(&board); - Fenetre::CreateMainWindow(&board); + std::shared_ptr snake = board.getSnake(); + if (!snake) + { + std::cout << "debug: snake pas trouvé\n\r"; + return 1; + } - std::shared_ptr snake = board.getSnake(); - if (!snake) - { - std::cout << "debug: snake pas trouvé\n\r"; - return 1; - } + board.spawnFruit(); - board.spawnFruit(); + MSG msg = {}; + while (GetMessage(&msg, NULL, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } - MSG msg = {}; - while (GetMessage(&msg, NULL, 0, 0)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - - std::cout << "partie fini" << std::endl; - return 0; + std::cout << "partie fini" << std::endl; + return 0; } diff --git a/src/point.cpp b/src/point.cpp index db51d51..fd4ce17 100644 --- a/src/point.cpp +++ b/src/point.cpp @@ -1,17 +1,15 @@ #include "point.h" - Point::Point(int x, int y) { - this->x = x; - this->y = y; - this->Position = y * 16 + x; + this->x = x; + this->y = y; + this->Position = y * 16 + x; } -std::ostream& operator<<(std::ostream& os, const Point& point) + +std::ostream& operator<<(std::ostream& os, const Point& /*point*/) { //os << "Point(x: " << point.x << ", y: " << point.y << ", place: " << point.place << ")"; os << 'o'; return os; } - - diff --git a/src/point.h b/src/point.h index 7304837..8ee2468 100644 --- a/src/point.h +++ b/src/point.h @@ -1,6 +1,7 @@ #pragma once #include "stdafx.h" #include "entity.h" + class Point : public Entity { public: @@ -19,6 +20,4 @@ class Point : public Entity int Position = 0; friend std::ostream& operator<<(std::ostream& os, const Point& point); -}; - - +}; \ No newline at end of file diff --git a/src/snake.cpp b/src/snake.cpp index d4aaf88..cab3168 100644 --- a/src/snake.cpp +++ b/src/snake.cpp @@ -4,59 +4,60 @@ void Snake::addSpeed(float speed) { m_Speed += speed; } + void Snake::removeSpeed(float speed) { m_Speed -= speed; } + int Snake::wrap(int value, int max) { - return (value + max) % max; + return (value + max) % max; } void Snake::move(int direction) { - //gros pavé pour check si le joueur fait demi tour direct* - //[TODO] rendre lisible et optimisé + //gros pavé pour check si le joueur fait demi tour direct* + //[TODO] rendre lisible et optimisé - direction = m_currentDirection; // on ignore si le joueur fait un 180° - int head = m_Body.front(); - int row = head / 16; - int col = head % 16; + direction = m_currentDirection; // on ignore si le joueur fait un 180° + int head = m_Body.front(); + int row = head / 16; + int col = head % 16; - switch (direction) - { - case 1: col--; break; - case 2: row--; break; - case 3: col++; break; - case 4: row++; break; - } + switch (direction) + { + case 1: col--; break; + case 2: row--; break; + case 3: col++; break; + case 4: row++; break; + } - row = wrap(row, 16); - col = wrap(col, 16); + row = wrap(row, 16); + col = wrap(col, 16); - int newHead = row * 16 + col; + int newHead = row * 16 + col; - // check la collision on skip la tete sinon probleme - for (size_t i = 1; i < m_Body.size(); ++i) - { - if (newHead == m_Body[i]) - { - std::cout << "Parti fini" << "\n"; - exit(0); // on quitte pour l'instant - //[TODO] faire un menu et un écran de fin - } - } + // check la collision on skip la tete sinon probleme + for (size_t i = 1; i < m_Body.size(); ++i) + { + if (newHead == m_Body[i]) + { + std::cout << "Parti fini" << "\n"; + exit(0); // on quitte pour l'instant + //[TODO] faire un menu et un écran de fin + } + } - for (int i = int(m_Body.size()) - 1; i > 0; --i) - { - m_Body[i] = m_Body[i - 1]; - } + for (int i = int(m_Body.size()) - 1; i > 0; --i) + { + m_Body[i] = m_Body[i - 1]; + } - m_Body[0] = newHead; - Position = newHead; + m_Body[0] = newHead; + Position = newHead; } - std::ostream& operator<<(std::ostream& os, const Snake& snake) { os << "~"; diff --git a/src/snake.h b/src/snake.h index 73047d2..2bc2bfc 100644 --- a/src/snake.h +++ b/src/snake.h @@ -2,7 +2,6 @@ #include "stdafx.h" #include "entity.h" - class Snake : public Entity { public: @@ -21,7 +20,6 @@ class Snake : public Entity } } - void addSpeed(float speed); void removeSpeed(float speed); @@ -56,12 +54,9 @@ class Snake : public Entity (dir1 == 2 && dir2 == 4) || (dir1 == 4 && dir2 == 2); } - bool canChangeDirection = true; - private: - float m_Speed = 3.0f*(0.3f*m_Length);//[TODO] rendre modulable si ajout difficulter int m_Length = 1; int position; @@ -71,18 +66,6 @@ class Snake : public Entity int m_nextDirection = 3; bool isAlive; - - - std::vector m_Body;//liste des segments du serpent friend std::ostream& operator<<(std::ostream& os, const Snake& snake); - - - -}; - - - - - - +}; \ No newline at end of file diff --git a/src/stdafx.h b/src/stdafx.h index a34479a..0e44147 100644 --- a/src/stdafx.h +++ b/src/stdafx.h @@ -7,4 +7,4 @@ #include #include #include -#include +#include \ No newline at end of file From ca7008baa9571bc91f5e8ac3bd0ed6a17500017a Mon Sep 17 00:00:00 2001 From: efool Date: Thu, 3 Jul 2025 13:21:36 -0400 Subject: [PATCH 05/17] apply snake namespace --- src/board.cpp | 4 ++++ src/board.h | 6 +++++- src/entity.h | 4 ++++ src/fenetre.cpp | 6 +++++- src/fenetre.h | 8 ++++---- src/fruit.h | 4 ++++ src/main.cpp | 9 ++++----- src/point.cpp | 4 ++++ src/point.h | 6 +++++- src/snake.cpp | 6 +++++- src/snake.h | 6 +++++- vc/snake.vcxproj | 4 ++++ 12 files changed, 53 insertions(+), 14 deletions(-) diff --git a/src/board.cpp b/src/board.cpp index af16f52..d42ba72 100644 --- a/src/board.cpp +++ b/src/board.cpp @@ -2,6 +2,8 @@ #include "snake.h" #include "fruit.h" +namespace snake { + int Board::m_BoardSize = 16; std::random_device rd; std::mt19937 gen(rd()); @@ -121,3 +123,5 @@ int Board::getSnakeSegmentOrder(int index) const } return -1; } + +} // namespace snake \ No newline at end of file diff --git a/src/board.h b/src/board.h index d0dcca3..d02630c 100644 --- a/src/board.h +++ b/src/board.h @@ -4,6 +4,8 @@ #include "snake.h" #include "fruit.h" +namespace snake { + class Board { public: @@ -25,4 +27,6 @@ class Board private: std::vector>m_Board; static int m_BoardSize; -}; \ No newline at end of file +}; + +} // namespace snake \ No newline at end of file diff --git a/src/entity.h b/src/entity.h index 868391a..7464863 100644 --- a/src/entity.h +++ b/src/entity.h @@ -1,6 +1,8 @@ #pragma once #include "stdafx.h" +namespace snake { + class Entity { public: @@ -14,3 +16,5 @@ class Entity protected: int Position; }; + +} // namespace snake \ No newline at end of file diff --git a/src/fenetre.cpp b/src/fenetre.cpp index 49972c3..809a0f4 100644 --- a/src/fenetre.cpp +++ b/src/fenetre.cpp @@ -2,6 +2,8 @@ #include #define TIMER_ID 1 +namespace snake { + using namespace std::chrono; namespace Fenetre { @@ -204,4 +206,6 @@ void Fenetre::WNDRenderBoard(HWND hwnd, HDC hdc, const Board& board) } } -} \ No newline at end of file +} + +} // namespace snake \ No newline at end of file diff --git a/src/fenetre.h b/src/fenetre.h index db326c9..4919e6d 100644 --- a/src/fenetre.h +++ b/src/fenetre.h @@ -3,11 +3,11 @@ #include "board.h" #include "fruit.h" -namespace Fenetre { +namespace snake::Fenetre { - LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); - HWND CreateMainWindow(Board* board); - void WNDRenderBoard(HWND hwnd, HDC hdc, const Board& board); +HWND CreateMainWindow(Board* board); +void WNDRenderBoard(HWND hwnd, HDC hdc, const Board& board); } \ No newline at end of file diff --git a/src/fruit.h b/src/fruit.h index 69b2863..115c225 100644 --- a/src/fruit.h +++ b/src/fruit.h @@ -2,6 +2,8 @@ #include "entity.h" #include "stdafx.h" +namespace snake { + class Fruit : public Entity { public: @@ -15,3 +17,5 @@ class Fruit : public Entity private: int points = 1000; }; + +} // namespace snake \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 38e4705..c3d1bbf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,13 +3,12 @@ #include #include "fenetre.h" - int main() { - Board board; + snake::Board board; - Fenetre::CreateMainWindow(&board); + snake::Fenetre::CreateMainWindow(&board); - std::shared_ptr snake = board.getSnake(); + std::shared_ptr snake = board.getSnake(); if (!snake) { std::cout << "debug: snake pas trouvé\n\r"; @@ -27,4 +26,4 @@ int main() { std::cout << "partie fini" << std::endl; return 0; -} +} \ No newline at end of file diff --git a/src/point.cpp b/src/point.cpp index fd4ce17..915e5f7 100644 --- a/src/point.cpp +++ b/src/point.cpp @@ -1,5 +1,7 @@ #include "point.h" +namespace snake { + Point::Point(int x, int y) { this->x = x; @@ -13,3 +15,5 @@ std::ostream& operator<<(std::ostream& os, const Point& /*point*/) os << 'o'; return os; } + +} // namespace snake \ No newline at end of file diff --git a/src/point.h b/src/point.h index 8ee2468..ed21628 100644 --- a/src/point.h +++ b/src/point.h @@ -2,6 +2,8 @@ #include "stdafx.h" #include "entity.h" +namespace snake { + class Point : public Entity { public: @@ -20,4 +22,6 @@ class Point : public Entity int Position = 0; friend std::ostream& operator<<(std::ostream& os, const Point& point); -}; \ No newline at end of file +}; + +} // namespace snake \ No newline at end of file diff --git a/src/snake.cpp b/src/snake.cpp index cab3168..0c66bec 100644 --- a/src/snake.cpp +++ b/src/snake.cpp @@ -1,5 +1,7 @@ #include "snake.h" +namespace snake { + void Snake::addSpeed(float speed) { m_Speed += speed; @@ -58,8 +60,10 @@ void Snake::move(int direction) } -std::ostream& operator<<(std::ostream& os, const Snake& snake) +std::ostream& operator<<(std::ostream& os, const Snake& /*snake*/) { os << "~"; return os; } + +} // namespace snake \ No newline at end of file diff --git a/src/snake.h b/src/snake.h index 2bc2bfc..b64dad5 100644 --- a/src/snake.h +++ b/src/snake.h @@ -2,6 +2,8 @@ #include "stdafx.h" #include "entity.h" +namespace snake { + class Snake : public Entity { public: @@ -68,4 +70,6 @@ class Snake : public Entity std::vector m_Body;//liste des segments du serpent friend std::ostream& operator<<(std::ostream& os, const Snake& snake); -}; \ No newline at end of file +}; + +} // namespace snake \ No newline at end of file diff --git a/vc/snake.vcxproj b/vc/snake.vcxproj index f5c6ee8..c01ec68 100644 --- a/vc/snake.vcxproj +++ b/vc/snake.vcxproj @@ -90,6 +90,7 @@ true WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true + stdcpp17 Console @@ -104,6 +105,7 @@ true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true + stdcpp17 Console @@ -116,6 +118,7 @@ true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true + stdcpp17 Console @@ -130,6 +133,7 @@ true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true + stdcpp17 Console From 92aa50613944c67527ac7db9181a45ce4a99917a Mon Sep 17 00:00:00 2001 From: efool Date: Thu, 3 Jul 2025 13:24:11 -0400 Subject: [PATCH 06/17] rename c++ header files to hpp --- src/board.cpp | 6 +++--- src/{board.h => board.hpp} | 6 +++--- src/{entity.h => entity.hpp} | 0 src/fenetre.cpp | 2 +- src/{fenetre.h => fenetre.hpp} | 4 ++-- src/{fruit.h => fruit.hpp} | 2 +- src/main.cpp | 4 ++-- src/point.cpp | 2 +- src/{point.h => point.hpp} | 2 +- src/snake.cpp | 2 +- src/{snake.h => snake.hpp} | 2 +- vc/snake.vcxproj | 12 ++++++------ vc/snake.vcxproj.filters | 12 ++++++------ 13 files changed, 28 insertions(+), 28 deletions(-) rename src/{board.h => board.hpp} (91%) rename src/{entity.h => entity.hpp} (100%) rename src/{fenetre.h => fenetre.hpp} (85%) rename src/{fruit.h => fruit.hpp} (93%) rename src/{point.h => point.hpp} (95%) rename src/{snake.h => snake.hpp} (98%) diff --git a/src/board.cpp b/src/board.cpp index d42ba72..ab5ef1b 100644 --- a/src/board.cpp +++ b/src/board.cpp @@ -1,6 +1,6 @@ -#include "board.h" -#include "snake.h" -#include "fruit.h" +#include "board.hpp" +#include "snake.hpp" +#include "fruit.hpp" namespace snake { diff --git a/src/board.h b/src/board.hpp similarity index 91% rename from src/board.h rename to src/board.hpp index d02630c..cfcfea2 100644 --- a/src/board.h +++ b/src/board.hpp @@ -1,8 +1,8 @@ #pragma once -#include "point.h" +#include "point.hpp" #include "stdafx.h" -#include "snake.h" -#include "fruit.h" +#include "snake.hpp" +#include "fruit.hpp" namespace snake { diff --git a/src/entity.h b/src/entity.hpp similarity index 100% rename from src/entity.h rename to src/entity.hpp diff --git a/src/fenetre.cpp b/src/fenetre.cpp index 809a0f4..333d940 100644 --- a/src/fenetre.cpp +++ b/src/fenetre.cpp @@ -1,4 +1,4 @@ -#include "fenetre.h" +#include "fenetre.hpp" #include #define TIMER_ID 1 diff --git a/src/fenetre.h b/src/fenetre.hpp similarity index 85% rename from src/fenetre.h rename to src/fenetre.hpp index 4919e6d..138fb12 100644 --- a/src/fenetre.h +++ b/src/fenetre.hpp @@ -1,7 +1,7 @@ #pragma once #include "stdafx.h" -#include "board.h" -#include "fruit.h" +#include "board.hpp" +#include "fruit.hpp" namespace snake::Fenetre { diff --git a/src/fruit.h b/src/fruit.hpp similarity index 93% rename from src/fruit.h rename to src/fruit.hpp index 115c225..bd08bd5 100644 --- a/src/fruit.h +++ b/src/fruit.hpp @@ -1,5 +1,5 @@ #pragma once -#include "entity.h" +#include "entity.hpp" #include "stdafx.h" namespace snake { diff --git a/src/main.cpp b/src/main.cpp index c3d1bbf..9c25bd4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,7 +1,7 @@ -#include "board.h" +#include "board.hpp" #include "stdafx.h" #include -#include "fenetre.h" +#include "fenetre.hpp" int main() { snake::Board board; diff --git a/src/point.cpp b/src/point.cpp index 915e5f7..0c3bc9d 100644 --- a/src/point.cpp +++ b/src/point.cpp @@ -1,4 +1,4 @@ -#include "point.h" +#include "point.hpp" namespace snake { diff --git a/src/point.h b/src/point.hpp similarity index 95% rename from src/point.h rename to src/point.hpp index ed21628..463d45f 100644 --- a/src/point.h +++ b/src/point.hpp @@ -1,6 +1,6 @@ #pragma once #include "stdafx.h" -#include "entity.h" +#include "entity.hpp" namespace snake { diff --git a/src/snake.cpp b/src/snake.cpp index 0c66bec..7e73483 100644 --- a/src/snake.cpp +++ b/src/snake.cpp @@ -1,4 +1,4 @@ -#include "snake.h" +#include "snake.hpp" namespace snake { diff --git a/src/snake.h b/src/snake.hpp similarity index 98% rename from src/snake.h rename to src/snake.hpp index b64dad5..9626bd7 100644 --- a/src/snake.h +++ b/src/snake.hpp @@ -1,6 +1,6 @@ #pragma once #include "stdafx.h" -#include "entity.h" +#include "entity.hpp" namespace snake { diff --git a/vc/snake.vcxproj b/vc/snake.vcxproj index c01ec68..4cfb252 100644 --- a/vc/snake.vcxproj +++ b/vc/snake.vcxproj @@ -148,12 +148,12 @@ - - - - - - + + + + + + diff --git a/vc/snake.vcxproj.filters b/vc/snake.vcxproj.filters index 7f883c3..a6e4b98 100644 --- a/vc/snake.vcxproj.filters +++ b/vc/snake.vcxproj.filters @@ -23,22 +23,22 @@ - + src - + src - + src - + src - + src - + src From f115a6981875222359bbae2c297cd2e450c46032 Mon Sep 17 00:00:00 2001 From: efool Date: Thu, 3 Jul 2025 13:29:08 -0400 Subject: [PATCH 07/17] fix precompiled header usage --- src/board.cpp | 4 +++- src/board.hpp | 4 ++-- src/entity.hpp | 1 - src/fenetre.cpp | 6 +++++- src/fenetre.hpp | 2 +- src/fruit.hpp | 2 +- src/main.cpp | 4 ++-- src/point.cpp | 2 ++ src/point.hpp | 2 +- src/snake.cpp | 2 ++ src/snake.hpp | 2 +- src/stdafx.h | 14 ++++++++------ vc/snake.vcxproj | 4 ++++ 13 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/board.cpp b/src/board.cpp index ab5ef1b..298f19d 100644 --- a/src/board.cpp +++ b/src/board.cpp @@ -1,6 +1,8 @@ +#include "stdafx.h" + #include "board.hpp" -#include "snake.hpp" #include "fruit.hpp" +#include "snake.hpp" namespace snake { diff --git a/src/board.hpp b/src/board.hpp index cfcfea2..b765cf7 100644 --- a/src/board.hpp +++ b/src/board.hpp @@ -1,8 +1,8 @@ #pragma once + +#include "fruit.hpp" #include "point.hpp" -#include "stdafx.h" #include "snake.hpp" -#include "fruit.hpp" namespace snake { diff --git a/src/entity.hpp b/src/entity.hpp index 7464863..0aae245 100644 --- a/src/entity.hpp +++ b/src/entity.hpp @@ -1,5 +1,4 @@ #pragma once -#include "stdafx.h" namespace snake { diff --git a/src/fenetre.cpp b/src/fenetre.cpp index 333d940..bee0220 100644 --- a/src/fenetre.cpp +++ b/src/fenetre.cpp @@ -1,5 +1,9 @@ -#include "fenetre.hpp" +#include "stdafx.h" + #include + +#include "fenetre.hpp" + #define TIMER_ID 1 namespace snake { diff --git a/src/fenetre.hpp b/src/fenetre.hpp index 138fb12..8d63861 100644 --- a/src/fenetre.hpp +++ b/src/fenetre.hpp @@ -1,5 +1,5 @@ #pragma once -#include "stdafx.h" + #include "board.hpp" #include "fruit.hpp" diff --git a/src/fruit.hpp b/src/fruit.hpp index bd08bd5..b0e2030 100644 --- a/src/fruit.hpp +++ b/src/fruit.hpp @@ -1,6 +1,6 @@ #pragma once + #include "entity.hpp" -#include "stdafx.h" namespace snake { diff --git a/src/main.cpp b/src/main.cpp index 9c25bd4..ca28ee5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,6 @@ -#include "board.hpp" #include "stdafx.h" -#include + +#include "board.hpp" #include "fenetre.hpp" int main() { diff --git a/src/point.cpp b/src/point.cpp index 0c3bc9d..08c6f45 100644 --- a/src/point.cpp +++ b/src/point.cpp @@ -1,3 +1,5 @@ +#include "stdafx.h" + #include "point.hpp" namespace snake { diff --git a/src/point.hpp b/src/point.hpp index 463d45f..6e08c9b 100644 --- a/src/point.hpp +++ b/src/point.hpp @@ -1,5 +1,5 @@ #pragma once -#include "stdafx.h" + #include "entity.hpp" namespace snake { diff --git a/src/snake.cpp b/src/snake.cpp index 7e73483..afeb7b8 100644 --- a/src/snake.cpp +++ b/src/snake.cpp @@ -1,3 +1,5 @@ +#include "stdafx.h" + #include "snake.hpp" namespace snake { diff --git a/src/snake.hpp b/src/snake.hpp index 9626bd7..283df5a 100644 --- a/src/snake.hpp +++ b/src/snake.hpp @@ -1,5 +1,5 @@ #pragma once -#include "stdafx.h" + #include "entity.hpp" namespace snake { diff --git a/src/stdafx.h b/src/stdafx.h index 0e44147..d0b3622 100644 --- a/src/stdafx.h +++ b/src/stdafx.h @@ -1,10 +1,12 @@ #pragma once -#include + +#include + +#include #include -#include #include -#include -#include #include -#include -#include \ No newline at end of file +#include +#include +#include +#include \ No newline at end of file diff --git a/vc/snake.vcxproj b/vc/snake.vcxproj index 4cfb252..9031eae 100644 --- a/vc/snake.vcxproj +++ b/vc/snake.vcxproj @@ -91,6 +91,7 @@ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpp17 + Create Console @@ -106,6 +107,7 @@ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpp17 + Create Console @@ -119,6 +121,7 @@ _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpp17 + Create Console @@ -134,6 +137,7 @@ NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpp17 + Create Console From ca802c85f0560acb62c1a65c98379943eb6a0095 Mon Sep 17 00:00:00 2001 From: efool Date: Thu, 3 Jul 2025 13:39:57 -0400 Subject: [PATCH 08/17] removed console --- src/board.cpp | 13 ------------- src/fenetre.cpp | 11 ++++------- src/fruit.hpp | 1 - src/main.cpp | 10 ++++++---- src/point.cpp | 7 ------- src/point.hpp | 2 -- src/snake.cpp | 10 +--------- src/snake.hpp | 2 -- src/stdafx.h | 2 -- vc/snake.vcxproj | 8 ++++---- 10 files changed, 15 insertions(+), 51 deletions(-) diff --git a/src/board.cpp b/src/board.cpp index 298f19d..5d9eb0c 100644 --- a/src/board.cpp +++ b/src/board.cpp @@ -32,21 +32,8 @@ Board::Board() void Board::renderBoard() { - int TotalSize = m_BoardSize * m_BoardSize; - system("cls"); //clear le terminal à chaque nouveau render - - for (int i = 0; i < TotalSize; i++) - { - m_Board[i]->render(); - - if ((i + 1) % m_BoardSize == 0) - { - std::cout << std::endl; - } - } } - std::shared_ptr Board::getSnake() const { for (auto& entity : m_Board) diff --git a/src/fenetre.cpp b/src/fenetre.cpp index bee0220..3aea38d 100644 --- a/src/fenetre.cpp +++ b/src/fenetre.cpp @@ -44,17 +44,16 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) frames = 0; lastTime = currentTime; - std::cout << "FPS: " << fps << std::endl; std::wstring fpsText = L"FPS: " + std::to_wstring(fps); std::wstring title = L"Snake - FPS: " + std::to_wstring(fps); SetWindowText(hwnd, title.c_str()); - TextOut(hdc, 10, 10, fpsText.c_str(), int(fpsText.length())); + TextOut(hdc, 10, 10, fpsText.c_str(), int(fpsText.length())); // todo: show every frame } } //HBRUSH CustomBrush = CreateSolidBrush(50);//def de la couleur du pinceau //FillRect(hdc, &ps.rcPaint, CustomBrush);//application de la peinture sur le background //DeleteObject(CustomBrush);//nettoyage du pinceau - + EndPaint(hwnd, &ps); } break; @@ -132,12 +131,10 @@ HWND CreateMainWindow(Board *board) CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, GetModuleHandle(NULL), board ); - if (hwnd == NULL) { - std::cout << "debug: echec de creation de la fenetre\n"; - exit(1); + if (hwnd != NULL) { + ShowWindow(hwnd, SW_SHOW); } - ShowWindow(hwnd, SW_SHOW); return hwnd; } diff --git a/src/fruit.hpp b/src/fruit.hpp index b0e2030..b458b12 100644 --- a/src/fruit.hpp +++ b/src/fruit.hpp @@ -10,7 +10,6 @@ class Fruit : public Entity Fruit(int pos) { this->Position = pos; } bool isCollidable() override { return true; }; void render() const override { - std::cout << "%"; } int getPoints() { return points; }; diff --git a/src/main.cpp b/src/main.cpp index ca28ee5..1a14022 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,15 +3,18 @@ #include "board.hpp" #include "fenetre.hpp" -int main() { +int WINAPI wWinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, PWSTR /*pCmdLine*/, int /*nCmdShow*/) +{ snake::Board board; - snake::Fenetre::CreateMainWindow(&board); + if (snake::Fenetre::CreateMainWindow(&board) == NULL) + { + return 1; + } std::shared_ptr snake = board.getSnake(); if (!snake) { - std::cout << "debug: snake pas trouvé\n\r"; return 1; } @@ -24,6 +27,5 @@ int main() { DispatchMessage(&msg); } - std::cout << "partie fini" << std::endl; return 0; } \ No newline at end of file diff --git a/src/point.cpp b/src/point.cpp index 08c6f45..a133877 100644 --- a/src/point.cpp +++ b/src/point.cpp @@ -11,11 +11,4 @@ Point::Point(int x, int y) this->Position = y * 16 + x; } -std::ostream& operator<<(std::ostream& os, const Point& /*point*/) -{ - //os << "Point(x: " << point.x << ", y: " << point.y << ", place: " << point.place << ")"; - os << 'o'; - return os; -} - } // namespace snake \ No newline at end of file diff --git a/src/point.hpp b/src/point.hpp index 6e08c9b..fe231a8 100644 --- a/src/point.hpp +++ b/src/point.hpp @@ -13,8 +13,6 @@ class Point : public Entity int getPosY() {return y;}; bool isCollidable() override { return false; }; void render() const override { - //system("color 0A"); - std::cout << "\033[32mo\033[0m"; } private: diff --git a/src/snake.cpp b/src/snake.cpp index afeb7b8..d9e28c7 100644 --- a/src/snake.cpp +++ b/src/snake.cpp @@ -23,7 +23,7 @@ void Snake::move(int direction) //gros pavé pour check si le joueur fait demi tour direct* //[TODO] rendre lisible et optimisé - direction = m_currentDirection; // on ignore si le joueur fait un 180° + direction = m_currentDirection; // on ignore si le joueur fait un 180° int head = m_Body.front(); int row = head / 16; int col = head % 16; @@ -46,7 +46,6 @@ void Snake::move(int direction) { if (newHead == m_Body[i]) { - std::cout << "Parti fini" << "\n"; exit(0); // on quitte pour l'instant //[TODO] faire un menu et un écran de fin } @@ -59,13 +58,6 @@ void Snake::move(int direction) m_Body[0] = newHead; Position = newHead; - -} - -std::ostream& operator<<(std::ostream& os, const Snake& /*snake*/) -{ - os << "~"; - return os; } } // namespace snake \ No newline at end of file diff --git a/src/snake.hpp b/src/snake.hpp index 283df5a..ed25eca 100644 --- a/src/snake.hpp +++ b/src/snake.hpp @@ -31,8 +31,6 @@ class Snake : public Entity void move(int direction); void render() const override { - //system("color 0C"); - std::cout << "\033[34m~\033[0m"; //ANSI code color pour changement de la couleur dans terminal } void setPosition(int pos) { position = pos; }; diff --git a/src/stdafx.h b/src/stdafx.h index d0b3622..897ea68 100644 --- a/src/stdafx.h +++ b/src/stdafx.h @@ -2,8 +2,6 @@ #include -#include -#include #include #include #include diff --git a/vc/snake.vcxproj b/vc/snake.vcxproj index 9031eae..1f8412d 100644 --- a/vc/snake.vcxproj +++ b/vc/snake.vcxproj @@ -94,7 +94,7 @@ Create - Console + Windows true @@ -110,7 +110,7 @@ Create - Console + Windows true @@ -124,7 +124,7 @@ Create - Console + Windows true @@ -140,7 +140,7 @@ Create - Console + Windows true From cf31a1b7b496b8a78da0ac30e2ac199b1ff284e8 Mon Sep 17 00:00:00 2001 From: efool Date: Thu, 3 Jul 2025 14:00:07 -0400 Subject: [PATCH 09/17] remove Entity::render --- src/board.cpp | 5 ----- src/board.hpp | 7 +++---- src/entity.hpp | 11 ++++++++--- src/fruit.hpp | 9 ++++++--- src/point.hpp | 16 +++++++++------- src/snake.hpp | 15 ++++++--------- vc/snake.vcxproj | 1 - vc/snake.vcxproj.filters | 3 --- 8 files changed, 32 insertions(+), 35 deletions(-) diff --git a/src/board.cpp b/src/board.cpp index 5d9eb0c..4750624 100644 --- a/src/board.cpp +++ b/src/board.cpp @@ -30,10 +30,6 @@ Board::Board() } } -void Board::renderBoard() -{ -} - std::shared_ptr Board::getSnake() const { for (auto& entity : m_Board) @@ -78,7 +74,6 @@ void Board::moveSnake(int direction) } } - std::shared_ptr Board::spawnFruit() { std::vector emptyPositions; diff --git a/src/board.hpp b/src/board.hpp index b765cf7..187024a 100644 --- a/src/board.hpp +++ b/src/board.hpp @@ -9,10 +9,10 @@ namespace snake { class Board { public: - Board(); - void renderBoard(); static int getBoardSize() { return m_BoardSize; }; static void setBoardSize(int Size) { m_BoardSize = Size; } + + Board(); std::shared_ptr getSnake() const; void moveSnake(int direction); const std::vector>& getEntities() const { return m_Board; } @@ -23,10 +23,9 @@ class Board } int getSnakeSegmentOrder(int index) const; - private: - std::vector>m_Board; static int m_BoardSize; + std::vector>m_Board; }; } // namespace snake \ No newline at end of file diff --git a/src/entity.hpp b/src/entity.hpp index 0aae245..5730d0a 100644 --- a/src/entity.hpp +++ b/src/entity.hpp @@ -6,14 +6,19 @@ class Entity { public: virtual ~Entity() = default; - virtual void render() const = 0; + + virtual bool isCollidable() { return false; }; int getPosition() const { return Position; } void setPosition(int pos) { Position = pos; } - virtual bool isCollidable() { return false; }; protected: - int Position; + Entity(int pos) + : Position(pos) + { + } + + int Position; }; } // namespace snake \ No newline at end of file diff --git a/src/fruit.hpp b/src/fruit.hpp index b458b12..7cbb837 100644 --- a/src/fruit.hpp +++ b/src/fruit.hpp @@ -7,10 +7,13 @@ namespace snake { class Fruit : public Entity { public: - Fruit(int pos) { this->Position = pos; } - bool isCollidable() override { return true; }; - void render() const override { + Fruit(int pos) + : Entity(pos) + { } + + bool isCollidable() override { return true; }; + int getPoints() { return points; }; private: diff --git a/src/point.hpp b/src/point.hpp index fe231a8..87a11bc 100644 --- a/src/point.hpp +++ b/src/point.hpp @@ -7,19 +7,21 @@ namespace snake { class Point : public Entity { public: - Point(int x, int y); + Point(int x, int y) + : Entity(y*16 + x) + , x(x) + , y(y) + { + } - int getPosX() {return x;}; - int getPosY() {return y;}; bool isCollidable() override { return false; }; - void render() const override { - } + + int getPosX() { return x; }; + int getPosY() { return y; }; private: int x, y; int Position = 0; - - friend std::ostream& operator<<(std::ostream& os, const Point& point); }; } // namespace snake \ No newline at end of file diff --git a/src/snake.hpp b/src/snake.hpp index ed25eca..a22c763 100644 --- a/src/snake.hpp +++ b/src/snake.hpp @@ -8,12 +8,13 @@ class Snake : public Entity { public: Snake(float speed, int score, int startPosition) - : m_Speed(speed), m_Score(score) + : Entity(startPosition) + , m_Speed(speed) + , m_Score(score) { m_Body.push_back(startPosition); - Position = startPosition; - isAlive = true; } + void addSegment(int count) { for (int i = 0; i < count; ++i) @@ -30,9 +31,6 @@ class Snake : public Entity void move(int direction); - void render() const override { - } - void setPosition(int pos) { position = pos; }; int getPosition() const { return m_Body[0]; } @@ -64,10 +62,9 @@ class Snake : public Entity int m_Score = 0; int m_currentDirection = 1; int m_nextDirection = 3; - bool isAlive; + bool isAlive = true; - std::vector m_Body;//liste des segments du serpent - friend std::ostream& operator<<(std::ostream& os, const Snake& snake); + std::vector m_Body; }; } // namespace snake \ No newline at end of file diff --git a/vc/snake.vcxproj b/vc/snake.vcxproj index 1f8412d..c6c91c3 100644 --- a/vc/snake.vcxproj +++ b/vc/snake.vcxproj @@ -148,7 +148,6 @@ - diff --git a/vc/snake.vcxproj.filters b/vc/snake.vcxproj.filters index a6e4b98..354667a 100644 --- a/vc/snake.vcxproj.filters +++ b/vc/snake.vcxproj.filters @@ -15,9 +15,6 @@ src - - src - src From af5f862b4db57461413ebfed71a0d758ac881b30 Mon Sep 17 00:00:00 2001 From: efool Date: Thu, 3 Jul 2025 14:24:30 -0400 Subject: [PATCH 10/17] refactor win32 code --- src/board.cpp | 4 +- src/fenetre.hpp | 13 ---- src/main.cpp | 5 +- src/{fenetre.cpp => win32.cpp} | 123 ++++++++++++++++----------------- src/win32.hpp | 12 ++++ vc/snake.vcxproj | 12 ++-- vc/snake.vcxproj.filters | 4 +- 7 files changed, 82 insertions(+), 91 deletions(-) delete mode 100644 src/fenetre.hpp rename src/{fenetre.cpp => win32.cpp} (58%) create mode 100644 src/win32.hpp diff --git a/src/board.cpp b/src/board.cpp index 4750624..de2dd9b 100644 --- a/src/board.cpp +++ b/src/board.cpp @@ -35,9 +35,9 @@ std::shared_ptr Board::getSnake() const for (auto& entity : m_Board) { std::shared_ptr snake = std::dynamic_pointer_cast(entity); - if (snake != nullptr) + if (snake != nullptr) { - return snake; + return snake; } } return nullptr; diff --git a/src/fenetre.hpp b/src/fenetre.hpp deleted file mode 100644 index 8d63861..0000000 --- a/src/fenetre.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "board.hpp" -#include "fruit.hpp" - -namespace snake::Fenetre { - -LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); - -HWND CreateMainWindow(Board* board); -void WNDRenderBoard(HWND hwnd, HDC hdc, const Board& board); - -} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 1a14022..bcffb9e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,13 +1,12 @@ #include "stdafx.h" #include "board.hpp" -#include "fenetre.hpp" +#include "win32.hpp" int WINAPI wWinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, PWSTR /*pCmdLine*/, int /*nCmdShow*/) { snake::Board board; - - if (snake::Fenetre::CreateMainWindow(&board) == NULL) + if (snake::win32::CreateMainWindow(board) == NULL) { return 1; } diff --git a/src/fenetre.cpp b/src/win32.cpp similarity index 58% rename from src/fenetre.cpp rename to src/win32.cpp index 3aea38d..50a1919 100644 --- a/src/fenetre.cpp +++ b/src/win32.cpp @@ -2,19 +2,22 @@ #include -#include "fenetre.hpp" +#include "board.hpp" +#include "win32.hpp" -#define TIMER_ID 1 +namespace snake::win32 { -namespace snake { +constexpr UINT_PTR TIMER_ID = 1; -using namespace std::chrono; - -namespace Fenetre { +namespace { + Board* board = nullptr; + int frames = 0; + int fps = 0; + auto lastTime = std::chrono::steady_clock::now(); + std::wstring fpsText; +} -int frames = 0; -int fps = 0; -auto lastTime = steady_clock::now(); +void WNDRenderBoard(HWND hwnd, HDC hdc); LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { @@ -29,57 +32,54 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps); - - Board* board = (Board*)GetWindowLongPtr(hwnd, GWLP_USERDATA); - if (board) - { - WNDRenderBoard(hwnd, hdc, *board); - frames++; - auto currentTime = steady_clock::now(); - auto elapsed = duration_cast(currentTime - lastTime).count(); + WNDRenderBoard(hwnd, hdc); + frames++; - if (elapsed >= 1) { - fps = frames; - frames = 0; - lastTime = currentTime; + auto currentTime = std::chrono::steady_clock::now(); + auto elapsed = std::chrono::duration_cast(currentTime - lastTime).count(); - std::wstring fpsText = L"FPS: " + std::to_wstring(fps); - std::wstring title = L"Snake - FPS: " + std::to_wstring(fps); - SetWindowText(hwnd, title.c_str()); - TextOut(hdc, 10, 10, fpsText.c_str(), int(fpsText.length())); // todo: show every frame - } + if (elapsed >= 1) { + fps = frames; + frames = 0; + lastTime = currentTime; + + fpsText = L"FPS: " + std::to_wstring(fps); + std::wstring title = L"Snake - FPS: " + std::to_wstring(fps); + SetWindowText(hwnd, title.c_str()); } - //HBRUSH CustomBrush = CreateSolidBrush(50);//def de la couleur du pinceau - //FillRect(hdc, &ps.rcPaint, CustomBrush);//application de la peinture sur le background - //DeleteObject(CustomBrush);//nettoyage du pinceau + TextOut(hdc, 10, 10, fpsText.c_str(), int(fpsText.length())); // todo: show every frame EndPaint(hwnd, &ps); } - break; + return 0; + case WM_CREATE: { - LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam; - Board* board = (Board*)pcs->lpCreateParams; - SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)board); auto speed = board->getSnake()->getSpeed(); SetTimer(hwnd, TIMER_ID, UINT(50 - speed), NULL); // todo: round? - } - break; + return 0; + case WM_KEYDOWN: { - Board* board = (Board*)GetWindowLongPtr(hwnd, GWLP_USERDATA); auto snake = board->getSnake(); int desiredDirection = snake->getCurrentDirection(); switch (wParam) { +#ifdef SNAKE_USE_CURSOR_KEYS + case VK_LEFT : desiredDirection = 1; break; + case VK_UP : desiredDirection = 2; break; + case VK_RIGHT: desiredDirection = 3; break; + case VK_DOWN : desiredDirection = 4; break; +#else case 'Q': desiredDirection = 1; break; case 'Z': desiredDirection = 2; break; case 'D': desiredDirection = 3; break; case 'S': desiredDirection = 4; break; +#endif } if (!snake->isOpposite(snake->getNextDirection(), desiredDirection)) @@ -87,40 +87,37 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) snake->setNextDirection(desiredDirection); } } - break; + return 0; case WM_TIMER: { - Board* board = (Board*)GetWindowLongPtr(hwnd, GWLP_USERDATA); - if (board) + auto snake = board->getSnake(); + if (snake->getAlive()) { - auto snake = board->getSnake(); - if (snake->getAlive()) - { - board->moveSnake(snake->getNextDirection()); + board->moveSnake(snake->getNextDirection()); + snake->setCurrentDirection(snake->getNextDirection()); - snake->setCurrentDirection(snake->getNextDirection()); - - InvalidateRect(hwnd, NULL, TRUE); - } - else - { - KillTimer(hwnd, TIMER_ID); - } + InvalidateRect(hwnd, NULL, TRUE); + } + else + { + KillTimer(hwnd, TIMER_ID); } } - break; + return 0; } return DefWindowProc(hwnd, uMsg, wParam, lParam); } -HWND CreateMainWindow(Board *board) +HWND CreateMainWindow(Board& board_) { + board = &board_; + const wchar_t CLASS_NAME[] = L"SnakeWindow"; WNDCLASS wc = {}; - wc.lpfnWndProc = Fenetre::WindowProc; + wc.lpfnWndProc = WindowProc; wc.hInstance = GetModuleHandle(NULL); wc.lpszClassName = CLASS_NAME; @@ -128,7 +125,7 @@ HWND CreateMainWindow(Board *board) HWND hwnd = CreateWindowEx( 0, CLASS_NAME, L"Snake", WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, GetModuleHandle(NULL), board + CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, GetModuleHandle(NULL), NULL ); if (hwnd != NULL) { @@ -138,7 +135,7 @@ HWND CreateMainWindow(Board *board) return hwnd; } -void Fenetre::WNDRenderBoard(HWND hwnd, HDC hdc, const Board& board) +void WNDRenderBoard(HWND hwnd, HDC hdc) { RECT clientRect; GetClientRect(hwnd, &clientRect); @@ -158,14 +155,13 @@ void Fenetre::WNDRenderBoard(HWND hwnd, HDC hdc, const Board& board) }; int index = row * Board::getBoardSize() + col; - std::shared_ptr entity = board.getEntityAt(index); - + std::shared_ptr entity = board->getEntityAt(index); HBRUSH brush = nullptr; if (std::dynamic_pointer_cast(entity)) { - int segmentOrder = board.getSnakeSegmentOrder(index); - int snakeLength = int(board.getSnake()->getBody().size()); + int segmentOrder = board->getSnakeSegmentOrder(index); + int snakeLength = int(board->getSnake()->getBody().size()); if (segmentOrder != -1 && snakeLength > 1) { @@ -197,8 +193,7 @@ void Fenetre::WNDRenderBoard(HWND hwnd, HDC hdc, const Board& board) DeleteObject(brush); SetBkMode(hdc, TRANSPARENT); - - int segmentOrder = board.getSnakeSegmentOrder(index); + int segmentOrder = board->getSnakeSegmentOrder(index); if (segmentOrder != -1) { std::wstring text = std::to_wstring(segmentOrder); DrawText(hdc, text.c_str(), -1, &square, DT_CENTER | DT_VCENTER | DT_SINGLELINE); @@ -207,6 +202,4 @@ void Fenetre::WNDRenderBoard(HWND hwnd, HDC hdc, const Board& board) } } -} - -} // namespace snake \ No newline at end of file +} // namespace snake::win32 \ No newline at end of file diff --git a/src/win32.hpp b/src/win32.hpp new file mode 100644 index 0000000..0db6de0 --- /dev/null +++ b/src/win32.hpp @@ -0,0 +1,12 @@ +#pragma once + +namespace snake { + + class Board; + + namespace win32 { + +HWND CreateMainWindow(Board& board); + + } // namespace win32 +} // namespace snake \ No newline at end of file diff --git a/vc/snake.vcxproj b/vc/snake.vcxproj index c6c91c3..522a4b8 100644 --- a/vc/snake.vcxproj +++ b/vc/snake.vcxproj @@ -88,7 +88,7 @@ Level4 true - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);SNAKE_USE_CURSOR_KEYS true stdcpp17 Create @@ -104,7 +104,7 @@ true true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);SNAKE_USE_CURSOR_KEYS true stdcpp17 Create @@ -118,7 +118,7 @@ Level4 true - _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + _DEBUG;_CONSOLE;%(PreprocessorDefinitions);SNAKE_USE_CURSOR_KEYS true stdcpp17 Create @@ -134,7 +134,7 @@ true true true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions);SNAKE_USE_CURSOR_KEYS true stdcpp17 Create @@ -146,14 +146,14 @@ - + - + diff --git a/vc/snake.vcxproj.filters b/vc/snake.vcxproj.filters index 354667a..98f45b5 100644 --- a/vc/snake.vcxproj.filters +++ b/vc/snake.vcxproj.filters @@ -9,7 +9,7 @@ src - + src @@ -26,7 +26,7 @@ src - + src From 38451fb0fbf77fef9e8524058a2f104eb153661b Mon Sep 17 00:00:00 2001 From: efool Date: Thu, 3 Jul 2025 15:33:18 -0400 Subject: [PATCH 11/17] Begin removing shared_ptr --- src/board.cpp | 104 +++++++++++++++++---------------------- src/board.hpp | 28 +++++++---- src/main.cpp | 8 --- src/snake.hpp | 10 ++-- src/stdafx.h | 8 ++- src/util.hpp | 3 ++ src/win32.cpp | 27 +++++----- vc/snake.vcxproj | 1 + vc/snake.vcxproj.filters | 3 ++ 9 files changed, 94 insertions(+), 98 deletions(-) create mode 100644 src/util.hpp diff --git a/src/board.cpp b/src/board.cpp index de2dd9b..01fb6f9 100644 --- a/src/board.cpp +++ b/src/board.cpp @@ -7,105 +7,89 @@ namespace snake { int Board::m_BoardSize = 16; -std::random_device rd; -std::mt19937 gen(rd()); + +namespace { + std::random_device rd; + std::mt19937 gen(rd()); +} Board::Board() + : m_snake(5.0f, 1, 150) + , m_fruit(0) + , m_Board(m_BoardSize * m_BoardSize) { - for (int x = 0; x < m_BoardSize; x++) - { - for (int y = 0; y < m_BoardSize; y++) - { - int current = x * 16 + y; - - if (current == (m_BoardSize * m_BoardSize) / 2) - { - m_Board.push_back(std::make_shared(5.0f, 1, 150)); - } - else - { - m_Board.push_back(std::make_shared(y, x)); - } - } - } + m_Board[m_snake.getPosition()] = Entity::snake; + spawnFruit(); } -std::shared_ptr Board::getSnake() const +Entity const& Board::getEntityAt(int index) const { - for (auto& entity : m_Board) - { - std::shared_ptr snake = std::dynamic_pointer_cast(entity); - if (snake != nullptr) - { - return snake; - } + static Point pt {0, 0}; + + switch (m_Board[index]) { + case Entity::none: pt.setPosition(index); return pt; + case Entity::snake: return m_snake; + case Entity::fruit: return m_fruit; } - return nullptr; + SNAKE_UNREACHABLE; } void Board::moveSnake(int direction) { - std::shared_ptr snake = getSnake(); - if (!snake) return; - - std::vector oldBody = snake->getBody(); + std::vector oldBody = m_snake.getBody(); - snake->move(direction); + m_snake.move(direction); - int newHeadPosition = snake->getPosition(); + int newHeadPosition = m_snake.getPosition(); - if (std::dynamic_pointer_cast(m_Board[newHeadPosition])) + if (newHeadPosition == m_fruit.getPosition()) { - auto fruit = spawnFruit(); - snake->addSegment(1); - snake->addScore(fruit->getPoints()); + spawnFruit(); + m_snake.addSegment(1); + m_snake.addScore(m_fruit.getPoints()); } for (int pos : oldBody) { - int oldY = pos / m_BoardSize; - int oldX = pos % m_BoardSize; - m_Board[pos] = std::make_shared(oldX, oldY); + m_Board[pos] = Entity::none; } - for (int pos : snake->getBody()) + for (int pos : m_snake.getBody()) { - m_Board[pos] = snake; + m_Board[pos] = Entity::snake; } } -std::shared_ptr Board::spawnFruit() +int Board::getSnakeSegmentOrder(int index) +{ + const auto& body = getSnake().getBody(); + for (size_t i = 0; i < body.size(); ++i) { + if (body[i] == index) + return static_cast(i); + } + return -1; +} + +Fruit const& Board::spawnFruit() { std::vector emptyPositions; for (int i = 0; i < int(m_Board.size()); i++) { - if (std::dynamic_pointer_cast(m_Board[i])) + if (m_Board[i] == Entity::none) { emptyPositions.push_back(i); } } - if (emptyPositions.empty()) return nullptr; + assert(!emptyPositions.empty()); // todo: win? std::uniform_int_distribution<> distrib(0, int(emptyPositions.size()) - 1); int chosenIndex = emptyPositions[distrib(gen)]; - m_Board[chosenIndex] = std::make_shared(chosenIndex); - return std::dynamic_pointer_cast(m_Board[chosenIndex]); -} - -int Board::getSnakeSegmentOrder(int index) const -{ - auto snake = getSnake(); - - const auto& body = snake->getBody(); - - for (size_t i = 0; i < body.size(); ++i) { - if (body[i] == index) - return static_cast(i); - } - return -1; + m_fruit.setPosition(chosenIndex); + m_Board[chosenIndex] = Entity::fruit; + return m_fruit; } } // namespace snake \ No newline at end of file diff --git a/src/board.hpp b/src/board.hpp index 187024a..3c59dbf 100644 --- a/src/board.hpp +++ b/src/board.hpp @@ -10,22 +10,30 @@ class Board { public: static int getBoardSize() { return m_BoardSize; }; - static void setBoardSize(int Size) { m_BoardSize = Size; } + static void setBoardSize(int Size) { m_BoardSize = Size; } // todo: this is broken Board(); - std::shared_ptr getSnake() const; + + Entity const& getEntityAt(int index) const; + + Snake& getSnake() { return m_snake; } void moveSnake(int direction); - const std::vector>& getEntities() const { return m_Board; } - std::shared_ptr spawnFruit(); - std::shared_ptr getEntityAt(int index) const - { - return m_Board[index]; - } - int getSnakeSegmentOrder(int index) const; + int getSnakeSegmentOrder(int index); + + Fruit const& spawnFruit(); private: static int m_BoardSize; - std::vector>m_Board; + + Snake m_snake; + Fruit m_fruit; + + enum class Entity { + none, + snake, + fruit, + }; + std::vector m_Board; }; } // namespace snake \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index bcffb9e..cb374e2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,14 +11,6 @@ int WINAPI wWinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, PWSTR return 1; } - std::shared_ptr snake = board.getSnake(); - if (!snake) - { - return 1; - } - - board.spawnFruit(); - MSG msg = {}; while (GetMessage(&msg, NULL, 0, 0)) { diff --git a/src/snake.hpp b/src/snake.hpp index a22c763..5bf3646 100644 --- a/src/snake.hpp +++ b/src/snake.hpp @@ -27,7 +27,7 @@ class Snake : public Entity void removeSpeed(float speed); - float getSpeed() { return m_Speed; }; + float getSpeed() const { return m_Speed; }; void move(int direction); @@ -40,14 +40,14 @@ class Snake : public Entity void addScore(int score) { this->m_Score += score; }; int getScore() { return m_Score; }; - std::vector getBody() { return m_Body; }; + std::vector getBody() const { return m_Body; }; int wrap(int value, int max); bool getAlive() { return isAlive; }; void setCurrentDirection(int direction) {this->m_currentDirection = direction;}; - int getCurrentDirection() { return m_currentDirection; }; + int getCurrentDirection() const { return m_currentDirection; }; void setNextDirection(int nextDirection) {this->m_nextDirection = nextDirection; }; - int getNextDirection() { return m_nextDirection; }; - bool isOpposite(int dir1, int dir2) { + int getNextDirection() const { return m_nextDirection; }; + bool isOpposite(int dir1, int dir2) const { return (dir1 == 1 && dir2 == 3) || (dir1 == 3 && dir2 == 1) || (dir1 == 2 && dir2 == 4) || (dir1 == 4 && dir2 == 2); } diff --git a/src/stdafx.h b/src/stdafx.h index 897ea68..b7539ec 100644 --- a/src/stdafx.h +++ b/src/stdafx.h @@ -2,9 +2,15 @@ #include +#include +#include +#include + #include #include #include #include #include -#include \ No newline at end of file +#include + +#include "util.hpp" \ No newline at end of file diff --git a/src/util.hpp b/src/util.hpp new file mode 100644 index 0000000..fc0a0a6 --- /dev/null +++ b/src/util.hpp @@ -0,0 +1,3 @@ +#pragma once + +#define SNAKE_UNREACHABLE __assume(0) \ No newline at end of file diff --git a/src/win32.cpp b/src/win32.cpp index 50a1919..6d08f76 100644 --- a/src/win32.cpp +++ b/src/win32.cpp @@ -56,16 +56,15 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) case WM_CREATE: { - auto speed = board->getSnake()->getSpeed(); + auto speed = board->getSnake().getSpeed(); SetTimer(hwnd, TIMER_ID, UINT(50 - speed), NULL); // todo: round? } return 0; case WM_KEYDOWN: { - auto snake = board->getSnake(); - - int desiredDirection = snake->getCurrentDirection(); + auto& snake = board->getSnake(); + int desiredDirection = snake.getCurrentDirection(); switch (wParam) { @@ -82,20 +81,20 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) #endif } - if (!snake->isOpposite(snake->getNextDirection(), desiredDirection)) + if (!snake.isOpposite(snake.getNextDirection(), desiredDirection)) { - snake->setNextDirection(desiredDirection); + snake.setNextDirection(desiredDirection); } } return 0; case WM_TIMER: { - auto snake = board->getSnake(); - if (snake->getAlive()) + auto& snake = board->getSnake(); + if (snake.getAlive()) { - board->moveSnake(snake->getNextDirection()); - snake->setCurrentDirection(snake->getNextDirection()); + board->moveSnake(snake.getNextDirection()); + snake.setCurrentDirection(snake.getNextDirection()); InvalidateRect(hwnd, NULL, TRUE); } @@ -155,13 +154,13 @@ void WNDRenderBoard(HWND hwnd, HDC hdc) }; int index = row * Board::getBoardSize() + col; - std::shared_ptr entity = board->getEntityAt(index); + Entity const& entity = board->getEntityAt(index); HBRUSH brush = nullptr; - if (std::dynamic_pointer_cast(entity)) + if (dynamic_cast(&entity)) { int segmentOrder = board->getSnakeSegmentOrder(index); - int snakeLength = int(board->getSnake()->getBody().size()); + int snakeLength = int(board->getSnake().getBody().size()); if (segmentOrder != -1 && snakeLength > 1) { @@ -180,7 +179,7 @@ void WNDRenderBoard(HWND hwnd, HDC hdc) brush = CreateSolidBrush(RGB(0, 0, 255)); //bleu si ça bug } } - else if (std::dynamic_pointer_cast(entity)) + else if (dynamic_cast(&entity)) { brush = CreateSolidBrush(RGB(255, 0, 0)); } diff --git a/vc/snake.vcxproj b/vc/snake.vcxproj index 522a4b8..9e6a072 100644 --- a/vc/snake.vcxproj +++ b/vc/snake.vcxproj @@ -153,6 +153,7 @@ + diff --git a/vc/snake.vcxproj.filters b/vc/snake.vcxproj.filters index 98f45b5..a8dc2f8 100644 --- a/vc/snake.vcxproj.filters +++ b/vc/snake.vcxproj.filters @@ -41,5 +41,8 @@ src + + src + \ No newline at end of file From f1aa2b505e5f5d4c4c3e61f6a6670f825bc753cc Mon Sep 17 00:00:00 2001 From: efool Date: Thu, 3 Jul 2025 15:40:54 -0400 Subject: [PATCH 12/17] Entity no longer virtual Removed Point entity --- src/board.cpp | 12 ------------ src/board.hpp | 14 +++++++------- src/entity.hpp | 4 ---- src/fruit.hpp | 2 -- src/point.cpp | 14 -------------- src/point.hpp | 27 --------------------------- src/snake.hpp | 2 -- src/win32.cpp | 6 +++--- vc/snake.vcxproj | 1 - vc/snake.vcxproj.filters | 3 --- 10 files changed, 10 insertions(+), 75 deletions(-) delete mode 100644 src/point.cpp delete mode 100644 src/point.hpp diff --git a/src/board.cpp b/src/board.cpp index 01fb6f9..e42edd6 100644 --- a/src/board.cpp +++ b/src/board.cpp @@ -22,18 +22,6 @@ Board::Board() spawnFruit(); } -Entity const& Board::getEntityAt(int index) const -{ - static Point pt {0, 0}; - - switch (m_Board[index]) { - case Entity::none: pt.setPosition(index); return pt; - case Entity::snake: return m_snake; - case Entity::fruit: return m_fruit; - } - SNAKE_UNREACHABLE; -} - void Board::moveSnake(int direction) { std::vector oldBody = m_snake.getBody(); diff --git a/src/board.hpp b/src/board.hpp index 3c59dbf..16e09ca 100644 --- a/src/board.hpp +++ b/src/board.hpp @@ -1,7 +1,6 @@ #pragma once #include "fruit.hpp" -#include "point.hpp" #include "snake.hpp" namespace snake { @@ -14,7 +13,13 @@ class Board Board(); - Entity const& getEntityAt(int index) const; + enum class Entity { + none, + snake, + fruit, + }; + + Entity const& getEntityAt(int index) const { return m_Board[index]; } Snake& getSnake() { return m_snake; } void moveSnake(int direction); @@ -28,11 +33,6 @@ class Board Snake m_snake; Fruit m_fruit; - enum class Entity { - none, - snake, - fruit, - }; std::vector m_Board; }; diff --git a/src/entity.hpp b/src/entity.hpp index 5730d0a..b4e71b0 100644 --- a/src/entity.hpp +++ b/src/entity.hpp @@ -5,10 +5,6 @@ namespace snake { class Entity { public: - virtual ~Entity() = default; - - virtual bool isCollidable() { return false; }; - int getPosition() const { return Position; } void setPosition(int pos) { Position = pos; } diff --git a/src/fruit.hpp b/src/fruit.hpp index 7cbb837..4cffc94 100644 --- a/src/fruit.hpp +++ b/src/fruit.hpp @@ -12,8 +12,6 @@ class Fruit : public Entity { } - bool isCollidable() override { return true; }; - int getPoints() { return points; }; private: diff --git a/src/point.cpp b/src/point.cpp deleted file mode 100644 index a133877..0000000 --- a/src/point.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "stdafx.h" - -#include "point.hpp" - -namespace snake { - -Point::Point(int x, int y) -{ - this->x = x; - this->y = y; - this->Position = y * 16 + x; -} - -} // namespace snake \ No newline at end of file diff --git a/src/point.hpp b/src/point.hpp deleted file mode 100644 index 87a11bc..0000000 --- a/src/point.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include "entity.hpp" - -namespace snake { - -class Point : public Entity -{ -public: - Point(int x, int y) - : Entity(y*16 + x) - , x(x) - , y(y) - { - } - - bool isCollidable() override { return false; }; - - int getPosX() { return x; }; - int getPosY() { return y; }; - -private: - int x, y; - int Position = 0; -}; - -} // namespace snake \ No newline at end of file diff --git a/src/snake.hpp b/src/snake.hpp index 5bf3646..0de74b4 100644 --- a/src/snake.hpp +++ b/src/snake.hpp @@ -35,8 +35,6 @@ class Snake : public Entity int getPosition() const { return m_Body[0]; } - bool isCollidable() override { return true; }; - void addScore(int score) { this->m_Score += score; }; int getScore() { return m_Score; }; diff --git a/src/win32.cpp b/src/win32.cpp index 6d08f76..5adcb15 100644 --- a/src/win32.cpp +++ b/src/win32.cpp @@ -154,10 +154,10 @@ void WNDRenderBoard(HWND hwnd, HDC hdc) }; int index = row * Board::getBoardSize() + col; - Entity const& entity = board->getEntityAt(index); + auto entity = board->getEntityAt(index); HBRUSH brush = nullptr; - if (dynamic_cast(&entity)) + if (entity == Board::Entity::snake) { int segmentOrder = board->getSnakeSegmentOrder(index); int snakeLength = int(board->getSnake().getBody().size()); @@ -179,7 +179,7 @@ void WNDRenderBoard(HWND hwnd, HDC hdc) brush = CreateSolidBrush(RGB(0, 0, 255)); //bleu si ça bug } } - else if (dynamic_cast(&entity)) + else if (entity == Board::Entity::fruit) { brush = CreateSolidBrush(RGB(255, 0, 0)); } diff --git a/vc/snake.vcxproj b/vc/snake.vcxproj index 9e6a072..5f162b2 100644 --- a/vc/snake.vcxproj +++ b/vc/snake.vcxproj @@ -156,7 +156,6 @@ - diff --git a/vc/snake.vcxproj.filters b/vc/snake.vcxproj.filters index a8dc2f8..755d3b1 100644 --- a/vc/snake.vcxproj.filters +++ b/vc/snake.vcxproj.filters @@ -32,9 +32,6 @@ src - - src - src From 637b56d5721be09f5d4e4664462f56bf8c2cb8d0 Mon Sep 17 00:00:00 2001 From: efool Date: Thu, 3 Jul 2025 16:38:25 -0400 Subject: [PATCH 13/17] Refactor typing for positions and directions --- src/board.cpp | 50 +++++++++++++++++----------------------- src/board.hpp | 21 ++++------------- src/entity.hpp | 60 +++++++++++++++++++++++++++++++++++++++++++----- src/fruit.hpp | 9 ++++---- src/snake.cpp | 20 +++++++--------- src/snake.hpp | 48 +++++++++++++++++--------------------- src/win32.cpp | 34 +++++++++++++-------------- vc/snake.vcxproj | 8 +++---- 8 files changed, 134 insertions(+), 116 deletions(-) diff --git a/src/board.cpp b/src/board.cpp index e42edd6..13d40ef 100644 --- a/src/board.cpp +++ b/src/board.cpp @@ -6,66 +6,61 @@ namespace snake { -int Board::m_BoardSize = 16; - namespace { std::random_device rd; std::mt19937 gen(rd()); } Board::Board() - : m_snake(5.0f, 1, 150) - , m_fruit(0) - , m_Board(m_BoardSize * m_BoardSize) + : m_snake(5.0f, 1, Index{150}) + , m_fruit(Index{0}) + , m_board(boardSize * boardSize) { - m_Board[m_snake.getPosition()] = Entity::snake; + m_board[m_snake.getPosition().idx] = Entity::Kind::snake; spawnFruit(); } -void Board::moveSnake(int direction) +void Board::moveSnake(Direction direction) { - std::vector oldBody = m_snake.getBody(); + auto oldBody = m_snake.getBody(); m_snake.move(direction); - - int newHeadPosition = m_snake.getPosition(); - - if (newHeadPosition == m_fruit.getPosition()) + if (m_snake.getPosition() == m_fruit.pos) { spawnFruit(); m_snake.addSegment(1); - m_snake.addScore(m_fruit.getPoints()); + m_snake.addScore(m_fruit.points); } - for (int pos : oldBody) + for (auto pos : oldBody) { - m_Board[pos] = Entity::none; + m_board[pos.idx] = Entity::Kind::none; } - for (int pos : m_snake.getBody()) + for (auto pos : m_snake.getBody()) { - m_Board[pos] = Entity::snake; + m_board[pos.idx] = Entity::Kind::snake; } } -int Board::getSnakeSegmentOrder(int index) +int Board::getSnakeSegmentOrder(Index index) { const auto& body = getSnake().getBody(); for (size_t i = 0; i < body.size(); ++i) { if (body[i] == index) - return static_cast(i); + return static_cast(i); } return -1; } -Fruit const& Board::spawnFruit() +void Board::spawnFruit() { - std::vector emptyPositions; - for (int i = 0; i < int(m_Board.size()); i++) + std::vector emptyPositions; + for (int i = 0; i < int(m_board.size()); i++) { - if (m_Board[i] == Entity::none) + if (m_board[i] == Entity::Kind::none) { - emptyPositions.push_back(i); + emptyPositions.push_back(Index{i}); } } @@ -73,11 +68,8 @@ Fruit const& Board::spawnFruit() std::uniform_int_distribution<> distrib(0, int(emptyPositions.size()) - 1); - int chosenIndex = emptyPositions[distrib(gen)]; - - m_fruit.setPosition(chosenIndex); - m_Board[chosenIndex] = Entity::fruit; - return m_fruit; + m_fruit.pos = emptyPositions[distrib(gen)]; + m_board[m_fruit.pos.idx] = Entity::Kind::fruit; } } // namespace snake \ No newline at end of file diff --git a/src/board.hpp b/src/board.hpp index 16e09ca..63f7112 100644 --- a/src/board.hpp +++ b/src/board.hpp @@ -8,32 +8,21 @@ namespace snake { class Board { public: - static int getBoardSize() { return m_BoardSize; }; - static void setBoardSize(int Size) { m_BoardSize = Size; } // todo: this is broken - Board(); - enum class Entity { - none, - snake, - fruit, - }; - - Entity const& getEntityAt(int index) const { return m_Board[index]; } + Entity::Kind getEntityAt(Index index) const { return m_board[index.idx]; } Snake& getSnake() { return m_snake; } - void moveSnake(int direction); - int getSnakeSegmentOrder(int index); + void moveSnake(Direction direction); + int getSnakeSegmentOrder(Index index); - Fruit const& spawnFruit(); + void spawnFruit(); private: - static int m_BoardSize; - Snake m_snake; Fruit m_fruit; - std::vector m_Board; + std::vector m_board; }; } // namespace snake \ No newline at end of file diff --git a/src/entity.hpp b/src/entity.hpp index b4e71b0..48ad12f 100644 --- a/src/entity.hpp +++ b/src/entity.hpp @@ -2,19 +2,67 @@ namespace snake { +constexpr int boardSize = 16; + +struct Index; + +struct Pos { + int x; + int y; + + Pos(int x, int y) : x(x), y(y) {} + Pos(int index) : x(index % boardSize), y(index / boardSize) {} + Pos(Index index); + + void wrap() { + x = (x + boardSize) % boardSize; + y = (y + boardSize) % boardSize; + } +}; + +struct Index { + int idx; + + Index(int idx) : idx(idx) {} + Index(int x, int y) : idx(y * boardSize + x) {} + Index(Pos p) : Index(p.x, p.y) {} + + constexpr bool operator==(Index const&) const noexcept = default; +}; + +inline Pos::Pos(Index index) : Pos(index.idx) {} + +enum class Direction { + left, + up, + right, + down, +}; + +constexpr bool isOpposite(Direction dir1, Direction dir2) noexcept +{ + return (dir1 == Direction::left && dir2 == Direction::right) + || (dir1 == Direction::right && dir2 == Direction::left ) + || (dir1 == Direction::up && dir2 == Direction::down ) + || (dir1 == Direction::down && dir2 == Direction::up ); +} + class Entity { public: - int getPosition() const { return Position; } - void setPosition(int pos) { Position = pos; } + enum class Kind : char { + none, + snake, + fruit, + }; + + Kind const kind; protected: - Entity(int pos) - : Position(pos) + Entity(Kind kind) + : kind(kind) { } - - int Position; }; } // namespace snake \ No newline at end of file diff --git a/src/fruit.hpp b/src/fruit.hpp index 4cffc94..10e8c3c 100644 --- a/src/fruit.hpp +++ b/src/fruit.hpp @@ -7,14 +7,13 @@ namespace snake { class Fruit : public Entity { public: - Fruit(int pos) - : Entity(pos) + Fruit(Index pos) + : Entity(Kind::fruit) + , pos(pos) { } - int getPoints() { return points; }; - -private: + Index pos; int points = 1000; }; diff --git a/src/snake.cpp b/src/snake.cpp index d9e28c7..1947ffb 100644 --- a/src/snake.cpp +++ b/src/snake.cpp @@ -18,28 +18,25 @@ int Snake::wrap(int value, int max) { return (value + max) % max; } -void Snake::move(int direction) +void Snake::move(Direction direction) { //gros pavé pour check si le joueur fait demi tour direct* //[TODO] rendre lisible et optimisé direction = m_currentDirection; // on ignore si le joueur fait un 180° - int head = m_Body.front(); - int row = head / 16; - int col = head % 16; + Pos p = m_Body.front(); switch (direction) { - case 1: col--; break; - case 2: row--; break; - case 3: col++; break; - case 4: row++; break; + case Direction::left : p.x--; break; + case Direction::up : p.y--; break; + case Direction::right: p.x++; break; + case Direction::down : p.y++; break; } - row = wrap(row, 16); - col = wrap(col, 16); + p.wrap(); - int newHead = row * 16 + col; + Index newHead = p; // check la collision on skip la tete sinon probleme for (size_t i = 1; i < m_Body.size(); ++i) @@ -57,7 +54,6 @@ void Snake::move(int direction) } m_Body[0] = newHead; - Position = newHead; } } // namespace snake \ No newline at end of file diff --git a/src/snake.hpp b/src/snake.hpp index 0de74b4..f677a16 100644 --- a/src/snake.hpp +++ b/src/snake.hpp @@ -7,12 +7,12 @@ namespace snake { class Snake : public Entity { public: - Snake(float speed, int score, int startPosition) - : Entity(startPosition) + Snake(float speed, int score, Index pos) + : Entity(Kind::snake) , m_Speed(speed) , m_Score(score) { - m_Body.push_back(startPosition); + m_Body.push_back(pos); } void addSegment(int count) @@ -24,31 +24,25 @@ class Snake : public Entity } void addSpeed(float speed); - void removeSpeed(float speed); - - float getSpeed() const { return m_Speed; }; - - void move(int direction); - - void setPosition(int pos) { position = pos; }; - - int getPosition() const { return m_Body[0]; } + float getSpeed() const { return m_Speed; } - void addScore(int score) { this->m_Score += score; }; + void move(Direction direction); + Index getPosition() const { return m_Body[0]; } - int getScore() { return m_Score; }; - std::vector getBody() const { return m_Body; }; + void addScore(int score) { this->m_Score += score; } + int getScore() { return m_Score; } + + std::vector getBody() const { return m_Body; } + int wrap(int value, int max); - bool getAlive() { return isAlive; }; - void setCurrentDirection(int direction) {this->m_currentDirection = direction;}; - int getCurrentDirection() const { return m_currentDirection; }; - void setNextDirection(int nextDirection) {this->m_nextDirection = nextDirection; }; - int getNextDirection() const { return m_nextDirection; }; - bool isOpposite(int dir1, int dir2) const { - return (dir1 == 1 && dir2 == 3) || (dir1 == 3 && dir2 == 1) || - (dir1 == 2 && dir2 == 4) || (dir1 == 4 && dir2 == 2); - } + + bool getAlive() { return isAlive; } + + void setCurrentDirection(Direction direction) { this->m_currentDirection = direction; } + Direction getCurrentDirection() const { return m_currentDirection; } + void setNextDirection(Direction nextDirection) { this->m_nextDirection = nextDirection; } + Direction getNextDirection() const { return m_nextDirection; } bool canChangeDirection = true; @@ -58,11 +52,11 @@ class Snake : public Entity int position; const int _OFFSET = 16; int m_Score = 0; - int m_currentDirection = 1; - int m_nextDirection = 3; + Direction m_currentDirection = Direction::left; + Direction m_nextDirection = Direction::right; bool isAlive = true; - std::vector m_Body; + std::vector m_Body; }; } // namespace snake \ No newline at end of file diff --git a/src/win32.cpp b/src/win32.cpp index 5adcb15..aff1d3c 100644 --- a/src/win32.cpp +++ b/src/win32.cpp @@ -64,24 +64,24 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) case WM_KEYDOWN: { auto& snake = board->getSnake(); - int desiredDirection = snake.getCurrentDirection(); + auto desiredDirection = snake.getCurrentDirection(); switch (wParam) { #ifdef SNAKE_USE_CURSOR_KEYS - case VK_LEFT : desiredDirection = 1; break; - case VK_UP : desiredDirection = 2; break; - case VK_RIGHT: desiredDirection = 3; break; - case VK_DOWN : desiredDirection = 4; break; + case VK_LEFT : desiredDirection = Direction::left ; break; + case VK_UP : desiredDirection = Direction::up ; break; + case VK_RIGHT: desiredDirection = Direction::right; break; + case VK_DOWN : desiredDirection = Direction::down ; break; #else - case 'Q': desiredDirection = 1; break; - case 'Z': desiredDirection = 2; break; - case 'D': desiredDirection = 3; break; - case 'S': desiredDirection = 4; break; + case 'Q': desiredDirection = Direction::left ; break; + case 'Z': desiredDirection = Direction::up ; break; + case 'D': desiredDirection = Direction::right; break; + case 'S': desiredDirection = Direction::down ; break; #endif } - if (!snake.isOpposite(snake.getNextDirection(), desiredDirection)) + if (!isOpposite(snake.getNextDirection(), desiredDirection)) { snake.setNextDirection(desiredDirection); } @@ -139,12 +139,12 @@ void WNDRenderBoard(HWND hwnd, HDC hdc) RECT clientRect; GetClientRect(hwnd, &clientRect); - int squareWidth = clientRect.right / Board::getBoardSize(); - int squareHeight = clientRect.bottom / Board::getBoardSize(); + int squareWidth = clientRect.right / boardSize; + int squareHeight = clientRect.bottom / boardSize; - for (int row = 0; row < Board::getBoardSize(); ++row) + for (int row = 0; row < boardSize; ++row) { - for (int col = 0; col < Board::getBoardSize(); ++col) + for (int col = 0; col < boardSize; ++col) { RECT square = { col * squareWidth, @@ -153,11 +153,11 @@ void WNDRenderBoard(HWND hwnd, HDC hdc) (row + 1) * squareHeight }; - int index = row * Board::getBoardSize() + col; + Index index { col, row }; auto entity = board->getEntityAt(index); HBRUSH brush = nullptr; - if (entity == Board::Entity::snake) + if (entity == Entity::Kind::snake) { int segmentOrder = board->getSnakeSegmentOrder(index); int snakeLength = int(board->getSnake().getBody().size()); @@ -179,7 +179,7 @@ void WNDRenderBoard(HWND hwnd, HDC hdc) brush = CreateSolidBrush(RGB(0, 0, 255)); //bleu si ça bug } } - else if (entity == Board::Entity::fruit) + else if (entity == Entity::Kind::fruit) { brush = CreateSolidBrush(RGB(255, 0, 0)); } diff --git a/vc/snake.vcxproj b/vc/snake.vcxproj index 5f162b2..0092e51 100644 --- a/vc/snake.vcxproj +++ b/vc/snake.vcxproj @@ -90,7 +90,7 @@ true WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);SNAKE_USE_CURSOR_KEYS true - stdcpp17 + stdcpp20 Create @@ -106,7 +106,7 @@ true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);SNAKE_USE_CURSOR_KEYS true - stdcpp17 + stdcpp20 Create @@ -120,7 +120,7 @@ true _DEBUG;_CONSOLE;%(PreprocessorDefinitions);SNAKE_USE_CURSOR_KEYS true - stdcpp17 + stdcpp20 Create @@ -136,7 +136,7 @@ true NDEBUG;_CONSOLE;%(PreprocessorDefinitions);SNAKE_USE_CURSOR_KEYS true - stdcpp17 + stdcpp20 Create From 65d45d4e4934a36bf51afcb3c911deb879fdbb7e Mon Sep 17 00:00:00 2001 From: efool Date: Thu, 3 Jul 2025 17:50:27 -0400 Subject: [PATCH 14/17] simplify entities --- src/board.cpp | 57 +++++++++++++++++++------------------------------- src/board.hpp | 14 +++++-------- src/entity.hpp | 12 +++++------ src/fruit.hpp | 2 +- src/snake.cpp | 41 +++++++++++++----------------------- src/snake.hpp | 57 ++++++++++++++++---------------------------------- src/stdafx.h | 1 + src/win32.cpp | 35 +++++++++++-------------------- 8 files changed, 79 insertions(+), 140 deletions(-) diff --git a/src/board.cpp b/src/board.cpp index 13d40ef..e38ad15 100644 --- a/src/board.cpp +++ b/src/board.cpp @@ -12,64 +12,49 @@ namespace { } Board::Board() - : m_snake(5.0f, 1, Index{150}) - , m_fruit(Index{0}) - , m_board(boardSize * boardSize) + : snake(5.0f, 1, Index{150}) + , fruit(Index{0}) { - m_board[m_snake.getPosition().idx] = Entity::Kind::snake; + for (auto pos : snake.body) + { + board[pos.idx] = Entity::Kind::snake; + } spawnFruit(); } -void Board::moveSnake(Direction direction) +void Board::moveSnake() { - auto oldBody = m_snake.getBody(); + auto last = snake.body.back(); - m_snake.move(direction); - if (m_snake.getPosition() == m_fruit.pos) + snake.move(); + if (snake.head() == fruit.pos) { + snake.score += fruit.points; spawnFruit(); - m_snake.addSegment(1); - m_snake.addScore(m_fruit.points); - } - - for (auto pos : oldBody) - { - m_board[pos.idx] = Entity::Kind::none; - } - - for (auto pos : m_snake.getBody()) - { - m_board[pos.idx] = Entity::Kind::snake; + snake.grow(); } -} -int Board::getSnakeSegmentOrder(Index index) -{ - const auto& body = getSnake().getBody(); - for (size_t i = 0; i < body.size(); ++i) { - if (body[i] == index) - return static_cast(i); - } - return -1; + board[last.idx] = Entity::Kind::none; + board[snake.body.back ().idx] = Entity::Kind::snake; // in case snake.body.back() == last (like grow) + board[snake.body.front().idx] = Entity::Kind::snake; } void Board::spawnFruit() { std::vector emptyPositions; - for (int i = 0; i < int(m_board.size()); i++) + for (int i = 0; i < int(board.size()); i++) { - if (m_board[i] == Entity::Kind::none) + if (board[i] == Entity::Kind::none) { emptyPositions.push_back(Index{i}); } } - assert(!emptyPositions.empty()); // todo: win? - - std::uniform_int_distribution<> distrib(0, int(emptyPositions.size()) - 1); + if (emptyPositions.empty()) + exit(0); // todo: win? - m_fruit.pos = emptyPositions[distrib(gen)]; - m_board[m_fruit.pos.idx] = Entity::Kind::fruit; + fruit.pos = emptyPositions[std::uniform_int_distribution<>(0, int(emptyPositions.size()) - 1)(gen)]; + board[fruit.pos.idx] = Entity::Kind::fruit; } } // namespace snake \ No newline at end of file diff --git a/src/board.hpp b/src/board.hpp index 63f7112..0c238a2 100644 --- a/src/board.hpp +++ b/src/board.hpp @@ -10,19 +10,15 @@ class Board public: Board(); - Entity::Kind getEntityAt(Index index) const { return m_board[index.idx]; } - - Snake& getSnake() { return m_snake; } - void moveSnake(Direction direction); - int getSnakeSegmentOrder(Index index); + Entity::Kind getEntityAt(Index index) const { return board[index.idx]; } + void moveSnake(); void spawnFruit(); -private: - Snake m_snake; - Fruit m_fruit; + Snake snake; + Fruit fruit; - std::vector m_board; + std::array board; }; } // namespace snake \ No newline at end of file diff --git a/src/entity.hpp b/src/entity.hpp index 48ad12f..b1d6236 100644 --- a/src/entity.hpp +++ b/src/entity.hpp @@ -7,8 +7,8 @@ constexpr int boardSize = 16; struct Index; struct Pos { - int x; - int y; + int x = 0; + int y = 0; Pos(int x, int y) : x(x), y(y) {} Pos(int index) : x(index % boardSize), y(index / boardSize) {} @@ -21,7 +21,7 @@ struct Pos { }; struct Index { - int idx; + int idx = 0; Index(int idx) : idx(idx) {} Index(int x, int y) : idx(y * boardSize + x) {} @@ -56,11 +56,11 @@ class Entity fruit, }; - Kind const kind; + //Kind const kind; // it's never used protected: - Entity(Kind kind) - : kind(kind) + Entity(Kind /*kind*/) + //: kind(kind) { } }; diff --git a/src/fruit.hpp b/src/fruit.hpp index 10e8c3c..47b115c 100644 --- a/src/fruit.hpp +++ b/src/fruit.hpp @@ -14,7 +14,7 @@ class Fruit : public Entity } Index pos; - int points = 1000; + static constexpr int points = 1000; }; } // namespace snake \ No newline at end of file diff --git a/src/snake.cpp b/src/snake.cpp index 1947ffb..8425390 100644 --- a/src/snake.cpp +++ b/src/snake.cpp @@ -4,27 +4,19 @@ namespace snake { -void Snake::addSpeed(float speed) +void Snake::grow(int count) { - m_Speed += speed; -} - -void Snake::removeSpeed(float speed) -{ - m_Speed -= speed; -} - -int Snake::wrap(int value, int max) { - return (value + max) % max; + body.reserve(body.size() + count); + auto const p = body.back(); + for (int i = 0; i < count; ++i) + { + body.push_back(p); + } } -void Snake::move(Direction direction) +void Snake::move() { - //gros pavé pour check si le joueur fait demi tour direct* - //[TODO] rendre lisible et optimisé - - direction = m_currentDirection; // on ignore si le joueur fait un 180° - Pos p = m_Body.front(); + Pos p = head(); switch (direction) { @@ -37,23 +29,20 @@ void Snake::move(Direction direction) p.wrap(); Index newHead = p; - - // check la collision on skip la tete sinon probleme - for (size_t i = 1; i < m_Body.size(); ++i) + for (size_t i = 1; i < body.size(); ++i) { - if (newHead == m_Body[i]) + if (newHead == body[i]) { - exit(0); // on quitte pour l'instant - //[TODO] faire un menu et un écran de fin + exit(0); // todo: lose } } - for (int i = int(m_Body.size()) - 1; i > 0; --i) + for (int i = size() - 1; i > 0; --i) { - m_Body[i] = m_Body[i - 1]; + body[i] = body[i - 1]; } - m_Body[0] = newHead; + body[0] = newHead; } } // namespace snake \ No newline at end of file diff --git a/src/snake.hpp b/src/snake.hpp index f677a16..81d1c95 100644 --- a/src/snake.hpp +++ b/src/snake.hpp @@ -9,54 +9,33 @@ class Snake : public Entity public: Snake(float speed, int score, Index pos) : Entity(Kind::snake) - , m_Speed(speed) - , m_Score(score) + , speed(speed) + , score(score) { - m_Body.push_back(pos); + body.push_back(pos); } - void addSegment(int count) + void grow(int count = 1); + void move(); + + Index head() const { return body[0]; } + int size() const { return int(body.size()); } + + int getSnakeSegmentOrder(Index index) const { - for (int i = 0; i < count; ++i) - { - m_Body.push_back(m_Body.back()); //rajout d'un segment dans la derniere position + for (size_t i = 0; i < body.size(); ++i) { + if (body[i] == index) + return static_cast(i); } + return -1; } - void addSpeed(float speed); - void removeSpeed(float speed); - float getSpeed() const { return m_Speed; } - - void move(Direction direction); - Index getPosition() const { return m_Body[0]; } - - void addScore(int score) { this->m_Score += score; } - int getScore() { return m_Score; } - - std::vector getBody() const { return m_Body; } - - int wrap(int value, int max); - - bool getAlive() { return isAlive; } - - void setCurrentDirection(Direction direction) { this->m_currentDirection = direction; } - Direction getCurrentDirection() const { return m_currentDirection; } - void setNextDirection(Direction nextDirection) { this->m_nextDirection = nextDirection; } - Direction getNextDirection() const { return m_nextDirection; } - - bool canChangeDirection = true; + float speed = 1.0f; + int score = 0; -private: - float m_Speed = 3.0f*(0.3f*m_Length);//[TODO] rendre modulable si ajout difficulter - int m_Length = 1; - int position; - const int _OFFSET = 16; - int m_Score = 0; - Direction m_currentDirection = Direction::left; - Direction m_nextDirection = Direction::right; - bool isAlive = true; + Direction direction = Direction::right; - std::vector m_Body; + std::vector body; }; } // namespace snake \ No newline at end of file diff --git a/src/stdafx.h b/src/stdafx.h index b7539ec..c651d8a 100644 --- a/src/stdafx.h +++ b/src/stdafx.h @@ -6,6 +6,7 @@ #include #include +#include #include #include #include diff --git a/src/win32.cpp b/src/win32.cpp index aff1d3c..ce6209e 100644 --- a/src/win32.cpp +++ b/src/win32.cpp @@ -56,15 +56,14 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) case WM_CREATE: { - auto speed = board->getSnake().getSpeed(); - SetTimer(hwnd, TIMER_ID, UINT(50 - speed), NULL); // todo: round? + SetTimer(hwnd, TIMER_ID, UINT(50 - board->snake.speed), NULL); // todo: round? } return 0; case WM_KEYDOWN: { - auto& snake = board->getSnake(); - auto desiredDirection = snake.getCurrentDirection(); + auto& snake = board->snake; + auto desiredDirection = snake.direction; switch (wParam) { @@ -81,27 +80,17 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) #endif } - if (!isOpposite(snake.getNextDirection(), desiredDirection)) + if (!isOpposite(snake.direction, desiredDirection)) { - snake.setNextDirection(desiredDirection); + snake.direction = desiredDirection; } } return 0; case WM_TIMER: { - auto& snake = board->getSnake(); - if (snake.getAlive()) - { - board->moveSnake(snake.getNextDirection()); - snake.setCurrentDirection(snake.getNextDirection()); - - InvalidateRect(hwnd, NULL, TRUE); - } - else - { - KillTimer(hwnd, TIMER_ID); - } + board->moveSnake(); + InvalidateRect(hwnd, NULL, TRUE); } return 0; @@ -159,8 +148,8 @@ void WNDRenderBoard(HWND hwnd, HDC hdc) HBRUSH brush = nullptr; if (entity == Entity::Kind::snake) { - int segmentOrder = board->getSnakeSegmentOrder(index); - int snakeLength = int(board->getSnake().getBody().size()); + int segmentOrder = board->snake.getSnakeSegmentOrder(index); + int snakeLength = board->snake.size(); if (segmentOrder != -1 && snakeLength > 1) { @@ -176,7 +165,7 @@ void WNDRenderBoard(HWND hwnd, HDC hdc) } else { - brush = CreateSolidBrush(RGB(0, 0, 255)); //bleu si ça bug + brush = CreateSolidBrush(RGB(0, 0, 255)); } } else if (entity == Entity::Kind::fruit) @@ -185,14 +174,14 @@ void WNDRenderBoard(HWND hwnd, HDC hdc) } else { - brush = CreateSolidBrush(RGB(0, 255, 0)); + brush = CreateSolidBrush(RGB(0, 255, 0)); } FillRect(hdc, &square, brush); DeleteObject(brush); SetBkMode(hdc, TRANSPARENT); - int segmentOrder = board->getSnakeSegmentOrder(index); + int segmentOrder = board->snake.getSnakeSegmentOrder(index); if (segmentOrder != -1) { std::wstring text = std::to_wstring(segmentOrder); DrawText(hdc, text.c_str(), -1, &square, DT_CENTER | DT_VCENTER | DT_SINGLELINE); From 8aab59d989010ea2b6c589027149d4b1c8f7903f Mon Sep 17 00:00:00 2001 From: efool Date: Thu, 3 Jul 2025 18:23:52 -0400 Subject: [PATCH 15/17] improve draw performance --- src/board.hpp | 2 - src/entity.hpp | 9 ++-- src/snake.hpp | 9 ---- src/stdafx.h | 4 +- src/util.hpp | 3 -- src/win32.cpp | 108 +++++++++++++++++++-------------------- vc/snake.vcxproj | 1 - vc/snake.vcxproj.filters | 3 -- 8 files changed, 58 insertions(+), 81 deletions(-) delete mode 100644 src/util.hpp diff --git a/src/board.hpp b/src/board.hpp index 0c238a2..42abf5e 100644 --- a/src/board.hpp +++ b/src/board.hpp @@ -10,8 +10,6 @@ class Board public: Board(); - Entity::Kind getEntityAt(Index index) const { return board[index.idx]; } - void moveSnake(); void spawnFruit(); diff --git a/src/entity.hpp b/src/entity.hpp index b1d6236..4e86bcf 100644 --- a/src/entity.hpp +++ b/src/entity.hpp @@ -39,12 +39,11 @@ enum class Direction { down, }; -constexpr bool isOpposite(Direction dir1, Direction dir2) noexcept +constexpr bool isOpposite(Direction a, Direction b) noexcept { - return (dir1 == Direction::left && dir2 == Direction::right) - || (dir1 == Direction::right && dir2 == Direction::left ) - || (dir1 == Direction::up && dir2 == Direction::down ) - || (dir1 == Direction::down && dir2 == Direction::up ); + unsigned const aa = unsigned(a) & 0b1; + unsigned const bb = unsigned(b) & 0b1; + return aa == bb; } class Entity diff --git a/src/snake.hpp b/src/snake.hpp index 81d1c95..633a0e6 100644 --- a/src/snake.hpp +++ b/src/snake.hpp @@ -21,15 +21,6 @@ class Snake : public Entity Index head() const { return body[0]; } int size() const { return int(body.size()); } - int getSnakeSegmentOrder(Index index) const - { - for (size_t i = 0; i < body.size(); ++i) { - if (body[i] == index) - return static_cast(i); - } - return -1; - } - float speed = 1.0f; int score = 0; diff --git a/src/stdafx.h b/src/stdafx.h index c651d8a..b218726 100644 --- a/src/stdafx.h +++ b/src/stdafx.h @@ -12,6 +12,4 @@ #include #include #include -#include - -#include "util.hpp" \ No newline at end of file +#include \ No newline at end of file diff --git a/src/util.hpp b/src/util.hpp deleted file mode 100644 index fc0a0a6..0000000 --- a/src/util.hpp +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -#define SNAKE_UNREACHABLE __assume(0) \ No newline at end of file diff --git a/src/win32.cpp b/src/win32.cpp index ce6209e..55967e7 100644 --- a/src/win32.cpp +++ b/src/win32.cpp @@ -128,65 +128,63 @@ void WNDRenderBoard(HWND hwnd, HDC hdc) RECT clientRect; GetClientRect(hwnd, &clientRect); - int squareWidth = clientRect.right / boardSize; - int squareHeight = clientRect.bottom / boardSize; + int const squareWidth = clientRect.right / boardSize; + int const squareHeight = clientRect.bottom / boardSize; - for (int row = 0; row < boardSize; ++row) + // assume mostly empty and accept larger overdraw as snake grows { - for (int col = 0; col < boardSize; ++col) + auto const brush = CreateSolidBrush(RGB(0, 255, 0)); + FillRect(hdc, &clientRect, brush); + DeleteObject(brush); + } + + // fruit + { + auto const brush = CreateSolidBrush(RGB(255, 0, 0)); + Pos const p = board->fruit.pos; + RECT r = { + p.x * squareWidth, + p.y * squareHeight, + (p.x + 1) * squareWidth, + (p.y + 1) * squareHeight + }; + FillRect(hdc, &r, brush); + DeleteObject(brush); + } + + // snake + for (int i = 0, len = board->snake.size(); i < len; ++i) { + HBRUSH brush = nullptr; + if (len > 1) + { + float const ratio = static_cast(i) / (len - 1); + int const brightness = static_cast(ratio * 200); + + int const red = brightness; + int const green = brightness; + int const blue = 255; + + brush = CreateSolidBrush(RGB(red, green, blue)); + } + else { - RECT square = { - col * squareWidth, - row * squareHeight, - (col + 1) * squareWidth, - (row + 1) * squareHeight - }; - - Index index { col, row }; - auto entity = board->getEntityAt(index); - - HBRUSH brush = nullptr; - if (entity == Entity::Kind::snake) - { - int segmentOrder = board->snake.getSnakeSegmentOrder(index); - int snakeLength = board->snake.size(); - - if (segmentOrder != -1 && snakeLength > 1) - { - float ratio = static_cast(segmentOrder) / (snakeLength - 1); - - int brightness = static_cast(ratio * 200); - - int red = brightness; - int green = brightness; - int blue = 255; - - brush = CreateSolidBrush(RGB(red, green, blue)); - } - else - { - brush = CreateSolidBrush(RGB(0, 0, 255)); - } - } - else if (entity == Entity::Kind::fruit) - { - brush = CreateSolidBrush(RGB(255, 0, 0)); - } - else - { - brush = CreateSolidBrush(RGB(0, 255, 0)); - } - - FillRect(hdc, &square, brush); - DeleteObject(brush); - SetBkMode(hdc, TRANSPARENT); - - int segmentOrder = board->snake.getSnakeSegmentOrder(index); - if (segmentOrder != -1) { - std::wstring text = std::to_wstring(segmentOrder); - DrawText(hdc, text.c_str(), -1, &square, DT_CENTER | DT_VCENTER | DT_SINGLELINE); - } + brush = CreateSolidBrush(RGB(0, 0, 255)); } + + Pos const p = board->snake.body[i]; + RECT square = { + p.x * squareWidth, + p.y * squareHeight, + (p.x + 1) * squareWidth, + (p.y + 1) * squareHeight + }; + + FillRect(hdc, &square, brush); + DeleteObject(brush); + + std::wstring text = std::to_wstring(i); + SetBkMode(hdc, TRANSPARENT); + DrawText(hdc, text.c_str(), -1, &square, DT_CENTER | DT_VCENTER | DT_SINGLELINE); } } diff --git a/vc/snake.vcxproj b/vc/snake.vcxproj index 0092e51..1c4774b 100644 --- a/vc/snake.vcxproj +++ b/vc/snake.vcxproj @@ -153,7 +153,6 @@ - diff --git a/vc/snake.vcxproj.filters b/vc/snake.vcxproj.filters index 755d3b1..f2a26c1 100644 --- a/vc/snake.vcxproj.filters +++ b/vc/snake.vcxproj.filters @@ -38,8 +38,5 @@ src - - src - \ No newline at end of file From d6c435f1a48d2650fcb6c193e6ebe821b8755145 Mon Sep 17 00:00:00 2001 From: efool Date: Thu, 3 Jul 2025 22:09:31 -0400 Subject: [PATCH 16/17] draw with backbuffer change fps to more precise floating point renamed isOpposite to more accurate isColinear --- src/entity.hpp | 2 +- src/win32.cpp | 194 +++++++++++++++++++++++++++---------------------- 2 files changed, 109 insertions(+), 87 deletions(-) diff --git a/src/entity.hpp b/src/entity.hpp index 4e86bcf..735cdfe 100644 --- a/src/entity.hpp +++ b/src/entity.hpp @@ -39,7 +39,7 @@ enum class Direction { down, }; -constexpr bool isOpposite(Direction a, Direction b) noexcept +constexpr bool isColinear(Direction a, Direction b) noexcept { unsigned const aa = unsigned(a) & 0b1; unsigned const bb = unsigned(b) & 0b1; diff --git a/src/win32.cpp b/src/win32.cpp index 55967e7..b1bfa71 100644 --- a/src/win32.cpp +++ b/src/win32.cpp @@ -7,40 +7,136 @@ namespace snake::win32 { +namespace { + constexpr UINT_PTR TIMER_ID = 1; -namespace { - Board* board = nullptr; - int frames = 0; - int fps = 0; - auto lastTime = std::chrono::steady_clock::now(); - std::wstring fpsText; +Board* board = nullptr; +int width = 0; +int height = 0; + +HDC backDC = nullptr; +HBITMAP backBuf = nullptr; + +int frames = 0; +float fps = 0; +auto lastTime = std::chrono::steady_clock::now(); +std::wstring fpsText; + +void draw(HDC hdc) +{ + int const squareWidth = width / boardSize; + int const squareHeight = height / boardSize; + + // assume mostly empty and accept larger overdraw as snake grows + { + auto const brush = CreateSolidBrush(RGB(0, 255, 0)); + RECT rect { 0, 0, width, height }; + FillRect(hdc, &rect, brush); + DeleteObject(brush); + } + + // fruit + { + auto const brush = CreateSolidBrush(RGB(255, 0, 0)); + Pos const p = board->fruit.pos; + RECT r = { + p.x * squareWidth, + p.y * squareHeight, + (p.x + 1) * squareWidth, + (p.y + 1) * squareHeight + }; + FillRect(hdc, &r, brush); + DeleteObject(brush); + } + + // snake + for (int i = 0, len = board->snake.size(); i < len; ++i) { + HBRUSH brush = nullptr; + if (len > 1) + { + float const ratio = static_cast(i) / (len - 1); + int const brightness = static_cast(ratio * 200); + + int const red = brightness; + int const green = brightness; + int const blue = 255; + + brush = CreateSolidBrush(RGB(red, green, blue)); + } + else + { + brush = CreateSolidBrush(RGB(0, 0, 255)); + } + + Pos const p = board->snake.body[i]; + RECT square = { + p.x * squareWidth, + p.y * squareHeight, + (p.x + 1) * squareWidth, + (p.y + 1) * squareHeight + }; + + FillRect(hdc, &square, brush); + DeleteObject(brush); + + std::wstring text = std::to_wstring(i); + SetBkMode(hdc, TRANSPARENT); + DrawText(hdc, text.c_str(), -1, &square, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + } + + TextOut(hdc, 10, 10, fpsText.c_str(), int(fpsText.length())); } -void WNDRenderBoard(HWND hwnd, HDC hdc); +} // namespace LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { + case WM_CREATE: + SetTimer(hwnd, TIMER_ID, UINT(50 - board->snake.speed), NULL); // todo: round? + return 0; + case WM_DESTROY: KillTimer(hwnd, TIMER_ID); + if (backDC) DeleteDC(backDC); + if (backBuf) DeleteObject(backBuf); PostQuitMessage(0); return 0; + case WM_SIZE: + { + width = LOWORD(lParam); + height = HIWORD(lParam); + + auto hdc = GetDC(hwnd); + if (backDC) DeleteDC(backDC); + backDC = CreateCompatibleDC(hdc); + + if (backBuf) DeleteObject(backBuf); + backBuf = CreateCompatibleBitmap(hdc, width, height); + + SelectObject(backDC, backBuf); + ReleaseDC(hwnd, hdc); + } + return 0; + case WM_PAINT: { PAINTSTRUCT ps; - HDC hdc = BeginPaint(hwnd, &ps); + auto hdc = BeginPaint(hwnd, &ps); + draw(backDC); + BitBlt(hdc, 0, 0, width, height, backDC, 0, 0, SRCCOPY); + EndPaint(hwnd, &ps); - WNDRenderBoard(hwnd, hdc); frames++; auto currentTime = std::chrono::steady_clock::now(); - auto elapsed = std::chrono::duration_cast(currentTime - lastTime).count(); + float elapsed = std::chrono::duration(currentTime - lastTime).count(); if (elapsed >= 1) { - fps = frames; + fps = float(frames) / elapsed; frames = 0; lastTime = currentTime; @@ -48,15 +144,6 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) std::wstring title = L"Snake - FPS: " + std::to_wstring(fps); SetWindowText(hwnd, title.c_str()); } - TextOut(hdc, 10, 10, fpsText.c_str(), int(fpsText.length())); // todo: show every frame - - EndPaint(hwnd, &ps); - } - return 0; - - case WM_CREATE: - { - SetTimer(hwnd, TIMER_ID, UINT(50 - board->snake.speed), NULL); // todo: round? } return 0; @@ -80,7 +167,7 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) #endif } - if (!isOpposite(snake.direction, desiredDirection)) + if (!isColinear(snake.direction, desiredDirection)) { snake.direction = desiredDirection; } @@ -123,69 +210,4 @@ HWND CreateMainWindow(Board& board_) return hwnd; } -void WNDRenderBoard(HWND hwnd, HDC hdc) -{ - RECT clientRect; - GetClientRect(hwnd, &clientRect); - - int const squareWidth = clientRect.right / boardSize; - int const squareHeight = clientRect.bottom / boardSize; - - // assume mostly empty and accept larger overdraw as snake grows - { - auto const brush = CreateSolidBrush(RGB(0, 255, 0)); - FillRect(hdc, &clientRect, brush); - DeleteObject(brush); - } - - // fruit - { - auto const brush = CreateSolidBrush(RGB(255, 0, 0)); - Pos const p = board->fruit.pos; - RECT r = { - p.x * squareWidth, - p.y * squareHeight, - (p.x + 1) * squareWidth, - (p.y + 1) * squareHeight - }; - FillRect(hdc, &r, brush); - DeleteObject(brush); - } - - // snake - for (int i = 0, len = board->snake.size(); i < len; ++i) { - HBRUSH brush = nullptr; - if (len > 1) - { - float const ratio = static_cast(i) / (len - 1); - int const brightness = static_cast(ratio * 200); - - int const red = brightness; - int const green = brightness; - int const blue = 255; - - brush = CreateSolidBrush(RGB(red, green, blue)); - } - else - { - brush = CreateSolidBrush(RGB(0, 0, 255)); - } - - Pos const p = board->snake.body[i]; - RECT square = { - p.x * squareWidth, - p.y * squareHeight, - (p.x + 1) * squareWidth, - (p.y + 1) * squareHeight - }; - - FillRect(hdc, &square, brush); - DeleteObject(brush); - - std::wstring text = std::to_wstring(i); - SetBkMode(hdc, TRANSPARENT); - DrawText(hdc, text.c_str(), -1, &square, DT_CENTER | DT_VCENTER | DT_SINGLELINE); - } -} - } // namespace snake::win32 \ No newline at end of file From 9db43665674be2de1251a9f221fc86f80c4ccf4c Mon Sep 17 00:00:00 2001 From: efool Date: Fri, 4 Jul 2025 09:48:22 -0400 Subject: [PATCH 17/17] added smooth movement - higher frame rate - moved win32 code into main - has a warping defect when wrapping from left/top to right/bottom --- src/board.cpp | 6 +- src/main.cpp | 254 +++++++++++++++++++++++++++++++++++++-- src/snake.cpp | 3 +- src/snake.hpp | 6 +- src/stdafx.h | 5 +- src/win32.cpp | 213 -------------------------------- src/win32.hpp | 12 -- vc/snake.vcxproj | 2 - vc/snake.vcxproj.filters | 6 - 9 files changed, 258 insertions(+), 249 deletions(-) delete mode 100644 src/win32.cpp delete mode 100644 src/win32.hpp diff --git a/src/board.cpp b/src/board.cpp index e38ad15..f7ec4d6 100644 --- a/src/board.cpp +++ b/src/board.cpp @@ -24,7 +24,7 @@ Board::Board() void Board::moveSnake() { - auto last = snake.body.back(); + auto last = snake.last(); snake.move(); if (snake.head() == fruit.pos) @@ -35,8 +35,8 @@ void Board::moveSnake() } board[last.idx] = Entity::Kind::none; - board[snake.body.back ().idx] = Entity::Kind::snake; // in case snake.body.back() == last (like grow) - board[snake.body.front().idx] = Entity::Kind::snake; + board[snake.last().idx] = Entity::Kind::snake; // in case snake.last() == last (like grow) + board[snake.head().idx] = Entity::Kind::snake; } void Board::spawnFruit() diff --git a/src/main.cpp b/src/main.cpp index cb374e2..f4f649d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,22 +1,258 @@ #include "stdafx.h" #include "board.hpp" -#include "win32.hpp" -int WINAPI wWinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, PWSTR /*pCmdLine*/, int /*nCmdShow*/) +namespace snake { + +namespace { + +Board board; +int width = 0; +int height = 0; + +HDC backDC = nullptr; +HBITMAP backBuf = nullptr; + +int frames = 0; + +using clock = std::chrono::steady_clock; + +std::chrono::milliseconds periodUpdate; +clock::time_point lastUpdateTime; + +constexpr std::chrono::milliseconds periodDraw { 16 }; +clock::time_point lastDrawTime; + +clock::time_point lastFPSUpdateTime; +float fps = 0; +std::wstring fpsText; + +void draw(HDC hdc, float dt) { - snake::Board board; - if (snake::win32::CreateMainWindow(board) == NULL) + int const squareWidth = width / boardSize; + int const squareHeight = height / boardSize; + + // assume mostly empty and accept larger overdraw as snake grows { - return 1; + auto const brush = CreateSolidBrush(RGB(0, 255, 0)); + RECT rect { 0, 0, width, height }; + FillRect(hdc, &rect, brush); + DeleteObject(brush); + } + + // fruit + { + auto const brush = CreateSolidBrush(RGB(255, 0, 0)); + Pos const p = board.fruit.pos; + RECT r = { + p.x * squareWidth, + p.y * squareHeight, + (p.x + 1) * squareWidth, + (p.y + 1) * squareHeight + }; + FillRect(hdc, &r, brush); + DeleteObject(brush); + } + + // snake + for (int i = 0, len = int(board.snake.bodyPrev.size()); i < len; ++i) { + HBRUSH brush = nullptr; + if (len > 1) + { + float const ratio = static_cast(i) / (len - 1); + int const brightness = static_cast(ratio * 200); + + int const red = brightness; + int const green = brightness; + int const blue = 255; + + brush = CreateSolidBrush(RGB(red, green, blue)); + } + else + { + brush = CreateSolidBrush(RGB(0, 0, 255)); + } + + // todo: wrapping from left to right draws the entire rect on the right + // when warping there should be 2 rect draws to show partially on both sides + Pos const p[2] { board.snake.body[i], board.snake.bodyPrev[i] }; + float dx = std::fmodf((p[0].x - p[1].x)*squareWidth + width /2.0f, float(width )) - width /2.0f; + float dy = std::fmodf((p[0].y - p[1].y)*squareHeight + height/2.0f, float(height)) - height/2.0f; + if (dx < -width /2.0f) dx += width; + if (dy < -height/2.0f) dy += height; + int x = int(std::fmodf(p[1].x*squareWidth + dx*dt + width , float(width ))); + int y = int(std::fmodf(p[1].y*squareHeight + dy*dt + height, float(height))); + RECT rect = { + x, y, + x + squareWidth, y + squareHeight + }; + + FillRect(hdc, &rect, brush); + DeleteObject(brush); + + std::wstring text = std::to_wstring(i); + SetBkMode(hdc, TRANSPARENT); + DrawText(hdc, text.c_str(), -1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + } + + TextOut(hdc, 10, 10, fpsText.c_str(), int(fpsText.length())); +} + +void update() +{ + auto const now = clock::now(); + if (now - lastUpdateTime >= periodUpdate) + { + board.moveSnake(); + lastUpdateTime = now; + } +} + +void sleepTargetDrawPeriod() +{ + std::this_thread::sleep_for(std::chrono::milliseconds(1)); +} + +LRESULT CALLBACK windowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_CREATE: + periodUpdate = std::chrono::milliseconds{ 50 - int(board.snake.speed) }; + return 0; + + case WM_DESTROY: + if (backDC) DeleteDC(backDC); + if (backBuf) DeleteObject(backBuf); + PostQuitMessage(0); + return 0; + + case WM_SIZE: + { + width = LOWORD(lParam); + height = HIWORD(lParam); + + auto hdc = GetDC(hwnd); + if (backDC) DeleteDC(backDC); + backDC = CreateCompatibleDC(hdc); + + if (backBuf) DeleteObject(backBuf); + backBuf = CreateCompatibleBitmap(hdc, width, height); + + SelectObject(backDC, backBuf); + ReleaseDC(hwnd, hdc); + } + return 0; + + case WM_PAINT: + { + auto now = clock::now(); + PAINTSTRUCT ps; + auto hdc = BeginPaint(hwnd, &ps); + auto const dt = std::chrono::duration(now - lastUpdateTime).count() / std::chrono::duration(periodUpdate).count(); + draw(backDC, dt); + BitBlt(hdc, 0, 0, width, height, backDC, 0, 0, SRCCOPY); + EndPaint(hwnd, &ps); + lastDrawTime = clock::now(); + + frames++; + + float elapsed = std::chrono::duration(lastDrawTime - lastFPSUpdateTime).count(); + if (elapsed >= 1) { + fps = float(frames) / elapsed; + frames = 0; + lastFPSUpdateTime = lastDrawTime; + + fpsText = L"FPS: " + std::to_wstring(fps); + std::wstring title = L"Snake - FPS: " + std::to_wstring(fps); + SetWindowText(hwnd, title.c_str()); + } } + return 0; - MSG msg = {}; - while (GetMessage(&msg, NULL, 0, 0)) + case WM_KEYDOWN: { - TranslateMessage(&msg); - DispatchMessage(&msg); + auto& snake = board.snake; + auto desiredDirection = snake.direction; + + switch (wParam) + { +#ifdef SNAKE_USE_CURSOR_KEYS + case VK_LEFT : desiredDirection = Direction::left ; break; + case VK_UP : desiredDirection = Direction::up ; break; + case VK_RIGHT: desiredDirection = Direction::right; break; + case VK_DOWN : desiredDirection = Direction::down ; break; +#else + case 'Q': desiredDirection = Direction::left ; break; + case 'Z': desiredDirection = Direction::up ; break; + case 'D': desiredDirection = Direction::right; break; + case 'S': desiredDirection = Direction::down ; break; +#endif + } + + if (!isColinear(snake.direction, desiredDirection)) + { + snake.direction = desiredDirection; + } + } + return 0; + + } + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +HWND createMainWindow(WNDPROC proc) +{ + const wchar_t CLASS_NAME[] = L"SnakeWindow"; + + WNDCLASS wc = {}; + wc.lpfnWndProc = proc; + wc.hInstance = GetModuleHandle(NULL); + wc.lpszClassName = CLASS_NAME; + + RegisterClass(&wc); + + HWND hwnd = CreateWindowEx( + 0, CLASS_NAME, L"Snake", WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, GetModuleHandle(NULL), NULL + ); + + if (hwnd != NULL) { + ShowWindow(hwnd, SW_SHOW); + } + + return hwnd; +} + +} // namespace + +} // namespace snake + +int WINAPI wWinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, PWSTR /*pCmdLine*/, int /*nCmdShow*/) +{ + auto hwnd = snake::createMainWindow(snake::windowProc); + if (!hwnd) + return 1; + + for (;;) + { + for (MSG msg {}; PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE); ) + { + if (msg.message == WM_QUIT) + goto L_quit; + + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + snake::update(); + + InvalidateRect(hwnd, nullptr, FALSE); + UpdateWindow(hwnd); + + snake::sleepTargetDrawPeriod(); } +L_quit: return 0; } \ No newline at end of file diff --git a/src/snake.cpp b/src/snake.cpp index 8425390..306d69e 100644 --- a/src/snake.cpp +++ b/src/snake.cpp @@ -16,8 +16,9 @@ void Snake::grow(int count) void Snake::move() { - Pos p = head(); + bodyPrev = body; + Pos p = head(); switch (direction) { case Direction::left : p.x--; break; diff --git a/src/snake.hpp b/src/snake.hpp index 633a0e6..b94dae1 100644 --- a/src/snake.hpp +++ b/src/snake.hpp @@ -11,14 +11,15 @@ class Snake : public Entity : Entity(Kind::snake) , speed(speed) , score(score) + , body{ pos } { - body.push_back(pos); } void grow(int count = 1); void move(); - Index head() const { return body[0]; } + Index head() const { return body.front(); } + Index last() const { return body.back(); } int size() const { return int(body.size()); } float speed = 1.0f; @@ -27,6 +28,7 @@ class Snake : public Entity Direction direction = Direction::right; std::vector body; + std::vector bodyPrev; }; } // namespace snake \ No newline at end of file diff --git a/src/stdafx.h b/src/stdafx.h index b218726..829545d 100644 --- a/src/stdafx.h +++ b/src/stdafx.h @@ -7,9 +7,12 @@ #include #include +#include +#include #include #include #include #include #include -#include \ No newline at end of file +#include +#include \ No newline at end of file diff --git a/src/win32.cpp b/src/win32.cpp deleted file mode 100644 index b1bfa71..0000000 --- a/src/win32.cpp +++ /dev/null @@ -1,213 +0,0 @@ -#include "stdafx.h" - -#include - -#include "board.hpp" -#include "win32.hpp" - -namespace snake::win32 { - -namespace { - -constexpr UINT_PTR TIMER_ID = 1; - -Board* board = nullptr; -int width = 0; -int height = 0; - -HDC backDC = nullptr; -HBITMAP backBuf = nullptr; - -int frames = 0; -float fps = 0; -auto lastTime = std::chrono::steady_clock::now(); -std::wstring fpsText; - -void draw(HDC hdc) -{ - int const squareWidth = width / boardSize; - int const squareHeight = height / boardSize; - - // assume mostly empty and accept larger overdraw as snake grows - { - auto const brush = CreateSolidBrush(RGB(0, 255, 0)); - RECT rect { 0, 0, width, height }; - FillRect(hdc, &rect, brush); - DeleteObject(brush); - } - - // fruit - { - auto const brush = CreateSolidBrush(RGB(255, 0, 0)); - Pos const p = board->fruit.pos; - RECT r = { - p.x * squareWidth, - p.y * squareHeight, - (p.x + 1) * squareWidth, - (p.y + 1) * squareHeight - }; - FillRect(hdc, &r, brush); - DeleteObject(brush); - } - - // snake - for (int i = 0, len = board->snake.size(); i < len; ++i) { - HBRUSH brush = nullptr; - if (len > 1) - { - float const ratio = static_cast(i) / (len - 1); - int const brightness = static_cast(ratio * 200); - - int const red = brightness; - int const green = brightness; - int const blue = 255; - - brush = CreateSolidBrush(RGB(red, green, blue)); - } - else - { - brush = CreateSolidBrush(RGB(0, 0, 255)); - } - - Pos const p = board->snake.body[i]; - RECT square = { - p.x * squareWidth, - p.y * squareHeight, - (p.x + 1) * squareWidth, - (p.y + 1) * squareHeight - }; - - FillRect(hdc, &square, brush); - DeleteObject(brush); - - std::wstring text = std::to_wstring(i); - SetBkMode(hdc, TRANSPARENT); - DrawText(hdc, text.c_str(), -1, &square, DT_CENTER | DT_VCENTER | DT_SINGLELINE); - } - - TextOut(hdc, 10, 10, fpsText.c_str(), int(fpsText.length())); -} - -} // namespace - -LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) - { - case WM_CREATE: - SetTimer(hwnd, TIMER_ID, UINT(50 - board->snake.speed), NULL); // todo: round? - return 0; - - case WM_DESTROY: - KillTimer(hwnd, TIMER_ID); - if (backDC) DeleteDC(backDC); - if (backBuf) DeleteObject(backBuf); - PostQuitMessage(0); - return 0; - - case WM_SIZE: - { - width = LOWORD(lParam); - height = HIWORD(lParam); - - auto hdc = GetDC(hwnd); - if (backDC) DeleteDC(backDC); - backDC = CreateCompatibleDC(hdc); - - if (backBuf) DeleteObject(backBuf); - backBuf = CreateCompatibleBitmap(hdc, width, height); - - SelectObject(backDC, backBuf); - ReleaseDC(hwnd, hdc); - } - return 0; - - case WM_PAINT: - { - PAINTSTRUCT ps; - auto hdc = BeginPaint(hwnd, &ps); - draw(backDC); - BitBlt(hdc, 0, 0, width, height, backDC, 0, 0, SRCCOPY); - EndPaint(hwnd, &ps); - - frames++; - - auto currentTime = std::chrono::steady_clock::now(); - float elapsed = std::chrono::duration(currentTime - lastTime).count(); - - if (elapsed >= 1) { - fps = float(frames) / elapsed; - frames = 0; - lastTime = currentTime; - - fpsText = L"FPS: " + std::to_wstring(fps); - std::wstring title = L"Snake - FPS: " + std::to_wstring(fps); - SetWindowText(hwnd, title.c_str()); - } - } - return 0; - - case WM_KEYDOWN: - { - auto& snake = board->snake; - auto desiredDirection = snake.direction; - - switch (wParam) - { -#ifdef SNAKE_USE_CURSOR_KEYS - case VK_LEFT : desiredDirection = Direction::left ; break; - case VK_UP : desiredDirection = Direction::up ; break; - case VK_RIGHT: desiredDirection = Direction::right; break; - case VK_DOWN : desiredDirection = Direction::down ; break; -#else - case 'Q': desiredDirection = Direction::left ; break; - case 'Z': desiredDirection = Direction::up ; break; - case 'D': desiredDirection = Direction::right; break; - case 'S': desiredDirection = Direction::down ; break; -#endif - } - - if (!isColinear(snake.direction, desiredDirection)) - { - snake.direction = desiredDirection; - } - } - return 0; - - case WM_TIMER: - { - board->moveSnake(); - InvalidateRect(hwnd, NULL, TRUE); - } - return 0; - - } - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} - -HWND CreateMainWindow(Board& board_) -{ - board = &board_; - - const wchar_t CLASS_NAME[] = L"SnakeWindow"; - - WNDCLASS wc = {}; - wc.lpfnWndProc = WindowProc; - wc.hInstance = GetModuleHandle(NULL); - wc.lpszClassName = CLASS_NAME; - - RegisterClass(&wc); - - HWND hwnd = CreateWindowEx( - 0, CLASS_NAME, L"Snake", WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, GetModuleHandle(NULL), NULL - ); - - if (hwnd != NULL) { - ShowWindow(hwnd, SW_SHOW); - } - - return hwnd; -} - -} // namespace snake::win32 \ No newline at end of file diff --git a/src/win32.hpp b/src/win32.hpp deleted file mode 100644 index 0db6de0..0000000 --- a/src/win32.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -namespace snake { - - class Board; - - namespace win32 { - -HWND CreateMainWindow(Board& board); - - } // namespace win32 -} // namespace snake \ No newline at end of file diff --git a/vc/snake.vcxproj b/vc/snake.vcxproj index 1c4774b..199e05c 100644 --- a/vc/snake.vcxproj +++ b/vc/snake.vcxproj @@ -146,14 +146,12 @@ - - diff --git a/vc/snake.vcxproj.filters b/vc/snake.vcxproj.filters index f2a26c1..87dd723 100644 --- a/vc/snake.vcxproj.filters +++ b/vc/snake.vcxproj.filters @@ -9,9 +9,6 @@ src - - src - src @@ -26,9 +23,6 @@ src - - src - src