Compare commits

..

No commits in common. "wolf-patch-1.2" and "main" have entirely different histories.

7 changed files with 112 additions and 393 deletions

View file

@ -1,58 +0,0 @@
#include "enemy.hpp"
Enemy::Enemy(float x, float y, float leftB, float rightB)
: shape(sf::Vector2f(40.f, 50.f)),
leftBound(leftB),
rightBound(rightB),
speed(200.f),
movingRight(true),
aggro(false),
platformY(y)
{
shape.setPosition(x, y);
shape.setFillColor(sf::Color::Red); // просто колір, без текстури
}
void Enemy::update(float dt, const sf::Vector2f& playerPos) {
float x = shape.getPosition().x;
if (aggro) {
if (playerPos.x < x)
x -= speed * dt;
else
x += speed * dt;
} else {
if (movingRight) {
x += speed * dt;
if (x + shape.getSize().x >= rightBound) movingRight = false;
} else {
x -= speed * dt;
if (x <= leftBound) movingRight = true;
}
}
if (x < leftBound) x = leftBound;
if (x + shape.getSize().x > rightBound) x = rightBound - shape.getSize().x;
shape.setPosition(x, platformY);
}
void Enemy::draw(sf::RenderWindow& window) {
window.draw(shape);
}
void Enemy::setAggro(bool value) {
aggro = value;
}
float Enemy::getPlatformY() const {
return platformY;
}
sf::FloatRect Enemy::getBounds() const {
return shape.getGlobalBounds();
}
sf::RectangleShape& Enemy::getShape() {
return shape;
}

View file

@ -1,25 +0,0 @@
#pragma once
#include <SFML/Graphics.hpp>
class Enemy {
private:
sf::RectangleShape shape;
float leftBound;
float rightBound;
float speed;
bool movingRight;
bool aggro;
float platformY;
public:
Enemy(float x, float y, float leftB, float rightB);
void update(float dt, const sf::Vector2f& playerPos);
void draw(sf::RenderWindow& window);
void setAggro(bool value);
float getPlatformY() const;
sf::FloatRect getBounds() const;
sf::RectangleShape& getShape();
};

139
game.cpp
View file

@ -1,52 +1,23 @@
#include <SFML/Graphics.hpp>
#include "vokzal.hpp"
#include "enemy.hpp"
#include <vector>
#include <iostream>
using namespace std;
int main() {
// Завантаження фону
sf::Texture backgroundTexture;
if (!backgroundTexture.loadFromFile("img/background.png")) {
cout << "ERROR: Cannot load background.png\n";
}
sf::Sprite backgroundSprite;
backgroundSprite.setTexture(backgroundTexture);
float scaleX = 1950.f / backgroundTexture.getSize().x;
float scaleY = 1200.f / backgroundTexture.getSize().y;
backgroundSprite.setScale(scaleX, scaleY);
sf::RenderWindow window(sf::VideoMode(1950, 1200), "2D Platformer");
window.setFramerateLimit(65);
// Платформи
// Створюємо вікно 1950x1200
sf::RenderWindow window(sf::VideoMode(1950, 1200), "Test Game Window");
//
vector<Platform> platforms;
platforms.push_back(Platform(299.f, 900.f, 200.f, 40.f));
platforms.push_back(Platform(700.f, 725.f, 200.f, 40.f));
platforms.push_back(Platform(1300.f, 700.f, 300.f, 50.f));
platforms.push_back(Platform(400.f, 600.f, 250.f, 30.f));
platforms.push_back(Platform(700.f, 900.f, 400.f, 30.f));
Platform ground(100.f, 1050.f, 300.f, 50.f);
// Гравець
window.setFramerateLimit(90); //вище 200 не рокимендую піднімати частоту після 600 буде чути писк дроселів
Player player;
// Вороги
vector<Enemy> enemies;
for (auto& platform : platforms) {
float left = platform.getBounds().left;
float top = platform.getBounds().top;
float width = platform.getBounds().width;
enemies.push_back(Enemy(left + 10.f, top - 50.f, left, left + width));
}
// Кулі
vector<Bullet> bullets;
sf::Clock fireClock;
float fireCooldown = 0.3f;
sf::Clock gameClock;
while (window.isOpen()) {
@ -58,102 +29,22 @@ int main() {
float deltaTime = gameClock.restart().asSeconds();
// Рух гравця
player.update(deltaTime, platforms);
player.update(deltaTime, platforms); // логіка гравця
// Створення кулі при натиску пробілу
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Space) &&
fireClock.getElapsedTime().asSeconds() >= fireCooldown)
{
fireClock.restart();
sf::Vector2f playerPos(
player.getShape().getPosition().x + player.getShape().getSize().x / 2,
player.getShape().getPosition().y + player.getShape().getSize().y / 2
);
bullets.push_back(Bullet(playerPos, player.isFacingRight()));
}
window.clear(sf::Color::Black); // очистка вікна
// Оновлення і видалення куль
for (auto it = bullets.begin(); it != bullets.end(); ) {
it->update(deltaTime);
if (it->isOffScreen() || it->collidesWithPlatform(platforms)) {
it = bullets.erase(it);
} else ++it;
}
// Оновлення ворогів (агро на гравця)
sf::Vector2f playerPosVec(player.getShape().getPosition().x, player.getShape().getPosition().y);
for (auto& enemy : enemies) {
float playerBottom = player.getShape().getPosition().y + player.getShape().getSize().y;
float platformY = enemy.getPlatformY();
float tolerance = 10.f;
// якщо гравець на тій же платформі
if (playerBottom >= platformY - tolerance && playerBottom <= platformY + tolerance) {
enemy.setAggro(true);
} else {
enemy.setAggro(false);
}
enemy.update(deltaTime, playerPosVec);
}
// Колізія куль з ворогами
for (auto it = bullets.begin(); it != bullets.end(); ) {
bool bulletRemoved = false;
for (auto enemyIt = enemies.begin(); enemyIt != enemies.end(); ++enemyIt) {
if (it->getBounds().intersects(enemyIt->getBounds())) {
it = bullets.erase(it);
enemies.erase(enemyIt);
bulletRemoved = true;
break;
}
}
if (!bulletRemoved) ++it;
}
// Кінець гри, якщо всі вороги вбиті
if (enemies.empty()) {
cout << "Вітаємо! Ви перемогли всіх ворогів!\n";
window.close();
}
// Колізія ворогів з гравцем
bool playerHit = false;
for (auto& enemy : enemies) {
if (enemy.getBounds().intersects(sf::FloatRect(player.getShape().getPosition(), player.getShape().getSize()))) {
playerHit = true;
break;
}
}
// Ресет гри
if (playerHit) {
player.setPosition(sf::Vector2f(50.f, 1040.f));
player.setVelocityY(0.f);
player.setOnGround(true);
enemies.clear();
// малюємо платформи
for (auto& platform : platforms) {
float left = platform.getBounds().left;
float top = platform.getBounds().top;
float width = platform.getBounds().width;
enemies.push_back(Enemy(left + 10.f, top - 50.f, left, left + width));
platform.draw(window);
}
bullets.clear();
}
// Відмалювання
window.clear(sf::Color::Black);
window.draw(backgroundSprite);
for (auto& platform : platforms) platform.draw(window);
ground.draw(window);
// малюємо гравця
player.draw(window);
for (auto& enemy : enemies) enemy.draw(window);
for (auto& bullet : bullets) bullet.draw(window);
window.display();
window.display(); // відображення
}
return 0;
}

View file

@ -1,37 +0,0 @@
#include <SFML/Graphics.hpp>
int main()
{
// Create the main window
sf::RenderWindow app(sf::VideoMode(800, 600), "SFML window");
// Load a sprite to display
sf::Texture texture;
if (!texture.loadFromFile("cb.bmp"))
return EXIT_FAILURE;
sf::Sprite sprite(texture);
// Start the game loop
while (app.isOpen())
{
// Process events
sf::Event event;
while (app.pollEvent(event))
{
// Close window : exit
if (event.type == sf::Event::Closed)
app.close();
}
// Clear screen
app.clear();
// Draw the sprite
app.draw(sprite);
// Update the window
app.display();
}
return EXIT_SUCCESS;
}

View file

@ -1,140 +1,99 @@
#include "player.hpp"
#include <iostream>
#include "player.hpp" // Включаємо заголовок класу Player, щоб компілятор знав про його методи та змінні.
using namespace std;
// Конструктор класу Player. Він автоматично викликається при створенні об'єкта Player.
Player::Player()
: shape(sf::Vector2f(60.f, 60.f)),
speed(500.f),
: shape(sf::Vector2f(50.f, 50.f)), // тут лише "чисте" створення
speed(500.f), //швидкість
velocityY(0.f),
jumpStrength(700.f),
jumpStrength(700.f), // пиржок
onGround(true),
gravity(1500.f),
groundLevel(1040.f),
facingRight(true),
runFrames(),
idleFrame(),
sprite(),
currentFrame(0),
animationTimer(0.f),
animationSpeed(0.1f),
isMoving(false)
groundLevel(1040.f)
{
// А тут уже викликаємо методи, які налаштовують shape
shape.setFillColor(sf::Color::Green);
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
);
shape.setPosition(50.f, 1040.f);
}
void Player::loadIdleFrame() {
if (!idleFrame.loadFromFile("img/FA_PENGUIN_Idle_000.png")) {
cout << "Cannot load idle frame\n";
}
}
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);
}
}
}
void Player::update(float deltaTime, const std::vector<Platform>& platforms) {
// Закоментований метод `update` (робота на потім).
// Він призначений для оновлення логіки гравця у кожному кадрі гри.
// Усередині цього методу, ви будете обробляти рух, зіткнення, анімацію тощо.
// `deltaTime` — це час, що минув з попереднього кадру, і він забезпечує плавний рух незалежно від швидкості комп'ютера.
void Player::update(float deltaTime, const std::vector<Platform>& platforms) { // Тут буде логіка руху гравця
float moveX = 0.f;
isMoving = false;
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;
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.f;
velocityY = 0;
onGround = true;
} else onGround = false;
}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);
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);
velocityY = 0.f;
onGround = true;
} else if (playerBounds.top > platBounds.top) {
shape.setPosition(shape.getPosition().x, platBounds.top + platBounds.height);
velocityY = 0.f;
}else if(playerBounds.top> platformBounds.top){shape.setPosition(shape.getPosition().x, platformBounds.top +platformBounds.height);
velocityY =0.f;}
}
}
}
// Межі екрану
if (shape.getPosition().x < 0.f) shape.setPosition(0.f, shape.getPosition().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);
// Анімація
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);
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);
}
// Центруємо спрайт по хітбоксу
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);
// Метод `draw` для відмальовування гравця на екрані.
// Приймає посилання на вікно, щоб знати, де малювати.
void Player::draw(sf::RenderWindow& window)
{
// Викликаємо метод `draw` вікна, щоб намалювати наш об'єкт `shape`.
window.draw(shape);
}
void Player::draw(sf::RenderWindow& window) {
window.draw(sprite);
}

View file

@ -1,45 +1,33 @@
#pragma once
#include <SFML/Graphics.hpp>
#include <vector>
#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;
std::vector<sf::Texture> runFrames;
sf::Texture idleFrame;
sf::Sprite sprite;
private:
sf::RectangleShape shape; // форма гравця
float speed; //швидкість гравця
float velocityY; // швидкість по вертикалі
float jumpStrength; // сила стрибка
bool onGround; //чи стоїть на землі
float gravity; // сила гравітації
float groundLevel; // висота "землі"
size_t currentFrame;
float animationTimer;
float animationSpeed;
bool isMoving;
void loadRunAnimation();
void loadIdleFrame();
public:
Player();
Player(); // порожній конструктор
void update(float deltaTime, const std::vector<Platform>& 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; }
};

View file

@ -5,3 +5,4 @@
#include "platform.hpp"
#include "bullet.hpp"