Как визуализировать спрайты для игры со змеями, используя SFML и C++C++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Как визуализировать спрайты для игры со змеями, используя SFML и C++

Сообщение Anonymous »

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

Код: Выделить всё

#include   // Graphics module
#include      // Sound module
#include            // Basic input/output (for errors)
#include              // Dynamic arrays (for snake body)
#include              // For random food positions

class Game {
private:
sf::Vector2u windowSize;        // Size of the game window
int a, b;                       // Length and width of a block
sf::RenderWindow window;        // Window object for drawing
sf::Font font;                  // Text font
sf::Clock clock;                // For time measurement
std::vector body; // Snake body (segments as coordinates)
sf::Vector2i food;              // Food position
sf::Vector2i direction;         // Snake direction
int score;                      // Player's score
bool gameOver;                  // Game state: finished or not
int n, m;                       // Number of rows and columns
float delay, timer;             // Update delay and elapsed time
sf::Music eat;                  // Sound effect for eating

public:
Game(unsigned short x, unsigned short y); // Constructor
void start();                   // Start the game
private:
void loop();                    // Main game loop
void events();                  // Process events (keyboard, etc.)
void update();                  // Update game logic
void render();                  // Render elements on screen
void gameOverScreen();          // Show "Game Over" screen
sf::Vector2i getFoodPosition(); // Generate new food position
};

int WinMain() {
Game game(800, 600);
game.start();
}

int main() {
Game game(800, 600);    // Create object with window size 800x600
game.start();           // Call the start function
}

Game::Game(uint16_t x, uint16_t y) {
windowSize = { x, y };  // Save window width and height
window.create(sf::VideoMode(windowSize.x, windowSize.y, 1), "Snake");
// Create the window
a = 50;                 // Set block width
b = 50;                 // Set block height
n = windowSize.x / a;   // Calculate number of horizontal blocks
m = windowSize.y / b;   // Calculate number of vertical blocks
font.loadFromFile("resources/Fonts/sfpro_bold.OTF"); // Load font for text
eat.openFromFile("resources/Audio/eating_apple.mp3");
}

void Game::start() {
body.clear();            // Clear the snake body
body.push_back({ 5,3 }); // Head
body.push_back({ 4,3 }); // Body segment
body.push_back({ 3,3 }); // Tail
direction = { 0, 0 };    // Direction
food = { getFoodPosition() }; // Initial food position
gameOver = false;        // Game not over (false)
score = 0;               // Start score from 0
loop();                  // Main loop
}

void Game::loop() {
timer = 0.f;             // Accumulated time
delay = 0.125f;          // Game update delay
while (window.isOpen()) {
events();            // Handle user inputs (keyboard and mouse)
timer += clock.getElapsedTime().asSeconds(); // Add elapsed time in seconds to the timer
if (timer > delay) {
update();        // Update the game (move snake, etc.)
render();        // Render the screen (blocks, snake, food, text, etc.)
timer = 0;       // Reset timer
}
clock.restart();    // Restart the clock for the next cycle
}
}

void Game::events() {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed)
window.close();
if (event.type == sf::Event::KeyPressed) {
if (event.key.code == sf::Keyboard::Escape) window.close();
else if (event.key.code == sf::Keyboard::Up && (direction.y != 1)) direction = { 0, -1 };
else if (event.key.code == sf::Keyboard::Down && (direction.y != -1)) direction = { 0, 1 };
else if (event.key.code == sf::Keyboard::Left && (direction.x != 1)) direction = { -1, 0 };
else if (event.key.code == sf::Keyboard::Right &&  (direction.x != -1)) direction = { 1, 0 };
else if (event.key.code == sf::Keyboard::R) /*if (gameOver)*/ start();
}
}
}

void Game::update() {
if (gameOver || direction == sf::Vector2i{ 0,0 }) return;
sf::Vector2i newHead = body[0] + direction;
for (size_t i = 1; i < body.size(); i++) {
if (newHead == body[i]) {
gameOver = true;
return;
}
}
if (newHead.x > n - 1 || newHead.x < 0 || newHead.y > m - 1 || newHead.y < 0) {
gameOver = true;
return;
}
if (newHead == food) {
body.insert(body.begin(), newHead);
food = getFoodPosition();
score++;
eat.play();
}
else {
body.insert(body.begin(), newHead);
body.pop_back();
}
}

void Game::render() {
window.clear();
sf::RectangleShape block(sf::Vector2f(a, b));
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
block.setPosition(i * a, j * b);
int p = (i + j) % 2;
block.setFillColor(sf::Color(172 - p * 7, 214 - p * 7, 67 - p * 7, 255));
window.draw(block);
}
}

block.setPosition(food.x * a, food.y * b);
block.setFillColor(sf::Color::Red);
window.draw(block);

for (int i = 0; i < body.size(); i++) {
if (i == 0)
block.setFillColor(sf::Color::Magenta);
else
block.setFillColor(sf::Color(0, 71, 181));
block.setPosition(body[i].x * a, body[i].y * b);
window.draw(block);
}

sf::Text scr("Score: " + std::to_string(score), font, 32);
scr.setFillColor(sf::Color::White);
scr.setPosition(4, 0);
window.draw(scr);
if (gameOver) gameOverScreen();

window.display();
}

void Game::gameOverScreen() {
eat.stop();
sf::RectangleShape screen({ float(windowSize.x), float(windowSize.y) });
screen.setPosition({ 0,0 });
screen.setFillColor(sf::Color(0, 0, 0, 100));
sf::Text gameOverText("      Game over!\nPress R to restart", font, 38);
gameOverText.setFillColor(sf::Color::White);
gameOverText.setPosition((windowSize.x / 2) - 150, (windowSize.y / 2) - 20);
window.draw(screen);
window.draw(gameOverText);
}

sf::Vector2i Game::getFoodPosition() {
std::random_device randomDevice;
std::mt19937 randomNumberGenerator(randomDevice());

std::uniform_int_distribution distX(0, n - 1);
std::uniform_int_distribution distY(0, m - 1);
sf::Vector2i position;
do {
position.x = distX(randomNumberGenerator);
position.y = distY(randomNumberGenerator);
if (std::find(body.begin(), body.end(), position) == body.end()) {
return position;
}
} while (true);
}
В приведенном выше коде в настоящее время нет функций спрайтов, но вот подход, который я попробовал (который сработал для рендеринга спрайтов): создал карту текстур и спрайтов, загрузил текстуры. из файлов, сопоставил их со спрайтами, а затем у меня была готова карта спрайтов. Эта часть была не такой уж сложной, скорее всего, у меня были ошибки в логике рендеринга. Код был взят из тех времен, когда у меня была логика спрайтов. В основном я использую строку, чтобы определить, какой спрайт мне следует загрузить.

Код: Выделить всё

sf::Vector2i prev = body[i + 1]; //
sf::Vector2i next = body[i - 1]; //because i pop the tail and insert new part at the beginning
if (next.x == prev.x) {
spriteName = "body_vertical"; //vertical sprite |
}
else if (next.y == prev.y) {
spriteName = "body_horizontal"; // horizontal   --
}
else {
if (prev.x < next.x) {
if (prev.y > next.y)
spriteName = "body_topright"; // start top curve right downwards
else
spriteName = "body_bottomleft"; // bottom -> left
}
else if (prev.y < next.y) {
spriteName = "body_topleft"; // top -> left

else
spriteName = "body_bottomright"; // bottom -> right
}
}
else{
if (prev.y > next.y) {
spriteName = "body_topleft"; // top -> left
else
spriteName = "body_bottomright"; // bottom -> right
}
else if (prev.y < next.y) {
spriteName = "body_topright"; // top -> right
else
spriteName = "body_bottomleft"; // bottom -> left
}
}
}
Ссылка на спрайты: opengameart.org/content/snake-game-assets. По сути, мне нужны отзывы о том, как выбрать правильный спрайт для загрузки и для какой ситуации (голова и хвост тоже будут признательны 🥹). Спасибо!

Подробнее здесь: https://stackoverflow.com/questions/782 ... sfml-and-c
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»