下面是一个使用C++和SFML库实现的简单贪吃蛇游戏。这个示例展示了游戏开发的基本概念,包括游戏循环、图形渲染、用户输入处理和游戏逻辑。
cpp
#include <SFML/Graphics.hpp>
#include <vector>
#include <random>
// 游戏常量
const int WINDOW_WIDTH = 800;
const int WINDOW_HEIGHT = 600;
const int GRID_SIZE = 20;
const int GRID_WIDTH = WINDOW_WIDTH / GRID_SIZE;
const int GRID_HEIGHT = WINDOW_HEIGHT / GRID_SIZE;
// 方向枚举
enum class Direction { Up, Down, Left, Right };
class Snake {
public:
Snake() {
// 初始化蛇身,从屏幕中央开始
body.push_back(sf::Vector2i(GRID_WIDTH / 2, GRID_HEIGHT / 2));
direction = Direction::Right;
growPending = 3; // 初始长度为4
}
void changeDirection(Direction newDirection) {
// 防止直接反向移动
if ((direction == Direction::Up && newDirection != Direction::Down) ||
(direction == Direction::Down && newDirection != Direction::Up) ||
(direction == Direction::Left && newDirection != Direction::Right) ||
(direction == Direction::Right && newDirection != Direction::Left)) {
direction = newDirection;
rd.xjyl.gov.cn/upload/1982074940999303168.html
rd.xjyl.gov.cn/upload/1982074941032857600.html
rd.xjyl.gov.cn/upload/1982074941074800640.html
rd.xjyl.gov.cn/upload/1982074941158686720.html
rd.xjyl.gov.cn/upload/1982074941171269633.html
rd.xjyl.gov.cn/upload/1982074941171269632.html
rd.xjyl.gov.cn/upload/1982074941234184192.html
rd.xjyl.gov.cn/upload/1982074941485842432.html
rd.xjyl.gov.cn/upload/1982074941506813952.html
rd.xjyl.gov.cn/upload/1982074941515202560.html
rd.xjyl.gov.cn/upload/1982074941544562688.html
rd.xjyl.gov.cn/upload/1982074941607477248.html
rd.xjyl.gov.cn/upload/1982074941670391808.html
rd.xjyl.gov.cn/upload/1982074941792026624.html
rd.xjyl.gov.cn/upload/1982074941850746880.html
rd.xjyl.gov.cn/upload/1982074942056267776.html
rd.xjyl.gov.cn/upload/1982074942106599424.html
rd.xjyl.gov.cn/upload/1982074942135959552.html
rd.xjyl.gov.cn/upload/1982074942144348160.html
rd.xjyl.gov.cn/upload/1982074942190485504.html
rd.xjyl.gov.cn/upload/1982074942307926016.html
rd.xjyl.gov.cn/upload/1982074942505058304.html
rd.xjyl.gov.cn/upload/1982074942484086784.html
}
}
void update() {
// 移动蛇身
sf::Vector2i newHead = body.front();
switch (direction) {
case Direction::Up:
newHead.y--;
break;
case Direction::Down:
newHead.y++;
break;
case Direction::Left:
newHead.x--;
break;
case Direction::Right:
newHead.x++;
break;
}
// 检查边界碰撞
if (newHead.x < 0 || newHead.x >= GRID_WIDTH ||
newHead.y < 0 || newHead.y >= GRID_HEIGHT) {
reset();
return;
}
// 检查自身碰撞
for (auto segment : body) {
if (segment == newHead) {
reset();
return;
}
}
// 添加新头部
body.insert(body.begin(), newHead);
// 如果不需要增长,移除尾部
if (growPending > 0) {
growPending--;
} else {
body.pop_back();
}
}
void grow() {
growPending++;
}
void reset() {
body.clear();
body.push_back(sf::Vector2i(GRID_WIDTH / 2, GRID_HEIGHT / 2));
direction = Direction::Right;
growPending = 3;
}
const std::vector<sf::Vector2i>& getBody() const {
return body;
}
sf::Vector2i getHead() const {
return body.front();
}
private:
std::vector<sf::Vector2i> body;
Direction direction;
int growPending;
};
class Food {
public:
Food() {
respawn();
}
void respawn() {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> disX(0, GRID_WIDTH - 1);
std::uniform_int_distribution<> disY(0, GRID_HEIGHT - 1);
position.x = disX(gen);
position.y = disY(gen);
}
sf::Vector2i getPosition() const {
return position;
}
private:
sf::Vector2i position;
};
class Game {
public:
Game() : window(sf::VideoMode(WINDOW_WIDTH, WINDOW_HEIGHT), "Snake Game"),
snake(), food(), score(0) {
// 设置帧率限制
window.setFramerateLimit(10);
// 加载字体
if (!font.loadFromFile("arial.ttf")) {
// 如果无法加载字体,使用默认字体
font.loadFromFile("C:/Windows/Fonts/arial.ttf");
}
scoreText.setFont(font);
scoreText.setCharacterSize(24);
scoreText.setFillColor(sf::Color::White);
scoreText.setPosition(10, 10);
updateScoreText();
}
void run() {
while (window.isOpen()) {
handleEvents();
update();
render();
}
}
private:
void handleEvents() {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) {
window.close();
} else if (event.type == sf::Event::KeyPressed) {
switch (event.key.code) {
case sf::Keyboard::Up:
snake.changeDirection(Direction::Up);
break;
case sf::Keyboard::Down:
snake.changeDirection(Direction::Down);
break;
case sf::Keyboard::Left:
snake.changeDirection(Direction::Left);
break;
case sf::Keyboard::Right:
snake.changeDirection(Direction::Right);
break;
case sf::Keyboard::Escape:
window.close();
break;
default:
break;
}
}
}
}
void update() {
snake.update();
// 检查是否吃到食物
if (snake.getHead() == food.getPosition()) {
snake.grow();
food.respawn();
score += 10;
updateScoreText();
}
}
void render() {
window.clear(sf::Color::Black);
// 绘制蛇
sf::RectangleShape segment(sf::Vector2f(GRID_SIZE - 1, GRID_SIZE - 1));
segment.setFillColor(sf::Color::Green);
for (auto pos : snake.getBody()) {
segment.setPosition(pos.x * GRID_SIZE, pos.y * GRID_SIZE);
window.draw(segment);
}
// 绘制食物
sf::CircleShape foodShape(GRID_SIZE / 2 - 1);
foodShape.setFillColor(sf::Color::Red);
foodShape.setPosition(food.getPosition().x * GRID_SIZE, food.getPosition().y * GRID_SIZE);
window.draw(foodShape);
// 绘制分数
window.draw(scoreText);
window.display();
rd.xjyl.gov.cn/upload/1982074942513446912.html
rd.xjyl.gov.cn/upload/1982074942693801984.html
rd.xjyl.gov.cn/upload/1982074942681219072.html
rd.xjyl.gov.cn/upload/1982074942777688064.html
rd.xjyl.gov.cn/upload/1982074942765105152.html
rd.xjyl.gov.cn/upload/1982074942828019712.html
rd.xjyl.gov.cn/upload/1982074942953848832.html
rd.xjyl.gov.cn/upload/1982074942949654528.html
rd.xjyl.gov.cn/upload/1982074943130009601.html
rd.xjyl.gov.cn/upload/1982074943150981120.html
rd.xjyl.gov.cn/upload/1982074943130009600.html
rd.xjyl.gov.cn/upload/1982074943176146944.html
rd.xjyl.gov.cn/upload/1982074943272615936.html
rd.xjyl.gov.cn/upload/1982074943339724800.html
rd.xjyl.gov.cn/upload/1982074943490719744.html
rd.xjyl.gov.cn/upload/1982074943520079872.html
rd.xjyl.gov.cn/upload/1982074943608160256.html
rd.xjyl.gov.cn/upload/1982074943629131776.html
rd.xjyl.gov.cn/upload/1982074943801098240.html
rd.xjyl.gov.cn/upload/1982074943935315968.html
rd.xjyl.gov.cn/upload/1982074943981453312.html
rd.xjyl.gov.cn/upload/1982074944308609024.html
rd.xjyl.gov.cn/upload/1982074944455409664.html
rd.xjyl.gov.cn/upload/1982074944560267264.html
rd.xjyl.gov.cn/upload/1982074944606404608.html
}
void updateScoreText() {
scoreText.setString("Score: " + std::to_string(score));
}
sf::RenderWindow window;
Snake snake;
Food food;
int score;
sf::Font font;
sf::Text scoreText;
};
int main() {
Game game;
game.run();
return 0;
}
如何运行这个游戏
-
确保安装了SFML库。你可以从SFML官网下载并安装。
-
使用以下命令编译(假设使用g++):
text
g++ -c snake_game.cpp -I/path/to/SFML/include g++ snake_game.o -o snake_game -L/path/to/SFML/lib -lsfml-graphics -lsfml-window -lsfml-system -
运行游戏:
text
./snake_game
游戏功能
-
使用方向键控制蛇的移动
-
吃到红色食物会增加蛇的长度和分数
-
撞到墙壁或自身会重置游戏
-
按ESC键退出游戏
扩展建议
-
添加游戏开始和结束界面
-
实现难度级别(通过改变蛇的移动速度)
-
添加音效和更多视觉效果
-
实现高分记录功能
-
添加不同类型的食物,具有不同的效果
这个示例展示了C++游戏开发的基本概念,你可以基于此代码进一步扩展和完善游戏功能。