Игровые объекты движутся влево и вверх, но не движутся вправо и вниз - PullRequest
0 голосов
/ 03 января 2019

ОБНОВЛЕНИЕ

Я вижу, предоставление кода частично не решает проблему.Есть много файлов, поэтому я предоставлю все заявки через GitHub для всех, кто хотел бы попытаться решить эту проблему:

https://github.com/johnydominus/CrimsonLikeGameSMFL


Заранее извините за мойЗнание английского и программирования.Я новичок.Я делаю 2D-игру, используя C ++ и SFML SDK.Игра похожа на CrimsonLand (2003): игрок должен ходить по карте и стрелять в монстров, пытаясь добраться до него.На данный момент игрок идет и монстры преследуют его, но только если их направление оставлено или вверх.Если нужное направление верное или нисходящее - они не двигаются.Монстры просто стоят и смотрят в сторону игроков.И игрок просто не двигается, когда нажаты кнопки «вправо» или «вниз».

Я реализовал 2 системы координат движения - относительно карты (для обработки игровых событий, таких как пересечение монстров с пулями) и относительно игрока (дляцентр "камера" на плеере).Движение записывается сначала в координаты карты, затем оно преобразуется в относительные координаты игрока.Следовательно, рисование использует относительные координаты игрока.Однако, похоже, что проблема не в рисовании.

Ввод работает - я пытался изменить назначение движения (только для проверки) и настроен на перемещение влево при нажатии правой кнопки и вверх при нажатии кнопки вниз - и это сработало: игрок перемещался вверх как вверх, так икнопки «вниз» и кнопки «влево» и «вправо».

Я постараюсь удалить все строки, которые не связаны с проблемой.Но из-за того, что я не имею четкого представления о том, что не так - кода будет довольно много.Заголовки карт, монстров и игроков, а также файлы .cpp - объявление и определение игровых объектов.Заголовок движка и .cpp - объявление и определение движка, который обрабатывает взаимодействие объектов.Ввод и обновление .cpp's - определение методов Engine, которые обрабатывают соответственно ввод с клавиатуры и обновляют положение и состояние объектов.

player.h

class Player :
    public Object
{
private:
    std::vector<float> mapSize{0,0};
    int speed = 1;

    POINT prevPosition;
    std::vector<float> relatMovement{ 0,0 };

    bool leftPressed;
    bool rightPressed;
    bool upPressed;
    bool downPressed;

public:
    POINT Position;
    POINT relatPosition;

    void moveLeft();
    void moveRight();
    void moveUp();
    void moveDown();
    void stopLeft();
    void stopRight();
    void stopUp();
    void stopDown();

    void update(float elapsedTime);
};

player.cpp

void Player::moveLeft()
{
    leftPressed = true;
}

void Player::moveRight()
{
    rightPressed = true;
}

void Player::moveUp()
{
    upPressed = true;
}

void Player::moveDown()
{
    downPressed = true;
}

void Player::stopLeft()
{
    leftPressed = false;
}

void Player::stopRight()
{
    rightPressed = false;
}

void Player::stopUp()
{
    upPressed = false;
}

void Player::stopDown()
{
    downPressed = false;
}

void Player::update(float elapsedTime)
{
    if (rightPressed) 
        Position.x += speed * elapsedTime;

    if (leftPressed)
        Position.x -= speed * elapsedTime;

    if (upPressed) 
        Position.y -= speed * elapsedTime;

    if (downPressed) 
        Position.y += speed * elapsedTime;

    relatMovement[0] = Position.x - prevPosition.x;
    relatMovement[1] = Position.y - prevPosition.y;

    prevPosition = Position;
}

monster.h

class Monster :
public Object
{
private:
float pathLength;
Player* thePlayer;
Map* theMap;
POINT playerPosition;
POINT playerRelatPosition;
POINT nextStep;
std::vector<float> playerRelatMovement{0,0};
std::vector<float> direction{ 0,0 };
std::vector<float> vSpeed{ 0,0 };

public:
POINT Position;
POINT relatPosition;

POINT checkUpdate(float elapsedTime);
void update(float elapsedTime, POINT position);
};

monster.cpp

POINT Monster::checkUpdate(float elapsedTime)
{
nextStep = Position;
playerPosition = *(thePlayer->getPosition());

direction[0] = playerPosition.x - Position.x;
direction[1] = playerPosition.y - Position.y;

pathLength = sqrt(pow(direction[0], 2) + pow(direction[1], 2));

direction[0] /= pathLength;
direction[1] /= pathLength;

vSpeed[0] = ((float)direction[0] * (float)speed)/10.0;
vSpeed[1] = ((float)direction[1] * (float)speed)/10.0;

nextStep.x += vSpeed[0];
nextStep.y += vSpeed[1];

return nextStep;
}

void Monster::update(float elapsedTime, POINT aNextStep)
{
Position = aNextStep;
playerPosition = *(thePlayer->getPosition());
playerRelatPosition = *(thePlayer->getRelatPosition());

relatPosition.x = playerRelatPosition.x + (Position.x - playerPosition.x);
relatPosition.y = playerRelatPosition.y + (Position.y - playerPosition.y);

shape.left = Position.x - (size[0] / 2);
shape.right = Position.x + (size[0] / 2);
shape.top = Position.y - (size[1] / 2);
shape.bottom = Position.y + (size[1] / 2);

}

map.h

class Map:
public Object
{
private:
std::vector<float> relatMovement{0,0};
std::vector<float> size{0,0};
Player* thePlayer;

public:
POINT Position;
POINT relatPosition;

void update();
};

map.cpp

Map::Map()
{
Position.x = 0;
Position.y = 0;
}

void Map::update()
{
relatMovement = *(thePlayer->getRelatMovement());
relatPosition.x -= relatMovement[0];
relatPosition.y -= relatMovement[1];
}

Engine.h

class Engine
{
private:
Player thePlayer;
Map theMap;
Monster* allMonsters;

    int mapXstart=0, mapYstart=0, ammoNumberStart=0, enemiesNumberStart=0;

void input();
void update(float timeInSeconds);
void draw();

void setWindowSize(int mapX, int mapY);
void setMapSize(float mapWidth, float mapHeight);

public:
void start();
};

Engine.cpp

Engine::Engine()
{
//setting map sprites
a = ((mapY+windowY) / theMap.mSprite.getTexture()->getSize().y) + 1;
b = ((mapX+windowX) / theMap.mSprite.getTexture()->getSize().x) + 1;
mapSprites = new sf::Sprite*[a];
for (i = 0; i < a; i++) {
    mapSprites[i] = new sf::Sprite[b];
    for (j = 0; j < b; j++) {
        mapSprites[i][j].setTexture(*theMap.mSprite.getTexture());
    }
}

//setting window
mWindow.create(sf::VideoMode(windowX, windowY), "CrimsonLikeGame", sf::Style::Default);

//setting game objects
//map
int mapRelX, mapRelY;
mapRelX = (windowX / 2) - (mapX / 2);
mapRelY = (windowY / 2) - (mapY / 2);

theMap.setRelativePosition(mapRelX, mapRelY);
theMap.setSize(mapX, mapY);
theMap.setPlayer(&thePlayer);

//player
thePlayer.setPosition(mapX/2,mapY/2);
thePlayer.setRelativePosition(windowX / 2, windowY / 2);
thePlayer.setMapSize(mapX, mapY);

//monsters
allMonsters = new Monster[enemiesNumber];

for (i = 0; i < enemiesNumber; i++) {
    allMonsters[i].setPlayer(&thePlayer);
    allMonsters[i].setMap(&theMap);
}
}   

void Engine::start()
{
sf::Clock clock;

//game loop
while (mWindow.isOpen()) {
    sf::Time dt = clock.restart();
    float dtAsSeconds = dt.asSeconds();

    input();
    update(dtAsSeconds);
    draw();
}
}

input.cpp

void Engine::input() {
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape)) {
    mWindow.close();
}

if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) {
    thePlayer.moveLeft();
}
else {
    thePlayer.stopLeft();
}

if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) {
    thePlayer.moveRight();
}
else {
    thePlayer.stopRight();
}

if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) {
    thePlayer.moveUp();
}
else {
    thePlayer.stopUp();
}

if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) {
    thePlayer.moveDown();
}
else {
    thePlayer.stopDown();
}

if (sf::Mouse::isButtonPressed(sf::Mouse::Left)) {
    mouseButtonPressed = true;
}
else {
    mouseButtonPressed = false;
}
}

update.cpp

void Engine::update(float timeInSeconds) {

if (thePlayer.isAlive()&&enemiesAlive) {

    thePlayer.update(timeInSeconds);
    theMap.update();

    //Writing down, where each monster is going to go by it's next step
    for (i = 0; i < enemiesNumber; i++) {
        if (allMonsters[i].isAlive()) {
            enemiesNextSteps[i] = allMonsters[i].checkUpdate(timeInSeconds);
        }
    }

    //cheking - does anybody is going to collide
    for (i = 0; i < enemiesNumber; i++) {
        if (allMonsters[i].isAlive()) {
            int j;
            for (j = 0; j < enemiesNumber; j++) {
                if (j == i)
                    continue;
                else {
                    if ((((allMonsters[i].shape.left <= allMonsters[j].shape.right) && (allMonsters[i].shape.left >= allMonsters[j].shape.left)) || ((allMonsters[i].shape.right <= allMonsters[j].shape.right) && (allMonsters[i].shape.right >= allMonsters[j].shape.left))) && (((allMonsters[i].shape.bottom >= allMonsters[j].shape.top) && (allMonsters[i].shape.bottom <= allMonsters[j].shape.bottom)) || ((allMonsters[i].shape.top >= allMonsters[j].shape.top) && (allMonsters[i].shape.top <= allMonsters[j].shape.bottom)))) {
                        monstersCollide[i] = true;
                    }
                }
            }
        }
    }

    //updating each alive monster position without collisions
    for (i = 0; i < enemiesNumber; i++) {
        if (allMonsters[i].isAlive()/*&&!monstersCollide[i]*/) {
            allMonsters[i].setPosition(enemiesNextSteps[i]);
            allMonsters[i].update(timeInSeconds, enemiesNextSteps[i]);
        }
    }
}
else {                                       
//if player is dead - restart the game
    thePlayer.setAlive(true);
    for (i = 0; i < enemiesNumber; i++) {
        allMonsters[i].setAlive(true);
    }
}
}

Я пытался выяснить это полдня.Надеюсь, вы поможете мне с этой проблемой.

1 Ответ

0 голосов
/ 04 января 2019

Хорошо.Я на самом деле создал и запустил этот код, и основной причиной вашей проблемы с перемещением является использование целых чисел для ваших координат и последующей ассиметрии:

if (rightPressed) 
    Position.x += speed * elapsedTime;

if (leftPressed)
    Position.x -= speed * elapsedTime;

Эти два вначале кажутся довольно равными, но когда вы считаете,Что на самом деле происходит, они немного отличаются.Поскольку ваша скорость относительно низкая (1.0), а также ваше прошедшее время (например, ~0.016 для одного кадра), различия в конечном итоге уменьшаются на единицу.Чтобы понять, что происходит дальше, вам нужно взглянуть на преобразования типов.

Эти операторы фактически эквивалентны:

Position.x = Position.x + (speed * elapsedTime);

Поскольку speed и elapsedTime являются числами с плавающей запятой, Position.x также получает звание поплавка.Затем дробь либо прибавляется и вычитается, и затем результат преобразуется обратно в целое число.

В случае перемещения влево число, например 100, преобразуется в 100.0затем 0.016 вычитается, в результате чего 99.984.Затем целочисленное преобразование удаляет десятичную часть, что приводит к значению 99 и заметному изменению позиции вашего игрока.

В случае движения вправо мы делаем то же самое, но в итоге получаемзначение 100.016 вместо.Это преобразовало обратно в целочисленные результаты со значением 100 снова.


Чтобы исправить это, самое простое решение состоит в том, чтобы заставить положение игрока использовать поплавки.Тогда небольшие изменения будут правильно накапливаться.Вы можете заметить, что игрок движется намного медленнее, чем вы ожидаете, потому что эффект целочисленного сжатия исчезнет;установка скорости на 60 должна более или менее вернуть вас туда, где она была.

...