📄 game.cpp
字号:
// Game.cpp
//
/////////////////////////////////////////////////////////////////////////////
#include "Game.h"
#include "InitState.h"
#include "DemoState.h"
#include "CharacterSubstate.h"
#include "CoinInsertedState.h"
#include "GhostDeadSubstates.h"
#include "PlayingState.h"
#include "RedGhost.h"
#include "PinkGhost.h"
#include "BlueGhost.h"
#include "OrangeGhost.h"
#include "../Operations.h"
#include "Pacman.h"
#include "Video.h"
#include "Writer.h"
GameState *Game::states[4];
/////////////////////////////////////////////////////////////////////////////
// initialization and cleanup
/////////////////////////////////////////////////////////////////////////////
Game::Game()
{
resetState();
// inits scheduled tasks list
Task::initScheduledTasksList();
state = 0;
// creates the states
states[0] = new InitState();
states[1] = new DemoState();
states[2] = new CoinInsertedState();
states[3] = new PlayingState();
// creates the characters
pacman = new Pacman();
ghost[RED] = new RedGhost();
ghost[PINK] = new PinkGhost();
ghost[BLUE] = new BlueGhost();
ghost[ORANGE] = new OrangeGhost();
ghostDeadSubstates[0x00] = new GhostInitKillSubstate();
ghostDeadSubstates[0x01] = new GhostDeadNopSubstate();
ghostDeadSubstates[0x02] = new GhostEndKillSubstate();
}
Game::~Game()
{
// deletes dead substates
for (int i = 0; i < 3; i++){
delete ghostDeadSubstates[i];
}
// deletes the characters
delete pacman;
for (int i = 0; i < 4; i++){
delete ghost[i];
}
// delete game states
for (int i = 0; i < 4; i++){
delete states[i];
}
// deletes scheduled tasks list
Task::endScheduledTasksList();
}
void Game::resetState()
{
for (int i = 0; i < 7; i++){
ghostsOrientationChanges[i] = 0;
}
indexOrientationChanges = cntOrientationChanges = 0;
// counters for movement
cntGhostsMovHome = 0;
cntGhostsAnimations = ghostsAnimationFrame = 0;
cntGhostsPanicAnim = 0;
cntSuperPillsAnimation = 0;
// difficulty
firstDiffFlag = secondDiffFlag = false;
pillsFirstDiffFlag = pillsSecondDiffFlag = 0;
pinkGhostExitHomeCounterLimit = blueGhostExitHomeCounterLimit = orangeGhostExitHomeCounterLimit = 0;
inactivityCounterLimit = inactivityCounter = 0;
eatenPillsAfterDead = 0;
timeInPanicState = remainingTimeInPanicState = 0;
currentKills = 0;
fruitPosition = fruitEntry = fruitSprite = fruitColor = 0;
cntShowHide1P2P = 0;
collisionObject = 0;
killingGhostState = ghostDeadAnimState = 0;
for (int i = 0; i < 3; i++){
cutsceneState[i] = 0;
}
currentPlayer = 0;
numberOfPlayers = 0;
score1P = score2P = highScore = 0;
gotBonusLife1P = gotBonusLife2P = false;
}
/////////////////////////////////////////////////////////////////////////////
// game's initialization methods
/////////////////////////////////////////////////////////////////////////////
void Game::initGameState()
{
pacman->resetState();
for (int i = 0; i < 4; i++){
ghost[i]->resetState();
}
for (int i = 0; i < 7; i++){
ghostsOrientationChanges[i] = 0;
}
indexOrientationChanges = cntOrientationChanges = 0;
cntGhostsMovHome = 0;
cntGhostsAnimations = ghostsAnimationFrame = 0;
cntGhostsPanicAnim = 0;
cntSuperPillsAnimation = 0;
firstDiffFlag = secondDiffFlag = false;
pillsFirstDiffFlag = pillsSecondDiffFlag = 0;
pinkGhostExitHomeCounterLimit = blueGhostExitHomeCounterLimit = orangeGhostExitHomeCounterLimit = 0;
inactivityCounter = inactivityCounterLimit = 0;
eatenPillsAfterDead = 0;
timeInPanicState = remainingTimeInPanicState = 0;
currentKills = 0;
fruitPosition = fruitEntry = fruitSprite = fruitColor = 0;
cntShowHide1P2P = 0;
collisionObject = 0;
killingGhostState = ghostDeadAnimState = 0;
}
void Game::initCharacterState(bool special)
{
pacman->initState(special);
for (int i = 0; i < 4; i++){
ghost[i]->initState(special);
}
fruitSprite = 0x3f;
fruitColor = 0x00;
fruitPosition = 0;
}
void Game::resetCharacterPositions()
{
fruitPosition = 0;
pacman->posX = pacman->posY = 0;
ghost[RED]->posX = ghost[RED]->posY = 0;
ghost[PINK]->posX = ghost[PINK]->posY = 0;
ghost[BLUE]->posX = ghost[BLUE]->posY = 0;
ghost[ORANGE]->posX = ghost[ORANGE]->posY = 0;
}
void Game::initPlayersLevelData()
{
currentPlayer = 0;
// init player state
PlayerLevelState *p = &levelState[0];
p->diffEntry = 0;
p->firstFruit = false;
p->secondFruit = false;
p->eatenPills = 0;
p->pinkGhostHomeCounter = 0;
p->blueGhostHomeCounter = 0;
p->orangeGhostHomeCounter = 0;
p->easierFlag = false;
p->currentLevel = 0;
// init player pills
p->initPills();
// copy settings to the other player
levelState[1].clone(p);
}
/////////////////////////////////////////////////////////////////////////////
// main loop
/////////////////////////////////////////////////////////////////////////////
// resumes execution
void Game::run()
{
// fill sprite list
sprites.clear();
drawFruit();
pacman->draw();
for (int i = 0; i < 4; i++){
ghost[i]->draw();
}
// updates the internal timers
scheduler.updateInternalTimers();
// executes scheduled tasks
scheduler.executeScheduledTasks();
// resumes execution
states[state]->run();
// if we're not initializing, adjust and animate sprites
if (state != INIT){
// animate sprites
if (pacman->deadAnimState != 0){
for (int i = 0; i < 4; i++){
ghost[i]->selectProperAnimation();
}
} else {
if (collisionObject == 0){
pacman->selectProperAnimation();
for (int i = 0; i < 4; i++){
ghost[i]->selectProperAnimation();
}
}
}
// update credits if a new coin is inserted
settings.checkForCoinInserted();
settings.checkForNewCredit();
// show/hide 1UP or 2UP
Writer::showOrHide1UP2UP();
if (state == DEMO){
// TODOSOUND: if we're in demo mode, make sure that we aren't playing any sound
}
}
}
/////////////////////////////////////////////////////////////////////////////
// game counters
/////////////////////////////////////////////////////////////////////////////
// check if we have to set the difficulty flags
void Game::updateDifficultyFlags()
{
// if orange ghost has exited home
if (theGame->ghost[PINK]->substate != 0){
int remainingPills = 244 - theGame->levelState[0].eatenPills;
// check if we have to set the first difficulty flag
if (!theGame->firstDiffFlag){
if (remainingPills <= theGame->pillsFirstDiffFlag){
theGame->firstDiffFlag = true;
}
}
// check if we have to set the second difficulty flag
if (!theGame->secondDiffFlag){
if (remainingPills <= theGame->pillsSecondDiffFlag){
theGame->secondDiffFlag = true;
}
}
}
}
// check if a ghost has to exit home
void Game::checkGhostsExitHomeCounters()
{
// if pacman has died in this level, wait a bit to let the ghosts go out
if (levelState[0].easierFlag){
eatenPillsAfterDead++;
} else {
// increment ghosts counters checking which ones are out
if (ghost[ORANGE]->substate == 0){
if (ghost[BLUE]->substate == 0){
if (ghost[PINK]->substate == 0){
levelState[0].pinkGhostHomeCounter++;
} else {
levelState[0].blueGhostHomeCounter++;
}
} else {
levelState[0].orangeGhostHomeCounter++;
}
}
}
}
void Game::checkGhostsExitHomeInactivity()
{
// if pacman has just eaten a pill, reset inactivity counter
if (pacman->pillsInLastMove != levelState[0].eatenPills){
inactivityCounter = 0;
} else {
inactivityCounter++;
// if there's too much inactivity, get ghost out of home
if (inactivityCounter == inactivityCounterLimit){
inactivityCounter = 0;
// get a ghost out of home
if (ghost[PINK]->substate == 0) {
ghost[PINK]->substate = 2;
} else if (ghost[BLUE]->substate == 0){
ghost[BLUE]->substate = 3;
} else if (ghost[ORANGE]->substate == 0){
ghost[ORANGE]->substate = 3;
}
}
}
}
/////////////////////////////////////////////////////////////////////////////
// movement and collision detection
/////////////////////////////////////////////////////////////////////////////
void Game::moveAndHandleCollisions()
{
// if pacman is dying, keep animating
pacman->animateDead();
// if pacman is alive
if (pacman->deadAnimState == 0){
// if the game has to kill a ghost, does it
killGhosts();
// move killed ghosts
for (int i = 0; i < 4; i++){
ghost[i]->moveWhenKilled();
}
// if there's a ghost dying, animate it
if (collisionObject > 0){
animateGhostDead();
} else {
moveAndCheckCollisions();
}
}
}
void Game::moveAndCheckCollisions()
{
// calculate pacman collision with each ghost at tile level
checkTileColision();
// calculate pacman collision with each ghost using absolute positions
checkAbsolutePosColision();
// if there wasn't a collision
if (collisionObject == 0){
// move pacman
pacman->run();
// move the ghosts
for (int i = 0; i < 4; i++){
ghost[i]->run();
}
// if we're playing
if (states[PLAYING]->substate == 0x03){
// check if the big pill effect has ended, and update ghosts accordingly
checkEndOfSuperPillEffect();
// check if the ghosts have to go out
checkIfPinkGhostGoesOut();
checkIfBlueGhostGoesOut();
checkIfOrangeGhostGoesOut();
}
}
}
// check collisions at the tile level
void Game::checkTileColision()
{
bool collision = false;
for (int i = 3; i >= 0; i--){
// if the ghost is alive
if (ghost[i]->state == 0){
// if it's in the same tile as pacman, we've detected a collision
if ((pacman->tilePosX == ghost[i]->actualTilePosX) && (pacman->tilePosY == ghost[i]->actualTilePosY)){
collisionObject = i + 1;
pacman->deadAnimState = i + 1;
collision = true;
break;
}
}
}
if (collision){
// if the ghost was in panic state, pacman continues alive
if (ghost[collisionObject - 1]->panicMode){
pacman->deadAnimState = 0;
// increment number of kills
currentKills++;
// updates the score
updateScore(currentKills + 1);
// TODOSOUND: set eaten sound in channel 2
}
}
}
// check collisions using absolute positions
void Game::checkAbsolutePosColision()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -