diff --git a/player.cpp b/player.cpp index 300a984..4f2392f 100644 --- a/player.cpp +++ b/player.cpp @@ -1,99 +1,140 @@ -#include "player.hpp" // Включаємо заголовок класу Player, щоб компілятор знав про його методи та змінні. +#include "player.hpp" +#include using namespace std; -// Конструктор класу Player. Він автоматично викликається при створенні об'єкта Player. Player::Player() - : shape(sf::Vector2f(50.f, 50.f)), // тут лише "чисте" створення - speed(500.f), //швидкість + : shape(sf::Vector2f(60.f, 60.f)), + speed(500.f), velocityY(0.f), - jumpStrength(700.f), // пиржок + jumpStrength(700.f), onGround(true), gravity(1500.f), - groundLevel(1040.f) + groundLevel(1040.f), + facingRight(true), + runFrames(), + idleFrame(), + sprite(), + currentFrame(0), + animationTimer(0.f), + animationSpeed(0.1f), + isMoving(false) { - // А тут уже викликаємо методи, які налаштовують shape shape.setFillColor(sf::Color::Green); - shape.setPosition(50.f, 1040.f); + shape.setPosition(50.f, groundLevel); + + loadIdleFrame(); + loadRunAnimation(); + + sprite.setTexture(idleFrame); + sprite.setOrigin(idleFrame.getSize().x / 2.f, idleFrame.getSize().y / 2.f); + + float scaleX = shape.getSize().x / idleFrame.getSize().x; + float scaleY = shape.getSize().y / idleFrame.getSize().y; + + // Початкове віддзеркалення: PNG дивиться вліво, потрібно вправо + sprite.setScale(-scaleX, scaleY); + + sprite.setPosition( + shape.getPosition().x + shape.getSize().x / 2.f, + shape.getPosition().y + shape.getSize().y / 2.f + ); } +void Player::loadIdleFrame() { + if (!idleFrame.loadFromFile("img/FA_PENGUIN_Idle_000.png")) { + cout << "Cannot load idle frame\n"; + } +} - -// Закоментований метод `update` (робота на потім). -// Він призначений для оновлення логіки гравця у кожному кадрі гри. -// Усередині цього методу, ви будете обробляти рух, зіткнення, анімацію тощо. -// `deltaTime` — це час, що минув з попереднього кадру, і він забезпечує плавний рух незалежно від швидкості комп'ютера. -void Player::update(float deltaTime, const std::vector& platforms) { // Тут буде логіка руху гравця - float moveX = 0.f; - - - - if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)){ - moveX -= speed * deltaTime;} //рух вліво - - if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)){ - moveX += speed * deltaTime;} //рух вправо - - if (sf::Keyboard::isKeyPressed(sf::Keyboard::W) && onGround==true) { - velocityY = -jumpStrength; - } - velocityY += gravity * deltaTime; - - shape.move(moveX, 0.f); - shape.move(0.f , velocityY * deltaTime); - - //перевірка чи є земля та обмеження щоб фігура не вилитіла - - if(shape.getPosition().y + shape.getSize().y >= groundLevel){ - shape.setPosition(shape.getPosition().x, groundLevel -shape.getSize().y); - velocityY = 0; - onGround = true; - }else{ - onGround = false; +void Player::loadRunAnimation() { + runFrames.clear(); + for (size_t i = 0; i < 10; ++i) { // припустимо 10 кадрів + sf::Texture tex; + string filename = "img/04-Run/FA_PENGUIN_Run_00" + to_string(i) + ".png"; + if (!tex.loadFromFile(filename)) { + cout << "Cannot load " << filename << "\n"; + } else { + runFrames.push_back(tex); } - ///////////////////////////////////////////////////// + } +} - sf::FloatRect playerBounds = shape.getGlobalBounds(); +void Player::update(float deltaTime, const std::vector& platforms) { + float moveX = 0.f; + isMoving = false; - for (const auto& platform : platforms) { - sf::FloatRect platformBounds = platform.getBounds(); - if (playerBounds.intersects(platformBounds)){ - if (playerBounds.intersects(platformBounds)) { - // Додатковий if — перевіряємо, чи гравець зверху - if (playerBounds.top + playerBounds.height <= platformBounds.top + 20.f) { - shape.setPosition(shape.getPosition().x, platformBounds.top - shape.getSize().y); + if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) { + moveX -= speed * deltaTime; + facingRight = false; + isMoving = true; + } + if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) { + moveX += speed * deltaTime; + facingRight = true; + isMoving = true; + } + if (sf::Keyboard::isKeyPressed(sf::Keyboard::W) && onGround) + velocityY = -jumpStrength; + + velocityY += gravity * deltaTime; + shape.move(moveX, 0.f); + shape.move(0.f, velocityY * deltaTime); + + // Земля + if (shape.getPosition().y + shape.getSize().y >= groundLevel) { + shape.setPosition(shape.getPosition().x, groundLevel - shape.getSize().y); velocityY = 0.f; onGround = true; - }else if(playerBounds.top> platformBounds.top){shape.setPosition(shape.getPosition().x, platformBounds.top +platformBounds.height); - velocityY =0.f;} - } - } + } else onGround = false; + + // Колізії з платформами + for (const auto& platform : platforms) { + sf::FloatRect playerBounds = shape.getGlobalBounds(); + sf::FloatRect platBounds = platform.getBounds(); + if (playerBounds.intersects(platBounds)) { + if (playerBounds.top + playerBounds.height <= platBounds.top + 20.f) { + shape.setPosition(shape.getPosition().x, platBounds.top - shape.getSize().y); + velocityY = 0.f; + onGround = true; + } else if (playerBounds.top > platBounds.top) { + shape.setPosition(shape.getPosition().x, platBounds.top + platBounds.height); + velocityY = 0.f; } - - - - - - ///////////////////////////////////////////////////// - - if(shape.getPosition().x < 0.f) - shape.setPosition(0.f, shape.getPosition().y); - - if(shape.getPosition().x+shape.getSize().x>1925.f) - shape.setPosition(1925.f - shape.getSize().x ,shape.getPosition().y); - - - if(shape.getPosition().y < 0.f) - shape.setPosition(shape.getPosition().x,0.f); - - if(shape.getPosition().y+shape.getSize().y>1200.f) - shape.setPosition(shape.getPosition().x, 1200.f - shape.getSize().y); } + } + // Межі екрану + if (shape.getPosition().x < 0.f) shape.setPosition(0.f, shape.getPosition().y); + if (shape.getPosition().x + shape.getSize().x > 1925.f) + shape.setPosition(1925.f - shape.getSize().x, shape.getPosition().y); -// Метод `draw` для відмальовування гравця на екрані. -// Приймає посилання на вікно, щоб знати, де малювати. -void Player::draw(sf::RenderWindow& window) -{ - // Викликаємо метод `draw` вікна, щоб намалювати наш об'єкт `shape`. - window.draw(shape); + // Анімація + animationTimer += deltaTime; + if (isMoving && !runFrames.empty()) { + if (animationTimer >= animationSpeed) { + animationTimer = 0.f; + currentFrame = (currentFrame + 1) % runFrames.size(); + sprite.setTexture(runFrames[currentFrame]); + } + } else { + sprite.setTexture(idleFrame); + } + + // Центруємо спрайт по хітбоксу + sprite.setOrigin(sprite.getTexture()->getSize().x / 2.f, + sprite.getTexture()->getSize().y / 2.f); + + sprite.setPosition(shape.getPosition().x + shape.getSize().x / 2.f, + shape.getPosition().y + shape.getSize().y / 2.f); + + float scaleX = shape.getSize().x / sprite.getTexture()->getSize().x; + float scaleY = shape.getSize().y / sprite.getTexture()->getSize().y; + + // Віддзеркалення за напрямком погляду + sprite.setScale(facingRight ? -scaleX : scaleX, scaleY); } + +void Player::draw(sf::RenderWindow& window) { + window.draw(sprite); +} + diff --git a/player.hpp b/player.hpp index 49557f5..3d1e4cd 100644 --- a/player.hpp +++ b/player.hpp @@ -1,33 +1,45 @@ - #pragma once #include #include #include "platform.hpp" - -//float velocityY; -//float gravity; -//float jumpStrength; -//bool isOnGround; - - class Player { + sf::RectangleShape shape; + float speed; + float velocityY; + float jumpStrength; + bool onGround; + float gravity; + float groundLevel; + bool facingRight; -private: - sf::RectangleShape shape; // форма гравця - float speed; //швидкість гравця - float velocityY; // швидкість по вертикалі - float jumpStrength; // сила стрибка - bool onGround; //чи стоїть на землі - float gravity; // сила гравітації - float groundLevel; // висота "землі" + std::vector runFrames; + sf::Texture idleFrame; + sf::Sprite sprite; + size_t currentFrame; + float animationTimer; + float animationSpeed; + bool isMoving; + void loadRunAnimation(); + void loadIdleFrame(); public: - Player(); // порожній конструктор - void update(float deltaTime, const std::vector& platforms); + Player(); + void update(float deltaTime, const std::vector& platforms); void draw(sf::RenderWindow& window); + // Геттери + sf::RectangleShape& getShape() { return shape; } + float getVelocityY() const { return velocityY; } + bool isOnGround() const { return onGround; } + + // Сеттери + void setPosition(const sf::Vector2f& pos) { shape.setPosition(pos); } + void setVelocityY(float v) { velocityY = v; } + void setOnGround(bool val) { onGround = val; } + + bool isFacingRight() const { return facingRight; } }; diff --git a/vokzal.hpp b/vokzal.hpp index 02bef39..b0bd00d 100644 --- a/vokzal.hpp +++ b/vokzal.hpp @@ -5,4 +5,3 @@ #include "platform.hpp" #include "bullet.hpp" -