用c++和SFML实现简易的界面版贪吃蛇

运行截图

等待开始界面

运行过程

失败界面截图

SFML配置

csdn上面已经有很多SFML配置的blog,随便就能搜到。正常配置好SFML后,还需要将字体ttf文件放在源代码同一目录和exe同一目录中,不然无法显示字符

代码部分

下面贴上各个部分的代码

头文件和全局常量

#include <SFML/Graphics.hpp>
#include <time.h>
#include<iostream>
#include<conio.h>

const int BodyMaxLong = 2000;        //最长蛇身
const int SnakeInitLongth = 10;      //初始蛇身
const sf::Vector2f SnakeInitPos = {200,200}; //蛇头初始位置
const int BodyRadius = 5;             //蛇身半径
const sf::Vector2i WindowSize = { 500,500 };
const int FoodRadius = 2;
const int FoodNum = 30;
#define SnakeColor sf::Color::Green
#define FoodColor sf::Color::Red

 

sfml中已经定义了颜色可以直接用,还有图形类和二维向量类(int型vector2i,float型vector2f),都在名称空间sf中。

既然是贪吃蛇游戏,那么一定有蛇啦。

class Snake {                       //蛇
private:
    int longth;                            //蛇身长度
    sf::Vector2f dir;                        //蛇当前行进方向
    sf::CircleShape body[BodyMaxLong];        //用圆形类来建造蛇身
public:
    Snake() {
        longth = SnakeInitLongth;
        dir = { 5 , 0 };                       //初始方向
        for (int i = 0;i < 5;i++) {            //初始化位置和蛇身每个圆形之间的间距
            sf::Vector2f pos = { SnakeInitPos.x - i * 5, SnakeInitPos.y };
            body[i].setPosition(pos);
        }
        for (int i = 0;i < BodyMaxLong;i++) {        //初始化蛇身半径和颜色
            body[i].setRadius(BodyRadius);
            body[i].setFillColor(SnakeColor);
        }
    }
    void SnakeMove() {                      //整体移动蛇身函数,用一个循环依次移动每一个蛇身
        for (int i = longth - 1;i > 0;i--)
        {
            body[i].setPosition(body[i - 1].getPosition().x,body[i - 1].getPosition().y);
        }
        body[0].move(dir);
    }
    void SnakeHolding(sf::Event &event) {            //控制蛇行进方向
        switch (event.key.code)
        {
        case sf::Keyboard::Up:
        case sf::Keyboard::W:if (dir.x != 0 && dir.y != 5) { dir = { 0,-5 }; }break;
        case sf::Keyboard::Left:
        case sf::Keyboard::A:if (dir.x != 5 && dir.y != 0) { dir = { -5,0 }; }break;
        case sf::Keyboard::Right:
        case sf::Keyboard::D:if (dir.x != -5 && dir.y != 0) { dir = { 5,0 }; }break;
        case sf::Keyboard::Down:
        case sf::Keyboard::S:if (dir.x != 0 && dir.y != -5) { dir = { 0 , 5 }; }break;
        default:
            break;
        }
    }
    sf::CircleShape PreDrawSnake(int i) {        //在主函数绘制蛇时需要返回每个圆形对象
        return this->body[i];
    }

    int GetSnakeLongth() {
        return this->longth;
    }
    void UpLevel() { this->longth++; }            //吃到食物升级,长度自增
    sf::Vector2f GetDir() { return dir; }
};

食物

typedef struct {        //一个包含下x,y两个整型的结构体,用于表示坐标,本来可以用vector2i的,发现下面老是报错就尝试自己写个结构体,发现可以运行就这么运行了
    int x;
    int y;
}PosData;

class Food {                            //食物类
private:
    PosData pos;
    sf::CircleShape Body;
public:
    Food() {
        pos = { rand() % 500,rand() % 500 };            //初始化随机食物位置
        Body.setFillColor(FoodColor);                    //初始化食物颜色
        Body.setPosition({(float)pos.x,(float)pos.y});        //将位置设置进图形对象中
        Body.setRadius(FoodRadius);                        //初始化食物的图形半径
    }
    sf::Vector2f GetFoodPos() {                           //返回食物位置的函数 
        return { (float)this->pos.x+FoodRadius,(float)this->pos.y+FoodRadius };
    }
    void SetFoodPos() {                    //一旦被吃掉,重新随机获得一个位置
        pos = { rand() % WindowSize.x, rand() % WindowSize.y };
        Body.setPosition({(float)pos.x,(float)pos.y});
    }
    sf::CircleShape PreDraFood() { return this->Body; }        //返回图形对象,以便绘制和其他功能
};

判断函数

检查有没有吃到食物用的函数

void GetFoodCheck(Snake& snake, Food& food) {
    sf::Vector2f snakepos = { snake.PreDrawSnake(0).getPosition().x+BodyRadius,snake.PreDrawSnake(0).getPosition().y+BodyRadius};
    sf::Vector2f foodpos = food.GetFoodPos();
    if (foodpos.x >= snakepos.x - BodyRadius && foodpos.x <= snakepos.x + BodyRadius && foodpos.y>=snakepos.y - BodyRadius && foodpos.y<=snakepos.y + BodyRadius) {
        snake.UpLevel();
        food.SetFoodPos();
    }
}

检查有没有撞墙或者咬到尾巴的函数,都没有则返回1,有其一则返回0

bool CollideCheck(Snake& snake) {
    sf::CircleShape head = snake.PreDrawSnake(0);
    if (head.getPosition().x >= WindowSize.x || head.getPosition().x <= 0 || head.getPosition().y >= WindowSize.y || head.getPosition().y <= 0)
    {
        return 0;
    }
    int longth = snake.GetSnakeLongth();
    for (int i = 1;i < longth;i++) {
        if (snake.GetDir().x == 0)
        {
            if (snake.PreDrawSnake(0).getPosition().x + BodyRadius >= snake.PreDrawSnake(i).getPosition().x && snake.PreDrawSnake(0).getPosition().x + BodyRadius <= snake.PreDrawSnake(i).getPosition().x + BodyRadius * 2)
            {
                if (snake.GetDir().y > 0)
                {
                    if (snake.PreDrawSnake(0).getPosition().y + BodyRadius * 2 >= snake.PreDrawSnake(i).getPosition().y && snake.PreDrawSnake(0).getPosition().y + BodyRadius * 2 <= snake.PreDrawSnake(i).getPosition().y + BodyRadius * 2)
                    {
                        return 0;
                    }
                }
                else {
                    if (snake.PreDrawSnake(0).getPosition().y >= snake.PreDrawSnake(i).getPosition().y && snake.PreDrawSnake(0).getPosition().y <= snake.PreDrawSnake(i).getPosition().y + BodyRadius * 2)
                    {
                        return 0;
                    }
                }
            }
        }
        if (snake.GetDir().y == 0)
        {
            if (snake.PreDrawSnake(0).getPosition().y + BodyRadius >= snake.PreDrawSnake(i).getPosition().y && snake.PreDrawSnake(0).getPosition().y + BodyRadius <= snake.PreDrawSnake(i).getPosition().y + BodyRadius * 2)
            {
                if (snake.GetDir().x > 0)
                {
                    if (snake.PreDrawSnake(0).getPosition().x + BodyRadius * 2 >= snake.PreDrawSnake(i).getPosition().x && snake.PreDrawSnake(0).getPosition().x + BodyRadius * 2 <= snake.PreDrawSnake(i).getPosition().x + BodyRadius * 2)
                    {
                        return 0;
                    }
                }
                else {
                    if (snake.PreDrawSnake(0).getPosition().x  >= snake.PreDrawSnake(i).getPosition().x && snake.PreDrawSnake(0).getPosition().x  <= snake.PreDrawSnake(i).getPosition().x + BodyRadius * 2)
                    {
                        return 0;
                    }
                }
            }
        }
               
    }
    return 1;
}

main函数

int main()
{
    sf::Text text,score,pretext;
    sf::Font font,cnfont;
    font.loadFromFile("arial.ttf");            //加载字体文件
    cnfont.loadFromFile("hpsimplifiedhans-light.ttf");
    text.setPosition(1, 1);        //设置字体的位置
    score.setPosition(100, 1);
    pretext.setPosition(20,150);        
    pretext.setString("Welcome to shushuSnake Game\npress space button\n start the game");                        //设置字符内容
    pretext.setFont(font);
    pretext.setFillColor(sf::Color::Blue);
    text.setString("Score:");
    text.setFont(font);score.setFont(font);
    text.setFillColor(sf::Color::Black);score.setFillColor(sf::Color::Black);
    std::string str;
    srand((int)time(0));        
    sf::RenderWindow window(sf::VideoMode(WindowSize.x,WindowSize.y),"shushuSnake");
    Snake snake;            //创建蛇
    Food food[FoodNum];        //创建食物
    sf::Clock clock;                //
    double timer = 0, delay = 0.05;           //
    bool prep = 0;            //若prep = 0 等待玩家按空格开始游戏,开始游戏后prep = 1
    int longth;
    while (window.isOpen())
    {
        if (!prep)
        {
            sf::Event event;
            while (window.pollEvent(event)) {
                if (event.type == sf::Event::Closed) {
                    window.close();
                }
                if (event.type == sf::Event::KeyPressed) {
                    if (event.key.code == sf::Keyboard::Space)
                    {
                        prep = 1;
                    }
                }
            }
            window.clear(sf::Color::White);
            window.draw(text);
            score.setString("0");
            window.draw(score);
            window.draw(pretext);
            window.display();
        }
        if (prep) {
            float time = clock.getElapsedTime().asSeconds();        //
            clock.restart();                        //
            timer += time;
            sf::Event event;
            while (window.pollEvent(event)) {
                if (event.type == sf::Event::Closed) {
                    window.close();
                }
                if (event.type == sf::Event::KeyPressed) {
                    snake.SnakeHolding(event);
                }

            }
            longth = snake.GetSnakeLongth();
            window.clear(sf::Color::White);
            for (int i = 0;i < FoodNum; i++)                     //食物绘制
            {
                window.draw(food[i].PreDraFood());
            }
            if (timer > delay) {
                timer = 0;snake.SnakeMove();
                for (int i = 0; i < FoodNum;i++)
                {
                    GetFoodCheck(snake, food[i]);
                }
                if (CollideCheck(snake) == 0)        //咬到尾巴或者撞到墙失败了
                {
                    sf::Text endtext;
                    endtext.setString("Game Over!!");
                    endtext.setPosition(100, 150);
                    endtext.setFont(font);
                    endtext.setCharacterSize(50);
                    endtext.setFillColor(sf::Color::Red);  
                    window.clear(sf::Color::White);
                    window.draw(text);
                    window.draw(score);
                    window.draw(endtext);
                    longth = snake.GetSnakeLongth();
                    for (int i = 0; i < longth;i++)                     //蛇身绘制
                        window.draw(snake.PreDrawSnake(i));
                    window.display();
                    if (_getch())return 0;
                }
                str = std::to_string(snake.GetSnakeLongth() - SnakeInitLongth);
                score.setString(str);
            }
            for (int i = 0; i < longth;i++)                     //蛇身绘制
                window.draw(snake.PreDrawSnake(i));
            window.draw(text);
            window.draw(score);
            window.display();
        }
        
    }
    
    return 0;
}

 

欢迎大家一起讨论!

  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
好的,以下是一个简单的贪吃游戏实现。 首先,需要定义一个Snake类来保存的信息,包括身的坐标和头的方向,以及是否存活等信息。 ```C++ class Snake { public: Snake(int init_size, int width, int height); ~Snake(); void move(); void change_direction(int direction); bool is_alive(); void grow(); std::vector<std::pair<int, int>> get_body(); std::pair<int, int> get_head(); private: bool check_collision(); int width_, height_; std::deque<std::pair<int, int>> body_; int direction_; bool alive_; }; ``` 然后,实现Snake类的构造函数和析构函数: ```C++ Snake::Snake(int init_size, int width, int height) { width_ = width; height_ = height; direction_ = 0; alive_ = true; for (int i = 0; i < init_size; ++i) { body_.push_front(std::make_pair(i, 0)); } } Snake::~Snake() { body_.clear(); } ``` 接下来,实现Snake类的主要函数: `move()`函数用来移动,每次移动时需要判断是否与墙或者自己相撞,如果相撞,则死亡。 ```C++ void Snake::move() { auto head = body_.front(); switch (direction_) { case 0: head.second -= 1; break; case 1: head.first += 1; break; case 2: head.second += 1; break; case 3: head.first -= 1; break; } if (head.first < 0 || head.first >= width_ || head.second < 0 || head.second >= height_ || std::find(body_.begin() + 1, body_.end(), head) != body_.end()) { alive_ = false; return; } body_.push_front(head); if (head == food_) { grow(); generate_food(); } else { body_.pop_back(); } } ``` `change_direction()`函数用来改变的方向。 ```C++ void Snake::change_direction(int direction) { if (direction_ % 2 != direction % 2) { direction_ = direction; } } ``` `is_alive()`函数用来判断是否存活。 ```C++ bool Snake::is_alive() { return alive_; } ``` `grow()`函数用来让变长。 ```C++ void Snake::grow() { auto tail = body_.back(); switch (direction_) { case 0: tail.second += 1; break; case 1: tail.first -= 1; break; case 2: tail.second -= 1; break; case 3: tail.first += 1; break; } body_.push_back(tail); } ``` `get_body()`函数和`get_head()`函数用来获取身和头的坐标。 ```C++ std::vector<std::pair<int, int>> Snake::get_body() { std::vector<std::pair<int, int>> coordinates(body_.begin(), body_.end()); return coordinates; } std::pair<int, int> Snake::get_head() { return body_.front(); } ``` 最后,实现main函数来启动游戏。 ```C++ int main() { const int WIDTH = 20; const int HEIGHT = 20; const int INIT_SIZE = 3; const int FPS = 10; Snake snake(INIT_SIZE, WIDTH, HEIGHT); sf::RenderWindow window(sf::VideoMode(WIDTH * BLOCK_SIZE, HEIGHT * BLOCK_SIZE), "Snake"); window.setFramerateLimit(FPS); while (window.isOpen() && snake.is_alive()) { 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.change_direction(0); break; case sf::Keyboard::Right: snake.change_direction(1); break; case sf::Keyboard::Down: snake.change_direction(2); break; case sf::Keyboard::Left: snake.change_direction(3); break; } } } window.clear(); snake.move(); auto body = snake.get_body(); for (auto& block : body) { sf::RectangleShape rectangle(sf::Vector2f(BLOCK_SIZE, BLOCK_SIZE)); rectangle.setPosition(block.first * BLOCK_SIZE, block.second * BLOCK_SIZE); rectangle.setFillColor(sf::Color::Green); window.draw(rectangle); } window.display(); sf::sleep(sf::milliseconds(1000 / FPS)); } return 0; } ``` 这里使用了SFML库来绘制游戏界面,需要在编译时链接该库。完整代码如下:

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cgxx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值