├── .gitignore ├── README.md ├── pacplusplusman.sln └── src ├── Constants.h ├── Game.cpp ├── Game.h ├── Ghost.cpp ├── Ghost.h ├── Main.cpp ├── Pacman.cpp ├── Pacman.h ├── Pellet.cpp ├── Pellet.h ├── SetConsoleAttributes.cpp ├── SetConsoleAttributes.h ├── pacplusplusman.ico ├── pacplusplusman.rc ├── pacplusplusman.vcxproj └── resource.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Applications 2 | *.exe 3 | 4 | # Incremental Linker Files 5 | *.ilk 6 | 7 | # Program Debug Databases 8 | *.pdb 9 | *.ipdb 10 | 11 | # SQL Database Files 12 | *.sdf 13 | *.opensdf 14 | *.db 15 | *.opendb 16 | 17 | # Visual Studio Solution User Options 18 | *.suo 19 | 20 | # Visual Studio Project User Options 21 | *.vcxproj.user 22 | 23 | # Object Files 24 | *.obj 25 | *.iobj 26 | 27 | # Log Files 28 | *.log 29 | *.tlog 30 | *.lastbuildstate 31 | 32 | # Compiled Resource Scripts 33 | *.res 34 | *.aps 35 | 36 | # Dependency Files 37 | *.idb 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | PAC++MAN 2 | ======== 3 | 4 | A C++ Console Application 5 | 6 | 7 | This is a C++ console application video game that I have written 8 | by myself, modeled after the classic arcade game, PAC-MAN. 9 | 10 | A demo can be found here: 11 | https://www.youtube.com/watch?v=nAFCtZF92UY 12 | 13 | No copyright infringement intended. 14 | -------------------------------------------------------------------------------- /pacplusplusman.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.21005.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pacplusplusman", "src\pacplusplusman.vcxproj", "{0C9D0898-DCA7-471B-9249-C9CE92A07F4A}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Release|Win32 = Release|Win32 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {0C9D0898-DCA7-471B-9249-C9CE92A07F4A}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {0C9D0898-DCA7-471B-9249-C9CE92A07F4A}.Debug|Win32.Build.0 = Debug|Win32 16 | {0C9D0898-DCA7-471B-9249-C9CE92A07F4A}.Release|Win32.ActiveCfg = Release|Win32 17 | {0C9D0898-DCA7-471B-9249-C9CE92A07F4A}.Release|Win32.Build.0 = Release|Win32 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /src/Constants.h: -------------------------------------------------------------------------------- 1 | #ifndef CONSTANTS_H 2 | #define CONSTANTS_H 3 | 4 | #include 5 | 6 | // level properties 7 | const int LEVEL_HEIGHT = 31; 8 | const int LEVEL_WIDTH = 28; 9 | const char NO_COLLISION_TILES[3] = {' ','o','\xfa'}; 10 | const int GATE_X = 13; 11 | const int GATE_Y = 12; 12 | 13 | // directions and icons 14 | const char ALL_DIRS[4] = {'w','a','s','d'}; 15 | const char ICONS[4] = {'v','>','^','<'}; 16 | const char GHOST_ICON = 'M'; 17 | const char DEAD_GHOST_ICON = '"'; 18 | 19 | // colors 20 | const int WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY; 21 | const int RED = FOREGROUND_RED | FOREGROUND_INTENSITY; 22 | const int BLUE = FOREGROUND_BLUE | FOREGROUND_INTENSITY; 23 | const int DARK_BLUE = FOREGROUND_BLUE; 24 | const int CYAN = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY; 25 | const int MAGENTA = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY; 26 | const int YELLOW = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY; 27 | const int BLACK = 0; 28 | 29 | // timers 30 | const int SUPER_MAX = 500; 31 | const int ONE_UP_MAX = 13; 32 | const int PELLET_MAX = 8; 33 | const int PACMAN_MAX = 8; 34 | const int GHOST_MAX = 10; 35 | const int RUN_MAX = 16; 36 | const int DEAD_MAX = 3; 37 | const int MODE_MAX = 1000; 38 | 39 | // Ghost Names 40 | const int BLINKY = 0; 41 | const int PINKY = 1; 42 | const int INKY = 2; 43 | const int CLYDE = 3; 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/Game.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "Constants.h" 5 | 6 | #include "Game.h" 7 | #include "Pacman.h" 8 | #include "Ghost.h" 9 | #include "Pellet.h" 10 | #include "SetConsoleAttributes.h" 11 | 12 | using namespace std; 13 | 14 | Game::Game() { 15 | SetWindowTitle("PAC++MAN"); 16 | SetWindowSize(LEVEL_HEIGHT + 4, LEVEL_WIDTH); 17 | SetCursorVisibility(false); 18 | player = new Pacman(this); 19 | for (int i = 0; i < 4; ++i) { 20 | ghosts[i] = new Ghost(this); 21 | pellets[i] = new Pellet(this); 22 | } 23 | } 24 | 25 | Game::~Game() { 26 | delete player; 27 | for (int i = 0; i < 4; ++i) { 28 | delete ghosts[i]; 29 | delete pellets[i]; 30 | } 31 | } 32 | 33 | void Game::Go() { 34 | while (true) { 35 | MainLoop(); 36 | } 37 | } 38 | 39 | void Game::MainLoop() { 40 | player->SetScore(0); 41 | player->SetLives(3); 42 | bool gameOver = false; 43 | for (int levelNum = 1; levelNum <= 255; ++levelNum) { 44 | LoadLevel(); 45 | // while there are still dots on the screen, 46 | while (player->GetLeft() != 0) { 47 | player->Move(); 48 | CheckForDeath(); 49 | if (!player->GetLives()) { 50 | gameOver = true; 51 | break; 52 | } 53 | MoveGhosts(); 54 | CheckForDeath(); 55 | if (!player->GetLives()) { 56 | gameOver = true; 57 | break; 58 | } 59 | UpdateTimers(); 60 | } 61 | if (gameOver) { 62 | break; 63 | } 64 | NextLevel(); 65 | } 66 | } 67 | 68 | void Game::LoadLevel() { 69 | char levelMap[LEVEL_HEIGHT][LEVEL_WIDTH + 1] = { 70 | "1555555555555555555555555552", 71 | "6............^^............6", 72 | "6.!%%@.!%%%@.^^.!%%%@.!%%@.6", 73 | "67^ ^.^ ^.^^.^ ^.^ ^86", 74 | "6.#%%$.#%%%$.#$.#%%%$.#%%$.6", 75 | "6..........................6", 76 | "6.!%%@.!@.!%%%%%%@.!@.!%%@.6", 77 | "6.#%%$.^^.#%%@!%%$.^^.#%%$.6", 78 | "6......^^....^^....^^......6", 79 | "355552.^#%%@ ^^ !%%$^.155554", 80 | " 6.^!%%$ #$ #%%@^.6 ", 81 | " 6.^^ B ^^.6 ", 82 | " 6.^^ 155&&552 ^^.6 ", 83 | "555554.#$ 6 6 #$.355555", 84 | " . 6I C 6 . ", 85 | "555552.!@ 6 P 6 !@.155555", 86 | " 6.^^ 35555554 ^^.6 ", 87 | " 6.^^ ^^.6 ", 88 | " 6.^^ !%%%%%%@ ^^.6 ", 89 | "155554.#$ #%%@!%%$ #$.355552", 90 | "6............^^............6", 91 | "6.!%%@.!%%%@.^^.!%%%@.!%%@.6", 92 | "6.#%@^.#%%%$.#$.#%%%$.^!%$.6", 93 | "69..^^.......X .......^^..06", 94 | "6%@.^^.!@.!%%%%%%@.!@.^^.!%6", 95 | "6%$.#$.^^.#%%@!%%$.^^.#$.#%6", 96 | "6......^^....^^....^^......6", 97 | "6.!%%%%$#%%@.^^.!%%$#%%%%@.6", 98 | "6.#%%%%%%%%$.#$.#%%%%%%%%$.6", 99 | "6..........................6", 100 | "3555555555555555555555555554"}; 101 | char curChar; 102 | SetTextColor(WHITE); 103 | SetCursorPosition(-3, 3); 104 | cout << "1UP"; 105 | SetCursorPosition(-3, 9); 106 | cout << "HIGH SCORE"; 107 | player->PrintScore(0); 108 | SetCursorPosition(0, 0); 109 | player->SetLeft(0); 110 | for (int y = 0; y < LEVEL_HEIGHT; ++y) { 111 | for (int x = 0; x < LEVEL_WIDTH; ++x) { 112 | curChar = levelMap[y][x]; 113 | SetTextColor(DARK_BLUE); 114 | switch (curChar) { 115 | case 'X': 116 | player->SetYInit(y); 117 | player->SetXInit(x); 118 | level[y][x] = ' '; 119 | break; 120 | case 'B': 121 | ghosts[BLINKY]->SetYInit(y); 122 | ghosts[BLINKY]->SetXInit(x); 123 | ghosts[BLINKY]->SetColorInit(RED); 124 | ghosts[BLINKY]->SetDirOpp('s'); 125 | level[y][x] = ' '; 126 | break; 127 | case 'P': 128 | ghosts[PINKY]->SetYInit(y); 129 | ghosts[PINKY]->SetXInit(x); 130 | ghosts[PINKY]->SetColorInit(MAGENTA); 131 | level[y][x] = ' '; 132 | break; 133 | case 'I': 134 | ghosts[INKY]->SetYInit(y); 135 | ghosts[INKY]->SetXInit(x); 136 | ghosts[INKY]->SetColorInit(CYAN); 137 | level[y][x] = ' '; 138 | break; 139 | case 'C': 140 | ghosts[CLYDE]->SetYInit(y); 141 | ghosts[CLYDE]->SetXInit(x); 142 | ghosts[CLYDE]->SetColorInit(YELLOW); 143 | level[y][x] = ' '; 144 | break; 145 | case '7': 146 | pellets[0]->SetY(y); 147 | pellets[0]->SetX(x); 148 | SetTextColor(WHITE); 149 | level[y][x] = 'o'; 150 | player->SetLeft(player->GetLeft() + 1); 151 | break; 152 | case '8': 153 | pellets[1]->SetY(y); 154 | pellets[1]->SetX(x); 155 | SetTextColor(WHITE); 156 | level[y][x] = 'o'; 157 | player->SetLeft(player->GetLeft() + 1); 158 | break; 159 | case '9': 160 | pellets[2]->SetY(y); 161 | pellets[2]->SetX(x); 162 | SetTextColor(WHITE); 163 | level[y][x] = 'o'; 164 | player->SetLeft(player->GetLeft() + 1); 165 | break; 166 | case '0': 167 | pellets[3]->SetY(y); 168 | pellets[3]->SetX(x); 169 | SetTextColor(WHITE); 170 | level[y][x] = 'o'; 171 | player->SetLeft(player->GetLeft() + 1); 172 | break; 173 | case '.': 174 | SetTextColor(WHITE); 175 | level[y][x] = char(250); 176 | player->SetLeft(player->GetLeft() + 1); 177 | break; 178 | case ' ': 179 | level[y][x] = curChar; 180 | break; 181 | case '&': 182 | SetTextColor(WHITE); 183 | curChar = '%'; 184 | } 185 | if (curChar == '1') { 186 | level[y][x] = char(201); 187 | } 188 | else if (curChar == '2') { 189 | level[y][x] = char(187); 190 | } 191 | else if (curChar == '3') { 192 | level[y][x] = char(200); 193 | } 194 | else if (curChar == '4') { 195 | level[y][x] = char(188); 196 | } 197 | else if (curChar == '5') { 198 | level[y][x] = char(205); 199 | } 200 | else if (curChar == '6') { 201 | level[y][x] = char(186); 202 | } 203 | else if (curChar == '!') { 204 | level[y][x] = char(218); 205 | } 206 | else if (curChar == '@') { 207 | level[y][x] = char(191); 208 | } 209 | else if (curChar == '#') { 210 | level[y][x] = char(192); 211 | } 212 | else if (curChar == '$') { 213 | level[y][x] = char(217); 214 | } 215 | else if (curChar == '%') { 216 | level[y][x] = char(196); 217 | } 218 | else if (curChar == '^') { 219 | level[y][x] = char(179); 220 | } 221 | cout << level[y][x]; 222 | } 223 | SetCursorPosition(y + 1, 0); 224 | } 225 | InitAll(); 226 | ShowAll(); 227 | player->PrintLives(); 228 | PrintReady(); 229 | } 230 | 231 | void Game::NextLevel() { 232 | Sleep(1000); 233 | HideAll(); 234 | SetCursorPosition(12, 13); 235 | cout << " "; 236 | for (int i = 0; i < 4; ++i) { 237 | SetScreenColor(WHITE); 238 | player->Show(); 239 | Sleep(200); 240 | SetScreenColor(DARK_BLUE); 241 | player->Show(); 242 | Sleep(200); 243 | } 244 | SetCursorPosition(0, 0); 245 | InitAll(); 246 | } 247 | 248 | void Game::PrintReady() { 249 | SetTextColor(YELLOW); 250 | SetCursorPosition(17, 11); 251 | cout << "READY!"; 252 | Sleep(2000); 253 | SetCursorPosition(17, 11); 254 | cout << " "; 255 | } 256 | 257 | void Game::PrintGameOver() { 258 | SetCursorPosition(17, 9); 259 | SetTextColor(RED); 260 | cout << "GAME OVER"; 261 | Sleep(1000); 262 | } 263 | 264 | void Game::MoveGhosts() { 265 | // check for ghost mode changes 266 | if (player->GetSuper() == SUPER_MAX) { 267 | player->SetKillCount(0); 268 | for (int i = 0; i < 4; ++i) { 269 | if (ghosts[i]->GetMode() != 'd') { 270 | ghosts[i]->SetColor(BLUE); 271 | } 272 | if (ghosts[i]->GetMode() == 's' || ghosts[i]->GetMode() == 'c') { 273 | ghosts[i]->SetMode('r'); 274 | } 275 | } 276 | ShowAll(); 277 | } 278 | if (player->GetLeft() == 235 && ghosts[PINKY]->GetMode() == 'w') { 279 | ghosts[PINKY]->SetMode('e'); 280 | } 281 | if (player->GetLeft() == 200 && ghosts[INKY]->GetMode() == 'w') { 282 | ghosts[INKY]->SetMode('e'); 283 | } 284 | if (player->GetLeft() == 165 && ghosts[CLYDE]->GetMode() == 'w') { 285 | ghosts[CLYDE]->SetMode('e'); 286 | } 287 | for (int i = 0; i < 4; ++i) { 288 | ghosts[i]->Move(player->GetY(), player->GetX()); 289 | } 290 | ShowAll(); 291 | } 292 | 293 | void Game::UpdateTimers() { 294 | // handle super pacman 295 | if (player->GetSuper()) { 296 | player->SetSuper(player->GetSuper() - 1); 297 | if (player->GetSuper() <= 112 && player->GetSuper() % 28 == 0) { 298 | for (int i = 0; i < 4; ++i) 299 | if (ghosts[i]->GetColor() == BLUE) { 300 | ghosts[i]->SetColor(WHITE); 301 | } 302 | ShowAll(); 303 | } 304 | if (player->GetSuper() <= 98 && (player->GetSuper() + 14) % 28 == 0) { 305 | for (int i = 0; i < 4; ++i) { 306 | if (ghosts[i]->GetColor() == WHITE && ghosts[i]->GetMode() != 'd' && ghosts[i]->GetMode() != 'n') { 307 | ghosts[i]->SetColor(BLUE); 308 | } 309 | } 310 | ShowAll(); 311 | } 312 | if (!player->GetSuper()) { 313 | for (int i = 0; i < 4; ++i) { 314 | if (ghosts[i]->GetMode() != 'd' && ghosts[i]->GetMode() != 'n') { 315 | ghosts[i]->SetColor(ghosts[i]->GetColorInit()); 316 | } 317 | if (ghosts[i]->GetMode() == 'r') { 318 | ghosts[i]->SetModeOld(ghosts[i]->GetMode()); 319 | ghosts[i]->SetMode('c'); 320 | } 321 | } 322 | ShowAll(); 323 | } 324 | } 325 | // handle flashing 1UP 326 | if (oneUpTimer) { 327 | --oneUpTimer; 328 | } 329 | else { 330 | if (oneUpColor == WHITE) { 331 | oneUpColor = BLACK; 332 | } 333 | else { 334 | oneUpColor = WHITE; 335 | } 336 | SetTextColor(oneUpColor); 337 | SetCursorPosition(-3, 3); 338 | cout << "1UP"; 339 | oneUpTimer = ONE_UP_MAX; 340 | } 341 | // handle flashing super pellets 342 | if (pelletTimer) { 343 | --pelletTimer; 344 | } 345 | else { 346 | if (pelletColor == WHITE) { 347 | pelletColor = BLACK; 348 | } 349 | else { 350 | pelletColor = WHITE; 351 | } 352 | SetTextColor(pelletColor); 353 | for (int i = 0; i < 4; ++i) { 354 | pellets[i]->Print(); 355 | } 356 | ShowAll(); 357 | pelletTimer = PELLET_MAX; 358 | } 359 | // handle ghost chase/scatter mode 360 | if (ghostModeTimer) { 361 | --ghostModeTimer; 362 | if (ghostModeTimer == MODE_MAX / 4) { 363 | for (int i = 0; i < 4; ++i) { 364 | if (ghosts[i]->GetMode() == 'c') { 365 | ghosts[i]->SetMode('s'); 366 | } 367 | } 368 | } 369 | } 370 | else { 371 | for (int i = 0; i < 4; ++i) { 372 | if (ghosts[i]->GetMode() == 's') { 373 | ghosts[i]->SetMode('c'); 374 | } 375 | } 376 | ghostModeTimer = MODE_MAX; 377 | } 378 | Sleep(15); 379 | } 380 | 381 | void Game::CheckForDeath() { 382 | for (int i = 0; i < 4; ++i) { 383 | if (player->GetX() == ghosts[i]->GetX() && player->GetY() == ghosts[i]->GetY() && 384 | ghosts[i]->GetMode() != 'd' && ghosts[i]->GetMode() != 'n') { 385 | if (ghosts[i]->GetMode() != 'r') { 386 | player->Dead(); 387 | } 388 | else { 389 | player->PrintKillScore(); 390 | ghosts[i]->Dead(); 391 | } 392 | } 393 | } 394 | } 395 | 396 | void Game::ShowAll() { 397 | player->Show(); 398 | for (int i = 0; i < 4; ++i) { 399 | ghosts[i]->Show(); 400 | } 401 | } 402 | 403 | void Game::HideAll() { 404 | player->Hide(); 405 | for (int i = 0; i < 4; ++i) { 406 | ghosts[i]->Hide(); 407 | } 408 | } 409 | 410 | void Game::InitAll() { 411 | player->SetY(player->GetYInit()); 412 | player->SetX(player->GetXInit()); 413 | player->SetColor(YELLOW); 414 | player->SetIcon(ICONS[1]); 415 | player->SetDirOld('a'); 416 | player->SetWait(0); 417 | player->SetSuper(0); 418 | for (int i = 0; i < 4; ++i) { 419 | ghosts[i]->SetY(ghosts[i]->GetYInit()); 420 | ghosts[i]->SetX(ghosts[i]->GetXInit()); 421 | ghosts[i]->SetColor(ghosts[i]->GetColorInit()); 422 | ghosts[i]->SetMode('w'); 423 | ghosts[i]->SetWait(0); 424 | ghosts[i]->SetIcon(GHOST_ICON); 425 | } 426 | ghosts[BLINKY]->SetMode('c'); 427 | ghosts[BLINKY]->SetModeOld('c'); 428 | if (player->GetLeft() <= 235) { 429 | ghosts[PINKY]->SetMode('e'); 430 | } 431 | if (player->GetLeft() <= 200) { 432 | ghosts[INKY]->SetMode('e'); 433 | } 434 | if (player->GetLeft() <= 165) { 435 | ghosts[CLYDE]->SetMode('e'); 436 | } 437 | } 438 | -------------------------------------------------------------------------------- /src/Game.h: -------------------------------------------------------------------------------- 1 | #ifndef GAME_H 2 | #define GAME_H 3 | 4 | #include "Constants.h" 5 | 6 | class Pacman; 7 | class Ghost; 8 | class Pellet; 9 | 10 | class Game { 11 | private: 12 | char level[LEVEL_HEIGHT][LEVEL_WIDTH]; 13 | int oneUpTimer = ONE_UP_MAX; 14 | int oneUpColor = WHITE; 15 | int pelletTimer = PELLET_MAX; 16 | int pelletColor = WHITE; 17 | int ghostModeTimer = MODE_MAX; 18 | 19 | Pacman* player; 20 | Ghost* ghosts[4]; 21 | Pellet* pellets[4]; 22 | 23 | void MainLoop(); 24 | 25 | public: 26 | Game(); 27 | ~Game(); 28 | void Go(); 29 | 30 | void LoadLevel(); 31 | void NextLevel(); 32 | void PrintReady(); 33 | void PrintGameOver(); 34 | 35 | void MoveGhosts(); 36 | void UpdateTimers(); 37 | void CheckForDeath(); 38 | void ShowAll(); 39 | void HideAll(); 40 | void InitAll(); 41 | 42 | char GetLevel(int y, int x) { return level[y][x]; } 43 | int GetOneUpTimer() { return oneUpTimer; } 44 | int GetOneUpColor() { return oneUpColor; } 45 | int GetPelletTimer() { return pelletTimer; } 46 | int GetPelletColor() { return pelletColor; } 47 | int GetGhostModeTimer() { return ghostModeTimer; } 48 | 49 | void SetLevel(int y, int x, char c) { level[y][x] = c; } 50 | void SetOneUpTimer(int t) { oneUpTimer = t; } 51 | void SetOneUpColor(int c) { oneUpColor = c; } 52 | void SetPelletTimer(int t) { pelletTimer = t; } 53 | void SetPelletColor(int c) { pelletColor = c; } 54 | void SetGhostModeTimer(int t) { ghostModeTimer = t; } 55 | }; 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /src/Ghost.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "Constants.h" 4 | 5 | #include "Game.h" 6 | #include "Ghost.h" 7 | #include "SetConsoleAttributes.h" 8 | 9 | using namespace std; 10 | 11 | Ghost::Ghost(Game *const g) 12 | : game(g) {} 13 | 14 | // move the ghost based on the current mode every time the wait timer reaches 0 15 | void Ghost::Move(int playerY, int playerX) { 16 | if (wait) { 17 | --wait; 18 | } 19 | else { 20 | switch (mode) { 21 | // if 'waiting' 22 | // bounce up and down 23 | case 'w': 24 | Hide(); 25 | if (y == GATE_Y + 2) { 26 | ++y; 27 | } 28 | else { 29 | --y; 30 | } 31 | Show(); 32 | wait = GHOST_MAX; 33 | break; 34 | // if 'exiting' 35 | // make a path to get out of the gate 36 | // after exiting the gate if the player is super pacman, 'run' 37 | // otherwise, 'chase' 38 | case 'e': 39 | Hide(); 40 | wait = GHOST_MAX; 41 | if (y > GATE_Y + 1) { 42 | --y; 43 | } 44 | else if (x < GATE_X) { 45 | ++x; 46 | } 47 | else if (x > GATE_X) { 48 | --x; 49 | } 50 | else if (y != GATE_Y - 1) { 51 | --y; 52 | SetCursorPosition(GATE_Y, GATE_X + 1); 53 | cout << game->GetLevel(GATE_Y, GATE_X + 1); 54 | } 55 | else { 56 | modeOld = mode; 57 | if (color == BLUE) { 58 | mode = 'r'; 59 | } 60 | else { 61 | mode = 'c'; 62 | } 63 | dirOld = 'w'; 64 | wait = 0; 65 | } 66 | Show(); 67 | break; 68 | // if 'entering' 69 | // enter the ghost house, then 'exit' 70 | case 'n': 71 | if (y != GATE_Y + 1) { 72 | dir = 's'; 73 | ChangeCoords(); 74 | SetCursorPosition(GATE_Y, GATE_X + 1); 75 | cout << game->GetLevel(GATE_Y, GATE_X + 1); 76 | wait = DEAD_MAX; 77 | } 78 | else { 79 | color = colorInit; 80 | mode = 'e'; 81 | wait = GHOST_MAX; 82 | icon = GHOST_ICON; 83 | } 84 | break; 85 | // if 'scattering' 86 | // move in a random direction 87 | case 's': 88 | GetOpposite(); 89 | if (modeOld == 'e') { 90 | modeOld = mode; 91 | } 92 | if (mode != modeOld) { 93 | dir = dirOpp; 94 | ChangeCoords(); 95 | modeOld = mode; 96 | } 97 | else { 98 | RandomDirection(); 99 | } 100 | dirOld = dir; 101 | wait = GHOST_MAX; 102 | break; 103 | // if 'chasing' 104 | // target the player 105 | case 'c': 106 | GetOpposite(); 107 | if (modeOld == 'e') { 108 | modeOld = mode; 109 | } 110 | if (mode != modeOld) { 111 | dir = dirOpp; 112 | ChangeCoords(); 113 | modeOld = mode; 114 | } 115 | else { 116 | bool down = y < playerY; 117 | bool up = y > playerY; 118 | bool right = x < playerX; 119 | bool left = x > playerX; 120 | bool favorableDirs[4] = { up, left, down, right }; 121 | TargetObject(favorableDirs); 122 | } 123 | dirOld = dir; 124 | wait = GHOST_MAX; 125 | break; 126 | // if 'running' 127 | // avoid the player 128 | case 'r': 129 | GetOpposite(); 130 | if (modeOld == 'e') { 131 | modeOld = mode; 132 | } 133 | if (mode != modeOld) { 134 | dir = dirOpp; 135 | ChangeCoords(); 136 | modeOld = mode; 137 | } 138 | else { 139 | bool down = !(y < playerY); 140 | bool up = !(y > playerY); 141 | bool right = !(x < playerX); 142 | bool left = !(x > playerX); 143 | bool favorableDirs[4] = { up, left, down, right }; 144 | TargetObject(favorableDirs); 145 | } 146 | dirOld = dir; 147 | wait = RUN_MAX; 148 | break; 149 | // if 'dead' 150 | // target the ghost house gate 151 | // when the gate is reached, 'enter' 152 | case 'd': 153 | GetOpposite(); 154 | if (y != GATE_Y - 1 || x != GATE_X) { 155 | bool down = y < GATE_Y - 1; 156 | bool up = y > GATE_Y - 1; 157 | bool right = x < GATE_X; 158 | bool left = x > GATE_X; 159 | bool favorableDirs[4] = { up, left, down, right }; 160 | TargetObject(favorableDirs); 161 | } 162 | else { 163 | mode = 'n'; 164 | } 165 | dirOld = dir; 166 | wait = DEAD_MAX; 167 | } 168 | } 169 | } 170 | 171 | void Ghost::TargetObject(bool favorableDirs[4]) { 172 | int good = 0; 173 | char goodDirs[4] = {' ',' ',' ',' '}; 174 | for (int i = 0; i < 4; ++i) { 175 | dir = ALL_DIRS[i]; 176 | if (favorableDirs[i] && TestForCollision() == false && dir != dirOpp) { 177 | goodDirs[good] = dir; 178 | ++good; 179 | } 180 | } 181 | if (good == 0) { 182 | RandomDirection(); 183 | } 184 | else { 185 | dir = goodDirs[rand() % good]; 186 | ChangeCoords(); 187 | } 188 | } 189 | 190 | void Ghost::RandomDirection() { 191 | GetOpposite(); 192 | // pick a random direction that results in no collision 193 | do { 194 | // pick a randon direction that is not opposite of the previous direction 195 | do { 196 | dir = ALL_DIRS[rand() % 4]; 197 | } while (dir == dirOpp); 198 | } while (TestForCollision() == true); 199 | ChangeCoords(); 200 | } 201 | 202 | bool Ghost::TestForCollision() { 203 | // if the character in front of the ghost is a space, move in the appropriate direction 204 | switch(dir) { 205 | case 'a': 206 | // if travelling through the tunnel 207 | if (x == 0 || strchr(NO_COLLISION_TILES, game->GetLevel(y, x - 1))) { 208 | return false; 209 | } 210 | break; 211 | case 'd': 212 | // if travelling through the tunnel 213 | if (x == LEVEL_WIDTH - 1 || strchr(NO_COLLISION_TILES, game->GetLevel(y, x + 1))) { 214 | return false; 215 | } 216 | break; 217 | case 'w': 218 | if (strchr(NO_COLLISION_TILES, game->GetLevel(y - 1, x))) { 219 | return false; 220 | } 221 | break; 222 | case 's': 223 | if (strchr(NO_COLLISION_TILES, game->GetLevel(y + 1, x))) { 224 | return false; 225 | } 226 | break; 227 | } 228 | return true; 229 | } 230 | 231 | void Ghost::ChangeCoords() { 232 | Hide(); 233 | if (dir == 'a') { 234 | if (x == 0) { 235 | x = LEVEL_WIDTH - 1; 236 | } 237 | else { 238 | --x; 239 | } 240 | } 241 | if (dir == 'd') { 242 | if (x == LEVEL_WIDTH - 1) { 243 | x = 0; 244 | } 245 | else { 246 | ++x; 247 | } 248 | } 249 | if (dir == 'w') { 250 | --y; 251 | } 252 | if (dir == 's') { 253 | ++y; 254 | } 255 | Show(); 256 | } 257 | 258 | void Ghost::GetOpposite() { 259 | if (dirOld == 'a') { 260 | dirOpp = 'd'; 261 | } 262 | if (dirOld == 'd') { 263 | dirOpp = 'a'; 264 | } 265 | if (dirOld == 'w') { 266 | dirOpp = 's'; 267 | } 268 | if (dirOld == 's') { 269 | dirOpp = 'w'; 270 | } 271 | } 272 | 273 | void Ghost::Dead() { 274 | color = WHITE; 275 | modeOld = mode; 276 | mode = 'd'; 277 | icon = DEAD_GHOST_ICON; 278 | } 279 | 280 | void Ghost::Show() { 281 | SetTextColor(color); 282 | SetCursorPosition(y, x); 283 | cout << icon; 284 | } 285 | 286 | void Ghost::Hide() { 287 | SetTextColor(WHITE); 288 | if (game->GetLevel(y, x) == 'o') { 289 | SetTextColor(game->GetPelletColor()); 290 | } 291 | SetCursorPosition(y, x); 292 | cout << game->GetLevel(y, x); 293 | } 294 | -------------------------------------------------------------------------------- /src/Ghost.h: -------------------------------------------------------------------------------- 1 | #ifndef GHOST_H 2 | #define GHOST_H 3 | 4 | class Game; 5 | 6 | class Ghost { 7 | private: 8 | int y, x; 9 | int yInit, xInit; 10 | int wait; 11 | int color; 12 | int colorInit; 13 | char dir; 14 | char dirOld; 15 | char dirOpp; 16 | char mode; 17 | char modeOld; 18 | char icon; 19 | 20 | Game *game; 21 | 22 | public: 23 | Ghost(Game *const g); 24 | void Move(int, int); 25 | void TargetObject(bool[4]); 26 | void RandomDirection(); 27 | bool TestForCollision(); 28 | void ChangeCoords(); 29 | void GetOpposite(); 30 | void Dead(); 31 | void Show(); 32 | void Hide(); 33 | 34 | int GetY() { return y; } 35 | int GetX() { return x; } 36 | int GetYInit() { return yInit; } 37 | int GetXInit() { return xInit; } 38 | int GetColor() { return color; } 39 | int GetColorInit() { return colorInit; } 40 | char GetMode() { return mode; } 41 | 42 | void SetY(int y) { this->y = y; } 43 | void SetX(int x) { this->x = x; } 44 | void SetYInit(int y) { yInit = y; } 45 | void SetXInit(int x) { xInit = x; } 46 | void SetWait(int w) { wait = w; } 47 | void SetColor(int c) { color = c; } 48 | void SetColorInit(int c) { colorInit = c; } 49 | void SetDirOpp(char d) { dirOpp = d; } 50 | void SetMode(char m) { mode = m; } 51 | void SetModeOld(char m) { modeOld = m; } 52 | void SetIcon(char i) { icon = i; } 53 | }; 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /src/Main.cpp: -------------------------------------------------------------------------------- 1 | #include "Game.h" 2 | 3 | int main() { 4 | Game* game = new Game(); 5 | game->Go(); 6 | delete game; 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /src/Pacman.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "Constants.h" 7 | 8 | #include "Game.h" 9 | #include "Pacman.h" 10 | #include "SetConsoleAttributes.h" 11 | 12 | using namespace std; 13 | 14 | Pacman::Pacman(Game *const g) 15 | : game(g) { 16 | hiScore = 0; 17 | } 18 | 19 | // check for user input every time the wait timer reaches 0 20 | void Pacman::Move() { 21 | if (wait) { 22 | --wait; 23 | } 24 | else { 25 | GetDirection(); 26 | if (TestForCollision() == false) { 27 | // replace old coordinates with a space 28 | SetCursorPosition(yOld, xOld); 29 | cout << game->GetLevel(yOld, xOld); 30 | // if the player picked up a pellet 31 | if (game->GetLevel(y, x) != ' ') { 32 | int scoreInc; 33 | if (game->GetLevel(y, x) == 'o') { 34 | scoreInc = 50; 35 | super = SUPER_MAX; 36 | } 37 | else { 38 | scoreInc = 10; 39 | } 40 | PrintScore(scoreInc); 41 | game->SetLevel(y, x, ' '); 42 | --left; 43 | } 44 | Show(); 45 | dirOld = dir; 46 | wait = PACMAN_MAX; 47 | } 48 | } 49 | } 50 | 51 | void Pacman::GetDirection() { 52 | dir = 'x'; 53 | // check if the user has entered 'w', 'a', 's' or 'd' 54 | if (_kbhit()) { 55 | dir = tolower(_getch()); 56 | } 57 | // if not, try moving in the same direction as before 58 | if (!strchr(ALL_DIRS, dir)) { 59 | dir = dirOld; 60 | } 61 | } 62 | 63 | bool Pacman::TestForCollision() { 64 | // save old coordinates 65 | xOld = x; 66 | yOld = y; 67 | // if the character in front of the player is a space, move in the appropriate direction 68 | switch (dir) { 69 | case 'a': 70 | // if travelling through the tunnel 71 | if (x == 0) { 72 | x = LEVEL_WIDTH - 1; 73 | icon = ICONS[1]; 74 | } 75 | else if (strchr(NO_COLLISION_TILES, game->GetLevel(y, x - 1))) { 76 | --x; 77 | icon = ICONS[1]; 78 | } 79 | break; 80 | case 'd': 81 | // if travelling through the tunnel 82 | if (x == LEVEL_WIDTH - 1) { 83 | x = 0; 84 | icon = ICONS[3]; 85 | } 86 | else if (strchr(NO_COLLISION_TILES, game->GetLevel(y, x + 1))) { 87 | ++x; 88 | icon = ICONS[3]; 89 | } 90 | break; 91 | case 'w': 92 | if (strchr(NO_COLLISION_TILES, game->GetLevel(y - 1, x))) { 93 | --y; 94 | icon = ICONS[0]; 95 | } 96 | break; 97 | case 's': 98 | if (strchr(NO_COLLISION_TILES, game->GetLevel(y + 1, x))) { 99 | ++y; 100 | icon = ICONS[2]; 101 | } 102 | } 103 | // if coordinates were not changed, there was a collision 104 | if (x == xOld && y == yOld) { 105 | return true; 106 | } 107 | return false; 108 | } 109 | 110 | void Pacman::PrintScore(int scoreInc) { 111 | // gain a life every time the score crosses a multiple of 10000 112 | if (score / 10000 < (score + scoreInc) / 10000) { 113 | ++lives; 114 | PrintLives(); 115 | } 116 | score += scoreInc; 117 | SetTextColor(WHITE); 118 | SetCursorPosition(-2, 0); 119 | if (score == 0) { 120 | cout << setw(7) << "00"; 121 | } 122 | else { 123 | cout << setw(7) << score; 124 | } 125 | if (score > hiScore) { 126 | hiScore = score; 127 | cout << setw(11) << hiScore; 128 | } 129 | } 130 | 131 | void Pacman::PrintLives() { 132 | SetTextColor(color); 133 | SetCursorPosition(LEVEL_HEIGHT, 2); 134 | for (int i = 1; i < lives; ++i) { 135 | cout << ICONS[1] << " "; 136 | } 137 | cout << " "; 138 | } 139 | 140 | void Pacman::PrintKillScore() { 141 | ++killCount; 142 | int scoreInc = 200 * (int)pow(2, killCount - 1); 143 | int length = (int)floor(log10(scoreInc)) + 1; 144 | int killX = x - 1; 145 | if (x == 0) { 146 | killX = x; 147 | } 148 | if (x > LEVEL_WIDTH - length) { 149 | killX = LEVEL_WIDTH - length; 150 | } 151 | SetTextColor(CYAN); 152 | SetCursorPosition(y, killX); 153 | cout << scoreInc; 154 | PrintScore(scoreInc); 155 | Sleep(750); 156 | SetCursorPosition(y, killX); 157 | for (int i = killX; i < killX + length; ++i) { 158 | SetTextColor(DARK_BLUE); 159 | if (game->GetLevel(y, i) == char(250)) { 160 | SetTextColor(WHITE); 161 | } 162 | if (game->GetLevel(y, i) == 'o') { 163 | SetTextColor(game->GetPelletColor()); 164 | } 165 | cout << game->GetLevel(y, i); 166 | } 167 | Show(); 168 | } 169 | 170 | void Pacman::Dead() { 171 | Sleep(1000); 172 | game->HideAll(); 173 | for (int i = 0; i < 8; ++i) { 174 | icon = ICONS[i % 4]; 175 | Show(); 176 | Sleep(100); 177 | } 178 | Hide(); 179 | Sleep(500); 180 | --lives; 181 | if (lives != 0) { 182 | game->InitAll(); 183 | game->ShowAll(); 184 | PrintLives(); 185 | game->PrintReady(); 186 | } 187 | else { 188 | game->PrintGameOver(); 189 | } 190 | } 191 | 192 | void Pacman::Show() { 193 | SetTextColor(color); 194 | SetCursorPosition(y, x); 195 | cout << icon; 196 | } 197 | 198 | void Pacman::Hide() { 199 | SetCursorPosition(y, x); 200 | cout << game->GetLevel(y, x); 201 | } 202 | -------------------------------------------------------------------------------- /src/Pacman.h: -------------------------------------------------------------------------------- 1 | #ifndef PACMAN_H 2 | #define PACMAN_H 3 | 4 | class Game; 5 | 6 | class Pacman { 7 | private: 8 | int y, x; 9 | int yOld, xOld; 10 | int yInit, xInit; 11 | int wait; 12 | int left; 13 | int score; 14 | int hiScore; 15 | int lives; 16 | int super; 17 | int killCount; 18 | int color; 19 | char dir; 20 | char dirOld; 21 | char icon; 22 | 23 | Game *game; 24 | 25 | public: 26 | Pacman(Game *const g); 27 | void Move(); 28 | void GetDirection(); 29 | bool TestForCollision(); 30 | void PrintScore(int); 31 | void PrintLives(); 32 | void PrintKillScore(); 33 | void Dead(); 34 | void Show(); 35 | void Hide(); 36 | 37 | int GetY() { return y; } 38 | int GetX() { return x; } 39 | int GetYInit() { return yInit; } 40 | int GetXInit() { return xInit; } 41 | int GetLeft() { return left; } 42 | int GetLives() { return lives; } 43 | int GetSuper() { return super; } 44 | 45 | void SetY(int y) { this->y = y; } 46 | void SetX(int x) { this->x = x; } 47 | void SetYInit(int y) { yInit = y; } 48 | void SetXInit(int x) { xInit = x; } 49 | void SetWait(int w) { wait = w; } 50 | void SetLeft(int l) { left = l; } 51 | void SetScore(int s) { score = s; } 52 | void SetLives(int l) { lives = l; } 53 | void SetSuper(int s) { super = s; } 54 | void SetKillCount(int k) { killCount = k; } 55 | void SetColor(int c) { color = c; } 56 | void SetDirOld(char d) { dirOld = d; } 57 | void SetIcon(char i) { icon = i; } 58 | }; 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /src/Pellet.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "Game.h" 4 | #include "Pellet.h" 5 | #include "SetConsoleAttributes.h" 6 | 7 | using namespace std; 8 | 9 | Pellet::Pellet(Game *const g) 10 | : game(g) {} 11 | 12 | void Pellet::Print() { 13 | SetCursorPosition(y, x); 14 | cout << game->GetLevel(y, x); 15 | } 16 | -------------------------------------------------------------------------------- /src/Pellet.h: -------------------------------------------------------------------------------- 1 | #ifndef PELLET_H 2 | #define PELLET_H 3 | 4 | class Game; 5 | 6 | class Pellet { 7 | private: 8 | int y, x; 9 | 10 | Game *game; 11 | 12 | public: 13 | Pellet(Game *const g); 14 | void Print(); 15 | 16 | void SetY(int y) { this->y = y; } 17 | void SetX(int x) { this->x = x; } 18 | }; 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /src/SetConsoleAttributes.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "Constants.h" 4 | 5 | void SetWindowTitle(char title[]) { 6 | SetConsoleTitle(title); 7 | } 8 | 9 | void SetWindowSize(int height, int width) { 10 | SMALL_RECT window; 11 | window.Top = 0; 12 | window.Left = 0; 13 | window.Bottom = height - 1; 14 | window.Right = width - 1; 15 | SetConsoleWindowInfo(GetStdHandle(STD_OUTPUT_HANDLE), TRUE, &window); 16 | COORD buffer = {width,height}; 17 | SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), buffer); 18 | } 19 | 20 | void SetCursorVisibility(bool show) { 21 | CONSOLE_CURSOR_INFO cursor; 22 | GetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor); 23 | cursor.bVisible = show; 24 | SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor); 25 | } 26 | 27 | void SetCursorPosition(int y, int x) { 28 | COORD cursor = {x,y+3}; 29 | SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), cursor); 30 | } 31 | 32 | void SetTextColor(int color) { 33 | SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color); 34 | } 35 | 36 | void SetScreenColor(int color) { 37 | COORD coord = {0,3}; 38 | DWORD dwWritten; 39 | FillConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color, LEVEL_HEIGHT * LEVEL_WIDTH, coord, &dwWritten); 40 | } 41 | -------------------------------------------------------------------------------- /src/SetConsoleAttributes.h: -------------------------------------------------------------------------------- 1 | #ifndef SETCONSOLEATTRIBUTES_H 2 | #define SETCONSOLEATTRIBUTES_H 3 | 4 | void SetWindowTitle(char[]); 5 | void SetWindowSize(int, int); 6 | void SetCursorVisibility(bool); 7 | void SetCursorPosition(int, int); 8 | void SetTextColor(int); 9 | void SetScreenColor(int); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /src/pacplusplusman.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dannye/pacplusplusman/ecf874896362e5917c2f6a75ca0ed0e9cc4c5eeb/src/pacplusplusman.ico -------------------------------------------------------------------------------- /src/pacplusplusman.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dannye/pacplusplusman/ecf874896362e5917c2f6a75ca0ed0e9cc4c5eeb/src/pacplusplusman.rc -------------------------------------------------------------------------------- /src/pacplusplusman.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {0C9D0898-DCA7-471B-9249-C9CE92A07F4A} 15 | pacman 16 | 17 | 18 | 19 | Application 20 | true 21 | v140 22 | MultiByte 23 | 24 | 25 | Application 26 | false 27 | v140 28 | true 29 | MultiByte 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | PAC++MAN 43 | 44 | 45 | PAC++MAN 46 | 47 | 48 | 49 | Level3 50 | Disabled 51 | true 52 | 53 | 54 | true 55 | 56 | 57 | 58 | 59 | Level3 60 | MaxSpeed 61 | true 62 | true 63 | true 64 | 65 | 66 | true 67 | true 68 | true 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /src/resource.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dannye/pacplusplusman/ecf874896362e5917c2f6a75ca0ed0e9cc4c5eeb/src/resource.h --------------------------------------------------------------------------------