Поэтому моя единственная цель — переместить спрайт влево и вправо, и пока спрайт движется, я хочу переключаться между двумя различными частями листа спрайта каждые полсекунды.
Я перепробовал все, что мог придумать, поэтому я оставил его работающим без единой реализации необходимой функции. (РЕДАКТИРОВАТЬ: я изменил его, пытаясь следовать советам, данным другим пользователем) Я посмотрел в Интернете, но ничего, что я не смог найти, ответил на мой вопрос, насколько я мог судить. Я уверен, что есть кое-что, что я пропускаю, и что это довольно просто, но именно поэтому мне нужен ваш вклад.
Третья часть таблицы спрайтов, которую я хочу использовать, находится при x = 800, анимации, направленные влево, сверху при y = 0, а анимации, направленные вправо, — снизу при y = 600.
Вот спрайт, который я использую
Первые предназначены для того, чтобы стоять на месте, а вторые два в каждом ряду — это те, между которыми я хочу переключаться во время «ходьбы»
В любом случае, вот мой код:
#include "pch.h"#include <iostream>
#include "SFML/Graphics.hpp"#include <random>
#include <unordered_map>
enum State
{
Walking,
Standing
};
enum Direction
{
Left,
Right
};
int main(int argc, char ** argv)
{
/* Gregory */
sf::Texture GregorySpriteSheet_T;
GregorySpriteSheet_T.loadFromFile("Images/GregorySpriteSheet.png");
sf::IntRect GregorySpriteRect(0, 600, 400, 600);
sf::Sprite Gregory(GregorySpriteSheet_T, GregorySpriteRect);
sf::RenderWindow renderWindow(sf::VideoMode(1600,800), "SFML 2 Demo");
sf::Event event;sf::Time timePerFrame = sf::seconds(1.0f / 60.0f);
sf::Clock deltaClock;
sf::Time timeSinceLastUpdate = sf::Time::Zero;State isWalking{ Standing };
sf::Clock walkClock;
Direction direction = Right;/* RENDER WINDOW LOOP */while (renderWindow.isOpen())
{
sf::Time deltaTime = deltaClock.restart();
timeSinceLastUpdate += deltaTime;
while (timeSinceLastUpdate >= timePerFrame)
{
timeSinceLastUpdate -= timePerFrame;while (renderWindow.pollEvent(event))
{
if (event.type == sf::Event::EventType::Closed || sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
{
renderWindow.close();
}if (event.type == sf::Event::EventType::KeyPressed)
{
if (event.key.code == sf::Keyboard::Right)
{
isWalking = Walking;
direction = Right;
}
}
if (event.type == sf::Event::EventType::KeyReleased)
{
if (event.key.code == sf::Keyboard::Right)
{
isWalking = Standing;
}
}if (event.type == sf::Event::EventType::KeyPressed)
{
if (event.key.code == sf::Keyboard::Left)
{
isWalking = Walking;
direction = Left;
}
}
if (event.type == sf::Event::EventType::KeyReleased)
{
if (event.key.code == sf::Keyboard::Left)
{
isWalking = Standing;
}
}
}if (isWalking == Walking)
{
if (direction == Right)
GregorySpriteRect.top = 600;
if (direction == Left)
GregorySpriteRect.top = 0;
if (GregorySpriteRect.left == 0)
GregorySpriteRect.left = 400;
if ((int(walkClock.getElapsedTime().asSeconds() / 1.5f) % 2) == 1)
{
if (GregorySpriteRect.left == 400)
GregorySpriteRect.left == 800;
if (GregorySpriteRect.left == 800)
GregorySpriteRect.left == 400;
walkClock.restart();
}
}
{
using kb = sf::Keyboard;
if (kb::isKeyPressed(kb::Right))
{
Gregory.move(400 * timePerFrame.asSeconds(), 0.0f);
direction = Right;
isWalking = Walking;
}if (kb::isKeyPressed(kb::Left))
{
Gregory.move(-400 * timePerFrame.asSeconds(), 0.0f);
direction = Left;
isWalking = Walking;
}
if (kb::isKeyPressed(kb::Right) && kb::isKeyPressed(kb::Left))
{
isWalking = Standing;
}
}if (isWalking == Standing)
{
GregorySpriteRect.left = 0;
if (direction == Right)
GregorySpriteRect.top = 600;
if (direction == Left)
GregorySpriteRect.top = 0;
}
}Gregory.setTextureRect(GregorySpriteRect);
renderWindow.clear();
renderWindow.draw(Gregory);
renderWindow.display();
}
/* END RENDER WINDOW LOOP */}
Вот одно предложение, но есть много альтернатив:
Во-первых, немного переписайте обработку событий так, чтобы вы могли различать первый раз удержание клавиши и последующее время. Простой способ — это иметь enum State { Standing, Walking }
и установите для него соответствующее значение в вашем обработчике ключей (например, «не гуляете и ключ удерживается? установите состояние на ходьбу»)
Затем, когда игрок начинает ходить, (пере) запускайте часы «ходьбы».
Наконец, когда вы фактически рендерите своего игрока, проверьте эти часы и разделите истекшее время с момента ходьбы на период ходьбы (это определяет, как долго должна удерживаться одна из рамок для ходьбы). Если таких периодов ходьбы было четное количество, используйте левого шагающего спрайта, в противном случае правого шагающего спрайта.
Конечно, эта техника легко распространяется на большие наборы ходячих рамок.
Поэтому для любого, кто попадет сюда в будущем, мне не хватало жизненной линии:
Gregory.setTextureRect(GregorySpriteRect);
Либо в моем заявлении «если» для часов под «if (isWalking == Walking)», либо под ним (как я это сделал здесь). Вставил полный код ниже. Работает в обоих направлениях сейчас. Не уверен, насколько это оптимально, но если вы любитель, как я, это должно помочь.
Также учтите, что я вернул некоторые изменения, предложенные в ответе Ботье. Хотя я должен отдать ему должное за то, что он очень помог мне с рекомендацией использовать enum для ходьбы и стояния, а также для направления. Я также использовал оператор «>» вместо оператора «==», как предложил мой профессор из-за ошибок округления переменных с плавающей точкой.
Ура!
#include "pch.h"#include <iostream>
#include "SFML/Graphics.hpp"#include <random>
#include <unordered_map>
enum State
{
Walking,
Standing
};
enum Direction
{
Left,
Right
};
int main(int argc, char ** argv)
{
/* Gregory */
sf::Texture GregorySpriteSheet_T;
GregorySpriteSheet_T.loadFromFile("Images/GregorySpriteSheet.png");
sf::IntRect GregorySpriteRect(0, 600, 400, 600);
sf::Sprite Gregory(GregorySpriteSheet_T, GregorySpriteRect);
sf::RenderWindow renderWindow(sf::VideoMode(1600,800), "SFML 2 Demo");
sf::Event event;sf::Time timePerFrame = sf::seconds(1.0f / 60.0f);
sf::Clock deltaClock;
sf::Time timeSinceLastUpdate = sf::Time::Zero;State isWalking{ Standing };
sf::Clock walkClock;
Direction direction = Right;/* RENDER WINDOW LOOP */while (renderWindow.isOpen())
{
sf::Time deltaTime = deltaClock.restart();
timeSinceLastUpdate += deltaTime;
while (timeSinceLastUpdate >= timePerFrame)
{
timeSinceLastUpdate -= timePerFrame;while (renderWindow.pollEvent(event))
{
if (event.type == sf::Event::EventType::Closed || sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
{
renderWindow.close();
}if (event.type == sf::Event::EventType::KeyPressed)
{
if (event.key.code == sf::Keyboard::Right)
{
isWalking = Walking;
direction = Right;
GregorySpriteRect.top = 600;
}
}
if (event.type == sf::Event::EventType::KeyReleased)
{
if (event.key.code == sf::Keyboard::Right)
{
isWalking = Standing;
}
}if (event.type == sf::Event::EventType::KeyPressed)
{
if (event.key.code == sf::Keyboard::Left)
{
isWalking = Walking;
direction = Left;
GregorySpriteRect.top = 0;
}
}
if (event.type == sf::Event::EventType::KeyReleased)
{
if (event.key.code == sf::Keyboard::Left)
{
isWalking = Standing;
}
}
}if (isWalking == Walking)
{
if (direction == Right)
GregorySpriteRect.top = 600;
else if (direction == Left)
GregorySpriteRect.top = 0;
else
GregorySpriteRect.top = 600;
if (GregorySpriteRect.left == 0)
GregorySpriteRect.left = 400;
if (walkClock.getElapsedTime().asSeconds() > 0.5f)
{
if (GregorySpriteRect.left == 400)
GregorySpriteRect.left = 800;
else if (GregorySpriteRect.left == 800)
GregorySpriteRect.left = 400;
else
GregorySpriteRect.left += 0;
walkClock.restart();
}
Gregory.setTextureRect(GregorySpriteRect);
}
{
using kb = sf::Keyboard;
if (kb::isKeyPressed(kb::Right))
{
Gregory.move(400 * timePerFrame.asSeconds(), 0.0f);
direction = Right;
}if (kb::isKeyPressed(kb::Left))
{
Gregory.move(-400 * timePerFrame.asSeconds(), 0.0f);
direction = Left;
}
if (kb::isKeyPressed(kb::Right) && kb::isKeyPressed(kb::Left))
{
isWalking = Standing;
direction = Right;
}
}if (isWalking == Standing)
{
GregorySpriteRect.left = 0;
if (direction == Right)
GregorySpriteRect.top = 600;
if (direction == Left)
GregorySpriteRect.top = 0;
}
}Gregory.setTextureRect(GregorySpriteRect);
renderWindow.clear();
renderWindow.draw(Gregory);
renderWindow.display();
}
/* END RENDER WINDOW LOOP */}