c++ sdl 游戏在碰撞时停止(内存分配问题?)

问题描述 投票:0回答:0

我正在使用 C++ 和 SDL 制作经典吃豆人游戏的副本,但我似乎无法解决导致吃豆人和幽灵穿过地图回到碰撞地点的问题。问题发生在两个事件上:

  1. 当 Pacman 和 Ghost 相撞时,它们都被移回它们的重生点,但随后它们会自己飞过地图到达它们相撞的位置。
  2. 当吃豆人吃掉幽灵时,它会回到它的重生点,但随后就像它们之间发生碰撞的情况一样,它只是飞过地图到达它的死亡位置。 我包含了 gif,以便您更好地理解这个问题: Collision between Pacman and Ghost Ghost is eaten

同样重要的是,吃豆人和幽灵似乎不会返回到它们死亡/碰撞位置的下一个方块,但是更改“nextTile”并不能解决问题。

我试图修改“Die()”函数,但它似乎没有做任何更改。我怀疑它可能是“GetPath()”函数,因为当我尝试运行

aWorld->GetPath(myCurrentTileX, myCurrentTileY, 13, 13, myPath);
游戏停止移动时,但是我没有看到它的实现有任何问题。

Die() 函数:

void Ghost::Die(World* aWorld)
{
    myPath.clear();
    myPosition = Vector2f(13 * 22, 13 * 22);
    myDesiredMovementX = 0;
    myDesiredMovementY = -1;
    nextTileX = GetCurrentTileX() + myDesiredMovementX;
    nextTileY = GetCurrentTileY() + myDesiredMovementY;
    aWorld->GetPath(myCurrentTileX, myCurrentTileY, 13, 13, myPath);
}

GetPath() 函数:

void World::GetPath(int aFromX, int aFromY, int aToX, int aToY, std::list<PathmapTile*>& aList)
{
    PathmapTile* fromTile = GetTile(aFromX, aFromY);
    PathmapTile* toTile = GetTile(aToX, aToY);

    for (std::list<PathmapTile*>::iterator list_iter = myPathmapTiles.begin(); list_iter != myPathmapTiles.end(); list_iter++)
    {
        PathmapTile* tile = *list_iter;
        tile->myIsVisitedFlag = false;
    }

    Pathfind(fromTile, toTile, aList);
}

如果您需要更多代码:

全鬼.cpp:


Ghost::Ghost(const Vector2f& aPosition)
: MovableGameEntity(aPosition, "ghost_32.png")
{
    myIsClaimableFlag = false;
    myIsDeadFlag = false;
    myDesiredMovementX = 0;
    myDesiredMovementY = -1;
    myAvatar = std::make_unique<Avatar>(Vector2f(13 * 22, 22 * 22));
}

Ghost::~Ghost(void)
{
}

void Ghost::Die(World* aWorld)
{
    myPath.clear();
    myPosition = Vector2f(13 * 22, 13 * 22);
    myDesiredMovementX = 0;
    myDesiredMovementY = -1;
    nextTileX = GetCurrentTileX() + myDesiredMovementX;
    nextTileY = GetCurrentTileY() + myDesiredMovementY;
    //aWorld->GetPath(myCurrentTileX, myCurrentTileY, 13, 13, myPath);
}



void Ghost::Update(float aTime, World* aWorld)
{
    
    float speed = 30.f;
    nextTileX = GetCurrentTileX() + myDesiredMovementX;
    nextTileY = GetCurrentTileY() + myDesiredMovementY;
   
    if (myIsDeadFlag)
        speed = 30.f;
   
    if (IsAtDestination())
    {
        if (!myPath.empty())
        {
            PathmapTile* nextTile = myPath.front();
            myPath.pop_front();
            SetNextTile(nextTile->myX, nextTile->myY);
        }
        else if (aWorld->TileIsValid(nextTileX, nextTileY))
        {
            SetNextTile(nextTileX, nextTileY);
        }
        else
        {
            
            //std::cout << GetCurrentTileX() << GetCurrentTileY() << std::endl;
            float distanceToPacman = sqrt(pow(pacman_x - GetCurrentTileX(), 2) + pow(pacman_y - GetCurrentTileY(), 2));
            
            std::cout << distanceToPacman << std::endl;
            if (distanceToPacman <= -2)
            {
              
                std::cout << "distance between pacman and ghost <= 2"; // check if the condition is reached.
                myPath.clear();
                aWorld->GetPath(myCurrentTileX, myCurrentTileY, pacman_x, pacman_y, myPath);
                
                if (!myPath.empty())
                {
                    PathmapTile* nextTile = myPath.front();
                    myPath.pop_front();
                    SetNextTile(nextTile->myX, nextTile->myY);
                }
            }
            else // Pac-Man is not within range, so move randomly
            {
                std::vector<std::pair<int, int>> possibleDirections;
                if (aWorld->TileIsValid(GetCurrentTileX() + 1, GetCurrentTileY()))
                {
                    possibleDirections.push_back(std::make_pair(1, 0));
                }
                if (aWorld->TileIsValid(GetCurrentTileX() - 1, GetCurrentTileY()))
                {
                    possibleDirections.push_back(std::make_pair(-1, 0));
                }
                if (aWorld->TileIsValid(GetCurrentTileX(), GetCurrentTileY() + 1))
                {
                    possibleDirections.push_back(std::make_pair(0, 1));
                }
                if (aWorld->TileIsValid(GetCurrentTileX(), GetCurrentTileY() - 1))
                {
                    possibleDirections.push_back(std::make_pair(0, -1));
                }

                if (!possibleDirections.empty())
                {
                    std::random_device rd; 
                    std::mt19937 gen(rd()); 
                    std::uniform_int_distribution<> dist(0, possibleDirections.size() - 1); 

                    int randomIndex = dist(gen); 
                    myDesiredMovementX = possibleDirections[randomIndex].first;
                    myDesiredMovementY = possibleDirections[randomIndex].second;
                }
            }

            myIsDeadFlag = false;
        }
    }

    int tileSize = 22;
    Vector2f destination(myNextTileX * tileSize, myNextTileY * tileSize);
    Vector2f direction = destination - myPosition;

    float distanceToMove = aTime * speed;

    if (distanceToMove > direction.Length())
    {
        myPosition = destination;
        myCurrentTileX = myNextTileX;
        myCurrentTileY = myNextTileY;
    }
    else
    {
        direction.Normalize();
        myPosition += direction * distanceToMove;
    }
}




void Ghost::SetImage(const char* anImage)
{
    myImage = anImage;
}

void Ghost::Draw(Drawer* aDrawer)
{
    if (myIsDeadFlag)
        aDrawer->Draw("Ghost_Dead_32.png", (int)myPosition.myX + 220, (int)myPosition.myY + 60);
    else if (myIsClaimableFlag)
        aDrawer->Draw("Ghost_Vulnerable_32.png", (int)myPosition.myX + 220, (int)myPosition.myY + 60);
    else
        aDrawer->Draw(myImage, (int)myPosition.myX + 220, (int)myPosition.myY + 60);
}

完整的 Pacman.cpp:


std::unique_ptr<Pacman> Pacman::Create(Drawer* aDrawer)
{
    std::unique_ptr<Pacman> pacman(new Pacman(aDrawer));

    if (!pacman->Init())
    {
        return nullptr;
    }

    return pacman;
}



int pacman_x = 0;
int pacman_y = 0;

Pacman::Pacman(Drawer* aDrawer)
: myDrawer(aDrawer)
, myTimeToNextUpdate(0.f)
, myNextMovement(-1.f,0.f)
, myScore(0)
, myFps(0)
, myLives(3)
, myGhostGhostCounter(0.f)
{                               
    myAvatar = std::make_unique<Avatar>(Vector2f(13 * 22, 22 * 22));
    myGhost = std::make_unique<Ghost>(Vector2f(13 * 22, 13 * 22));
    myWorld = std::make_unique<World>();
}

Pacman::~Pacman(void)
{
    Free();//
}

bool Pacman::Init()
{
    myWorld->Init();

    return true;
}

//void Pacman::ResetNextMove()
//{
//  myNextMovement = Vector2f(-1.f, 0.f);
//  nextTileX = myAvatar->GetCurrentTileX() + myNextMovement.myX;
//  nextTileY = myAvatar->GetCurrentTileY() + myNextMovement.myY;
//}

bool Pacman::Update(float aTime)
{
    if (!UpdateInput())
        return false;

    if (CheckEndGameCondition())
    {
        myDrawer->DrawText("You win!", "freefont-ttf\\sfd\\FreeMono.ttf", 20, 70);
        return true;
    }
    else if (myLives <= 0) 
    {
        myDrawer->DrawText("You lose!", "freefont-ttf\\sfd\\FreeMono.ttf", 20, 70);
        std::cout << "You lose!";
        return true;
    }
    

    MoveAvatar();
    myAvatar->Update(aTime);
    myGhost->Update(aTime, myWorld.get());

    if (myWorld->HasIntersectedDot(myAvatar->GetPosition()))
        myScore += 10;

    myGhostGhostCounter -= aTime;

    pacman_x = myAvatar->GetPosition().myX / 22; // position of pacman for ghost.cpp
    pacman_y = myAvatar->GetPosition().myY / 22;

    if (myWorld->HasIntersectedBigDot(myAvatar->GetPosition()))
    {
        myScore += 20;
        myGhostGhostCounter = 20.f;
        myGhost->myIsClaimableFlag = true;
    }

    if (myGhostGhostCounter <= 0)
    {
        myGhost->myIsClaimableFlag = false;
    }

    if ((myGhost->GetPosition() - myAvatar->GetPosition()).Length() < 10.f)
    {
        if (myGhostGhostCounter <= 0.f)
        {
            std::cout << "lost a live";//check if the condition is reached
            myLives--;
            myAvatar->SetPosition(Vector2f(13*22,22*22));
            myGhost->SetPosition(Vector2f(13*22,13*22));
            //ResetNextMove();
        }
        else if (myGhost->myIsClaimableFlag && !myGhost->myIsDeadFlag)
        {
            
            myScore += 50;
            myGhost->myIsDeadFlag = true;
            std::cout << "check 1 - ghosts death"; 
            myGhost->Die(myWorld.get());
            std::cout << "check 2 - ghosts death";// Doesn't reach this point if 'aWorld->GetPath(myCurrentTileX, myCurrentTileY, 13, 13, myPath);' is executed
        }
    }
    
    if (aTime > 0)
        myFps = (int) (1 / aTime);

    return true;
}

void Pacman::Free() 
{
    myAvatar.reset();
    myGhost.reset();
    myWorld.reset();
}

bool Pacman::UpdateInput()
{
    const Uint8 *keystate = SDL_GetKeyboardState(NULL);

    if (keystate[SDL_SCANCODE_UP])
        myNextMovement = Vector2f(0.f, -1.f);
    else if (keystate[SDL_SCANCODE_DOWN])
        myNextMovement = Vector2f(0.f, 1.f);
    else if (keystate[SDL_SCANCODE_RIGHT])
        myNextMovement = Vector2f(1.f, 0.f);
    else if (keystate[SDL_SCANCODE_LEFT])
        myNextMovement = Vector2f(-1.f, 0.f);

    if (keystate[SDL_SCANCODE_ESCAPE])
        return false;

    return true;
}

void Pacman::MoveAvatar()
{
    nextTileX = myAvatar->GetCurrentTileX() + myNextMovement.myX;
    nextTileY = myAvatar->GetCurrentTileY() + myNextMovement.myY;

    if (myAvatar->IsAtDestination())
    {
        if (myWorld->TileIsValid(nextTileX, nextTileY))
        {
            myAvatar->SetNextTile(nextTileX, nextTileY);
        }

    }
}

bool Pacman::CheckEndGameCondition()
{
    
    return false;
}

bool Pacman::Draw()
{
    myWorld->Draw(myDrawer);
    myAvatar->Draw(myDrawer);
    myGhost->Draw(myDrawer);

    std::string scoreString;
    std::stringstream scoreStream;
    scoreStream << myScore;
    scoreString = scoreStream.str();
    myDrawer->DrawText("Score", "freefont-ttf\\sfd\\FreeMono.ttf", 20, 50);
    myDrawer->DrawText(scoreString.c_str(), "freefont-ttf\\sfd\\FreeMono.ttf", 90, 50);

    std::string livesString;
    std::stringstream liveStream;
    liveStream << myLives;
    livesString = liveStream.str();
    myDrawer->DrawText("Lives", "freefont-ttf\\sfd\\FreeMono.ttf", 20, 80);
    myDrawer->DrawText(livesString.c_str(), "freefont-ttf\\sfd\\FreeMono.ttf", 90, 80);

    myDrawer->DrawText("FPS", "freefont-ttf\\sfd\\FreeMono.ttf", 880, 50);
    std::string fpsString;
    std::stringstream fpsStream;
    fpsStream << myFps;
    fpsString = fpsStream.str();
    myDrawer->DrawText(fpsString.c_str(), "freefont-ttf\\sfd\\FreeMono.ttf", 930, 50);
    

    return true;
}

World.cpp(其中 GetPath 和 Pathfind 是:

World::World(void)
{
}

World::~World(void)
{
}

void World::Init()
{
    InitPathmap();
    InitDots();
    InitBigDots();
}

bool World::InitPathmap()
{
    std::string line;
    std::ifstream myfile("map.txt");
    if (myfile.is_open())
    {
        int lineIndex = 0;
        while (!myfile.eof())
        {
            std::getline(myfile, line);
            for (unsigned int i = 0; i < line.length(); i++)
            {
                PathmapTile* tile = new PathmapTile(i, lineIndex, (line[i] == 'x'));
                myPathmapTiles.push_back(tile);
            }

            lineIndex++;
        }
        myfile.close();
    }

    return true;
}

bool World::InitDots()
{
    std::string line;
    std::ifstream myfile("map.txt");
    if (myfile.is_open())
    {
        int lineIndex = 0;
        while (!myfile.eof())
        {
            std::getline(myfile, line);
            for (unsigned int i = 0; i < line.length(); i++)
            {
                if (line[i] == '.')
                {
                    Dot* dot = new Dot(Vector2f(i * 22, lineIndex * 22));
                    myDots.push_back(dot);
                }
            }

            lineIndex++;
        }
        myfile.close();
    }

    return true;
}

bool World::InitBigDots()
{
    std::string line;
    std::ifstream myfile("map.txt");
    if (myfile.is_open())
    {
        int lineIndex = 0;
        while (!myfile.eof())
        {
            std::getline(myfile, line);
            for (unsigned int i = 0; i < line.length(); i++)
            {
                if (line[i] == 'o')
                {
                    BigDot* dot = new BigDot(Vector2f(i * 22, lineIndex * 22));
                    myBigDots.push_back(dot);
                }
            }

            lineIndex++;
        }
        myfile.close();
    }

    return true;
}

void World::Draw(Drawer* aDrawer)
{
    aDrawer->Draw("playfield.png");

    for (std::list<Dot*>::iterator list_iter = myDots.begin(); list_iter != myDots.end(); list_iter++)
    {
        Dot* dot = *list_iter;
        dot->Draw(aDrawer);
    }

    for (std::list<BigDot*>::iterator list_iter = myBigDots.begin(); list_iter != myBigDots.end(); list_iter++)
    {
        BigDot* dot = *list_iter;
        dot->Draw(aDrawer);
    }
}

bool World::TileIsValid(int anX, int anY)
{
    for (std::list<PathmapTile*>::iterator list_iter = myPathmapTiles.begin(); list_iter != myPathmapTiles.end(); list_iter++)
    {
        PathmapTile* tile = *list_iter;

        if (anX == tile->myX && anY == tile->myY && !tile->myIsBlockingFlag)
            return true;
    }

    return false;
}

bool World::HasIntersectedDot(const Vector2f& aPosition)
{
    for (std::list<Dot*>::iterator list_iter = myDots.begin(); list_iter != myDots.end(); list_iter++)
    {
        Dot* dot = *list_iter;
        if ((dot->GetPosition() - aPosition).Length() < 5.f)
        {
            myDots.remove(dot);
            delete dot;
            return true;
        }
    }

    return false;
}

bool World::HasIntersectedBigDot(const Vector2f& aPosition)
{
    for (std::list<BigDot*>::iterator list_iter = myBigDots.begin(); list_iter != myBigDots.end(); list_iter++)
    {
        BigDot* dot = *list_iter;
        if ((dot->GetPosition() - aPosition).Length() < 5.f)
        {
            myBigDots.remove(dot);
            delete dot;
            return true;
        }
    }

    return false;
}

bool World::HasIntersectedCherry(const Vector2f& aPosition)
{
    return true;
}

**void World::GetPath**(int aFromX, int aFromY, int aToX, int aToY, std::list<PathmapTile*>& aList)
{
    PathmapTile* fromTile = GetTile(aFromX, aFromY);
    PathmapTile* toTile = GetTile(aToX, aToY);

    for (std::list<PathmapTile*>::iterator list_iter = myPathmapTiles.begin(); list_iter != myPathmapTiles.end(); list_iter++)
    {
        PathmapTile* tile = *list_iter;
        tile->myIsVisitedFlag = false;
    }

    Pathfind(fromTile, toTile, aList);
}

PathmapTile* World::GetTile(int aFromX, int aFromY)
{
    for (std::list<PathmapTile*>::iterator list_iter = myPathmapTiles.begin(); list_iter != myPathmapTiles.end(); list_iter++)
    {
        PathmapTile* tile = *list_iter;
        if (tile->myX == aFromX && tile->myY == aFromY)
        {
            return tile;
        }
    }

    return NULL;
}

bool World::ListDoesNotContain(PathmapTile* aFromTile, std::list<PathmapTile*>& aList)
{
    for (std::list<PathmapTile*>::iterator list_iter = aList.begin(); list_iter != aList.end(); list_iter++)
    {
        PathmapTile* tile = *list_iter;
        if (tile == aFromTile)
        {
            return false;
        }
    }

    return true;
}

bool SortFromGhostSpawn(PathmapTile* a, PathmapTile* b)
{
    int la = abs(a->myX - 13) + abs(a->myY - 13);
    int lb = abs(b->myX - 13) + abs(b->myY - 13);

    return la < lb;
}



**bool World::Pathfind**(PathmapTile* aFromTile, PathmapTile* aToTile, std::list<PathmapTile*>& aList)
{
    std::priority_queue<AStarNode> open_list;
    std::unordered_set<PathmapTile*> closed_set;

    // create start node
    AStarNode start_node(aFromTile, nullptr, 0, ManhattanDistance(aFromTile, aToTile));
    open_list.push(start_node);

    while (!open_list.empty())
    {
        // get node with lowest f value from open list
        AStarNode current_node = open_list.top();
        open_list.pop();

        // check if goal has been reached
        if (current_node.tile == aToTile)
        {
            // construct path by following parent pointers
            while (current_node.parent != nullptr)
            {
                aList.push_front(current_node.tile);
                current_node = *current_node.parent;
            }
            aList.push_front(aFromTile);
            return true;
        }

        // add current node to closed set
        closed_set.insert(current_node.tile);

        // generate neighbor nodes
        std::list<PathmapTile*> neighbor_list;
        PathmapTile* up = GetTile(current_node.tile->myX, current_node.tile->myY - 1);
        if (up && !up->myIsBlockingFlag && !closed_set.count(up))
            neighbor_list.push_back(up);
        PathmapTile* down = GetTile(current_node.tile->myX, current_node.tile->myY + 1);
        if (down && !down->myIsBlockingFlag && !closed_set.count(down))
            neighbor_list.push_back(down);
        PathmapTile* right = GetTile(current_node.tile->myX + 1, current_node.tile->myY);
        if (right && !right->myIsBlockingFlag && !closed_set.count(right))
            neighbor_list.push_back(right);
        PathmapTile* left = GetTile(current_node.tile->myX - 1, current_node.tile->myY);
        if (left && !left->myIsBlockingFlag && !closed_set.count(left))
            neighbor_list.push_back(left);

        // add neighbor nodes to open list
        for (PathmapTile* neighbor : neighbor_list)
        {
            float g_cost = current_node.g + 1; // assuming uniform movement cost
            float h_cost = ManhattanDistance(neighbor, aToTile);
            AStarNode neighbor_node(neighbor, &current_node, g_cost, h_cost);
            open_list.push(neighbor_node);
        }
    }

    // no path found
    return false;
}
c++ memory rendering sdl sdl-2
© www.soinside.com 2019 - 2024. All rights reserved.