/
trilirium
/
Pacman
Обзор
Документация
Войти
/
trilirium
/
Pacman
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
Ghost.cpp
246 строк
6 KB
Trilirium
first commit
19 июн 2026, 11:07
19 июн 2026, 11:07
d44591e
Код
Авторство
О чём код?
// Ghost.cpp // ///////////////////////////////////////////////////////////////////////////// #include "Ghost.h" #include "GameState.h" #include "../Operations.h" #include "Path.h" #include "GhostAction.h" #include "Video.h" #include "Game.h" using namespace Puckman; ///////////////////////////////////////////////////////////////////////////// // initialization and cleanup ///////////////////////////////////////////////////////////////////////////// Ghost::Ghost(GhostIDs ghostId) { id = ghostId; } Ghost::~Ghost() { } void Ghost::resetState() { Character::resetState(); prevOrientation = (Orientation)0; actualTilePosX = actualTilePosY = 0; prevMovOffsX = prevMovOffsY = 0; destTilePosX = destTilePosY = 0; movNormalPattern = movPanicPattern = movTunnelPattern = 0; state = substate = 0; panicMode = false; hasToChangeOrientation = false; } void Ghost::initState(bool special) { sprite = 0x20; color = 2*id + 1; if (special){ posX = 0x00; posY = 0x94; tilePosX = actualTilePosX = 0x1e; tilePosY = actualTilePosY = 0x32; movOffsX = prevMovOffsX = 0x01; movOffsY = prevMovOffsY = 0x00; orientation = prevOrientation = LEFT; } } ///////////////////////////////////////////////////////////////////////////// // movement ///////////////////////////////////////////////////////////////////////////// void Ghost::run() { // if it's going for pacman and alive, check if we have to move if ((state == 0) && (substate == 1)){ // 0x1b is set at the tunnels if (theGame->CRAM[Video::tilePos2ScreenCoord(actualTilePosX, actualTilePosY)] == 0x1b) { // check if we have to move according to the movement bit pattern movTunnelPattern = Operations::rotateLeft<UINT32, 32>(movTunnelPattern); if ((movTunnelPattern & 0x01) == 0) return; } else if (panicMode){ // check if we have to move according to the movement bit pattern movPanicPattern = Operations::rotateLeft<UINT32, 32>(movPanicPattern); if ((movPanicPattern & 0x01) == 0) return; } else { // check if we have to move according to the movement bit pattern movNormalPattern = Operations::rotateLeft<UINT32, 32>(movNormalPattern); if ((movNormalPattern & 0x01) == 0) return; } // move move(); } } void Ghost::move() { // if we are moving in the Y axis if (prevMovOffsY != 0){ // if we are in the middle of a tile in the Y axis if ((posY & 0x07) == 0x04){ moveMiddle(); } else { moveNoMiddle(); } } else { // if we are in the middle of a tile in the X axis if ((posX & 0x07) == 0x04){ moveMiddle(); } else { moveNoMiddle(); } } } // updates position and tile position if it's in the middle of a tile void Ghost::moveMiddle() { bool hasToMove = false; // if wraparound has happened or it's going to happen, don't search a better move if (!checkWrapAround()){ if (panicMode){ // if we're in panic mode, move hasToMove = true; } else { // get CRAM data in tile position int data = theGame->CRAM[Video::tilePos2ScreenCoord(tilePosX, tilePosY)]; // 0x1a is set at ghost home and near pacman initial positions if (data != 0x1a) { hasToMove = true; } } } // check if the ghost has to change it's orientation and act accordingly checkOrientationChanges(); // updates tile position tilePosX += movOffsX; tilePosY += movOffsY; prevMovOffsX = movOffsX; prevMovOffsY = movOffsY; // keep a copy of the current orientation in case we have to // change our orientation before the next move in the middle prevOrientation = orientation; moveNoMiddle(); // this need to be executed here because the original game moves after // the IRQ. If this is executed where hasToMove is set to true, the ghost // sometimes can't detect a wall (especially when data != 0x1a) if (hasToMove){ if (panicMode){ moveInPanicState(); } else { moveInNormalState(); } } } // updates position and tile position if it's not in the middle of a tile void Ghost::moveNoMiddle() { // moves posX += prevMovOffsX; posY += prevMovOffsY; posX &= 0xff; posY &= 0xff; // sets destination tile position (used in collision detection) Video::pos2TilePos(posX, posY, actualTilePosX, actualTilePosY); } void Ghost::moveAtHome() { moveAtHomeAction[substate]->run(this); } void Ghost::moveWhenKilled() { moveWhenKilledAction[state]->run(this); } void Ghost::moveInPanicState() { // if it's alive, moves randomly if (state == 0){ Path::calcRandomPath(tilePosX, tilePosY, orientation, movOffsX, movOffsY, orientation); } else { // otherwise, go home Path::calcPath(tilePosX, tilePosY, orientation, 0x2e, 0x2c, movOffsX, movOffsY, orientation); } } ///////////////////////////////////////////////////////////////////////////// // animation ///////////////////////////////////////////////////////////////////////////// void Ghost::selectProperAnimation() { // set panic mode sprite sprite = 0x1c + theGame->ghostsAnimationFrame; // if the ghost is alive and in panic mode, we're done if ((state == 0) && (panicMode)) return; // otherwise set ghost sprite in normal or dead state sprite = 0x20 + 2*((int)orientation) + theGame->ghostsAnimationFrame; } void Ghost::draw() { // draw ghost's sprites Sprite spr(posX, posY, sprite, color, flipX, flipY, (theGame->collisionObject == id + 1) ? 1 : 0); theGame->sprites.push_back(spr); // clear sprite attributes flipX = flipY = false; priority = 0; } ///////////////////////////////////////////////////////////////////////////// // orientation methods ///////////////////////////////////////////////////////////////////////////// // changes ghost orientation void Ghost::changeOrientation() { // set the opposite orientation and update movement offsets orientation = (Orientation) (prevOrientation ^ 0x02); movOffsX = movementOffsets[orientation][0]; movOffsY = movementOffsets[orientation][1]; // special case in demo mode if (theGame->states[DEMO]->substate == 0x22){ prevMovOffsX = movOffsX; prevMovOffsY = movOffsY; prevOrientation = orientation; } } // checks if the ghost has to change it's orientation (because pacman has eaten a big pill) void Ghost::checkOrientationChanges() { if (hasToChangeOrientation){ hasToChangeOrientation = false; // change orientation changeOrientation(); } }