├── .gitignore ├── Tetris.ico ├── Tetris.rc ├── small.ico ├── Point2D.h ├── Tetris.vcxproj.user ├── Matrix.h ├── targetver.h ├── README.md ├── Stack.h ├── Resource.h ├── App.h ├── Matrix.cpp ├── framework.h ├── Engine.h ├── Tetris.sln ├── Piece.h ├── Tetris.vcxproj.filters ├── Stack.cpp ├── Piece.cpp ├── App.cpp ├── Tetris.vcxproj └── Engine.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | x64/ 2 | .vs/ 3 | -------------------------------------------------------------------------------- /Tetris.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BuildSucceeded/Tetris/HEAD/Tetris.ico -------------------------------------------------------------------------------- /Tetris.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BuildSucceeded/Tetris/HEAD/Tetris.rc -------------------------------------------------------------------------------- /small.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BuildSucceeded/Tetris/HEAD/small.ico -------------------------------------------------------------------------------- /Point2D.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct Point2D 4 | { 5 | double x; 6 | double y; 7 | }; -------------------------------------------------------------------------------- /Tetris.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Matrix.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | class Matrix 3 | { 4 | public: 5 | Matrix(int sizeX, int sizeY); 6 | ~Matrix(); 7 | 8 | bool Get(int x, int y); 9 | void Set(int x, int y, bool value); 10 | int GetXSize(); 11 | int GetYSize(); 12 | private: 13 | int xSize; 14 | int ySize; 15 | 16 | bool** matrix; 17 | }; 18 | 19 | -------------------------------------------------------------------------------- /targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // // Including SDKDDKVer.h defines the highest available Windows platform. 4 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 5 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 6 | #include 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tetris 2 | 3 | https://youtu.be/8zXlWbEgfiY 4 | 5 | I'm going to explain how I've built a TETRIS game. 6 | I'm using Visual C++ and Direct2D. 7 | 8 | If you want to keep learning and need help, join our FREE Discord server! https://discord.gg/Rt6uTeC 9 | 10 | Facebook: https://www.facebook.com/GameBuildSucceeded/ 11 | 12 | Twitter: @SucceededBuild 13 | 14 | Patreon: https://www.patreon.com/BuildSucceeded 15 | -------------------------------------------------------------------------------- /Stack.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "resource.h" 4 | #include "Matrix.h" 5 | 6 | #define STACK_WIDTH 10 7 | #define STACK_HEIGHT 20 8 | 9 | class Stack 10 | { 11 | public: 12 | Stack(); 13 | ~Stack(); 14 | 15 | void InitializeD2D(ID2D1HwndRenderTarget* m_pRenderTarget); 16 | int RemoveLines(); 17 | void Draw(ID2D1HwndRenderTarget* m_pRenderTarget); 18 | 19 | Matrix* GetCells(); 20 | private: 21 | Matrix* cells; 22 | 23 | ID2D1SolidColorBrush* m_pBlueBrush; 24 | ID2D1SolidColorBrush* m_pGreenBrush; 25 | ID2D1SolidColorBrush* m_pYellowBrush; 26 | 27 | }; 28 | 29 | -------------------------------------------------------------------------------- /Resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by Tetris.rc 4 | 5 | #define IDS_APP_TITLE 103 6 | 7 | #define IDR_MAINFRAME 128 8 | #define IDD_TETRIS_DIALOG 102 9 | #define IDD_ABOUTBOX 103 10 | #define IDM_ABOUT 104 11 | #define IDM_EXIT 105 12 | #define IDI_TETRIS 107 13 | #define IDI_SMALL 108 14 | #define IDC_TETRIS 109 15 | #define IDC_MYICON 2 16 | #ifndef IDC_STATIC 17 | #define IDC_STATIC -1 18 | #endif 19 | // Next default values for new objects 20 | // 21 | #ifdef APSTUDIO_INVOKED 22 | #ifndef APSTUDIO_READONLY_SYMBOLS 23 | 24 | #define _APS_NO_MFC 130 25 | #define _APS_NEXT_RESOURCE_VALUE 129 26 | #define _APS_NEXT_COMMAND_VALUE 32771 27 | #define _APS_NEXT_CONTROL_VALUE 1000 28 | #define _APS_NEXT_SYMED_VALUE 110 29 | #endif 30 | #endif 31 | -------------------------------------------------------------------------------- /App.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "resource.h" 4 | 5 | 6 | #ifndef Assert 7 | #if defined( DEBUG ) || defined( _DEBUG ) 8 | #define Assert(b) do {if (!(b)) {OutputDebugStringA("Assert: " #b "\n");}} while(0) 9 | #else 10 | #define Assert(b) 11 | #endif //DEBUG || _DEBUG 12 | #endif 13 | 14 | 15 | 16 | #ifndef HINST_THISCOMPONENT 17 | EXTERN_C IMAGE_DOS_HEADER __ImageBase; 18 | #define HINST_THISCOMPONENT ((HINSTANCE)&__ImageBase) 19 | #endif 20 | 21 | 22 | class MainApp 23 | { 24 | public: 25 | MainApp(); 26 | ~MainApp(); 27 | 28 | HRESULT Initialize(); 29 | 30 | // Process and dispatch messages 31 | void RunMessageLoop(); 32 | 33 | private: 34 | 35 | HWND m_hwnd; 36 | 37 | Engine* engine; 38 | 39 | // The windows procedure. 40 | static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); 41 | 42 | }; -------------------------------------------------------------------------------- /Matrix.cpp: -------------------------------------------------------------------------------- 1 | #include "Matrix.h" 2 | 3 | Matrix::Matrix(int sizeX, int sizeY) 4 | { 5 | // Initializes the matrix 6 | xSize = sizeX; 7 | ySize = sizeY; 8 | 9 | matrix = new bool* [ySize]; 10 | for (int i = 0; i < ySize; ++i) 11 | { 12 | matrix[i] = new bool[xSize]; 13 | for (int j = 0; j < xSize; ++j) 14 | matrix[i][j] = false; 15 | } 16 | } 17 | 18 | Matrix::~Matrix() 19 | { 20 | // Destroys the matrix 21 | for (int i = 0; i < ySize; ++i) 22 | { 23 | delete[] matrix[i]; 24 | } 25 | delete[] matrix; 26 | } 27 | 28 | bool Matrix::Get(int x, int y) 29 | { 30 | // Returns the value of an element 31 | return matrix[y][x]; 32 | } 33 | 34 | void Matrix::Set(int x, int y, bool value) 35 | { 36 | // Sets the value of an element 37 | matrix[y][x] = value; 38 | } 39 | 40 | int Matrix::GetXSize() 41 | { 42 | return xSize; 43 | } 44 | 45 | int Matrix::GetYSize() 46 | { 47 | return ySize; 48 | } -------------------------------------------------------------------------------- /framework.h: -------------------------------------------------------------------------------- 1 | // header.h : include file for standard system include files, 2 | // or project specific include files 3 | // 4 | 5 | #pragma once 6 | 7 | #include "targetver.h" 8 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 9 | // Windows Header Files 10 | #include 11 | #include 12 | // C RunTime Header Files 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | 30 | template 31 | inline void SafeRelease(Interface** ppInterfaceToRelease) 32 | { 33 | if (*ppInterfaceToRelease != NULL) 34 | { 35 | (*ppInterfaceToRelease)->Release(); 36 | 37 | (*ppInterfaceToRelease) = NULL; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Engine.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "resource.h" 4 | #include "Piece.h" 5 | #include "Stack.h" 6 | 7 | #define RESOLUTION_X 800 8 | #define RESOLUTION_Y 600 9 | 10 | #define CELL_SIZE 20 11 | 12 | class Engine 13 | { 14 | public: 15 | Engine(); 16 | ~Engine(); 17 | 18 | HRESULT InitializeD2D(HWND m_hwnd); 19 | void KeyUp(WPARAM wParam); 20 | void KeyDown(WPARAM wParam); 21 | void MousePosition(int x, int y); 22 | void MouseButtonUp(bool left, bool right); 23 | void MouseButtonDown(bool left, bool right); 24 | void Logic(double elapsedTime); 25 | HRESULT Draw(); 26 | 27 | private: 28 | ID2D1Factory* m_pDirect2dFactory; 29 | ID2D1HwndRenderTarget* m_pRenderTarget; 30 | 31 | IDWriteFactory* m_pDWriteFactory; 32 | IDWriteTextFormat* m_pTextFormat; 33 | ID2D1SolidColorBrush* m_pWhiteBrush; 34 | 35 | void InitializeTextAndScore(); 36 | void DrawTextAndScore(); 37 | 38 | Stack* stack; 39 | Piece* activePiece; 40 | Piece* waitingPiece; 41 | 42 | bool gameOver = false; 43 | 44 | bool downPressed = false; 45 | bool leftPressed = false; 46 | bool rightPressed = false; 47 | bool spacePressed = false; 48 | 49 | int score = 0; 50 | 51 | double autoFallDelay; 52 | double autoFallAccumulated; 53 | double keyPressDelay; 54 | double keyPressAccumulated; 55 | }; 56 | 57 | -------------------------------------------------------------------------------- /Tetris.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29609.76 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tetris", "Tetris.vcxproj", "{79C2EA07-9615-4355-954E-7F53F4C7C538}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {79C2EA07-9615-4355-954E-7F53F4C7C538}.Debug|x64.ActiveCfg = Debug|x64 17 | {79C2EA07-9615-4355-954E-7F53F4C7C538}.Debug|x64.Build.0 = Debug|x64 18 | {79C2EA07-9615-4355-954E-7F53F4C7C538}.Debug|x86.ActiveCfg = Debug|Win32 19 | {79C2EA07-9615-4355-954E-7F53F4C7C538}.Debug|x86.Build.0 = Debug|Win32 20 | {79C2EA07-9615-4355-954E-7F53F4C7C538}.Release|x64.ActiveCfg = Release|x64 21 | {79C2EA07-9615-4355-954E-7F53F4C7C538}.Release|x64.Build.0 = Release|x64 22 | {79C2EA07-9615-4355-954E-7F53F4C7C538}.Release|x86.ActiveCfg = Release|Win32 23 | {79C2EA07-9615-4355-954E-7F53F4C7C538}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {6653EAED-BD0B-411E-B7E2-166CF2364C6C} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /Piece.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "resource.h" 4 | #include "Point2D.h" 5 | #include "Matrix.h" 6 | 7 | class Piece 8 | { 9 | public: 10 | Piece(); 11 | ~Piece(); 12 | 13 | void InitializeD2D(ID2D1HwndRenderTarget* m_pRenderTarget); 14 | void Activate(); 15 | bool Advance(Matrix* stackCells); 16 | void GoLeft(Matrix* stackCells); 17 | void GoRight(Matrix* stackCells); 18 | void Rotate(Matrix* stackCells); 19 | void Draw(ID2D1HwndRenderTarget* m_pRenderTarget); 20 | 21 | bool LeftWallCollision(); 22 | bool RightWallCollision(); 23 | bool StackCollision(Matrix* stackCells); 24 | Point2D GetPosition(); 25 | Matrix* GetCells(); 26 | 27 | private: 28 | Point2D position; 29 | Matrix* cells; 30 | 31 | bool waiting; // Is the current piece or the next piece? 32 | 33 | bool cellsTemplates[7][4][4] = { // This is where we define our pieces templates 34 | { { false, false, false, false }, 35 | { false, false, false, false }, 36 | { true, true, true, true }, 37 | { false, false, false, false } }, 38 | 39 | { { false, false, false, false }, 40 | { false, true, true, true }, 41 | { false, true, false, false }, 42 | { false, false, false, false } }, 43 | 44 | { { false, false, false, false }, 45 | { false, true, false, false }, 46 | { false, true, true, true }, 47 | { false, false, false, false } }, 48 | 49 | { { false, false, false, false }, 50 | { false, true, true, true }, 51 | { false, false, true, false }, 52 | { false, false, false, false } }, 53 | 54 | { { false, false, false, false }, 55 | { false, true, true, false }, 56 | { false, true, true, false }, 57 | { false, false, false, false } }, 58 | 59 | { { false, false, false, false }, 60 | { false, true, true, false }, 61 | { false, false, true, true }, 62 | { false, false, false, false } }, 63 | 64 | { { false, false, false, false }, 65 | { false, false, true, true }, 66 | { false, true, true, false }, 67 | { false, false, false, false } } 68 | }; 69 | 70 | ID2D1SolidColorBrush* m_pRedBrush; 71 | 72 | }; 73 | 74 | -------------------------------------------------------------------------------- /Tetris.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files 35 | 36 | 37 | Header Files 38 | 39 | 40 | Header Files 41 | 42 | 43 | Header Files 44 | 45 | 46 | 47 | 48 | Resource Files 49 | 50 | 51 | 52 | 53 | Resource Files 54 | 55 | 56 | Resource Files 57 | 58 | 59 | 60 | 61 | Source Files 62 | 63 | 64 | Source Files 65 | 66 | 67 | Source Files 68 | 69 | 70 | Source Files 71 | 72 | 73 | Source Files 74 | 75 | 76 | -------------------------------------------------------------------------------- /Stack.cpp: -------------------------------------------------------------------------------- 1 | #include "framework.h" 2 | #include "Matrix.h" 3 | #include "Stack.h" 4 | #include "Engine.h" 5 | 6 | Stack::Stack() : m_pBlueBrush(NULL), m_pGreenBrush(NULL), m_pYellowBrush(NULL) 7 | { 8 | cells = new Matrix(STACK_WIDTH, STACK_HEIGHT); 9 | } 10 | 11 | Stack::~Stack() 12 | { 13 | delete cells; 14 | SafeRelease(&m_pBlueBrush); 15 | SafeRelease(&m_pGreenBrush); 16 | SafeRelease(&m_pYellowBrush); 17 | } 18 | 19 | void Stack::InitializeD2D(ID2D1HwndRenderTarget* m_pRenderTarget) 20 | { 21 | // Creates the brushes for drawing 22 | m_pRenderTarget->CreateSolidColorBrush( 23 | D2D1::ColorF(D2D1::ColorF::Blue), 24 | &m_pBlueBrush 25 | ); 26 | m_pRenderTarget->CreateSolidColorBrush( 27 | D2D1::ColorF(D2D1::ColorF::Green), 28 | &m_pGreenBrush 29 | ); 30 | m_pRenderTarget->CreateSolidColorBrush( 31 | D2D1::ColorF(D2D1::ColorF::Yellow), 32 | &m_pYellowBrush 33 | ); 34 | } 35 | 36 | int Stack::RemoveLines() 37 | { 38 | // This removes the full rows 39 | int removed = 0; 40 | for (int i = STACK_HEIGHT - 1; i >= 0 ; i--) 41 | { 42 | bool entireLine = true; 43 | for (int j = 0; j < STACK_WIDTH; j++) 44 | { 45 | if (cells->Get(j, i) == false) 46 | { 47 | entireLine = false; 48 | } 49 | } 50 | if (entireLine) 51 | { 52 | removed++; 53 | for (int k = i; k > 0; k--) 54 | { 55 | for (int j = 0; j < STACK_WIDTH; j++) 56 | { 57 | cells->Set(j, k, cells->Get(j, k - 1)); 58 | } 59 | } 60 | i++; 61 | } 62 | } 63 | return removed; 64 | } 65 | 66 | void Stack::Draw(ID2D1HwndRenderTarget* m_pRenderTarget) 67 | { 68 | int padding = (RESOLUTION_Y - (STACK_HEIGHT + 1) * CELL_SIZE) / 2; 69 | 70 | // Drawing the walls first 71 | 72 | D2D1_RECT_F rectangle1 = D2D1::RectF( 73 | padding, padding, 74 | padding + CELL_SIZE, padding + (STACK_HEIGHT + 1) * CELL_SIZE 75 | ); 76 | m_pRenderTarget->FillRectangle(&rectangle1, m_pBlueBrush); 77 | 78 | D2D1_RECT_F rectangle2 = D2D1::RectF( 79 | padding, padding + STACK_HEIGHT * CELL_SIZE, 80 | padding + (STACK_WIDTH + 2) * CELL_SIZE, padding + (STACK_HEIGHT + 1) * CELL_SIZE 81 | ); 82 | m_pRenderTarget->FillRectangle(&rectangle2, m_pBlueBrush); 83 | 84 | D2D1_RECT_F rectangle3 = D2D1::RectF( 85 | padding + (STACK_WIDTH + 1) * CELL_SIZE, padding, 86 | padding + (STACK_WIDTH + 2) * CELL_SIZE, padding + (STACK_HEIGHT + 1) * CELL_SIZE 87 | ); 88 | m_pRenderTarget->FillRectangle(&rectangle3, m_pBlueBrush); 89 | 90 | // Drawing the cells 91 | 92 | for (int i = 0; i < STACK_HEIGHT; i++) 93 | { 94 | bool entireLine = true; 95 | for (int j = 0; j < STACK_WIDTH; j++) 96 | { 97 | if (cells->Get(j, i) == false) 98 | { 99 | entireLine = false; 100 | } 101 | } 102 | 103 | for (int j = 0; j < STACK_WIDTH; j++) 104 | { 105 | if (cells->Get(j, i) == true) 106 | { 107 | D2D1_RECT_F rectangle4 = D2D1::RectF( 108 | padding + (j + 1) * CELL_SIZE + 1, padding + i * CELL_SIZE + 1, 109 | padding + (j + 2) * CELL_SIZE - 1, padding + (i + 1) * CELL_SIZE - 1 110 | ); 111 | if (entireLine) 112 | { 113 | m_pRenderTarget->FillRectangle(&rectangle4, m_pYellowBrush); 114 | } 115 | else 116 | { 117 | m_pRenderTarget->FillRectangle(&rectangle4, m_pGreenBrush); 118 | } 119 | } 120 | } 121 | } 122 | 123 | } 124 | 125 | Matrix* Stack::GetCells() 126 | { 127 | return cells; 128 | } 129 | -------------------------------------------------------------------------------- /Piece.cpp: -------------------------------------------------------------------------------- 1 | #include "framework.h" 2 | #include "Point2D.h" 3 | #include "Matrix.h" 4 | #include "Piece.h" 5 | #include "Engine.h" 6 | 7 | Piece::Piece() : m_pRedBrush(NULL) 8 | { 9 | 10 | position.x = STACK_WIDTH / 2 - 2; 11 | position.y = 0; 12 | 13 | waiting = true; 14 | 15 | cells = new Matrix(4, 4); 16 | // Randomly select the piece type 17 | int pieceType = rand() % 7; 18 | for (int i = 0; i < 4; i++) 19 | { 20 | for (int j = 0; j < 4; j++) 21 | { 22 | cells->Set(j, i, cellsTemplates[pieceType][i][j]); 23 | } 24 | } 25 | } 26 | 27 | Piece::~Piece() 28 | { 29 | delete cells; 30 | SafeRelease(&m_pRedBrush); 31 | } 32 | 33 | void Piece::InitializeD2D(ID2D1HwndRenderTarget* m_pRenderTarget) 34 | { 35 | // Creates a red brush for drawing 36 | m_pRenderTarget->CreateSolidColorBrush( 37 | D2D1::ColorF(D2D1::ColorF::Red), 38 | &m_pRedBrush 39 | ); 40 | } 41 | 42 | void Piece::Activate() 43 | { 44 | waiting = false; 45 | } 46 | 47 | bool Piece::Advance(Matrix* stackCells) 48 | { 49 | // Advances the piece down. If there is a collision, returns true and reverts the movement 50 | position.y += 1; 51 | 52 | if (StackCollision(stackCells)) 53 | { 54 | position.y -= 1; 55 | return true; 56 | } 57 | 58 | return false; 59 | } 60 | 61 | void Piece::GoLeft(Matrix* stackCells) 62 | { 63 | // Tries to go left, and checks for collisions with the wall or current stack 64 | int initialPosX = position.x; 65 | position.x -= 1; 66 | 67 | if (LeftWallCollision()) 68 | { 69 | position.x = initialPosX; 70 | return; 71 | } 72 | 73 | if (StackCollision(stackCells)) 74 | { 75 | position.x = initialPosX; 76 | return; 77 | } 78 | } 79 | 80 | void Piece::GoRight(Matrix* stackCells) 81 | { 82 | // Tries to go right, and checks for collisions with the wall or current stack 83 | int initialPosX = position.x; 84 | position.x += 1; 85 | 86 | if (RightWallCollision()) 87 | { 88 | position.x = initialPosX; 89 | return; 90 | } 91 | 92 | if (StackCollision(stackCells)) 93 | { 94 | position.x = initialPosX; 95 | return; 96 | } 97 | } 98 | 99 | void Piece::Rotate(Matrix* stackCells) 100 | { 101 | // Store initial values 102 | Matrix* temp = new Matrix(4, 4); 103 | for (int i = 0; i < 4; i++) 104 | { 105 | for (int j = 0; j < 4; j++) 106 | { 107 | temp->Set(j, i, cells->Get(j, i)); 108 | } 109 | } 110 | int initialPosX = position.x; 111 | 112 | // Rotate 113 | for (int i = 0; i < 4; i++) 114 | { 115 | for (int j = 0; j < 4; j++) 116 | { 117 | cells->Set(j, i, temp->Get(i, 3 - j)); 118 | } 119 | } 120 | 121 | while(LeftWallCollision()) 122 | { 123 | position.x += 1; 124 | }; 125 | while (RightWallCollision()) 126 | { 127 | position.x -= 1; 128 | }; 129 | 130 | if (StackCollision(stackCells)) { 131 | // Revert 132 | for (int i = 0; i < 4; i++) 133 | { 134 | for (int j = 0; j < 4; j++) 135 | { 136 | cells->Set(j, i, temp->Get(j, i)); 137 | } 138 | } 139 | position.x = initialPosX; 140 | return; 141 | } 142 | } 143 | 144 | bool Piece::LeftWallCollision() 145 | { 146 | // Returns true if we're in a collision with the left wall 147 | for (int i = 0; i < 4; i++) 148 | { 149 | for (int j = 0; j < 4; j++) 150 | { 151 | if (cells->Get(j, i) == true) 152 | { 153 | int realx = position.x + j; 154 | if (realx < 0) 155 | { 156 | return true; 157 | } 158 | } 159 | } 160 | } 161 | 162 | return false; 163 | } 164 | 165 | bool Piece::RightWallCollision() 166 | { 167 | // Returns true if we're in a collision with the right wall 168 | for (int i = 0; i < 4; i++) 169 | { 170 | for (int j = 0; j < 4; j++) 171 | { 172 | if (cells->Get(j, i) == true) 173 | { 174 | int realx = position.x + j; 175 | if (realx >= STACK_WIDTH) 176 | { 177 | return true; 178 | } 179 | } 180 | } 181 | } 182 | 183 | return false; 184 | } 185 | 186 | bool Piece::StackCollision(Matrix* stackCells) 187 | { 188 | // Returns true if we're in a collision with the bottom wall or current stack 189 | for (int i = 0; i < 4; i++) 190 | { 191 | for (int j = 0; j < 4; j++) 192 | { 193 | if (cells->Get(j, i) == true) 194 | { 195 | int realx = position.x + j; 196 | int realy = position.y + i; 197 | // Check if we are colliding with the bottom 198 | if (realy >= STACK_HEIGHT) 199 | { 200 | return true; 201 | } 202 | // Check if we are colliding with existing stack 203 | if (stackCells->Get(realx, realy)) 204 | { 205 | return true; 206 | } 207 | } 208 | } 209 | } 210 | return false; 211 | } 212 | 213 | void Piece::Draw(ID2D1HwndRenderTarget* m_pRenderTarget) 214 | { 215 | int padding = (RESOLUTION_Y - (STACK_HEIGHT + 1) * CELL_SIZE) / 2; 216 | 217 | int centerRight = RESOLUTION_X - (RESOLUTION_X - padding - (STACK_WIDTH + 2) * CELL_SIZE) / 2; 218 | 219 | int center_x = centerRight; 220 | int center_y = padding + 2 * CELL_SIZE + 100; 221 | 222 | if (!waiting) 223 | { 224 | center_x = padding + (position.x + 1) * CELL_SIZE; 225 | center_y = padding + position.y * CELL_SIZE; 226 | } 227 | 228 | // Drawing the cells 229 | 230 | for (int i = 0; i < 4; i++) 231 | { 232 | for (int j = 0; j < 4; j++) 233 | { 234 | if (cells->Get(j, i) == true) 235 | { 236 | D2D1_RECT_F rectangle4 = D2D1::RectF( 237 | center_x + j * CELL_SIZE + 1, center_y + i * CELL_SIZE + 1, 238 | center_x + (j + 1) * CELL_SIZE - 1, center_y + (i + 1) * CELL_SIZE - 1 239 | ); 240 | m_pRenderTarget->FillRectangle(&rectangle4, m_pRedBrush); 241 | } 242 | } 243 | } 244 | 245 | } 246 | 247 | Point2D Piece::GetPosition() 248 | { 249 | return position; 250 | } 251 | 252 | Matrix* Piece::GetCells() 253 | { 254 | return cells; 255 | } -------------------------------------------------------------------------------- /App.cpp: -------------------------------------------------------------------------------- 1 | // Tetris.cpp : Defines the entry point for the application. 2 | // 3 | 4 | #include "framework.h" 5 | #include "Engine.h" 6 | #include "App.h" 7 | 8 | #pragma comment(lib, "d2d1") 9 | 10 | // Forward declarations of functions included in this code module: 11 | 12 | int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) 13 | { 14 | HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0); 15 | 16 | if (SUCCEEDED(CoInitialize(NULL))) 17 | { 18 | MainApp app; 19 | 20 | if (SUCCEEDED(app.Initialize())) 21 | { 22 | app.RunMessageLoop(); 23 | } 24 | 25 | CoUninitialize(); 26 | } 27 | 28 | return 0; 29 | } 30 | 31 | 32 | MainApp::MainApp() : m_hwnd(NULL) 33 | { 34 | engine = new Engine(); 35 | } 36 | 37 | 38 | MainApp::~MainApp() 39 | { 40 | } 41 | 42 | 43 | void MainApp::RunMessageLoop() 44 | { 45 | MSG msg; 46 | 47 | std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now(); 48 | std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now(); 49 | int frames = 0; 50 | double framesTime = 0; 51 | 52 | boolean running = true; 53 | while (running) 54 | { 55 | 56 | end = std::chrono::steady_clock::now(); 57 | double elapsed_secs = std::chrono::duration_cast(end - begin).count() / 1000000.0; 58 | begin = end; 59 | 60 | // Display FPS 61 | framesTime += elapsed_secs; 62 | frames++; 63 | if (framesTime > 1) { 64 | WCHAR fpsText[32]; 65 | swprintf(fpsText, 32, L"Game: %d FPS", frames); 66 | SetWindowText(m_hwnd, fpsText); 67 | frames = 0; 68 | framesTime = 0; 69 | } 70 | 71 | // Messages and user input 72 | while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 73 | { 74 | TranslateMessage(&msg); 75 | DispatchMessage(&msg); 76 | if (msg.message == WM_QUIT) 77 | running = false; 78 | } 79 | 80 | // Game logic 81 | engine->Logic(elapsed_secs); 82 | 83 | // Drawing 84 | engine->Draw(); 85 | } 86 | } 87 | 88 | 89 | HRESULT MainApp::Initialize() 90 | { 91 | HRESULT hr = S_OK; 92 | 93 | // Register the window class. 94 | WNDCLASSEX wcex = { sizeof(WNDCLASSEX) }; 95 | wcex.style = CS_HREDRAW | CS_VREDRAW; 96 | wcex.lpfnWndProc = MainApp::WndProc; 97 | wcex.cbClsExtra = 0; 98 | wcex.cbWndExtra = 0; 99 | wcex.hInstance = HINST_THISCOMPONENT; 100 | wcex.hbrBackground = NULL; 101 | wcex.lpszMenuName = NULL; 102 | wcex.hCursor = LoadCursor(NULL, IDI_APPLICATION); 103 | wcex.lpszClassName = L"D2DMainApp"; 104 | 105 | ATOM x = RegisterClassEx(&wcex); 106 | 107 | // Create the window. 108 | m_hwnd = CreateWindowEx( 109 | NULL, 110 | L"D2DMainApp", 111 | L"Game", 112 | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, 113 | CW_USEDEFAULT, 114 | CW_USEDEFAULT, 115 | RESOLUTION_X, 116 | RESOLUTION_Y, 117 | NULL, 118 | NULL, 119 | HINST_THISCOMPONENT, 120 | this 121 | ); 122 | hr = m_hwnd ? S_OK : E_FAIL; 123 | 124 | // Adjust it so the client area is RESOLUTION_X/RESOLUTION_Y 125 | RECT rect1; 126 | GetWindowRect(m_hwnd, &rect1); 127 | RECT rect2; 128 | GetClientRect(m_hwnd, &rect2); 129 | 130 | SetWindowPos( 131 | m_hwnd, 132 | NULL, 133 | rect1.left, 134 | rect1.top, 135 | RESOLUTION_X + ((rect1.right - rect1.left) - (rect2.right - rect2.left)), 136 | RESOLUTION_Y + ((rect1.bottom - rect1.top) - (rect2.bottom - rect2.top)), 137 | NULL 138 | ); 139 | 140 | if (SUCCEEDED(hr)) 141 | { 142 | engine->InitializeD2D(m_hwnd); 143 | 144 | ShowWindow(m_hwnd, SW_SHOWNORMAL); 145 | UpdateWindow(m_hwnd); 146 | } 147 | 148 | return hr; 149 | } 150 | 151 | LRESULT CALLBACK MainApp::WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 152 | { 153 | LRESULT result = 0; 154 | 155 | if (message == WM_CREATE) 156 | { 157 | LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam; 158 | MainApp* pMainApp = (MainApp*)pcs->lpCreateParams; 159 | 160 | ::SetWindowLongPtrW( 161 | hwnd, 162 | GWLP_USERDATA, 163 | reinterpret_cast(pMainApp) 164 | ); 165 | 166 | result = 1; 167 | } 168 | else 169 | { 170 | MainApp* pMainApp = reinterpret_cast(static_cast( 171 | ::GetWindowLongPtrW( 172 | hwnd, 173 | GWLP_USERDATA 174 | ))); 175 | 176 | bool wasHandled = false; 177 | 178 | if (pMainApp) 179 | { 180 | switch (message) 181 | { 182 | 183 | case WM_DISPLAYCHANGE: 184 | { 185 | InvalidateRect(hwnd, NULL, FALSE); 186 | } 187 | result = 0; 188 | wasHandled = true; 189 | break; 190 | 191 | case WM_KEYDOWN: 192 | { 193 | pMainApp->engine->KeyDown(wParam); 194 | } 195 | result = 0; 196 | wasHandled = true; 197 | break; 198 | 199 | case WM_KEYUP: 200 | { 201 | pMainApp->engine->KeyUp(wParam); 202 | } 203 | result = 0; 204 | wasHandled = true; 205 | break; 206 | 207 | case WM_MOUSEMOVE: 208 | { 209 | pMainApp->engine->MousePosition(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); 210 | } 211 | result = 0; 212 | wasHandled = true; 213 | break; 214 | 215 | case WM_LBUTTONUP: 216 | { 217 | pMainApp->engine->MouseButtonUp(true, false); 218 | } 219 | result = 0; 220 | wasHandled = true; 221 | break; 222 | 223 | case WM_LBUTTONDOWN: 224 | { 225 | pMainApp->engine->MouseButtonDown(true, false); 226 | } 227 | result = 0; 228 | wasHandled = true; 229 | break; 230 | 231 | case WM_RBUTTONUP: 232 | { 233 | pMainApp->engine->MouseButtonUp(false, true); 234 | } 235 | result = 0; 236 | wasHandled = true; 237 | break; 238 | 239 | case WM_RBUTTONDOWN: 240 | { 241 | pMainApp->engine->MouseButtonDown(false, true); 242 | } 243 | result = 0; 244 | wasHandled = true; 245 | break; 246 | 247 | case WM_DESTROY: 248 | { 249 | PostQuitMessage(0); 250 | } 251 | result = 1; 252 | wasHandled = true; 253 | break; 254 | } 255 | } 256 | 257 | if (!wasHandled) 258 | { 259 | result = DefWindowProc(hwnd, message, wParam, lParam); 260 | } 261 | } 262 | 263 | return result; 264 | } 265 | -------------------------------------------------------------------------------- /Tetris.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | {79C2EA07-9615-4355-954E-7F53F4C7C538} 24 | Win32Proj 25 | Tetris 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v142 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v142 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | true 78 | 79 | 80 | false 81 | 82 | 83 | false 84 | 85 | 86 | 87 | 88 | 89 | Level3 90 | true 91 | WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) 92 | true 93 | 94 | 95 | Windows 96 | true 97 | 98 | 99 | 100 | 101 | 102 | 103 | Level3 104 | true 105 | _DEBUG;_WINDOWS;%(PreprocessorDefinitions) 106 | true 107 | 108 | 109 | Windows 110 | true 111 | 112 | 113 | 114 | 115 | 116 | 117 | Level3 118 | true 119 | true 120 | true 121 | WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 122 | true 123 | 124 | 125 | Windows 126 | true 127 | true 128 | true 129 | 130 | 131 | 132 | 133 | 134 | 135 | Level3 136 | true 137 | true 138 | true 139 | NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 140 | true 141 | 142 | 143 | Windows 144 | true 145 | true 146 | true 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | -------------------------------------------------------------------------------- /Engine.cpp: -------------------------------------------------------------------------------- 1 | #include "framework.h" 2 | #include "Matrix.h" 3 | #include "Stack.h" 4 | #include "Piece.h" 5 | #include "Engine.h" 6 | 7 | #pragma comment(lib, "d2d1") 8 | #pragma comment(lib, "dwrite") 9 | #pragma comment(lib, "Windowscodecs.lib") 10 | 11 | Engine::Engine() : m_pDirect2dFactory(NULL), m_pRenderTarget(NULL) 12 | { 13 | // Constructor 14 | // Initialize your game elements here 15 | 16 | srand(time(NULL)); 17 | 18 | stack = new Stack(); 19 | 20 | activePiece = new Piece(); 21 | activePiece->Activate(); 22 | waitingPiece = new Piece(); 23 | 24 | autoFallDelay = 1; 25 | autoFallAccumulated = 0; 26 | keyPressDelay = 0.07; 27 | keyPressAccumulated = 0; 28 | 29 | } 30 | 31 | Engine::~Engine() 32 | { 33 | // Destructor 34 | 35 | SafeRelease(&m_pDirect2dFactory); 36 | SafeRelease(&m_pRenderTarget); 37 | 38 | // Safe-release your game elements here 39 | delete stack; 40 | delete waitingPiece; 41 | delete activePiece; 42 | } 43 | 44 | HRESULT Engine::InitializeD2D(HWND m_hwnd) 45 | { 46 | // Initializes Direct2D, for drawing 47 | D2D1_SIZE_U size = D2D1::SizeU(RESOLUTION_X, RESOLUTION_Y); 48 | D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_pDirect2dFactory); 49 | m_pDirect2dFactory->CreateHwndRenderTarget( 50 | D2D1::RenderTargetProperties(), 51 | D2D1::HwndRenderTargetProperties(m_hwnd, size, D2D1_PRESENT_OPTIONS_IMMEDIATELY), 52 | &m_pRenderTarget 53 | ); 54 | 55 | // Initialize the D2D part of your game elements here 56 | InitializeTextAndScore(); 57 | stack->InitializeD2D(m_pRenderTarget); 58 | activePiece->InitializeD2D(m_pRenderTarget); 59 | waitingPiece->InitializeD2D(m_pRenderTarget); 60 | 61 | return S_OK; 62 | } 63 | 64 | void Engine::InitializeTextAndScore() 65 | { 66 | DWriteCreateFactory( 67 | DWRITE_FACTORY_TYPE_SHARED, 68 | __uuidof(m_pDWriteFactory), 69 | reinterpret_cast(&m_pDWriteFactory) 70 | ); 71 | 72 | m_pDWriteFactory->CreateTextFormat( 73 | L"Verdana", 74 | NULL, 75 | DWRITE_FONT_WEIGHT_NORMAL, 76 | DWRITE_FONT_STYLE_NORMAL, 77 | DWRITE_FONT_STRETCH_NORMAL, 78 | 20, 79 | L"", //locale 80 | &m_pTextFormat 81 | ); 82 | 83 | m_pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER); 84 | 85 | m_pTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER); 86 | 87 | m_pRenderTarget->CreateSolidColorBrush( 88 | D2D1::ColorF(D2D1::ColorF::White), 89 | &m_pWhiteBrush 90 | ); 91 | } 92 | 93 | void Engine::KeyUp(WPARAM wParam) 94 | { 95 | // If keyup, un-set the keys flags 96 | // Don't do any logic here, you want to control the actual logic in the Logic method below 97 | if (wParam == VK_DOWN) 98 | downPressed = false; 99 | 100 | if (wParam == VK_LEFT) 101 | leftPressed = false; 102 | 103 | if (wParam == VK_RIGHT) 104 | rightPressed = false; 105 | 106 | if (wParam == VK_SPACE || wParam == VK_UP) 107 | spacePressed = false; 108 | } 109 | 110 | void Engine::KeyDown(WPARAM wParam) 111 | { 112 | // If keyup, set the keys flags 113 | // Don't do any logic here, you want to control the actual logic in the Logic method below 114 | if (wParam == VK_DOWN) 115 | downPressed = true; 116 | 117 | if (wParam == VK_LEFT) 118 | leftPressed = true; 119 | 120 | if (wParam == VK_RIGHT) 121 | rightPressed = true; 122 | 123 | if (wParam == VK_SPACE || wParam == VK_UP) 124 | spacePressed = true; 125 | } 126 | 127 | void Engine::MousePosition(int x, int y) 128 | { 129 | // Campture mouse position when the mouse moves 130 | // Don't do any logic here, you want to control the actual logic in the Logic method below 131 | } 132 | 133 | void Engine::MouseButtonUp(bool left, bool right) 134 | { 135 | // If mouse button is released, set the mouse flags 136 | // Don't do any logic here, you want to control the actual logic in the Logic method below 137 | } 138 | 139 | void Engine::MouseButtonDown(bool left, bool right) 140 | { 141 | // If mouse button is pressed, set the mouse flags 142 | // Don't do any logic here, you want to control the actual logic in the Logic method below 143 | } 144 | 145 | void Engine::Logic(double elapsedTime) 146 | { 147 | // This is the logic part of the engine. It receives the elapsed time from the app class, in seconds. 148 | // It uses this value for a smooth and consistent movement, regardless of the CPU or graphics speed 149 | 150 | if (gameOver) // Do nothing if game over 151 | { 152 | return; 153 | } 154 | 155 | // We will need the stack in several places below 156 | Matrix* stackCells = stack->GetCells(); 157 | 158 | // Due to a high FPS, we can't consider the keys at every frame because movement will be very fast 159 | // So we're using a delay, and if enough time has passed we take a key press into consideration 160 | keyPressAccumulated += elapsedTime; 161 | if (keyPressAccumulated > keyPressDelay) 162 | { 163 | keyPressAccumulated = 0; 164 | 165 | if (leftPressed || rightPressed || spacePressed) 166 | { 167 | // Remove any full rows 168 | int removed = stack->RemoveLines(); 169 | if (removed > 0) 170 | { 171 | score += pow(2, removed) * 100; 172 | autoFallDelay = autoFallDelay * 0.98; 173 | } 174 | } 175 | 176 | // Move left or right 177 | if (leftPressed) 178 | activePiece->GoLeft(stackCells); 179 | if (rightPressed) 180 | activePiece->GoRight(stackCells); 181 | 182 | // Rotate 183 | if (spacePressed) 184 | { 185 | activePiece->Rotate(stackCells); 186 | spacePressed = false; 187 | } 188 | 189 | // Move down 190 | // On this one we will just set autoFallAccumulated to be high, because we have the down movemenet logic below 191 | if (downPressed) 192 | autoFallAccumulated = autoFallDelay + 1; 193 | } 194 | 195 | // The piece falls automatically after a delay 196 | autoFallAccumulated += elapsedTime; 197 | if (autoFallAccumulated > autoFallDelay) 198 | { 199 | autoFallAccumulated = 0; 200 | 201 | // Remove any full rows 202 | int removed = stack->RemoveLines(); 203 | if (removed > 0) 204 | { 205 | score += pow(2, removed) * 100; 206 | autoFallDelay = autoFallDelay * 0.98; 207 | } 208 | 209 | // Move down the active piece 210 | bool isConflict = activePiece->Advance(stackCells); 211 | // If we have a conflict with the stack, it means we were sitting on the stack or bottom wall already 212 | if (isConflict) 213 | { 214 | // We add the piece to stack 215 | for (int i = 0; i < 4; i++) 216 | { 217 | for (int j = 0; j < 4; j++) 218 | { 219 | if (activePiece->GetCells()->Get(j, i) == true) 220 | { 221 | int realx = activePiece->GetPosition().x + j; 222 | int realy = activePiece->GetPosition().y + i; 223 | stackCells->Set(realx, realy, true); 224 | } 225 | } 226 | } 227 | 228 | // Delete active piece, activate the waiting piece and generate new waiting piece 229 | delete activePiece; 230 | activePiece = waitingPiece; 231 | activePiece->Activate(); 232 | waitingPiece = new Piece(); 233 | waitingPiece->InitializeD2D(m_pRenderTarget); 234 | 235 | // If we have a collision right after we generate the new piece, 236 | // it means the stack is too high, so game over 237 | if (activePiece->StackCollision(stackCells)) 238 | gameOver = true; 239 | } 240 | } 241 | 242 | } 243 | 244 | HRESULT Engine::Draw() 245 | { 246 | // This is the drawing method of the engine. 247 | // It runs every frame 248 | 249 | // Draws the elements in the game using Direct2D 250 | HRESULT hr; 251 | 252 | m_pRenderTarget->BeginDraw(); 253 | 254 | m_pRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity()); 255 | 256 | 257 | m_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::Black)); 258 | 259 | // Below you can add drawing logic for your game elements 260 | DrawTextAndScore(); 261 | stack->Draw(m_pRenderTarget); 262 | activePiece->Draw(m_pRenderTarget); 263 | waitingPiece->Draw(m_pRenderTarget); 264 | 265 | hr = m_pRenderTarget->EndDraw(); 266 | 267 | return S_OK; 268 | } 269 | 270 | void Engine::DrawTextAndScore() 271 | { 272 | // Text and score 273 | int padding = (RESOLUTION_Y - (STACK_HEIGHT + 1) * CELL_SIZE) / 2; 274 | int centerRight = RESOLUTION_X - (RESOLUTION_X - padding - (STACK_WIDTH + 2) * CELL_SIZE) / 2; 275 | 276 | 277 | D2D1_RECT_F rectangle1 = D2D1::RectF(centerRight - 200, padding, centerRight + 200, padding + 100); 278 | m_pRenderTarget->DrawText( 279 | L"Next Piece", 280 | 15, 281 | m_pTextFormat, 282 | rectangle1, 283 | m_pWhiteBrush 284 | ); 285 | 286 | 287 | D2D1_RECT_F rectangle2 = D2D1::RectF(centerRight - 200, padding + 200, centerRight + 200, padding + 300); 288 | m_pRenderTarget->DrawText( 289 | L"Score", 290 | 5, 291 | m_pTextFormat, 292 | rectangle2, 293 | m_pWhiteBrush 294 | ); 295 | 296 | 297 | D2D1_RECT_F rectangle3 = D2D1::RectF(centerRight - 200, padding + 300, centerRight + 200, padding + 400); 298 | WCHAR scoreStr[64]; 299 | swprintf_s(scoreStr, L"%d ", score); 300 | m_pRenderTarget->DrawText( 301 | scoreStr, 302 | 7, 303 | m_pTextFormat, 304 | rectangle3, 305 | m_pWhiteBrush 306 | ); 307 | } 308 | --------------------------------------------------------------------------------