#include <SFML/Graphics.hpp>
//全文仅供参考
#include <iostream>
#include <vector>
#include <cmath>
#include <ctime>
#include <thread>
#include <chrono>
#include <algorithm>
using namespace sf;
using namespace std;
// 资源管理器
class ResourceManager {
public:
static ResourceManager& getInstance() {
static ResourceManager instance;
return instance;
}
Font font;
Texture playerTexture;
Texture ghostTexture;
Texture bedTexture;
Texture doorTexture;
Texture turretTexture;
Texture backgroundTexture;
private:
ResourceManager() {
// 加载资源
if (!font.loadFromFile("arial.ttf")) {
cerr << "Failed to load font!" << endl;
}
if (!playerTexture.loadFromFile("player.png")) {
cerr << "Failed to load player texture!" << endl;
}
if (!ghostTexture.loadFromFile("ghost.png")) {
cerr << "Failed to load ghost texture!" << endl;
}
if (!bedTexture.loadFromFile("bed.png")) {
cerr << "Failed to load bed texture!" << endl;
}
if (!doorTexture.loadFromFile("door.png")) {
cerr << "Failed to load door texture!" << endl;
}
if (!turretTexture.loadFromFile("turret.png")) {
cerr << "Failed to load turret texture!" << endl;
}
if (!backgroundTexture.loadFromFile("background.png")) {
cerr << "Failed to load background texture!" << endl;
}
}
};
// 建筑基类
class Building {
public:
Sprite sprite;
Vector2f position;
int level = 1;
int maxLevel = 5;
int upgradeCost = 50;
Building(Vector2f pos, Texture& tex) : position(pos) {
sprite.setTexture(tex);
sprite.setPosition(pos);
sprite.setOrigin(tex.getSize().x / 2.0f, tex.getSize().y / 2.0f);
}
virtual void upgrade() {
if (level < maxLevel) {
level++;
upgradeCost *= 2;
sprite.setScale(1.0f + level * 0.1f, 1.0f + level * 0.1f);
}
}
virtual void draw(RenderWindow& window) {
window.draw(sprite);
}
};
// 门类
class Door : public Building {
public:
int health = 100;
int maxHealth = 100;
Door(Vector2f pos) : Building(pos, ResourceManager::getInstance().doorTexture) {
sprite.setScale(0.8f, 0.8f);
}
void upgrade() override {
Building::upgrade();
maxHealth = 100 + (level - 1) * 50;
health = maxHealth;
}
void takeDamage(int damage) {
health -= damage;
if (health < 0) health = 0;
// 根据血量改变颜色
float healthRatio = static_cast<float>(health) / maxHealth;
sprite.setColor(Color(255, 255 * healthRatio, 255 * healthRatio));
}
};
// 床类
class Bed : public Building {
public:
int coinGeneration = 1;
bool occupied = false;
Bed(Vector2f pos) : Building(pos, ResourceManager::getInstance().bedTexture) {
sprite.setScale(0.7f, 0.7f);
}
void upgrade() override {
Building::upgrade();
coinGeneration = level;
}
void generateCoins(int& coins) {
if (occupied) {
coins += coinGeneration;
}
}
};
// 炮台类
class Turret : public Building {
public:
int damage = 5;
float range = 150.0f;
float fireRate = 1.0f; // 每秒攻击次数
float fireTimer = 0.0f;
Turret(Vector2f pos) : Building(pos, ResourceManager::getInstance().turretTexture) {
sprite.setScale(0.6f, 0.6f);
}
void upgrade() override {
Building::upgrade();
damage += 3;
range += 20.0f;
fireRate += 0.2f;
}
void update(float deltaTime, Vector2f ghostPos, int& ghostHealth) {
fireTimer += deltaTime;
// 计算与猛鬼的距离
float distance = sqrt(pow(position.x - ghostPos.x, 2) + pow(position.y - ghostPos.y, 2));
// 如果在范围内且冷却结束
if (distance <= range && fireTimer >= 1.0f / fireRate) {
ghostHealth -= damage;
fireTimer = 0.0f;
// 显示攻击效果
attackEffect.setPosition(position);
attackEffect.setTarget(ghostPos);
attackEffect.active = true;
}
if (attackEffect.active) {
attackEffect.update(deltaTime);
}
}
void draw(RenderWindow& window) override {
Building::draw(window);
if (attackEffect.active) {
attackEffect.draw(window);
}
}
private:
class AttackEffect {
public:
Vector2f start;
Vector2f target;
float duration = 0.2f;
float timer = 0.0f;
bool active = false;
void setPosition(Vector2f pos) {
start = pos;
}
void setTarget(Vector2f tgt) {
target = tgt;
timer = 0.0f;
}
void update(float deltaTime) {
timer += deltaTime;
if (timer >= duration) {
active = false;
}
}
void draw(RenderWindow& window) {
float progress = timer / duration;
Vector2f current = start + (target - start) * progress;
CircleShape projectile(3);
projectile.setFillColor(Color::Yellow);
projectile.setOrigin(1.5f, 1.5f);
projectile.setPosition(current);
window.draw(projectile);
}
} attackEffect;
};
// 玩家类
class Player {
public:
Sprite sprite;
Vector2f position;
int coins = 50;
int power = 0;
bool isLying = false;
Bed* currentBed = nullptr;
Player(Vector2f pos) : position(pos) {
sprite.setTexture(ResourceManager::getInstance().playerTexture);
sprite.setPosition(pos);
sprite.setOrigin(ResourceManager::getInstance().playerTexture.getSize().x / 2.0f,
ResourceManager::getInstance().playerTexture.getSize().y / 2.0f);
sprite.setScale(0.6f, 0.6f);
}
void move(Vector2f offset) {
position += offset;
sprite.move(offset);
}
void lieDown(Bed& bed) {
if (!isLying && bed.occupied == false) {
isLying = true;
bed.occupied = true;
currentBed = &bed;
position = bed.position;
sprite.setPosition(position);
}
}
void standUp() {
if (isLying && currentBed) {
isLying = false;
currentBed->occupied = false;
currentBed = nullptr;
}
}
void draw(RenderWindow& window) {
window.draw(sprite);
}
};
// 猛鬼类
class Ghost {
public:
Sprite sprite;
Vector2f position;
Vector2f target;
int health = 100;
int maxHealth = 100;
int damage = 5;
float speed = 50.0f;
float attackTimer = 0.0f;
float attackCooldown = 1.0f;
Door* targetDoor = nullptr;
Ghost(Vector2f pos) : position(pos) {
sprite.setTexture(ResourceManager::getInstance().ghostTexture);
sprite.setPosition(pos);
sprite.setOrigin(ResourceManager::getInstance().ghostTexture.getSize().x / 2.0f,
ResourceManager::getInstance().ghostTexture.getSize().y / 2.0f);
sprite.setScale(0.7f, 0.7f);
}
void setTarget(Door& door) {
targetDoor = &door;
target = door.position;
}
void update(float deltaTime) {
// 移动到目标
if (targetDoor) {
Vector2f direction = target - position;
float distance = sqrt(direction.x * direction.x + direction.y * direction.y);
if (distance > 10.0f) {
direction /= distance;
position += direction * speed * deltaTime;
sprite.setPosition(position);
} else {
// 攻击门
attackTimer += deltaTime;
if (attackTimer >= attackCooldown) {
targetDoor->takeDamage(damage);
attackTimer = 0.0f;
}
}
}
// 更新健康条
healthBar.setSize(Vector2f(50.0f * (static_cast<float>(health) / maxHealth), 5.0f));
healthBar.setPosition(position.x - 25.0f, position.y - 50.0f);
}
void draw(RenderWindow& window) {
window.draw(sprite);
window.draw(healthBar);
}
private:
RectangleShape healthBar = RectangleShape(Vector2f(50.0f, 5.0f));
};
// 游戏类
class Game {
public:
RenderWindow window;
View view;
Player player;
Ghost ghost;
vector<unique_ptr<Building>> buildings;
vector<Bed> beds;
vector<Door> doors;
vector<Turret> turrets;
Clock gameClock;
Font font;
int coins = 50;
int power = 0;
Text coinsText;
Text powerText;
Text gameMessage;
RectangleShape coinIcon;
RectangleShape powerIcon;
Game() : window(VideoMode(1024, 768), "躺平发育"),
player(Vector2f(200, 300)),
ghost(Vector2f(800, 300)) {
window.setFramerateLimit(60);
view.setSize(1024, 768);
view.setCenter(512, 384);
font = ResourceManager::getInstance().font;
// 创建UI元素
coinsText.setFont(font);
coinsText.setCharacterSize(24);
coinsText.setFillColor(Color::Yellow);
coinsText.setPosition(40, 10);
powerText.setFont(font);
powerText.setCharacterSize(24);
powerText.setFillColor(Color::Cyan);
powerText.setPosition(40, 40);
gameMessage.setFont(font);
gameMessage.setCharacterSize(32);
gameMessage.setFillColor(Color::Red);
gameMessage.setPosition(300, 10);
gameMessage.setString("");
coinIcon.setSize(Vector2f(30, 30));
coinIcon.setFillColor(Color::Yellow);
coinIcon.setPosition(10, 10);
powerIcon.setSize(Vector2f(30, 30));
powerIcon.setFillColor(Color::Cyan);
powerIcon.setPosition(10, 40);
// 创建地图
createMap();
}
void createMap() {
// 创建宿舍房间
vector<Vector2f> roomPositions = {
Vector2f(200, 200), Vector2f(400, 200),
Vector2f(200, 400), Vector2f(400, 400)
};
// 为每个房间创建床和门
for (auto& pos : roomPositions) {
// 床在房间中央
beds.emplace_back(pos);
Bed& bed = beds.back();
// 门在床的右侧
Vector2f doorPos = pos + Vector2f(100, 0);
doors.emplace_back(doorPos);
}
// 设置玩家初始床
player.lieDown(beds[0]);
// 设置猛鬼目标
ghost.setTarget(doors[0]);
}
void run() {
while (window.isOpen()) {
float deltaTime = gameClock.restart().asSeconds();
processEvents();
update(deltaTime);
render();
}
}
void processEvents() {
Event event;
while (window.pollEvent(event)) {
if (event.type == Event::Closed) {
window.close();
}
if (event.type == Event::KeyPressed) {
// 玩家移动
if (!player.isLying) {
if (event.key.code == Keyboard::W) player.move(Vector2f(0, -5));
if (event.key.code == Keyboard::S) player.move(Vector2f(0, 5));
if (event.key.code == Keyboard::A) player.move(Vector2f(-5, 0));
if (event.key.code == Keyboard::D) player.move(Vector2f(5, 0));
}
// 躺下/站起
if (event.key.code == Keyboard::Space) {
if (player.isLying) {
player.standUp();
} else {
// 检查玩家是否在床附近
for (auto& bed : beds) {
float distance = sqrt(pow(player.position.x - bed.position.x, 2) +
pow(player.position.y - bed.position.y, 2));
if (distance < 50.0f) {
player.lieDown(bed);
break;
}
}
}
}
// 建筑升级
if (event.key.code == Keyboard::U) {
if (player.isLying && player.currentBed) {
if (coins >= player.currentBed->upgradeCost) {
coins -= player.currentBed->upgradeCost;
player.currentBed->upgrade();
}
}
}
// 建造炮台
if (event.key.code == Keyboard::T) {
if (coins >= 100) {
coins -= 100;
turrets.emplace_back(player.position + Vector2f(50, 0));
}
}
}
}
}
void update(float deltaTime) {
// 更新UI文本
coinsText.setString(to_string(coins));
powerText.setString(to_string(power));
// 玩家在床上时产生金币
if (player.isLying && player.currentBed) {
player.currentBed->generateCoins(coins);
}
// 更新猛鬼
ghost.update(deltaTime);
// 更新炮台
for (auto& turret : turrets) {
turret.update(deltaTime, ghost.position, ghost.health);
}
// 检查游戏结束条件
if (ghost.health <= 0) {
gameMessage.setString("胜利! 猛鬼已被击败!");
} else if (doors[0].health <= 0) {
gameMessage.setString("失败! 门被破坏了!");
}
}
void render() {
window.clear(Color(30, 30, 50));
// 绘制背景
Sprite background(ResourceManager::getInstance().backgroundTexture);
window.draw(background);
// 绘制床
for (auto& bed : beds) {
bed.draw(window);
}
// 绘制门
for (auto& door : doors) {
door.draw(window);
}
// 绘制炮台
for (auto& turret : turrets) {
turret.draw(window);
}
// 绘制玩家
player.draw(window);
// 绘制猛鬼
ghost.draw(window);
// 绘制UI
window.draw(coinIcon);
window.draw(powerIcon);
window.draw(coinsText);
window.draw(powerText);
window.draw(gameMessage);
// 显示控制提示
Text controls("WASD: 移动 空格: 躺下/站起 T: 建造炮台(100金币) U: 升级床", font, 20);
controls.setPosition(10, 700);
controls.setFillColor(Color::White);
window.draw(controls);
window.display();
}
};
int main() {
Game game;
game.run();
return 0;
}