├── .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 |
--------------------------------------------------------------------------------