📄 game.cpp
字号:
{
// if we haven't detected a collision yet and pacman has eaten a big pill
if ((collisionObject == 0) && (pacman->superPillEffect)) {
bool collision = false;
for (int i = 3; i >= 0; i--){
// if the ghost is alive
if (ghost[i]->state == 0){
// if the distance in both coordinates is < 4, we've detected a collision
if (((abs(ghost[i]->posX - pacman->posX)) < 4) && ((abs(ghost[i]->posY - pacman->posY)) < 4)){
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
}
}
}
}
/////////////////////////////////////////////////////////////////////////////
// game's animation methods
/////////////////////////////////////////////////////////////////////////////
void Game::animateGhostDead()
{
ghostDeadSubstates[ghostDeadAnimState]->run();
}
void Game::updateGhostAnimCounters()
{
cntGhostsAnimations++;
// change animation frame each 8 ticks
if (cntGhostsAnimations == 8){
cntGhostsAnimations = 0;
ghostsAnimationFrame = ghostsAnimationFrame ^ 1;
}
}
void Game::updateSuperPillState()
{
cntSuperPillsAnimation++;
// change pill state each 10 ticks
if (cntSuperPillsAnimation == 10){
cntSuperPillsAnimation = 0;
// if we're playing in the level
if (states[PLAYING]->substate == 3){
int color = (CRAM[0x064] == 0x010) ? 0x00 : 0x10;
// change super pills visibility
CRAM[0x064] = CRAM[0x078] = CRAM[0x384] = CRAM[0x398] = color;
} else {
// we are in the demo
int color = (CRAM[0x332] == 0x010) ? 0x00 : 0x10;
// change super pills visibility
CRAM[0x278] = CRAM[0x332] = color;
}
}
}
void Game::moveGhostAtHome()
{
// if there wasn't any unhandled collision
if (collisionObject == 0){
// update movement bit pattern
cntGhostsMovHome = Operations::rotateLeft<UINT8, 8>((UINT8)cntGhostsMovHome);
// if we have to move, update ghosts move at home
if (cntGhostsMovHome & 0x01){
for (int i = 0; i < 4; i++){
ghost[i]->moveAtHome();
}
}
}
}
void Game::setDeadGhostsColor()
{
// in demo, dead ghost are not visible, otherwise we see their eyes only
int color = (states[DEMO]->substate == 0x22) ? 0x00 : 0x19;
// change dead ghost colors
for (int i = 0; i < 4; i++){
if (ghost[i]->state != 0){
ghost[i]->color = color;
}
}
}
void Game::setGhostsColors()
{
// if there wasn't any unhandled collision
if (collisionObject == 0){
// when the counter is 0, update ghost colors
if (cntGhostsPanicAnim == 0){
cntGhostsPanicAnim = 0x0e;
if (pacman->superPillEffect){
if (remainingTimeInPanicState < 0x100){
// TODOSOUND: something sound related here
if (pacman->color != 0x09){
pacman->color = 0x09;
} else {
// TODOSOUND: something sound related here
}
}
}
// set ghost colors
for (int i = 0; i < 4; i++){
if (ghost[i]->panicMode){
// if super pill effect is ending, alternate colors
if (remainingTimeInPanicState < 0x100){
ghost[i]->color = (ghost[i]->color == 0x11) ? 0x12 : 0x11;
}
} else {
// set normal color
ghost[i]->color = i*2 + 1;
}
}
}
cntGhostsPanicAnim--;
}
}
/////////////////////////////////////////////////////////////////////////////
// misc methods
/////////////////////////////////////////////////////////////////////////////
// update score (and maybe hi-score) and check for bonus life after picking an item
void Game::updateScore(int action)
{
static int scorePoints[14] = {
10, 50, 200, 400, 800, 1600, 100, 300, 500, 700, 1000, 2000, 3000, 5000
};
// if we're not in demo mode
if (state != DEMO){
// get a pointer to the score and add the points for the action
int *score = (currentPlayer == 0) ? &score1P : &score2P;
bool *gotBonusLife = (currentPlayer == 0) ? &gotBonusLife1P : &gotBonusLife2P;
*score += scorePoints[action];
// check if the player deserves a bonus live
if ((!(*gotBonusLife)) && (*score > settings.bonusLife)){
// increments number of lives and set bonus flag
*gotBonusLife = true;
levelState[0].lives++;
levelState[0].displayedLives++;
// TODOSOUND: play a sound
// update lives
Video::drawLives(levelState[0].displayedLives);
}
// print current player score
Writer::printScore(*score, (currentPlayer == 0) ? 0x3fc : 0x3e9, 6, 4);
// check if the player has more points than the high score
if (*score > highScore){
highScore = *score;
// print high score
Writer::printScore(highScore, 0x3f2, 6, 4);
}
}
}
void Game::initSuperPillVars()
{
// init panic state time
remainingTimeInPanicState = timeInPanicState;
pacman->superPillEffect = true;
pacman->hasToChangeOrientation = true; // used in demo mode
// notify the ghosts of the super pill effect
for (int i = 0; i < 4; i++){
ghost[i]->panicMode = true;
ghost[i]->hasToChangeOrientation = true;
}
// init ghost animation counter
cntGhostsPanicAnim = 0;
currentKills = 0;
// change ghosts sprite numbers and colors
for (int i = 0; i < 4; i++){
ghost[i]->sprite = 0x1c;
ghost[i]->color = 0x11;
}
// TODOSOUND: change channel 1 sound
}
void Game::savePillsConfiguration()
{
int offset = 0;
// iterate through normal pills
for (int i = 0; i < 240; i++){
offset += Video::pillOffsets[i];
// save pill state
levelState[0].normalPills[i] = theGame->VRAM[offset] == 0x10;
}
// save big pills state
theGame->levelState[0].superPills[0] = theGame->VRAM[0x064];
theGame->levelState[0].superPills[1] = theGame->VRAM[0x078];
theGame->levelState[0].superPills[2] = theGame->VRAM[0x384];
theGame->levelState[0].superPills[3] = theGame->VRAM[0x398];
}
void Game::checkForOrienationChange()
{
if (pacman->superPillEffect || (indexOrientationChanges == 7)) return;
cntOrientationChanges++;
// get next change counter value
int nextChange = ghostsOrientationChanges[indexOrientationChanges];
// if it's time to change orientation
if (nextChange == cntOrientationChanges){
indexOrientationChanges++;
for (int i = 0; i < 4; i++){
ghost[i]->hasToChangeOrientation = true;
}
}
}
void Game::checkDisplayFruit()
{
static int fruitData[21][3] = {
{ 0x00, 0x14, 0x06 },
{ 0x01, 0x0f, 0x07 },
{ 0x02, 0x15, 0x08 },
{ 0x02, 0x15, 0x08 },
{ 0x04, 0x14, 0x09 },
{ 0x04, 0x14, 0x09 },
{ 0x05, 0x17, 0x0a },
{ 0x05, 0x17, 0x0a },
{ 0x06, 0x09, 0x0b },
{ 0x06, 0x09, 0x0b },
{ 0x03, 0x16, 0x0c },
{ 0x03, 0x16, 0x0c },
{ 0x07, 0x16, 0x0d },
{ 0x07, 0x16, 0x0d },
{ 0x07, 0x16, 0x0d },
{ 0x07, 0x16, 0x0d },
{ 0x07, 0x16, 0x0d },
{ 0x07, 0x16, 0x0d },
{ 0x07, 0x16, 0x0d },
{ 0x07, 0x16, 0x0d },
{ 0x07, 0x16, 0x0d }
};
if (pacman->deadAnimState == 0){
// if there's a fruit out, exits
if (fruitEntry != 0) return;
bool showFruit = false;
// check if it's time to show a fruit (if it hasn't showed up yet)
if (levelState[0].eatenPills == 0x46){
if (!levelState[0].firstFruit){
levelState[0].firstFruit = true;
showFruit = true;
}
} else if (levelState[0].eatenPills == 0xaa){
if (!levelState[0].secondFruit){
levelState[0].secondFruit = true;
showFruit = true;
}
}
if (showFruit){
int index = levelState[0].currentLevel;
if (index > 20) index = 20;
// set fruit data
fruitPosition = 0x8094;
fruitSprite = fruitData[index][0];
fruitColor = fruitData[index][1];
fruitEntry = fruitData[index][2];
// clear fruit in 10 seconds
theScheduler->addScheduledTask(new Task(4, Task::SECONDS, 10));
}
}
}
/////////////////////////////////////////////////////////////////////////////
// helper methods
/////////////////////////////////////////////////////////////////////////////
void Game::killGhosts()
{
// if there's a ghost to kill
if (killingGhostState != 0){
// kill ghost and reset state
ghost[killingGhostState - 1]->state = 1;
killingGhostState = 0;
}
}
void Game::checkEndOfSuperPillEffect()
{
if (pacman->superPillEffect){
bool anyGhostInPanicState = false;
// check if any ghost is in panic mode
for (int i = 0; i < 4; i++){
anyGhostInPanicState |= ghost[i]->panicMode;
}
if (anyGhostInPanicState){
remainingTimeInPanicState--;
// if the super pill effect hasn't expired yet, exits
if (remainingTimeInPanicState != 0) return;
}
// finish super pill effect
pacman->color = 0x09;
// if a ghost was alive, disables its panic mode
for (int i = 0; i < 4; i++){
if (ghost[i]->state == 0){
ghost[i]->panicMode = false;
}
}
remainingTimeInPanicState = 0;
pacman->superPillEffect = false;
cntGhostsPanicAnim = 0;
currentKills = 0;
}
}
void Game::checkIfPinkGhostGoesOut()
{
// if the ghost is at home
if (ghost[PINK]->substate == 0){
if (levelState[0].easierFlag){
// set pink ghost to cross the door after 7 eaten pills
if (eatenPillsAfterDead == 7){
ghost[PINK]->substate = 2;
}
} else {
// set pink ghost to cross the door if its home counter has exceeded the limit
if (levelState[0].pinkGhostHomeCounter >= pinkGhostExitHomeCounterLimit){
ghost[PINK]->substate = 2;
}
}
}
}
void Game::checkIfBlueGhostGoesOut()
{
// if the ghost is at home
if (ghost[BLUE]->substate == 0){
if (levelState[0].easierFlag){
// set blue ghost to cross the door after 17 eaten pills
if (eatenPillsAfterDead == 17){
ghost[BLUE]->substate = 3;
}
} else {
// set blue ghost to cross the door if its home counter has exceeded the limit
if (levelState[0].blueGhostHomeCounter >= blueGhostExitHomeCounterLimit){
ghost[BLUE]->substate = 3;
}
}
}
}
void Game::checkIfOrangeGhostGoesOut()
{
// if the ghost is at home
if (ghost[ORANGE]->substate == 0){
if (levelState[0].easierFlag){
// reset easier flag after 32 eaten pills
if (eatenPillsAfterDead == 32){
levelState[0].easierFlag = false;
eatenPillsAfterDead = 0;
}
} else {
// set orangeghost to cross the door if its home counter has exceeded the limit
if (levelState[0].orangeGhostHomeCounter >= orangeGhostExitHomeCounterLimit){
ghost[ORANGE]->substate = 3;
}
}
}
}
void Game::drawFruit()
{
// if there's a fruit displayed, add fruit sprite
if (fruitEntry != 0){
Sprite spr((fruitPosition >> 8) & 0xff, fruitPosition & 0xff, fruitSprite, fruitColor);
theGame->sprites.push_back(spr);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -