Нужна помощь в оптимизации игры на c++ sfml

У меня есть такой проект на c++ sfml 2.6.2. Я не особо сильно знаю c++, да и sfml тоже. Нужно для реализации проекта использовать. Сначала код писал на основном компьютере, все было хорошо. Но потом перенес на не очень мощный ноутбук (даже слабенький) и стало долго загружать. (Изначальное поле 64х64, вообще не грузило). Нужна помощь в оптимизации. ( если это возможно)

это cell.h

#ifndef CELL_H
#define CELL_H

#include <SFML/Graphics.hpp>
enum class CellState
{
    Empty,
    Cross,
    Circle
};

class Cell
{
private:
    CellState state;
    sf::Sprite sprite;
    sf::Texture emptyTexture;
    sf::Texture crossTexture;
    sf::Texture circleTexture;
    int x, y;
public:
    Cell();
    bool loadTextures();
    void setPosition(int x, int y);
    void setState(CellState newState);
    CellState getState() const;
    void draw(sf::RenderWindow& window, const sf::Vector2f& cameraOffset);
    bool contains(const sf::Vector2f& point, const sf::Vector2f& cameraOffset)
        const;
    sf::Vector2i getGridPosition() const;
};
#endif

cell.cpp

#include "cell.h"
Cell::Cell() : state(CellState::Empty), x(0), y(0)
{
}
bool Cell::loadTextures()
{
    if (!emptyTexture.loadFromFile("empty128.png") ||
        !crossTexture.loadFromFile("krest128.png") ||
        !circleTexture.loadFromFile("circle128.png"))
    {
        return false;
    }
    sprite.setTexture(emptyTexture);
}
void Cell::setPosition(int x, int y)
{
    this->x = x;
    this->y = y;
    sprite.setPosition(static_cast<float>(x * 128), static_cast<float>(y * 128));
}
void Cell::setState(CellState newState)
{
    state = newState;
    switch (state)
    {
    case CellState::Empty:
        sprite.setTexture(emptyTexture);
        break;
    case CellState::Cross:
        sprite.setTexture(crossTexture);
        break;
    case CellState::Circle:
        sprite.setTexture(circleTexture);
        break;
    }
}
CellState Cell::getState() const
{
    return state;
}
void Cell::draw(sf::RenderWindow& window, const sf::Vector2f& cameraOffset)
{
    sf::Vector2f originalPos = sprite.getPosition();
    sprite.setPosition(originalPos + cameraOffset);
    window.draw(sprite);
    sprite.setPosition(originalPos);
}
bool Cell::contains(const sf::Vector2f& point, const sf::Vector2f& cameraOffset)
const
{
    sf::FloatRect bounds = sprite.getGlobalBounds();
    bounds.left += cameraOffset.x;
    bounds.top += cameraOffset.y;
    return bounds.contains(point);
}
sf::Vector2i Cell::getGridPosition() const
{
    return sf::Vector2i(x, y);
}

board.h

#ifndef BOARD_H
#define BOARD_H
#include "cell.h"
#include <SFML/Graphics.hpp>
class Board {
private:
    Cell** cells;
    int width;
    int height;
    int offsetX;
    int offsetY;
    bool isCrossTurn;
    bool gameFinished;
    CellState winner;
    void expandBoardIfNeeded(int worldX, int worldY);
    void expandBoard(int newWidth, int newHeight, int newOffsetX, int newOffsetY);
    void cleanup();
    bool checkWin(int worldX, int worldY, CellState state) const;
    bool checkDirection(int worldX, int worldY, int dx, int dy, CellState state)
        const;
public:
    Board();
    ~Board();
    bool initialize();
    void makeMove(int worldX, int worldY);
    void draw(sf::RenderWindow& window, const sf::Vector2f& cameraOffset);
    void updateVisibleArea(const sf::Vector2f& cameraOffset, const sf::Vector2u&
        windowSize);
    bool handleClick(const sf::Vector2f& mousePos, const sf::Vector2f&
        cameraOffset);
    bool isGameFinished() const;
    CellState getWinner() const;
    bool getCurrentPlayer() const;
    void resetGame();
};
#endif

board.cpp

#include "board.h"
#include <cmath>
#include <iostream>
#include <algorithm>
Board::Board() : cells(nullptr), width(0), height(0),
offsetX(0), offsetY(0),
isCrossTurn(true), gameFinished(false),
winner(CellState::Empty) {}
Board::~Board()
{
    cleanup();
}
void Board::cleanup()
{
    if (cells)
    {
        for (int i = 0; i < width; ++i)
        {
            delete[] cells[i];
        }
        delete[] cells;
        cells = nullptr;
    }
    width = 0;
    height = 0;
}
bool Board::initialize()
{
    cleanup();
    // Начинаем с поля 64x64
    width = 32;
    height = 32;
    offsetX = -16; // Центрируем поле
    offsetY = -16;
    cells = new Cell * [width];
    for (int i = 0; i < width; ++i)
    {
        cells[i] = new Cell[height];
        for (int j = 0; j < height; ++j)
        {
            if (!cells[i][j].loadTextures())
            {
                std::cerr << "Failed to load textures for cell (" << i << ", " << j <<
                    ")" << std::endl;
                cleanup();
                return false;
            }
            int worldX = i + offsetX;
            int worldY = j + offsetY;
            cells[i][j].setPosition(worldX, worldY);
        }
    }
    std::cout << "Board initialized: " << width << "x" << height
        << " at offset (" << offsetX << ", " << offsetY << ")" << std::endl;
    return true;
}
void Board::expandBoardIfNeeded(int worldX, int worldY)
{
    // Проверяем, нужно ли расширять поле
    bool needExpand = false;
    int newOffsetX = offsetX;
    int newOffsetY = offsetY;
    int newWidth = width;
    int newHeight = height;
    // Проверяем границы и расширяем если нужно с запасом
    if (worldX < offsetX) {
        int expandLeft = offsetX - worldX + 16; // +16 запас
        newOffsetX -= expandLeft;
        newWidth += expandLeft;
        needExpand = true;
    }
    else if (worldX >= offsetX + width) {
        int expandRight = worldX - (offsetX + width) + 16;
        newWidth += expandRight;
        needExpand = true;
    }
    if (worldY < offsetY) {
        int expandTop = offsetY - worldY + 16;
        newOffsetY -= expandTop;
        newHeight += expandTop;
        needExpand = true;
    }
    else if (worldY >= offsetY + height) {
        int expandBottom = worldY - (offsetY + height) + 16;
        newHeight += expandBottom;
        needExpand = true;
    }
    if (needExpand) {
        std::cout << "Expanding board to: " << newWidth << "x" << newHeight
            << " at offset (" << newOffsetX << ", " << newOffsetY << ")" << std::endl;
        expandBoard(newWidth, newHeight, newOffsetX, newOffsetY);
    }
}
void Board::expandBoard(int newWidth, int newHeight, int newOffsetX, int newOffsetY)
{
    // Создаем новый массив
    Cell** newCells = new Cell * [newWidth];
    for (int i = 0; i < newWidth; ++i)
    {
        newCells[i] = new Cell[newHeight];
        for (int j = 0; j < newHeight; ++j)
        {
            int worldX = i + newOffsetX;
            int worldY = j + newOffsetY;
            if (!newCells[i][j].loadTextures())
            {
                std::cerr << "Failed to load textures during expansion" << std::endl;
                // Очистка в случае ошибки
                for (int x = 0; x <= i; ++x)
                {
                    delete[] newCells[x];
                }
                delete[] newCells;
                return;
            }
            newCells[i][j].setPosition(worldX, worldY);
            // Копируем состояние из старого массива, если ячейка существует в старых границах
                if (cells) {
                    int oldI = worldX - offsetX;
                    int oldJ = worldY - offsetY;
                    if (oldI >= 0 && oldI < width && oldJ >= 0 && oldJ < height)
                    {
                        CellState oldState = cells[oldI][oldJ].getState();
                        newCells[i][j].setState(oldState);
                    }
                }
        }
    }
    // Заменяем старый массив
    cleanup();
    cells = newCells;
    width = newWidth;
    height = newHeight;
    offsetX = newOffsetX;
    offsetY = newOffsetY;
}
void Board::makeMove(int worldX, int worldY)
{
    if (gameFinished) return;
    // Проверяем и расширяем поле если нужно
    expandBoardIfNeeded(worldX, worldY);
    // Преобразуем мировые координаты в локальные
    int localX = worldX - offsetX;
    int localY = worldY - offsetY;
    if (localX < 0 || localX >= width || localY < 0 || localY >= height)
    {
        std::cerr << "Cell out of bounds after expansion: (" << worldX << ", " << worldY
            << ")" << std::endl;
        return;
    }
    if (cells[localX][localY].getState() == CellState::Empty)
    {
        cells[localX][localY].setState(isCrossTurn ? CellState::Cross :
            CellState::Circle);
        if (checkWin(worldX, worldY, cells[localX][localY].getState()))
        {
            gameFinished = true;
            winner = cells[localX][localY].getState();
        }
        isCrossTurn = !isCrossTurn;
    }
}
bool Board::checkDirection(int worldX, int worldY, int dx, int dy, CellState state)
const {
    if (!cells) return false;
    int count = 1;
    // Проверяем в положительном направлении
    for (int i = 1; i < 5; ++i) {
        int checkX = worldX + i * dx;
        int checkY = worldY + i * dy;
        int localX = checkX - offsetX;
        int localY = checkY - offsetY;
        if (localX < 0 || localX >= width || localY < 0 || localY >= height)
        {
            break;
        }
        if (cells[localX][localY].getState() != state)
        {
            break;
        }
        count++;
    }
    // Проверяем в отрицательном направлении
    for (int i = 1; i < 5; ++i)
    {
        int checkX = worldX - i * dx;
        int checkY = worldY - i * dy;
        int localX = checkX - offsetX;
        int localY = checkY - offsetY;
        if (localX < 0 || localX >= width || localY < 0 || localY >= height)
        {
            break;
        }
        if (cells[localX][localY].getState() != state)
        {
            break;
        }
        count++;
    }
    return count >= 5;
}
bool Board::checkWin(int worldX, int worldY, CellState state) const
{
    if (!cells) return false;
    return checkDirection(worldX, worldY, 1, 0, state) || // Horizontal
        checkDirection(worldX, worldY, 0, 1, state) || // Vertical
        checkDirection(worldX, worldY, 1, 1, state) || // Diagonal
        checkDirection(worldX, worldY, 1, -1, state); // Diagonal /
}
void Board::draw(sf::RenderWindow& window, const sf::Vector2f& cameraOffset)
{
    if (!cells) return;
    // Определяем видимую область в мировых координатах
    int startWorldX = static_cast<int>((-cameraOffset.x) / 128) - 2;
    int endWorldX = static_cast<int>((-cameraOffset.x + window.getSize().x) / 128) + 2;
    int startWorldY = static_cast<int>((-cameraOffset.y) / 128) - 2;
    int endWorldY = static_cast<int>((-cameraOffset.y + window.getSize().y) / 128) + 2;
    // Преобразуем в локальные координаты с проверкой границ
    int startLocalX = std::max(0, startWorldX - offsetX);
    int endLocalX = std::min(width - 1, endWorldX - offsetX);
    int startLocalY = std::max(0, startWorldY - offsetY);
    int endLocalY = std::min(height - 1, endWorldY - offsetY);
    // Рисуем только видимые ячейки
    for (int i = startLocalX; i <= endLocalX; ++i)
    {
        for (int j = startLocalY; j <= endLocalY; ++j)
        {
            cells[i][j].draw(window, cameraOffset);
        }
    }
}
void Board::updateVisibleArea(const sf::Vector2f& cameraOffset, const sf::Vector2u&
    windowSize)
{
    // Предварительно расширяем поле для видимой области
    int startWorldX = static_cast<int>((-cameraOffset.x) / 128) - 8; // Запас
    int endWorldX = static_cast<int>((-cameraOffset.x + windowSize.x) / 128) + 8;
    int startWorldY = static_cast<int>((-cameraOffset.y) / 128) - 8;
    int endWorldY = static_cast<int>((-cameraOffset.y + windowSize.y) / 128) + 8;
    // Проверяем углы видимой области
    expandBoardIfNeeded(startWorldX, startWorldY);
    expandBoardIfNeeded(endWorldX, startWorldY);
    expandBoardIfNeeded(startWorldX, endWorldY);
    expandBoardIfNeeded(endWorldX, endWorldY);
}
bool Board::handleClick(const sf::Vector2f& mousePos, const sf::Vector2f& cameraOffset)
{
    if (!cells) return false;
    // Правильно преобразуем координаты мыши в мировые координаты сетки
    // mousePos - это координаты мыши в окне
    // cameraOffset - это смещение камеры
    // Правильная формула: worldX = (mousePos.x - cameraOffset.x) / cellSize
    float worldXFloat = (mousePos.x - cameraOffset.x) / 128.0f;
    float worldYFloat = (mousePos.y - cameraOffset.y) / 128.0f;
    // Округляем до ближайшей ячейки
    int worldX = static_cast<int>(std::round(worldXFloat));
    int worldY = static_cast<int>(std::round(worldYFloat));
    // Для отрицательных координат нужно правильно округлять
    if (worldXFloat < 0)
    {
        worldX = static_cast<int>(std::floor(worldXFloat));
    }
    if (worldYFloat < 0)
    {
        worldY = static_cast<int>(std::floor(worldYFloat));
    }
    std::cout << "Click at mouse (" << mousePos.x << ", " << mousePos.y
        << "), camera (" << cameraOffset.x << ", " << cameraOffset.y
        << "), world (" << worldX << ", " << worldY << ")" << std::endl;
    // Проверяем, попадает ли клик в какую-либо ячейку
    bool found = false;
    int startWorldX = worldX - 1;
    int endWorldX = worldX + 1;
    int startWorldY = worldY - 1;
    int endWorldY = worldY + 1;
    for (int checkX = startWorldX; checkX <= endWorldX && !found; ++checkX)
    {
        for (int checkY = startWorldY; checkY <= endWorldY && !found; ++checkY)
        {
            int localX = checkX - offsetX;
            int localY = checkY - offsetY;
            if (localX >= 0 && localX < width && localY >= 0 && localY < height)
            {
                // Создаем точку в мировых координатах для проверки попадания
                sf::Vector2f checkPoint(
                    static_cast<float>(checkX * 128 + cameraOffset.x + 64), // центр ячейки
                    static_cast<float>(checkY * 128 + cameraOffset.y + 64)
                );
                // Проверяем расстояние до центра ячейки
                float distance = std::sqrt(
                    std::pow(mousePos.x - checkPoint.x, 2) +
                    std::pow(mousePos.y - checkPoint.y, 2)
                );
                if (distance < 64.0f) { // Если в пределах ячейки
                    worldX = checkX;
                    worldY = checkY;
                    found = true;
                    std::cout << "Found cell at (" << worldX << ", " << worldY << ")" <<
                        std::endl;
                }
            }
        }
    }
    if (found)
    {
        makeMove(worldX, worldY);
        return true;
    }
    return false;
}
bool Board::isGameFinished() const
{
    return gameFinished;
}
CellState Board::getWinner() const
{
    return winner;
}
bool Board::getCurrentPlayer() const
{
    return isCrossTurn;
}
void Board::resetGame()
{
    if (!cells) return;
    for (int i = 0; i < width; ++i)
    {
        for (int j = 0; j < height; ++j)
        {
            cells[i][j].setState(CellState::Empty);
        }
    }
    isCrossTurn = true;
    gameFinished = false;
    winner = CellState::Empty;
}

main.cpp

#include <SFML/Graphics.hpp>
#include "board.h"

int main() {
    sf::RenderWindow window(sf::VideoMode(800, 600), "5 in a Row - Tic Tac Toe");

    Board board;
    if (!board.initialize()) {
        return -1;
    }

    sf::Vector2f cameraOffset(0.0f, 0.0f);
    bool isDragging = false;
    sf::Vector2f lastMousePos;

    while (window.isOpen()) {
        sf::Event event;
        while (window.pollEvent(event)) {
            if (event.type == sf::Event::Closed) {
                window.close();
            }

            if (event.type == sf::Event::MouseButtonPressed) {
                if (event.mouseButton.button == sf::Mouse::Left) {
                    sf::Vector2f mousePos = window.mapPixelToCoords(
                        sf::Vector2i(event.mouseButton.x, event.mouseButton.y));

                    if (sf::Keyboard::isKeyPressed(sf::Keyboard::LControl)) {
                        isDragging = true;
                        lastMousePos = mousePos;
                    }
                    else {
                        board.handleClick(mousePos, cameraOffset);
                    }
                }
            }

            if (event.type == sf::Event::MouseButtonReleased) {
                if (event.mouseButton.button == sf::Mouse::Left) {
                    isDragging = false;
                }
            }

            if (event.type == sf::Event::MouseMoved && isDragging) {
                sf::Vector2f mousePos = window.mapPixelToCoords(
                    sf::Vector2i(event.mouseMove.x, event.mouseMove.y));
                sf::Vector2f delta = mousePos - lastMousePos;
                cameraOffset += delta;
                lastMousePos = mousePos;
            }

            if (event.type == sf::Event::KeyPressed) {
                if (event.key.code == sf::Keyboard::R) {
                    board.resetGame();
                }
            }
        }

        board.updateVisibleArea(cameraOffset, window.getSize());

        window.clear(sf::Color::White);
        board.draw(window, cameraOffset);
        window.display();
    }

    return 0;
}

Ответы (1 шт):

Автор решения: FloodyK

изменение загрузки текстур помогли.

→ Ссылка