/
DESTORRENSS
/
NEON-ASCENT
Обзор
Документация
Войти
/
DESTORRENSS
/
NEON-ASCENT
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
main.cpp
393 строки
65 KB
DESTORRENSS
NEON ASCENT - Final Build
26 май 2026, 00:59
26 май 2026, 00:59
d637806
Код
Авторство
О чём код?
#include <SFML/Graphics.hpp> #include <vector> #include <cstdlib> #include <ctime> #include <string> #include <algorithm> #include <cmath> #include <cctype> #include <fstream> enum GameState { MENU, PLAYING, PAUSED, BOSS_APPROACH, BOSS_INTRO, BOSS_FIGHT, BOSS_CLEAR, GAME_OVER_SCREEN, LEADERBOARD, NAME_ENTRY }; enum PlatformType { NORMAL = 0, MOVING = 1, BREAKING = 2, TRAMPOLINE = 3, BOOSTER_PAD = 4, GOLDEN = 5, PORTAL = 6 }; enum PlatformObject { OBJ_NONE = 0, OBJ_SPRING = 1, OBJ_JETPACK = 2 }; enum AirBoosterType { AIR_PROPELLER = 0, AIR_SPREAD = 1, AIR_SPEAR = 2, AIR_SHIELD = 3, AIR_HEART = 4 }; enum EnemyType { ENEMY_NORMAL = 0, ENEMY_FAT = 1, ENEMY_DRONE = 2, ENEMY_BOSS = 3 }; struct AirBooster { sf::RectangleShape frame, fill, iconLine, iconDiamond; sf::CircleShape iconDot1, iconDot2, iconDot3; sf::RectangleShape wing1, wing2; sf::RectangleShape crossH, crossV; AirBoosterType type; float fallSpeed = 0.0f; bool falling = false; float animTimer = 0; AirBooster(float x, float y, AirBoosterType t, bool fall = false) { type = t; falling = fall; fallSpeed = 1.5f + (std::rand() % 100) / 50.0f; frame.setSize(sf::Vector2f(30, 30)); frame.setOrigin(15, 15); frame.setPosition(x, y); frame.setFillColor(sf::Color::Transparent); frame.setOutlineThickness(2.5f); fill.setSize(sf::Vector2f(20, 20)); fill.setOrigin(10, 10); fill.setPosition(x, y); fill.setFillColor(sf::Color::Transparent); if (type == AIR_PROPELLER) { frame.setOutlineColor(sf::Color(100, 220, 255)); fill.setFillColor(sf::Color(80, 240, 255, 200)); wing1.setSize(sf::Vector2f(14, 4)); wing1.setOrigin(7, 2); wing1.setPosition(x, y); wing1.setFillColor(sf::Color(150, 240, 255)); wing2.setSize(sf::Vector2f(14, 4)); wing2.setOrigin(7, 2); wing2.setPosition(x, y); wing2.setFillColor(sf::Color(150, 240, 255)); } else if (type == AIR_SHIELD) { frame.setOutlineColor(sf::Color(100, 220, 255)); fill.setFillColor(sf::Color(100, 200, 255, 200)); iconDot1 = sf::CircleShape(7); iconDot1.setFillColor(sf::Color::Transparent); iconDot1.setOutlineColor(sf::Color::White); iconDot1.setOutlineThickness(2); iconDot1.setOrigin(7, 7); iconDot1.setPosition(x, y); } else if (type == AIR_HEART) { frame.setOutlineColor(sf::Color(255, 120, 180)); iconDiamond.setSize(sf::Vector2f(14, 14)); iconDiamond.setOrigin(7, 7); iconDiamond.setPosition(x, y); iconDiamond.setFillColor(sf::Color(255, 120, 180)); iconDiamond.setRotation(45); crossH.setSize(sf::Vector2f(8, 2)); crossH.setOrigin(4, 1); crossH.setPosition(x, y); crossH.setFillColor(sf::Color(255, 200, 220)); crossV.setSize(sf::Vector2f(2, 8)); crossV.setOrigin(1, 4); crossV.setPosition(x, y); crossV.setFillColor(sf::Color(255, 200, 220)); } else { frame.setOutlineColor(sf::Color(220, 120, 255)); } if (type == AIR_SPREAD) { iconDot1 = sf::CircleShape(3.5f); iconDot1.setFillColor(sf::Color(255, 255, 100)); iconDot1.setOrigin(3.5f, 3.5f); iconDot1.setPosition(x, y - 7); iconDot2 = sf::CircleShape(3.5f); iconDot2.setFillColor(sf::Color(255, 255, 100)); iconDot2.setOrigin(3.5f, 3.5f); iconDot2.setPosition(x - 7, y + 5); iconDot3 = sf::CircleShape(3.5f); iconDot3.setFillColor(sf::Color(255, 255, 100)); iconDot3.setOrigin(3.5f, 3.5f); iconDot3.setPosition(x + 7, y + 5); } if (type == AIR_SPEAR) { iconLine.setSize(sf::Vector2f(3.5f, 20)); iconLine.setOrigin(1.75f, 10); iconLine.setPosition(x, y); iconLine.setFillColor(sf::Color(255, 200, 100)); } } void updateAnim(float dt) { animTimer += dt; if (type == AIR_PROPELLER) { float rot = std::sin(animTimer * 10) * 20; wing1.setRotation(rot); wing2.setRotation(-rot); } } }; struct EnemyBullet { sf::RectangleShape shape; float vx, vy; EnemyBullet(float x, float y, float vx, float vy) { shape.setSize(sf::Vector2f(8, 8)); shape.setOrigin(4, 4); shape.setPosition(x, y); shape.setFillColor(sf::Color(255, 70, 100)); this->vx = vx; this->vy = vy; } }; struct BossBullet : EnemyBullet { BossBullet(float x, float y, float vx, float vy) : EnemyBullet(x, y, vx, vy) { shape.setFillColor(sf::Color(255, 80, 220)); shape.setSize(sf::Vector2f(10, 10)); shape.setOrigin(5, 5); } }; struct Enemy { sf::RectangleShape shape, innerShape; sf::RectangleShape crown1, crown2, crown3; float speed, dir; EnemyType type; int hp, maxHp; float shootTimer, shootInterval; float vertDir = 1, vertTimer = 0; Enemy(float x, float y, float spd, EnemyType et = ENEMY_NORMAL) { type = et; shootTimer = 0; if (et == ENEMY_BOSS) { shape.setSize(sf::Vector2f(80, 80)); shape.setOrigin(40, 40); shape.setFillColor(sf::Color(200, 60, 255)); maxHp = 25; shootInterval = 5; crown1.setSize(sf::Vector2f(14, 14)); crown1.setFillColor(sf::Color(255, 220, 50)); crown1.setOrigin(7, 7); crown1.setPosition(x - 16, y - 50); crown2.setSize(sf::Vector2f(14, 14)); crown2.setFillColor(sf::Color(255, 220, 50)); crown2.setOrigin(7, 7); crown2.setPosition(x, y - 58); crown3.setSize(sf::Vector2f(14, 14)); crown3.setFillColor(sf::Color(255, 220, 50)); crown3.setOrigin(7, 7); crown3.setPosition(x + 16, y - 50); } else if (et == ENEMY_DRONE) { shape.setSize(sf::Vector2f(28, 28)); shape.setOrigin(14, 14); shape.setFillColor(sf::Color(100, 200, 255)); maxHp = 2; shootInterval = 2 + (rand() % 100) / 100.0f; innerShape.setSize(sf::Vector2f(6, 12)); innerShape.setFillColor(sf::Color(20, 30, 50)); innerShape.setOrigin(3, 6); innerShape.setPosition(x - 5, y); } else if (et == ENEMY_FAT) { shape.setSize(sf::Vector2f(56, 56)); shape.setOrigin(28, 28); shape.setFillColor(sf::Color(255, 80, 120)); maxHp = 3; shootInterval = 0; innerShape.setSize(sf::Vector2f(24, 24)); innerShape.setFillColor(sf::Color(180, 30, 60)); innerShape.setOrigin(12, 12); innerShape.setPosition(x, y); } else { shape.setSize(sf::Vector2f(40, 40)); shape.setOrigin(20, 20); shape.setFillColor(sf::Color(255, 100, 80)); maxHp = 1; shootInterval = 0; innerShape.setSize(sf::Vector2f(16, 4)); innerShape.setFillColor(sf::Color(200, 50, 40)); innerShape.setOrigin(8, 2); innerShape.setPosition(x, y); } shape.setPosition(x, y); speed = spd; dir = (rand() % 2 == 0) ? 1 : -1; hp = maxHp; } void updateColor() { if (type == ENEMY_BOSS) { float r = (float)hp / maxHp; shape.setFillColor(sf::Color(200, (int)(60 * r), (int)(255 * r))); } else if (type == ENEMY_FAT) { float r = (float)hp / maxHp; shape.setFillColor(sf::Color(255, (int)(80 * r), (int)(120 * r))); innerShape.setFillColor(sf::Color(180, (int)(30 * r), (int)(60 * r))); } else if (type == ENEMY_DRONE) { float r = (float)hp / maxHp; shape.setFillColor(sf::Color((int)(100 * r), (int)(200 * r), 255)); } } }; struct Bullet { sf::RectangleShape shape; float vx, vy; bool piercing; int damage; std::vector<Enemy*> hitEnemies; Bullet(float x, float y, float vx, float vy, bool p = false, int d = 1) { damage = d; if (p) { shape.setSize(sf::Vector2f(6, 30)); shape.setOrigin(3, 15); shape.setFillColor(sf::Color(255, 180, 50)); } else { shape.setSize(sf::Vector2f(8, 12)); shape.setOrigin(4, 6); shape.setFillColor(sf::Color(255, 255, 80)); } shape.setPosition(x, y); this->vx = vx; this->vy = vy; piercing = p; } void updateRotation() { shape.setRotation(atan2(vy, vx) * 180 / 3.14159f + 90); } }; struct Platform { sf::RectangleShape shape; PlatformType type; PlatformObject obj; sf::CircleShape spring, jetStar; float speed, dir; bool breaking, trampUsed, jetCollected; float breakTimer; Platform(float x, float y, PlatformType t, float spd) { shape.setSize(sf::Vector2f(80, 20)); shape.setPosition(x, y); type = t; obj = OBJ_NONE; speed = spd; dir = (rand() % 2 == 0) ? 1 : -1; breaking = false; breakTimer = 0; trampUsed = false; jetCollected = false; switch (type) { case NORMAL: shape.setFillColor(sf::Color(255, 80, 200)); break; case MOVING: shape.setFillColor(sf::Color(255, 220, 50)); break; case BREAKING: shape.setFillColor(sf::Color(255, 50, 80)); break; case TRAMPOLINE: shape.setFillColor(sf::Color(255, 140, 30)); break; case BOOSTER_PAD: shape.setFillColor(sf::Color(200, 180, 255)); break; case GOLDEN: shape.setFillColor(sf::Color(255, 220, 60)); break; case PORTAL: shape.setFillColor(sf::Color(160, 60, 255)); break; } } void initObj() { if (type == NORMAL && (rand() % 100 < 10)) { obj = OBJ_SPRING; spring = sf::CircleShape(12, 3); spring.setFillColor(sf::Color::Yellow); spring.setOrigin(12, 12); spring.setPosition(shape.getPosition().x + 40, shape.getPosition().y - 22); } if (type == BOOSTER_PAD) { obj = OBJ_JETPACK; jetStar = sf::CircleShape(18, 10); jetStar.setFillColor(sf::Color(255, 150, 50)); jetStar.setOrigin(18, 18); jetStar.setPosition(shape.getPosition().x + 40, shape.getPosition().y - 27); } } bool isActive() const { return !(trampUsed || jetCollected || (breaking && breakTimer > 0.5f)); } }; struct Particle { sf::RectangleShape shape; float vx, vy; float life, maxLife; Particle(float x, float y, sf::Color color) { shape.setSize(sf::Vector2f(4, 4)); shape.setOrigin(2, 2); shape.setPosition(x, y); shape.setFillColor(color); float angle = (std::rand() % 180 - 90) * 3.14159f / 180.0f; float speed = 2.0f + (std::rand() % 100) / 50.0f; vx = std::cos(angle) * speed; vy = std::sin(angle) * speed - 3.0f; maxLife = 0.3f + (std::rand() % 100) / 300.0f; life = maxLife; } void update(float dt) { shape.move(vx, vy); life -= dt; float alpha = (life / maxLife) * 255; sf::Color c = shape.getFillColor(); c.a = std::max(0, std::min(255, (int)alpha)); shape.setFillColor(c); } bool isDead() const { return life <= 0; } }; struct Star { sf::CircleShape shape; float speed; Star(float x, float y) { shape.setRadius(1.0f + (std::rand() % 3) * 0.5f); shape.setOrigin(shape.getRadius(), shape.getRadius()); shape.setPosition(x, y); shape.setFillColor(sf::Color(255, 255, 255, 50 + std::rand() % 100)); speed = 0.2f + (std::rand() % 100) / 200.0f; } }; struct LeaderEntry { std::string name; int score; }; bool tooClosePlat(float nx, float ny, const std::vector<Platform>& ps, float minDY = 60) { for (auto& p : ps) { if (!p.isActive()) continue; if (abs(p.shape.getPosition().y - ny) < minDY && abs(p.shape.getPosition().x - nx) < 100) return true; } return false; } bool tooCloseEnemy(float nx, float ny, const std::vector<Enemy>& es, float minD = 120) { for (auto& e : es) { if (hypot(e.shape.getPosition().x - nx, e.shape.getPosition().y - ny) < minD) return true; } return false; } bool tooCloseBoost(float nx, float ny, const std::vector<AirBooster>& bs, float minD = 120) { for (auto& b : bs) { if (hypot(b.frame.getPosition().x - nx, b.frame.getPosition().y - ny) < minD) return true; } return false; } int diffLvl(int s) { return s / 200; } void loadLeaderboard(std::vector<LeaderEntry>& lb) { std::ifstream file("leaderboard.txt"); if (file.is_open()) { std::string line; while (std::getline(file, line)) { size_t pos = line.find('|'); if (pos != std::string::npos) { LeaderEntry e; e.name = line.substr(0, pos); e.score = std::stoi(line.substr(pos + 1)); lb.push_back(e); } } file.close(); std::sort(lb.begin(), lb.end(), [](auto& a, auto& b) { return a.score > b.score; }); if (lb.size() > 10) lb.resize(10); } } void saveLeaderboard(const std::vector<LeaderEntry>& lb) { std::ofstream file("leaderboard.txt"); if (file.is_open()) { for (auto& e : lb) file << e.name << "|" << e.score << "\n"; file.close(); } } int main() { srand(time(0)); sf::RenderWindow window(sf::VideoMode(400, 600), "NEON ASCENT"); window.setFramerateLimit(60); sf::View gameView = window.getDefaultView(), uiView = window.getDefaultView(); sf::Font font; bool hasFont = font.loadFromFile("C:/Windows/Fonts/arial.ttf") || font.loadFromFile("C:/Windows/Fonts/consola.ttf") || font.loadFromFile("C:/Windows/Fonts/segoeui.ttf"); sf::RectangleShape player(sf::Vector2f(40, 40)); player.setFillColor(sf::Color(50, 200, 255)); player.setOutlineColor(sf::Color(150, 230, 255)); player.setOutlineThickness(2.0f); player.setOrigin(20, 20); player.setPosition(200, 500); sf::RectangleShape playerInner(sf::Vector2f(20, 20)); playerInner.setFillColor(sf::Color(20, 100, 150)); playerInner.setOrigin(10, 10); sf::RectangleShape shield(sf::Vector2f(48, 48)); shield.setFillColor(sf::Color::Transparent); shield.setOutlineColor(sf::Color(150, 230, 255)); shield.setOutlineThickness(3.0f); shield.setOrigin(24, 24); sf::RectangleShape playerWing1, playerWing2; bool playerWingsActive = false; float playerWingRotation = 0; playerWing1.setSize(sf::Vector2f(16, 5)); playerWing1.setFillColor(sf::Color(150, 240, 255, 200)); playerWing1.setOrigin(8, 2.5f); playerWing2.setSize(sf::Vector2f(16, 5)); playerWing2.setFillColor(sf::Color(150, 240, 255, 200)); playerWing2.setOrigin(8, 2.5f); float pvy = 0, baseGrav = 0.5f, grav = baseGrav; const float jumpF = -14.0f, springF = -22, trampF = -28, dashF = -17; const float moveSpd = 6, slowSpd = 2.5f; int hp = 3; const int maxHp = 3; bool shieldOn = false; float invTimer = 0; const float invDur = 1.5f; bool vis = true; float shieldPulse = 0, globalTimer = 0; bool moveBoost = false; int moveType = -1; float moveTimer = 0; const float propDur = 3, jetDur = 2.5f, propSpd = -4, jetSpd = -9; int weapType = -1; float weapTimer = 0; const float spreadDur = 12, spearDur = 10; float dashCd = 0; const float dashCdMax = 15.0f; std::vector<Bullet> bullets; std::vector<EnemyBullet> eBullets; std::vector<BossBullet> bBullets; std::vector<Particle> particles; std::vector<Particle> uiParticles; // ��������� ������ ��� UI-������ std::vector<Star> stars; std::vector<sf::RectangleShape> trail; const int trailLength = 8; const float bulSpd = 10, spearSpd = 18, eBulSpd = 3, bBulSpd = 4; float shootCd = 0; const float normCd = 0.3f, spreadCd = 0.4f, spearCd = 0.8f; int score = 0, hiScore = 0; float highY = 500; int diff = 0; GameState state = MENU, previousState = MENU; float goTimer = 0, menuTimer = 0, introTimer = 0, clearTimer = 0; int nextBoss = 800, bossLvl = 1; bool bossUp = false, goldTouch = false; bool transitioning = false; float transitionAlpha = 0; std::vector<Platform> plats; std::vector<AirBooster> boosts; std::vector<Enemy> enemies; float platSpd = 2.5f, eneSpd = 1.5f, platGap = 90; float arenaY = 0, dropTimer = 0; std::vector<LeaderEntry> leaderboard; std::string playerName = ""; bool nameEntered = false; std::string nameInput = ""; loadLeaderboard(leaderboard); auto clearAll = [&]() { plats.clear(); boosts.clear(); bullets.clear(); enemies.clear(); eBullets.clear(); bBullets.clear(); particles.clear(); uiParticles.clear(); }; auto genArena = [&](float cy) { clearAll(); arenaY = cy; for (int i = 0; i < 10; i++) plats.push_back(Platform(5 + i * 42, arenaY, NORMAL, 0)); enemies.push_back(Enemy(200, arenaY - 250, 1, ENEMY_BOSS)); enemies.back().maxHp = 25 + (bossLvl - 1) * 15; enemies.back().hp = enemies.back().maxHp; enemies.back().vertDir = -1; enemies.back().vertTimer = 0; bossUp = true; dropTimer = 5; }; auto reset = [&]() { player.setPosition(200, 500); pvy = 0; highY = 500; score = 0; diff = 0; grav = baseGrav; platSpd = 2.5f; eneSpd = 1.5f; platGap = 90; hp = maxHp; shieldOn = false; invTimer = 0; vis = true; dashCd = 0; shieldPulse = 0; globalTimer = 0; transitioning = false; transitionAlpha = 0; moveBoost = false; moveType = -1; weapType = -1; playerWingsActive = false; playerWingRotation = 0; nextBoss = 800; bossLvl = 1; bossUp = false; goldTouch = false; gameView.setCenter(200, 300); clearAll(); trail.clear(); for (int i = 0; i < trailLength; i++) { sf::RectangleShape t(sf::Vector2f(40, 40)); t.setFillColor(sf::Color(50, 200, 255, 200 - i * 25)); t.setOutlineColor(sf::Color(150, 230, 255, 100 - i * 12)); t.setOutlineThickness(2.0f); t.setOrigin(20, 20); t.setPosition(player.getPosition()); trail.push_back(t); } stars.clear(); for (int i = 0; i < 30; i++) stars.push_back(Star(std::rand() % 400, std::rand() % 600)); plats.push_back(Platform(160, 540, NORMAL, 0)); plats.back().initObj(); float cy = 400; while (cy > -100) { float rx = rand() % 320; int att = 0; while (tooClosePlat(rx, cy, plats) && att < 10) { rx = rand() % 320; att++; } PlatformType t = NORMAL; int r = rand() % 100; if (r < 55)t = NORMAL; else if (r < 80)t = MOVING; else if (r < 93)t = BREAKING; else if (r < 97)t = TRAMPOLINE; else t = BOOSTER_PAD; if (t == BOOSTER_PAD || t == TRAMPOLINE)cy -= 30; plats.push_back(Platform(rx, cy, t, platSpd)); plats.back().initObj(); cy -= platGap + rand() % 50; } }; reset(); while (window.isOpen()) { float dt = 1.0f / 60; sf::Event ev; while (window.pollEvent(ev)) { if (ev.type == sf::Event::Closed) { saveLeaderboard(leaderboard); window.close(); } if (ev.type == sf::Event::KeyPressed) { if (ev.key.code == sf::Keyboard::Escape) { if (state == MENU) { saveLeaderboard(leaderboard); window.close(); } else if (state == GAME_OVER_SCREEN || state == PAUSED) { state = MENU; menuTimer = 0; } else if (state == LEADERBOARD || state == NAME_ENTRY) { state = MENU; menuTimer = 0; } } if (state == MENU && ev.key.code == sf::Keyboard::Space) { if (nameEntered) { state = PLAYING; reset(); } else { state = NAME_ENTRY; nameInput = playerName; } } if (state == MENU && ev.key.code == sf::Keyboard::L) { state = LEADERBOARD; } if (state == MENU && ev.key.code == sf::Keyboard::N) { state = NAME_ENTRY; nameInput = ""; nameEntered = false; } if (state == NAME_ENTRY && ev.key.code == sf::Keyboard::Enter) { if (!nameInput.empty()) { playerName = nameInput; nameEntered = true; state = MENU; } } if (state == NAME_ENTRY && ev.key.code == sf::Keyboard::BackSpace) { if (!nameInput.empty()) nameInput.pop_back(); } if (state == GAME_OVER_SCREEN && goTimer > 1 && ev.key.code == sf::Keyboard::R) { reset(); state = PLAYING; } if (ev.key.code == sf::Keyboard::P && state != MENU && state != GAME_OVER_SCREEN && state != LEADERBOARD && state != NAME_ENTRY) { if (state == PAUSED) state = previousState; else { previousState = state; state = PAUSED; } } } if (ev.type == sf::Event::TextEntered && state == NAME_ENTRY) { if (ev.text.unicode < 128 && ev.text.unicode != 8 && ev.text.unicode != 13) { char c = static_cast<char>(ev.text.unicode); if (std::isprint(c) && nameInput.length() < 12) nameInput += c; } } } if (state == MENU) menuTimer += dt; if (state != PAUSED && state != LEADERBOARD && state != NAME_ENTRY) globalTimer += dt; for (auto& s : stars) { s.shape.move(0, s.speed); if (s.shape.getPosition().y > 620) { s.shape.setPosition(std::rand() % 400, -10); } } if (shieldOn) shieldPulse += dt * 5.0f; for (auto& b : boosts) b.updateAnim(dt); if (playerWingsActive) { playerWingRotation += dt * 15; playerWing1.setPosition(player.getPosition().x - 18, player.getPosition().y); playerWing2.setPosition(player.getPosition().x + 18, player.getPosition().y); playerWing1.setRotation(std::sin(playerWingRotation) * 20); playerWing2.setRotation(-std::sin(playerWingRotation) * 20); } playerInner.setPosition(player.getPosition()); // ===== ����� ===== if (state == PAUSED) { window.clear(sf::Color(8, 8, 20)); window.setView(uiView); for (int gx = 0; gx < 400; gx += 40) { sf::RectangleShape gl(sf::Vector2f(1, 600)); gl.setPosition(gx, 0); gl.setFillColor(sf::Color(255, 255, 255, 8)); window.draw(gl); } for (int gy = 0; gy < 600; gy += 40) { sf::RectangleShape gl(sf::Vector2f(400, 1)); gl.setPosition(0, gy); gl.setFillColor(sf::Color(255, 255, 255, 8)); window.draw(gl); } for (auto& s : stars) window.draw(s.shape); window.setView(gameView); for (auto& p : plats) { window.draw(p.shape); if (p.obj == OBJ_SPRING && p.spring.getFillColor() != sf::Color::Transparent)window.draw(p.spring); if (p.obj == OBJ_JETPACK && !p.jetCollected)window.draw(p.jetStar); } for (auto& b : boosts) { if (b.type == AIR_PROPELLER) { window.draw(b.wing1); window.draw(b.wing2); } if (b.type == AIR_PROPELLER || b.type == AIR_SHIELD)window.draw(b.fill); window.draw(b.frame); if (b.type == AIR_SPREAD) { window.draw(b.iconDot1); window.draw(b.iconDot2); window.draw(b.iconDot3); } else if (b.type == AIR_SPEAR)window.draw(b.iconLine); else if (b.type == AIR_SHIELD)window.draw(b.iconDot1); else if (b.type == AIR_HEART) { window.draw(b.iconDiamond); window.draw(b.crossH); window.draw(b.crossV); } } for (auto& e : enemies) { window.draw(e.shape); window.draw(e.innerShape); if (e.type == ENEMY_BOSS) { window.draw(e.crown1); window.draw(e.crown2); window.draw(e.crown3); } } for (auto& b : bullets) window.draw(b.shape); for (auto& eb : eBullets) window.draw(eb.shape); for (auto& bb : bBullets) window.draw(bb.shape); for (auto& pt : particles) window.draw(pt.shape); if (!trail.empty()) for (int i = trailLength - 1; i >= 0; i--) window.draw(trail[i]); window.draw(player); window.draw(playerInner); if (playerWingsActive) { window.draw(playerWing1); window.draw(playerWing2); } if (shieldOn) { shield.setPosition(player.getPosition()); window.draw(shield); } window.setView(uiView); for (auto& pt : uiParticles) window.draw(pt.shape); sf::RectangleShape overlay(sf::Vector2f(400, 600)); overlay.setFillColor(sf::Color(0, 0, 0, 150)); window.draw(overlay); if (hasFont) { float pausePulse = (std::sin(menuTimer * 2.0f) + 1.0f) / 2.0f; int pAlpha = 180 + pausePulse * 75; sf::Text pauseText("PAUSE", font, 40); pauseText.setFillColor(sf::Color(255, 255, 255, pAlpha)); pauseText.setPosition(200 - pauseText.getLocalBounds().width / 2, 260); window.draw(pauseText); sf::Text resumeText("Press P to resume, Esc to menu", font, 12); resumeText.setFillColor(sf::Color(200, 200, 200)); resumeText.setPosition(200 - resumeText.getLocalBounds().width / 2, 320); window.draw(resumeText); } sf::RectangleShape pauseBar1(sf::Vector2f(5, 16)); pauseBar1.setFillColor(sf::Color::White); pauseBar1.setPosition(14, 572); window.draw(pauseBar1); sf::RectangleShape pauseBar2(sf::Vector2f(5, 16)); pauseBar2.setFillColor(sf::Color::White); pauseBar2.setPosition(24, 572); window.draw(pauseBar2); window.display(); continue; } // ===== LEADERBOARD & NAME_ENTRY ===== if (state == LEADERBOARD) { window.clear(sf::Color(8, 8, 20)); window.setView(uiView); for (int gx = 0; gx < 400; gx += 40) { sf::RectangleShape gl(sf::Vector2f(1, 600)); gl.setPosition(gx, 0); gl.setFillColor(sf::Color(255, 255, 255, 8)); window.draw(gl); } for (int gy = 0; gy < 600; gy += 40) { sf::RectangleShape gl(sf::Vector2f(400, 1)); gl.setPosition(0, gy); gl.setFillColor(sf::Color(255, 255, 255, 8)); window.draw(gl); } for (auto& s : stars) window.draw(s.shape); sf::RectangleShape bg(sf::Vector2f(400, 600)); bg.setFillColor(sf::Color(10, 10, 25, 200)); window.draw(bg); if (hasFont) { sf::Text title("LEADERBOARD", font, 28); title.setFillColor(sf::Color(255, 220, 50)); title.setPosition(200 - title.getLocalBounds().width / 2, 40); window.draw(title); if (leaderboard.empty()) { sf::Text empty("No scores yet!", font, 16); empty.setFillColor(sf::Color(150, 150, 150)); empty.setPosition(200 - empty.getLocalBounds().width / 2, 200); window.draw(empty); } else { for (size_t i = 0; i < leaderboard.size(); i++) { sf::Text entry(std::to_string(i + 1) + ". " + leaderboard[i].name + " - " + std::to_string(leaderboard[i].score), font, 16); entry.setFillColor(i == 0 ? sf::Color(255, 220, 50) : sf::Color(200, 200, 200)); entry.setPosition(60, 100 + i * 35); window.draw(entry); } } sf::Text back("Press ESC to return", font, 12); back.setFillColor(sf::Color(150, 150, 150)); back.setPosition(200 - back.getLocalBounds().width / 2, 550); window.draw(back); } window.display(); continue; } if (state == NAME_ENTRY) { window.clear(sf::Color(8, 8, 20)); window.setView(uiView); for (int gx = 0; gx < 400; gx += 40) { sf::RectangleShape gl(sf::Vector2f(1, 600)); gl.setPosition(gx, 0); gl.setFillColor(sf::Color(255, 255, 255, 8)); window.draw(gl); } for (int gy = 0; gy < 600; gy += 40) { sf::RectangleShape gl(sf::Vector2f(400, 1)); gl.setPosition(0, gy); gl.setFillColor(sf::Color(255, 255, 255, 8)); window.draw(gl); } for (auto& s : stars) window.draw(s.shape); sf::RectangleShape bg(sf::Vector2f(400, 600)); bg.setFillColor(sf::Color(10, 10, 25, 200)); window.draw(bg); if (hasFont) { sf::Text prompt("Enter your name:", font, 22); prompt.setFillColor(sf::Color::White); prompt.setPosition(200 - prompt.getLocalBounds().width / 2, 200); window.draw(prompt); sf::Text nameText(nameInput + "_", font, 24); nameText.setFillColor(sf::Color(100, 255, 200)); nameText.setPosition(200 - nameText.getLocalBounds().width / 2, 260); window.draw(nameText); sf::Text enterHint("Press ENTER to confirm", font, 14); enterHint.setFillColor(sf::Color(150, 150, 150)); enterHint.setPosition(200 - enterHint.getLocalBounds().width / 2, 320); window.draw(enterHint); } window.display(); continue; } if (dashCd > 0) dashCd -= dt; if (state != MENU && state != GAME_OVER_SCREEN && sf::Keyboard::isKeyPressed(sf::Keyboard::W) && dashCd <= 0) { pvy = dashF; dashCd = dashCdMax; moveBoost = false; } if (state == PLAYING && score >= nextBoss && !bossUp && !transitioning) { state = BOSS_APPROACH; float highPlat = player.getPosition().y; for (auto& p : plats) { if (p.shape.getPosition().y < highPlat) highPlat = p.shape.getPosition().y; } plats.push_back(Platform(160, highPlat - 120, PORTAL, 0)); } if (state == BOSS_APPROACH) { for (auto& p : plats) { if (p.type == PORTAL && player.getGlobalBounds().intersects(p.shape.getGlobalBounds())) { genArena(player.getPosition().y - 1000); state = BOSS_INTRO; introTimer = 0; pvy = jumpF; goto skipPortal; } } skipPortal:; } if (state == BOSS_INTRO) { introTimer += dt; float tgtY = arenaY - 250; gameView.setCenter(gameView.getCenter().x + (200 - gameView.getCenter().x) * 0.1f, gameView.getCenter().y + (tgtY - gameView.getCenter().y) * 0.1f); if (introTimer > 2) { state = BOSS_FIGHT; introTimer = 0; player.setPosition(200, arenaY - 50); pvy = jumpF; highY = player.getPosition().y; } } // ===== PLAYING & BOSS_APPROACH ===== if (state == PLAYING || state == BOSS_APPROACH) { float cms = (moveBoost && moveType == 1) ? slowSpd : moveSpd; if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) player.move(-cms, 0); if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) player.move(cms, 0); sf::Vector2f pp = player.getPosition(); if (pp.x > 420) player.setPosition(-20, pp.y); if (pp.x < -20) player.setPosition(420, pp.y); shootCd -= dt; float cc = (weapType == 0) ? spreadCd : ((weapType == 1) ? spearCd : normCd); if (shootCd <= 0) { bool shot = false; float bx = player.getPosition().x, by = player.getPosition().y; bool up = sf::Keyboard::isKeyPressed(sf::Keyboard::Up), left = sf::Keyboard::isKeyPressed(sf::Keyboard::Left), right = sf::Keyboard::isKeyPressed(sf::Keyboard::Right); auto sh = [&](float vx, float vy, bool p, int d) { bullets.push_back(Bullet(bx, by, vx, vy, p, d)); }; if (weapType == 1) { if (up && !left && !right) sh(0, -spearSpd, true, 3); else if (left && !up) sh(-spearSpd, 0, true, 3); else if (right && !up) sh(spearSpd, 0, true, 3); else if (up && left) sh(-spearSpd * 0.7f, -spearSpd * 0.7f, true, 3); else if (up && right) sh(spearSpd * 0.7f, -spearSpd * 0.7f, true, 3); else goto skip; } else if (weapType == 0) { if (up && !left && !right) { sh(0, -bulSpd, false, 1); sh(-bulSpd * 0.3f, -bulSpd, false, 1); sh(bulSpd * 0.3f, -bulSpd, false, 1); } else if (left && !up) { sh(-bulSpd, 0, false, 1); sh(-bulSpd, -bulSpd * 0.3f, false, 1); sh(-bulSpd, bulSpd * 0.3f, false, 1); } else if (right && !up) { sh(bulSpd, 0, false, 1); sh(bulSpd, -bulSpd * 0.3f, false, 1); sh(bulSpd, bulSpd * 0.3f, false, 1); } else if (up && left) { sh(-bulSpd * 0.7f, -bulSpd * 0.7f, false, 1); sh(-bulSpd, -bulSpd, false, 1); sh(-bulSpd * 0.3f, -bulSpd, false, 1); } else if (up && right) { sh(bulSpd * 0.7f, -bulSpd * 0.7f, false, 1); sh(bulSpd, -bulSpd, false, 1); sh(bulSpd * 0.3f, -bulSpd, false, 1); } else goto skip; } else { if (up && !left && !right) sh(0, -bulSpd, false, 1); else if (left && !up) sh(-bulSpd, 0, false, 1); else if (right && !up) sh(bulSpd, 0, false, 1); else if (up && left) sh(-bulSpd * 0.7f, -bulSpd * 0.7f, false, 1); else if (up && right) sh(bulSpd * 0.7f, -bulSpd * 0.7f, false, 1); else goto skip; } shootCd = cc; skip:; } for (auto& b : bullets) { if (b.piercing) b.updateRotation(); } if (moveBoost) { moveTimer -= dt; if (moveTimer <= 0) { if (playerWingsActive && moveType == 0) { for (int pi = 0; pi < 12; pi++) { float angle = (std::rand() % 360) * 3.14159f / 180.0f; float speed = 1.5f + (std::rand() % 200) / 50.0f; Particle pw(player.getPosition().x, player.getPosition().y, sf::Color(150, 240, 255)); pw.vx = std::cos(angle) * speed; pw.vy = std::sin(angle) * speed - 2.0f; pw.maxLife = 0.4f + (std::rand() % 100) / 250.0f; pw.life = pw.maxLife; particles.push_back(pw); } playerWingsActive = false; } moveBoost = false; moveType = -1; } else { player.move(0, (moveType == 0) ? propSpd : jetSpd); pvy = 0; } } for (auto& p : plats) { if (p.type == MOVING) { p.shape.move(p.speed * p.dir, 0); if (p.obj == OBJ_SPRING) p.spring.move(p.speed * p.dir, 0); if (p.shape.getPosition().x < 0 || p.shape.getPosition().x > 320) p.dir *= -1; } if (p.type == BREAKING && p.breaking) { p.breakTimer += dt; if (p.breakTimer > 0.3f) p.shape.setFillColor(sf::Color::Transparent); if (p.breakTimer > 0.5f) p.shape.setPosition(-1000, -1000); } } for (auto& e : enemies) { if (e.type == ENEMY_DRONE) { e.shape.move(e.speed * e.dir * 0.5f, 0); if (e.shape.getPosition().x < 40 || e.shape.getPosition().x>360) e.dir *= -1; e.shape.move(0, (gameView.getCenter().y - 250 - e.shape.getPosition().y) * 0.02f); e.innerShape.setPosition(e.shape.getPosition().x - 5, e.shape.getPosition().y); e.shootTimer += dt; if (e.shootTimer >= e.shootInterval) { e.shootTimer = 0; e.shootInterval = 2 + (rand() % 100) / 100.0f; float a = (rand() % 60 - 30) * 3.14159f / 180; eBullets.push_back(EnemyBullet(e.shape.getPosition().x, e.shape.getPosition().y + 15, sin(a) * eBulSpd, cos(a) * eBulSpd)); } } else { e.shape.move(e.speed * e.dir, 0); if (e.shape.getPosition().x < 30 || e.shape.getPosition().x>370) e.dir *= -1; e.innerShape.setPosition(e.shape.getPosition()); if (e.type == ENEMY_BOSS) { e.crown1.setPosition(e.shape.getPosition().x - 16, e.shape.getPosition().y - 50); e.crown2.setPosition(e.shape.getPosition().x, e.shape.getPosition().y - 58); e.crown3.setPosition(e.shape.getPosition().x + 16, e.shape.getPosition().y - 50); } } } for (auto& b : bullets) b.shape.move(b.vx, b.vy); for (auto& eb : eBullets) eb.shape.move(eb.vx, eb.vy); if (!moveBoost) { pvy += grav; player.move(0, pvy); } if (!trail.empty()) { for (int i = trailLength - 1; i > 0; i--) { trail[i].setPosition(trail[i - 1].getPosition()); } trail[0].setPosition(player.getPosition()); } if (player.getPosition().y < highY) { highY = player.getPosition().y; score = std::max(score, (int)((600 - highY) / 10)); } if (!moveBoost) { for (auto& p : plats) { if (state == BOSS_APPROACH && p.type == PORTAL) continue; if (!p.isActive() || p.shape.getFillColor() == sf::Color::Transparent) continue; if (player.getGlobalBounds().intersects(p.shape.getGlobalBounds()) && pvy > 0) { float jf = jumpF; if (p.obj == OBJ_SPRING) { jf = springF; p.obj = OBJ_NONE; p.spring.setFillColor(sf::Color::Transparent); } else if (p.type == TRAMPOLINE) { jf = trampF; p.trampUsed = true; p.shape.setFillColor(sf::Color::Transparent); } else if (p.obj == OBJ_JETPACK) { moveBoost = true; moveType = 1; moveTimer = jetDur; pvy = 0; p.jetCollected = true; p.jetStar.setFillColor(sf::Color::Transparent); p.shape.setFillColor(sf::Color(100, 100, 100)); continue; } else if (p.type == BREAKING && !p.breaking) { sf::Color pc = p.shape.getFillColor(); for (int pi = 0; pi < 20; pi++) { float angle = (std::rand() % 360) * 3.14159f / 180.0f; float speed = 2.0f + (std::rand() % 200) / 50.0f; Particle bp(p.shape.getPosition().x + std::rand() % 80, p.shape.getPosition().y + std::rand() % 20, pc); bp.vx = std::cos(angle) * speed; bp.vy = std::sin(angle) * speed - 2.0f; bp.maxLife = 0.5f + (std::rand() % 100) / 200.0f; bp.life = bp.maxLife; particles.push_back(bp); } p.breaking = true; p.breakTimer = 0; p.shape.setPosition(-1000, -1000); } pvy = jf; sf::Color platColor = p.shape.getFillColor(); if (platColor != sf::Color::Transparent && platColor != sf::Color(100, 100, 100) && p.type != BREAKING) { for (int pi = 0; pi < 7; pi++) particles.push_back(Particle(player.getPosition().x, p.shape.getPosition().y, platColor)); } } } } for (auto it = boosts.begin(); it != boosts.end();) { if (player.getGlobalBounds().intersects(it->frame.getGlobalBounds())) { if (it->type == AIR_PROPELLER) { moveBoost = true; moveType = 0; moveTimer = propDur; pvy = 0; playerWingsActive = true; playerWingRotation = 0; } else if (it->type == AIR_SPREAD) { weapType = 0; weapTimer = spreadDur; } else if (it->type == AIR_SPEAR) { weapType = 1; weapTimer = spearDur; } else if (it->type == AIR_SHIELD) { shieldOn = true; shieldPulse = 0; } else if (it->type == AIR_HEART) { if (hp < maxHp) hp++; } it = boosts.erase(it); } else ++it; } for (auto bit = bullets.begin(); bit != bullets.end();) { bool used = false; for (auto eit = enemies.begin(); eit != enemies.end();) { if (bit->shape.getGlobalBounds().intersects(eit->shape.getGlobalBounds())) { bool alreadyHit = false; for (auto& he : bit->hitEnemies) { if (he == &(*eit)) { alreadyHit = true; break; } } if (alreadyHit) { ++eit; continue; } bit->hitEnemies.push_back(&(*eit)); eit->hp -= bit->damage; eit->updateColor(); used = true; if (eit->hp <= 0) { sf::Color ec = eit->shape.getFillColor(); for (int pi = 0; pi < 12; pi++) { float angle = (std::rand() % 360) * 3.14159f / 180.0f; float speed = 2.0f + (std::rand() % 200) / 50.0f; Particle ep(eit->shape.getPosition().x, eit->shape.getPosition().y, ec); ep.vx = std::cos(angle) * speed; ep.vy = std::sin(angle) * speed - 2.0f; ep.maxLife = 0.4f + (std::rand() % 100) / 250.0f; ep.life = ep.maxLife; particles.push_back(ep); } score += (eit->type == ENEMY_FAT ? 150 : (eit->type == ENEMY_DRONE ? 100 : 50)); eit = enemies.erase(eit); } else ++eit; if (!bit->piercing) break; } else ++eit; } if (used && !bit->piercing) bit = bullets.erase(bit); else ++bit; } bool dmg = false; if (invTimer <= 0) { for (auto it = eBullets.begin(); it != eBullets.end();) { if (player.getGlobalBounds().intersects(it->shape.getGlobalBounds())) { dmg = true; it = eBullets.erase(it); break; } else ++it; } if (!dmg) for (auto& e : enemies) if (player.getGlobalBounds().intersects(e.shape.getGlobalBounds())) { dmg = true; break; } if (player.getPosition().y > gameView.getCenter().y + 350) dmg = true; if (dmg) { if (shieldOn) { shieldOn = false; invTimer = invDur; float shieldIconX = 17 + maxHp * 22 + 10; float shieldIconY = 17; for (int pi = 0; pi < 8; pi++) { float angle = (std::rand() % 360) * 3.14159f / 180.0f; float speed = 2.0f + (std::rand() % 200) / 50.0f; Particle sp(shieldIconX, shieldIconY, sf::Color(100, 200, 255)); sp.vx = std::cos(angle) * speed; sp.vy = std::sin(angle) * speed - 2.0f; sp.maxLife = 0.5f + (std::rand() % 100) / 200.0f; sp.life = sp.maxLife; uiParticles.push_back(sp); } } else { hp--; invTimer = invDur; float heartX = 17 + (hp) * 22; float heartY = 17; for (int pi = 0; pi < 10; pi++) { float angle = (std::rand() % 360) * 3.14159f / 180.0f; float speed = 2.0f + (std::rand() % 200) / 50.0f; Particle hpP(heartX, heartY, sf::Color(255, 100, 180)); hpP.vx = std::cos(angle) * speed; hpP.vy = std::sin(angle) * speed - 2.0f; hpP.maxLife = 0.5f + (std::rand() % 100) / 200.0f; hpP.life = hpP.maxLife; uiParticles.push_back(hpP); } if (hp <= 0) { for (int pi = 0; pi < 20; pi++) { float angle = (std::rand() % 360) * 3.14159f / 180.0f; float speed = 2.0f + (std::rand() % 300) / 50.0f; Particle pp(player.getPosition().x, player.getPosition().y, sf::Color(50, 200, 255)); pp.vx = std::cos(angle) * speed; pp.vy = std::sin(angle) * speed - 2.0f; pp.maxLife = 0.6f + (std::rand() % 100) / 200.0f; pp.life = pp.maxLife; particles.push_back(pp); } if (playerWingsActive) { for (int pi = 0; pi < 8; pi++) { float angle = (std::rand() % 360) * 3.14159f / 180.0f; float speed = 1.5f + (std::rand() % 200) / 50.0f; Particle pw(player.getPosition().x, player.getPosition().y, sf::Color(150, 240, 255)); pw.vx = std::cos(angle) * speed; pw.vy = std::sin(angle) * speed - 2.0f; pw.maxLife = 0.4f + (std::rand() % 100) / 250.0f; pw.life = pw.maxLife; particles.push_back(pw); } playerWingsActive = false; } player.setPosition(-1000, -1000); trail.clear(); state = GAME_OVER_SCREEN; goTimer = 0; if (score > hiScore) hiScore = score; if (!playerName.empty()) { leaderboard.push_back({ playerName, score }); std::sort(leaderboard.begin(), leaderboard.end(), [](auto& a, auto& b) { return a.score > b.score; }); if (leaderboard.size() > 10) leaderboard.resize(10); saveLeaderboard(leaderboard); } } else if (player.getPosition().y > gameView.getCenter().y + 350) { player.setPosition(200, gameView.getCenter().y); pvy = 0; } } } } if (score > hiScore) hiScore = score; if (player.getPosition().y < gameView.getCenter().y - 100) gameView.setCenter(gameView.getCenter().x, player.getPosition().y + 100); } // ��������� (PLAYING) if (state == PLAYING && !transitioning) { int nd = diffLvl(score); if (nd > diff) { diff = nd; grav = std::min(baseGrav + diff * 0.03f, 0.75f); platSpd = std::min(2.5f + diff * 0.5f, 7.0f); eneSpd = std::min(1.5f + diff * 0.3f, 5.0f); platGap = std::max(90.0f - diff * 5.0f, 50.0f); } float topEdge = gameView.getCenter().y - 350; if (!plats.empty()) { float lastY = plats.back().shape.getPosition().y; while (lastY > topEdge - 200) { float newY = lastY - (80 + rand() % 60), newX = rand() % 320; int att = 0; while (tooClosePlat(newX, newY, plats, 50) && att < 10) { newX = rand() % 320; att++; } PlatformType t = NORMAL; int r = rand() % 100; int bc = std::min(15 + diff * 3, 40), nc = std::max(55 - diff * 2, 30); if (r < nc)t = NORMAL; else if (r < nc + 25)t = MOVING; else if (r < nc + 25 + bc)t = BREAKING; else if (r < nc + 25 + bc + 5)t = TRAMPOLINE; else t = BOOSTER_PAD; if (t == BOOSTER_PAD || t == TRAMPOLINE)newY -= 30; plats.push_back(Platform(newX, newY, t, platSpd)); plats.back().initObj(); lastY = newY; } } int esc = std::max(300 - diff * 20, 80); if (rand() % esc == 0 && enemies.size() < 6 + diff) { float ex = rand() % 340 + 30, ey = topEdge - rand() % 200; int att = 0; bool bad = true; while (bad && att < 20) { bad = false; if (tooClosePlat(ex, ey, plats, 50))bad = true; if (!bad && tooCloseEnemy(ex, ey, enemies, 100))bad = true; if (bad) { ex = rand() % 340 + 30; ey = topEdge - rand() % 200; att++; } } if (!bad) { EnemyType et; int r = rand() % 100; int dc = std::min(10 + diff * 3, 30), fc = std::min(20 + diff * 5, 50); if (r < dc)et = ENEMY_DRONE; else if (r < dc + fc)et = ENEMY_FAT; else et = ENEMY_NORMAL; enemies.push_back(Enemy(ex, ey, eneSpd, et)); } } if (rand() % 300 == 0 && boosts.size() < 4) { float bx = rand() % 360 + 20, by = topEdge - rand() % 200; int att = 0; bool bad = true; while (bad && att < 20) { bad = false; if (tooClosePlat(bx, by, plats, 50))bad = true; if (!bad && tooCloseBoost(bx, by, boosts, 100))bad = true; if (bad) { bx = rand() % 360 + 20; by = topEdge - rand() % 200; att++; } } if (!bad) { AirBoosterType bt; int r = rand() % 100; if (r < 30)bt = AIR_PROPELLER; else if (r < 55)bt = AIR_SPREAD; else if (r < 75)bt = AIR_SPEAR; else if (r < 90)bt = AIR_SHIELD; else bt = AIR_HEART; boosts.push_back(AirBooster(bx, by, bt)); } } } // BOSS_FIGHT if (state == BOSS_FIGHT) { bool bossAlive = false; for (auto& e : enemies) { if (e.type == ENEMY_BOSS) { bossAlive = true; break; } } if (!bossAlive && bossUp) { clearAll(); for (int i = 0; i < 10; i++) plats.push_back(Platform(5 + i * 42, arenaY, (i == 5) ? GOLDEN : NORMAL, 0)); player.setPosition(200, arenaY - 50); pvy = jumpF; gameView.setCenter(200, arenaY - 200); state = BOSS_CLEAR; clearTimer = 0; goldTouch = false; bossUp = false; continue; } if (!moveBoost) { pvy += grav; player.move(0, pvy); } if (!trail.empty()) { for (int i = trailLength - 1; i > 0; i--) { trail[i].setPosition(trail[i - 1].getPosition()); } trail[0].setPosition(player.getPosition()); } if (player.getPosition().y < highY) { highY = player.getPosition().y; score = std::max(score, (int)((600 - highY) / 10)); } dropTimer -= dt; if (dropTimer <= 0 && boosts.size() < 5) { dropTimer = 4 + (rand() % 300) / 100.0f; AirBoosterType bt; int r = rand() % 100; if (r < 30)bt = AIR_SPREAD; else if (r < 55)bt = AIR_SPEAR; else if (r < 75)bt = AIR_SHIELD; else bt = AIR_HEART; boosts.push_back(AirBooster(rand() % 360 + 20, gameView.getCenter().y - 350, bt, true)); } for (auto& b : boosts) { if (b.falling) { b.frame.move(0, b.fallSpeed); b.fill.move(0, b.fallSpeed); if (b.type == AIR_SPREAD) { b.iconDot1.move(0, b.fallSpeed); b.iconDot2.move(0, b.fallSpeed); b.iconDot3.move(0, b.fallSpeed); } else if (b.type == AIR_SPEAR) b.iconLine.move(0, b.fallSpeed); else if (b.type == AIR_SHIELD) b.iconDot1.move(0, b.fallSpeed); else if (b.type == AIR_HEART) { b.iconDiamond.move(0, b.fallSpeed); b.crossH.move(0, b.fallSpeed); b.crossV.move(0, b.fallSpeed); } } } float cms = (moveBoost && moveType == 1) ? slowSpd : moveSpd; if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) player.move(-cms, 0); if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) player.move(cms, 0); shootCd -= dt; float cc = (weapType == 0) ? spreadCd : ((weapType == 1) ? spearCd : normCd); if (shootCd <= 0) { bool shot = false; float bx = player.getPosition().x, by = player.getPosition().y; bool up = sf::Keyboard::isKeyPressed(sf::Keyboard::Up), left = sf::Keyboard::isKeyPressed(sf::Keyboard::Left), right = sf::Keyboard::isKeyPressed(sf::Keyboard::Right); auto sh = [&](float vx, float vy, bool p, int d) {bullets.push_back(Bullet(bx, by, vx, vy, p, d)); }; if (weapType == 1) { if (up && !left && !right)sh(0, -spearSpd, true, 3); else if (left && !up)sh(-spearSpd, 0, true, 3); else if (right && !up)sh(spearSpd, 0, true, 3); else if (up && left)sh(-spearSpd * 0.7f, -spearSpd * 0.7f, true, 3); else if (up && right)sh(spearSpd * 0.7f, -spearSpd * 0.7f, true, 3); else goto skip2; } else if (weapType == 0) { if (up && !left && !right) { sh(0, -bulSpd, false, 1); sh(-bulSpd * 0.3f, -bulSpd, false, 1); sh(bulSpd * 0.3f, -bulSpd, false, 1); } else if (left && !up) { sh(-bulSpd, 0, false, 1); sh(-bulSpd, -bulSpd * 0.3f, false, 1); sh(-bulSpd, bulSpd * 0.3f, false, 1); } else if (right && !up) { sh(bulSpd, 0, false, 1); sh(bulSpd, -bulSpd * 0.3f, false, 1); sh(bulSpd, bulSpd * 0.3f, false, 1); } else if (up && left) { sh(-bulSpd * 0.7f, -bulSpd * 0.7f, false, 1); sh(-bulSpd, -bulSpd, false, 1); sh(-bulSpd * 0.3f, -bulSpd, false, 1); } else if (up && right) { sh(bulSpd * 0.7f, -bulSpd * 0.7f, false, 1); sh(bulSpd, -bulSpd, false, 1); sh(bulSpd * 0.3f, -bulSpd, false, 1); } else goto skip2; } else { if (up && !left && !right)sh(0, -bulSpd, false, 1); else if (left && !up)sh(-bulSpd, 0, false, 1); else if (right && !up)sh(bulSpd, 0, false, 1); else if (up && left)sh(-bulSpd * 0.7f, -bulSpd * 0.7f, false, 1); else if (up && right)sh(bulSpd * 0.7f, -bulSpd * 0.7f, false, 1); else goto skip2; } shootCd = cc; skip2:; } for (auto& b : bullets) { if (b.piercing) b.updateRotation(); } sf::Vector2f pp = player.getPosition(); if (pp.x > 420) player.setPosition(-20, pp.y); if (pp.x < -20) player.setPosition(420, pp.y); for (auto& e : enemies) { if (e.type == ENEMY_BOSS) { float bs = (e.hp < e.maxHp / 2) ? 1.5f : 0.8f; float vs = (e.hp < e.maxHp / 2) ? 1.0f : 0.6f; e.shape.move(e.speed * e.dir * bs, 0); if (e.shape.getPosition().x < 60 || e.shape.getPosition().x>340)e.dir *= -1; e.vertTimer += dt; if (e.vertTimer > 3) { e.vertTimer = 0; e.vertDir *= -1; } float ny = e.shape.getPosition().y + vs * e.vertDir; if (ny > arenaY - 40) { ny = arenaY - 40; e.vertDir = -1; } if (ny < arenaY - 250) { ny = arenaY - 250; e.vertDir = 1; } e.shape.setPosition(e.shape.getPosition().x, ny); e.crown1.setPosition(e.shape.getPosition().x - 16, e.shape.getPosition().y - 50); e.crown2.setPosition(e.shape.getPosition().x, e.shape.getPosition().y - 58); e.crown3.setPosition(e.shape.getPosition().x + 16, e.shape.getPosition().y - 50); e.shootTimer += dt; float interval = (e.hp < e.maxHp / 2) ? 3.5f : 5.0f; if (e.shootTimer >= interval) { e.shootTimer = 0; for (int i = -1; i <= 1; i++) bBullets.push_back(BossBullet(e.shape.getPosition().x, e.shape.getPosition().y + 40, cos(3.14159f / 2 + i * 0.3f) * bBulSpd, sin(3.14159f / 2 + i * 0.3f) * bBulSpd)); int ds = (e.hp < e.maxHp / 2) ? 2 : 1; for (int d = 0; d < ds; d++) enemies.push_back(Enemy(e.shape.getPosition().x + rand() % 100 - 50, e.shape.getPosition().y + rand() % 60 - 30, 1, ENEMY_DRONE)); } } else if (e.type == ENEMY_DRONE) { e.shape.move(e.speed * e.dir * 0.5f, 0); if (e.shape.getPosition().x < 40 || e.shape.getPosition().x>360)e.dir *= -1; e.innerShape.setPosition(e.shape.getPosition().x - 5, e.shape.getPosition().y); e.shootTimer += dt; if (e.shootTimer >= e.shootInterval) { e.shootTimer = 0; e.shootInterval = 2 + (rand() % 100) / 100.0f; float a = (rand() % 60 - 30) * 3.14159f / 180; eBullets.push_back(EnemyBullet(e.shape.getPosition().x, e.shape.getPosition().y + 15, sin(a) * eBulSpd, cos(a) * eBulSpd)); } } } for (auto& b : bullets) b.shape.move(b.vx, b.vy); for (auto& eb : eBullets) eb.shape.move(eb.vx, eb.vy); for (auto& bb : bBullets) bb.shape.move(bb.vx, bb.vy); if (!moveBoost) for (auto& p : plats) if (p.isActive() && p.shape.getFillColor() != sf::Color::Transparent && player.getGlobalBounds().intersects(p.shape.getGlobalBounds()) && pvy > 0) { pvy = jumpF; sf::Color platColor = p.shape.getFillColor(); if (platColor != sf::Color::Transparent && p.type != BREAKING) { for (int pi = 0; pi < 7; pi++) particles.push_back(Particle(player.getPosition().x, p.shape.getPosition().y, platColor)); } } for (auto it = boosts.begin(); it != boosts.end();) { bool col = false; if (player.getGlobalBounds().intersects(it->frame.getGlobalBounds())) { if (it->type == AIR_SPREAD) { weapType = 0; weapTimer = spreadDur; col = true; } else if (it->type == AIR_SPEAR) { weapType = 1; weapTimer = spearDur; col = true; } else if (it->type == AIR_SHIELD) { shieldOn = true; shieldPulse = 0; col = true; } else if (it->type == AIR_HEART) { if (hp < maxHp)hp++; col = true; } } if (col || it->frame.getPosition().y > gameView.getCenter().y + 400) it = boosts.erase(it); else ++it; } for (auto bit = bullets.begin(); bit != bullets.end();) { bool used = false; for (auto eit = enemies.begin(); eit != enemies.end();) { if (bit->shape.getGlobalBounds().intersects(eit->shape.getGlobalBounds())) { bool alreadyHit = false; for (auto& he : bit->hitEnemies) { if (he == &(*eit)) { alreadyHit = true; break; } }if (alreadyHit) { ++eit; continue; }bit->hitEnemies.push_back(&(*eit)); eit->hp -= bit->damage; eit->updateColor(); used = true; if (eit->hp <= 0) { sf::Color ec = eit->shape.getFillColor(); for (int pi = 0; pi < 12; pi++) { float angle = (std::rand() % 360) * 3.14159f / 180.0f; float speed = 2.0f + (std::rand() % 200) / 50.0f; Particle ep(eit->shape.getPosition().x, eit->shape.getPosition().y, ec); ep.vx = std::cos(angle) * speed; ep.vy = std::sin(angle) * speed - 2.0f; ep.maxLife = 0.4f + (std::rand() % 100) / 250.0f; ep.life = ep.maxLife; particles.push_back(ep); }if (eit->type == ENEMY_BOSS)score += 500; else if (eit->type == ENEMY_DRONE) { score += 100; if (rand() % 100 < 20) { AirBoosterType bt = (rand() % 2 == 0) ? AIR_SPREAD : AIR_SPEAR; boosts.push_back(AirBooster(eit->shape.getPosition().x, eit->shape.getPosition().y, bt, true)); } } eit = enemies.erase(eit); } else ++eit; if (!bit->piercing)break; } else ++eit; } if (used && !bit->piercing)bit = bullets.erase(bit); else ++bit; } bool dmg = false; if (invTimer <= 0) { for (auto it = eBullets.begin(); it != eBullets.end();) { if (player.getGlobalBounds().intersects(it->shape.getGlobalBounds())) { dmg = true; it = eBullets.erase(it); break; } else ++it; } for (auto it = bBullets.begin(); it != bBullets.end();) { if (player.getGlobalBounds().intersects(it->shape.getGlobalBounds())) { dmg = true; it = bBullets.erase(it); break; } else ++it; } if (!dmg)for (auto& e : enemies)if (player.getGlobalBounds().intersects(e.shape.getGlobalBounds())) { dmg = true; break; } if (player.getPosition().y > gameView.getCenter().y + 350)dmg = true; if (dmg) { if (shieldOn) { shieldOn = false; invTimer = invDur; float shieldIconX = 17 + maxHp * 22 + 10; float shieldIconY = 17; for (int pi = 0; pi < 8; pi++) { float angle = (std::rand() % 360) * 3.14159f / 180.0f; float speed = 2.0f + (std::rand() % 200) / 50.0f; Particle sp(shieldIconX, shieldIconY, sf::Color(100, 200, 255)); sp.vx = std::cos(angle) * speed; sp.vy = std::sin(angle) * speed - 2.0f; sp.maxLife = 0.5f + (std::rand() % 100) / 200.0f; sp.life = sp.maxLife; uiParticles.push_back(sp); } } else { hp--; invTimer = invDur; float heartX = 17 + (hp) * 22; float heartY = 17; for (int pi = 0; pi < 10; pi++) { float angle = (std::rand() % 360) * 3.14159f / 180.0f; float speed = 2.0f + (std::rand() % 200) / 50.0f; Particle hpP(heartX, heartY, sf::Color(255, 100, 180)); hpP.vx = std::cos(angle) * speed; hpP.vy = std::sin(angle) * speed - 2.0f; hpP.maxLife = 0.5f + (std::rand() % 100) / 200.0f; hpP.life = hpP.maxLife; uiParticles.push_back(hpP); } if (hp <= 0) { for (int pi = 0; pi < 20; pi++) { float angle = (std::rand() % 360) * 3.14159f / 180.0f; float speed = 2.0f + (std::rand() % 300) / 50.0f; Particle pp(player.getPosition().x, player.getPosition().y, sf::Color(50, 200, 255)); pp.vx = std::cos(angle) * speed; pp.vy = std::sin(angle) * speed - 2.0f; pp.maxLife = 0.6f + (std::rand() % 100) / 200.0f; pp.life = pp.maxLife; particles.push_back(pp); }if (playerWingsActive) { for (int pi = 0; pi < 8; pi++) { float angle = (std::rand() % 360) * 3.14159f / 180.0f; float speed = 1.5f + (std::rand() % 200) / 50.0f; Particle pw(player.getPosition().x, player.getPosition().y, sf::Color(150, 240, 255)); pw.vx = std::cos(angle) * speed; pw.vy = std::sin(angle) * speed - 2.0f; pw.maxLife = 0.4f + (std::rand() % 100) / 250.0f; pw.life = pw.maxLife; particles.push_back(pw); }playerWingsActive = false; }player.setPosition(-1000, -1000); trail.clear(); state = GAME_OVER_SCREEN; goTimer = 0; if (score > hiScore)hiScore = score; if (!playerName.empty()) { leaderboard.push_back({ playerName,score }); std::sort(leaderboard.begin(), leaderboard.end(), [](auto& a, auto& b) {return a.score > b.score; }); if (leaderboard.size() > 10)leaderboard.resize(10); saveLeaderboard(leaderboard); } } else if (player.getPosition().y > gameView.getCenter().y + 350) { player.setPosition(200, gameView.getCenter().y); pvy = 0; } } } } if (score > hiScore) hiScore = score; bullets.erase(std::remove_if(bullets.begin(), bullets.end(), [&](Bullet& b) {return b.shape.getPosition().y<gameView.getCenter().y - 400 || b.shape.getPosition().y>gameView.getCenter().y + 400 || b.shape.getPosition().x < -50 || b.shape.getPosition().x>450; }), bullets.end()); eBullets.erase(std::remove_if(eBullets.begin(), eBullets.end(), [&](EnemyBullet& eb) {return eb.shape.getPosition().y > gameView.getCenter().y + 400; }), eBullets.end()); bBullets.erase(std::remove_if(bBullets.begin(), bBullets.end(), [&](BossBullet& bb) {return bb.shape.getPosition().y > gameView.getCenter().y + 400; }), bBullets.end()); gameView.setCenter(200, arenaY - 200); } // BOSS_CLEAR if (state == BOSS_CLEAR) { clearTimer += dt; float cms = (moveBoost && moveType == 1) ? slowSpd : moveSpd; if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) player.move(-cms, 0); if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) player.move(cms, 0); sf::Vector2f pp = player.getPosition(); if (pp.x > 420) player.setPosition(-20, pp.y); if (pp.x < -20) player.setPosition(420, pp.y); if (!moveBoost) { pvy += grav; player.move(0, pvy); } if (!trail.empty()) { for (int i = trailLength - 1; i > 0; i--) { trail[i].setPosition(trail[i - 1].getPosition()); } trail[0].setPosition(player.getPosition()); } if (player.getPosition().y < highY) { highY = player.getPosition().y; score = std::max(score, (int)((600 - highY) / 10)); } if (!goldTouch) { for (auto& p : plats) { if (p.type == GOLDEN && player.getGlobalBounds().intersects(p.shape.getGlobalBounds()) && pvy > 0) { goldTouch = true; pvy = jumpF; clearTimer = 0; for (int pi = 0; pi < 12; pi++) particles.push_back(Particle(player.getPosition().x, p.shape.getPosition().y, sf::Color(255, 220, 60))); } } if (!moveBoost) { for (auto& p : plats) { if (p.type == GOLDEN) continue; if (player.getGlobalBounds().intersects(p.shape.getGlobalBounds()) && pvy > 0) { pvy = jumpF; sf::Color platColor = p.shape.getFillColor(); if (platColor != sf::Color::Transparent) { for (int pi = 0; pi < 7; pi++) particles.push_back(Particle(player.getPosition().x, p.shape.getPosition().y, platColor)); } } } } } if (goldTouch && !transitioning && clearTimer > 1.5f) { transitioning = true; transitionAlpha = 0; } if (transitioning) { transitionAlpha += dt * 1.5f; if (transitionAlpha >= 1.0f) { transitioning = false; transitionAlpha = 0; bossLvl++; diff++; nextBoss = 800 * bossLvl * bossLvl; grav = std::min(baseGrav + diff * 0.03f, 0.75f); platSpd = std::min(2.5f + diff * 0.5f, 7.0f); eneSpd = std::min(1.5f + diff * 0.3f, 5.0f); platGap = std::max(90.0f - diff * 5.0f, 50.0f); player.setPosition(200, arenaY - 40); pvy = jumpF; highY = player.getPosition().y; state = PLAYING; clearAll(); plats.push_back(Platform(160, arenaY - 20, NORMAL, 0)); plats.back().initObj(); float cy = arenaY - 120; while (cy > gameView.getCenter().y - 400) { float rx = rand() % 320; PlatformType t = NORMAL; int r = rand() % 100; if (r < 55) t = NORMAL; else if (r < 80) t = MOVING; else if (r < 93) t = BREAKING; else if (r < 97) t = TRAMPOLINE; else t = BOOSTER_PAD; plats.push_back(Platform(rx, cy, t, platSpd)); plats.back().initObj(); cy -= platGap + rand() % 50; } } } if (score > hiScore) hiScore = score; gameView.setCenter(200, arenaY - 200); } // ������� � ������� if (state == GAME_OVER_SCREEN) goTimer += dt; if (weapType >= 0) { weapTimer -= dt; if (weapTimer <= 0) weapType = -1; } if (invTimer > 0) { invTimer -= dt; vis = ((int)(invTimer * 10) % 2 == 0); } else vis = true; if (moveBoost && state != BOSS_FIGHT && state != BOSS_CLEAR && state != BOSS_APPROACH) { moveTimer -= dt; if (moveTimer <= 0) { if (playerWingsActive && moveType == 0) { for (int pi = 0; pi < 12; pi++) { float angle = (std::rand() % 360) * 3.14159f / 180.0f; float speed = 1.5f + (std::rand() % 200) / 50.0f; Particle pw(player.getPosition().x, player.getPosition().y, sf::Color(150, 240, 255)); pw.vx = std::cos(angle) * speed; pw.vy = std::sin(angle) * speed - 2.0f; pw.maxLife = 0.4f + (std::rand() % 100) / 250.0f; pw.life = pw.maxLife; particles.push_back(pw); } playerWingsActive = false; } moveBoost = false; moveType = -1; } } for (auto& pt : particles) pt.update(dt); particles.erase(std::remove_if(particles.begin(), particles.end(), [](Particle& pt) { return pt.isDead(); }), particles.end()); for (auto& pt : uiParticles) pt.update(dt); uiParticles.erase(std::remove_if(uiParticles.begin(), uiParticles.end(), [](Particle& pt) { return pt.isDead(); }), uiParticles.end()); float botEdge = gameView.getCenter().y + 400; plats.erase(std::remove_if(plats.begin(), plats.end(), [botEdge](Platform& p) {return p.shape.getPosition().y > botEdge; }), plats.end()); boosts.erase(std::remove_if(boosts.begin(), boosts.end(), [botEdge](AirBooster& b) {return b.frame.getPosition().y > botEdge; }), boosts.end()); enemies.erase(std::remove_if(enemies.begin(), enemies.end(), [botEdge](Enemy& e) {return e.shape.getPosition().y > botEdge; }), enemies.end()); eBullets.erase(std::remove_if(eBullets.begin(), eBullets.end(), [botEdge](EnemyBullet& eb) {return eb.shape.getPosition().y > botEdge; }), eBullets.end()); bBullets.erase(std::remove_if(bBullets.begin(), bBullets.end(), [botEdge](BossBullet& bb) {return bb.shape.getPosition().y > botEdge; }), bBullets.end()); // ��������� window.clear(sf::Color(8, 8, 20)); window.setView(uiView); for (int gx = 0; gx < 400; gx += 40) { sf::RectangleShape gl(sf::Vector2f(1, 600)); gl.setPosition(gx, 0); gl.setFillColor(sf::Color(255, 255, 255, 8)); window.draw(gl); } for (int gy = 0; gy < 600; gy += 40) { sf::RectangleShape gl(sf::Vector2f(400, 1)); gl.setPosition(0, gy); gl.setFillColor(sf::Color(255, 255, 255, 8)); window.draw(gl); } for (auto& s : stars) window.draw(s.shape); if (state != MENU) { window.setView(gameView); for (auto& p : plats) { if (p.type == NORMAL && !p.breaking) { float pulse = 1.0f + std::sin(globalTimer * 4.0f + p.shape.getPosition().x * 0.1f) * 0.05f; p.shape.setScale(pulse, 1.0f); } window.draw(p.shape); if (p.obj == OBJ_SPRING && p.spring.getFillColor() != sf::Color::Transparent)window.draw(p.spring); if (p.obj == OBJ_JETPACK && !p.jetCollected)window.draw(p.jetStar); } for (auto& b : boosts) { if (b.type == AIR_PROPELLER) { window.draw(b.wing1); window.draw(b.wing2); } if (b.type == AIR_PROPELLER || b.type == AIR_SHIELD)window.draw(b.fill); window.draw(b.frame); if (b.type == AIR_SPREAD) { window.draw(b.iconDot1); window.draw(b.iconDot2); window.draw(b.iconDot3); } else if (b.type == AIR_SPEAR)window.draw(b.iconLine); else if (b.type == AIR_SHIELD)window.draw(b.iconDot1); else if (b.type == AIR_HEART) { window.draw(b.iconDiamond); window.draw(b.crossH); window.draw(b.crossV); } } for (auto& e : enemies) { if (e.type != ENEMY_BOSS) { float enemyPulse = 1.0f + std::sin(globalTimer * 5.0f + e.shape.getPosition().x * 0.2f) * 0.06f; e.shape.setScale(enemyPulse, enemyPulse); e.innerShape.setScale(enemyPulse, enemyPulse); } window.draw(e.shape); window.draw(e.innerShape); if (e.type == ENEMY_BOSS) { window.draw(e.crown1); window.draw(e.crown2); window.draw(e.crown3); } } for (auto& b : bullets) window.draw(b.shape); for (auto& eb : eBullets) window.draw(eb.shape); for (auto& bb : bBullets) window.draw(bb.shape); for (auto& pt : particles) window.draw(pt.shape); if (vis || state == GAME_OVER_SCREEN) { if (!trail.empty()) for (int i = trailLength - 1; i >= 0; i--) window.draw(trail[i]); window.draw(player); window.draw(playerInner); if (playerWingsActive) { window.draw(playerWing1); window.draw(playerWing2); } if (shieldOn) { float pulse = 2.0f + std::sin(shieldPulse) * 1.5f; shield.setOutlineThickness(pulse); int alpha = 150 + std::sin(shieldPulse) * 100; shield.setOutlineColor(sf::Color(150, 230, 255, alpha)); shield.setPosition(player.getPosition()); window.draw(shield); } } } if (transitioning) { window.setView(uiView); sf::RectangleShape transitionOverlay(sf::Vector2f(400, 600)); int alpha = std::min(200, (int)(transitionAlpha * 255)); transitionOverlay.setFillColor(sf::Color(255, 220, 60, alpha)); window.draw(transitionOverlay); } window.setView(uiView); // UI-������� (HP � ���) for (auto& pt : uiParticles) window.draw(pt.shape); if (state == MENU) { sf::RectangleShape bg(sf::Vector2f(400, 600)); bg.setFillColor(sf::Color(10, 10, 25, 180)); window.draw(bg); if (hasFont) { float titlePulse = (std::sin(menuTimer * 3.0f) + 1.0f) / 2.0f; int r1 = 100 + titlePulse * 155; int g1 = 200 + titlePulse * 55; int b1 = 255; sf::Text t("NEON ASCENT", font, 32); t.setFillColor(sf::Color(r1, g1, b1)); t.setPosition(200 - t.getLocalBounds().width / 2, 140); window.draw(t); int r2 = 255; int g2 = 100 + (1 - titlePulse) * 155; int b2 = 200; sf::Text st("ARCADE", font, 16); st.setFillColor(sf::Color(r2, g2, b2)); st.setPosition(200 - st.getLocalBounds().width / 2, 180); window.draw(st); float a = (sin(menuTimer * 2.5f) + 1) / 2; sf::Text ss("Press SPACE to start", font, 16); ss.setFillColor(sf::Color(255, 255, 255, (int)(100 + a * 155))); ss.setPosition(200 - ss.getLocalBounds().width / 2, 360); window.draw(ss); sf::Text ph("P-pause L-leaders N-name Esc-exit", font, 9); ph.setFillColor(sf::Color(150, 150, 150)); ph.setPosition(200 - ph.getLocalBounds().width / 2, 390); window.draw(ph); if (!playerName.empty()) { sf::Text pn("Player: " + playerName, font, 12); pn.setFillColor(sf::Color(200, 200, 200)); pn.setPosition(200 - pn.getLocalBounds().width / 2, 420); window.draw(pn); } } } if (state != MENU) { for (int i = 0; i < maxHp; i++) { sf::RectangleShape h(sf::Vector2f(14, 14)); h.setOrigin(7, 7); h.setPosition(17 + i * 22, 17); h.setRotation(45); h.setFillColor(i < hp ? sf::Color(255, 100, 180) : sf::Color(40, 20, 50)); window.draw(h); } if (shieldOn) { sf::RectangleShape si(sf::Vector2f(14, 14)); si.setOrigin(7, 7); si.setPosition(17 + maxHp * 22 + 10, 17); si.setRotation(45); si.setFillColor(sf::Color(100, 200, 255)); window.draw(si); } if (hasFont) { sf::Text sc("Score: " + std::to_string(score), font, 14); sc.setFillColor(sf::Color::White); sc.setPosition(400 - sc.getLocalBounds().width - 10, 10); window.draw(sc); if (weapType >= 0) { std::string wb = (weapType == 0) ? "SPREAD" : "SPEAR"; sf::Text wt(wb, font, 11); wt.setFillColor(sf::Color(255, 255, 100)); wt.setPosition(10, 32); window.draw(wt); } if (dashCd > 0) { sf::Text dtxt("W: " + std::to_string((int)(dashCd * 10) / 10.0f).substr(0, 4), font, 10); dtxt.setFillColor(sf::Color(200, 200, 200)); dtxt.setPosition(10, 48); window.draw(dtxt); } else { sf::Text dtxt("W: READY", font, 10); dtxt.setFillColor(sf::Color(100, 255, 100)); dtxt.setPosition(10, 48); window.draw(dtxt); } } } if (state != PAUSED && state != MENU && state != GAME_OVER_SCREEN && state != LEADERBOARD && state != NAME_ENTRY) { sf::CircleShape playIcon(8, 3); playIcon.setFillColor(sf::Color(200, 200, 200, 120)); playIcon.setOrigin(8, 7); playIcon.setPosition(18, 578); playIcon.setRotation(90); window.draw(playIcon); } if (state == BOSS_APPROACH && hasFont) { float bossPulse = (std::sin(globalTimer * 6.0f) + 1.0f) / 2.0f; int bossR = 200 + bossPulse * 55; int bossG = 60 + bossPulse * 40; int bossB = 255; sf::Text bt("BOSS IS NEAR!", font, 18); bt.setFillColor(sf::Color(bossR, bossG, bossB)); bt.setPosition(200 - bt.getLocalBounds().width / 2, 200); float bossScale = 1.0f + bossPulse * 0.08f; bt.setScale(bossScale, bossScale); window.draw(bt); sf::Text jt("Jump on the purple portal!", font, 12); jt.setFillColor(sf::Color(200, 200, 200)); jt.setPosition(200 - jt.getLocalBounds().width / 2, 230); window.draw(jt); } if (state == BOSS_INTRO && hasFont) { float incPulse = (std::sin(introTimer * 8.0f) + 1.0f) / 2.0f; int incR = 255; int incG = 40 + incPulse * 80; int incB = 40 + incPulse * 80; sf::Text bt("BOSS INCOMING!", font, 22); bt.setFillColor(sf::Color(incR, incG, incB)); bt.setPosition(200 - bt.getLocalBounds().width / 2, 280); window.draw(bt); } if (state == BOSS_CLEAR && hasFont) { sf::Text ct("LEVEL CLEAR!", font, 24); ct.setFillColor(sf::Color(255, 220, 50)); ct.setPosition(200 - ct.getLocalBounds().width / 2, 280); window.draw(ct); if (goldTouch) { sf::Text nt("Next level...", font, 14); nt.setFillColor(sf::Color(200, 200, 200)); nt.setPosition(200 - nt.getLocalBounds().width / 2, 320); window.draw(nt); } else { sf::Text jt("Jump on the golden platform!", font, 12); jt.setFillColor(sf::Color(200, 200, 200)); jt.setPosition(200 - jt.getLocalBounds().width / 2, 320); window.draw(jt); } } if (state == GAME_OVER_SCREEN) { sf::RectangleShape ov(sf::Vector2f(400, 600)); ov.setFillColor(sf::Color(0, 0, 0, 180)); window.draw(ov); if (hasFont) { float goPulse = (std::sin(goTimer * 8.0f) + 1.0f) / 2.0f; int goR = 255; int goG = 30 + goPulse * 80; int goB = 30 + goPulse * 60; sf::Text go("GAME OVER", font, 30); go.setFillColor(sf::Color(goR, goG, goB)); go.setPosition(200 - go.getLocalBounds().width / 2, 230); window.draw(go); sf::Text sc("Score: " + std::to_string(score) + " Best: " + std::to_string(hiScore), font, 14); sc.setFillColor(sf::Color::White); sc.setPosition(200 - sc.getLocalBounds().width / 2, 275); window.draw(sc); if (goTimer > 1) { float a = (sin(goTimer * 3) + 1) / 2; sf::Text rs("Press R to restart", font, 14); rs.setFillColor(sf::Color(255, 255, 255, (int)(100 + a * 155))); rs.setPosition(200 - rs.getLocalBounds().width / 2, 310); window.draw(rs); sf::Text es("Press ESC for menu", font, 12); es.setFillColor(sf::Color(150, 150, 150)); es.setPosition(200 - es.getLocalBounds().width / 2, 340); window.draw(es); } } } window.display(); } return 0; }