最近用SFML(C++)写了一个贪吃蛇的小游戏,在这里分享一下,希望能够对各位有所帮助。

1、环境配置

操作系统:Win 10

C++平台:Visual Studio 2015

SFML的配置参考:https://www.sfml-dev.org/tutorials/2.5/start-vc.php

  • 在创建工程时,需要选择x64(对应于SFML版本)
     

  • 注意:附加依赖项如下

sfml-graphics-d.lib

sfml-window-d.lib

sfml-system-d.lib

2、SFML库学习

在正式编写游戏前,SFML库的学习是必不可少的。这里列出需要学习的模块:

  • 系统模块:处理时间线程数

  • 窗口模块:打开和管理SFML窗口活动说明键盘鼠标和操纵杆

  • 图像模块:绘制2D素材精灵和纹理文字和字体形状使用顶点数组设计自己的实体位置、旋转、比例:变换实体通过视图控制2D摄像机

其中小地图是通过视图控制2D摄像机实现的,使用视图过程中可能会改变精灵的形状,可以通过比例缩放来还原。这里列出的所有模块都可以在SFML给出的官方文档中学习和参考。

SFML官方文档:https://www.sfml-dev.org/tutorials/2.5/

3、源代码

源代码分为main.cpp和parameter.h,带有注释。

  • main.cpp
#include "parameter.h"//隐藏控制台
#pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")//全局对象
sf::RenderWindow window;    //主窗口
sf::Font font;  //字体
sf::Clock clock_sys;    //时钟,开始计时
sf::View mainView;
sf::View ParameterView;
sf::View miniMap;
sf::Texture texture;
sf::Sprite sprite;
sf::Text gameMsg;
sf::RectangleShape border;
ParameterText parametertext;
Snake snake;
Food food;
int Snake::growFactor = GROWFACTOR;
float Snake::sensitivity = 1.5;
float Snake::crawling_distance = 1.5*SNAKESIZE/GROWFACTOR;
int Difficulty = 3;
int Highest_score = 0;
bool pauseFlag = false;
const double PI = atan(1.)*4.; //圆周率int main()
{game_init();sf::Clock clock_game;gameMsg.setString("Playing...");while (window.isOpen()){sf::Vector2f centertmp(0, 0);//updatasnake.updataQueue(clock_game.restart());parametertext.upData();//更新主视角中心centertmp = snake.getSnakeHeadPosition();centertmp.x = limit_float(centertmp.x, WIDTH*(PWIDTH + MAINSCALE / 2), WIDTH*(1 - MAINSCALE / 2));centertmp.y = limit_float(centertmp.y, HIGTH*MAINSCALE / 2, HIGTH*(1 - MAINSCALE / 2));mainView.setCenter(centertmp);border.setPosition(centertmp - sf::Vector2f(WIDTH*MAINSCALE / 2 + 10, HIGTH*MAINSCALE / 2 + 10));//检测if (snake.isCapture(food.rec)){//小蛇吃到食物cout << "捕获" << endl;snake.grow();food.createFood();}if (snake.isCrashBorder()){//小蛇触碰到边界,游戏结束snake.dead = true;gameMsg.setString("GameOver\nPressEnter");cout << "碰撞边界" << endl;}//事件sf::Event event;while (window.pollEvent(event)){float xtmp = 0;float ytmp = 0;sf::Uint32 unicode = 0;switch (event.type){case sf::Event::Closed:                                  //关闭window.close();break;case sf::Event::TextEntered:                           //每次接受单个字符unicode = event.text.unicode;if (unicode < 128)cout << (char)unicode << endl;switch (unicode){case 'P':case 'p'://打印MainView的中心坐标cout << "View center x: " << mainView.getCenter().x << endl;cout << "View center y: " << mainView.getCenter().y << endl;cout << "size: " << snake.vertices_snake.size() << endl;if(snake.vertices_snake.size()>0)cout << snake.vertices_snake.back().position.x << endl;break;case 'A':case 'a'://控制小蛇左移,改变小蛇方向snake.vector = snake.vector + sf::Vector2f(-1, 0)*snake.sensitivity;snake.vector = snake.vector / (sqrt(snake.vector.x*snake.vector.x + snake.vector.y*snake.vector.y));break;case 'D':case 'd'://控制小蛇右移,改变小蛇方向snake.vector = snake.vector + sf::Vector2f(1, 0)*snake.sensitivity;snake.vector = snake.vector / (sqrt(snake.vector.x*snake.vector.x + snake.vector.y*snake.vector.y));break;case 'W':case 'w'://控制小蛇上移,改变小蛇方向snake.vector = snake.vector + sf::Vector2f(0, -1)*snake.sensitivity;snake.vector = snake.vector / (sqrt(snake.vector.x*snake.vector.x + snake.vector.y*snake.vector.y));break;case 'S':case 's'://控制小蛇下移,改变小蛇方向snake.vector = snake.vector + sf::Vector2f(0, 1)*snake.sensitivity;snake.vector = snake.vector / (sqrt(snake.vector.x*snake.vector.x + snake.vector.y*snake.vector.y));break;case 0x0D://回车键,重新开始游戏if(snake.dead)snake.restart();break;case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9'://设置难度setDifficulty(unicode-'0');break;case ' '://暂停pauseFlag = !pauseFlag;break;default:break;}break;default:break;}}//drawwindow.clear();window.setView(mainView);draw(false);window.setView(ParameterView);draw(false);window.setView(miniMap);draw(true);window.display();}return 0;
}void initView()
{//初始化VIEWmainView.setCenter(MAINCENTER);           //初始化mainViewmainView.setSize(MAINVIEWSIZE);mainView.setViewport(MAINVIEWPORT);ParameterView.setCenter(PCENTER);        //初始化ParameterViewParameterView.setSize(PVIEWSIZE);ParameterView.setViewport(PVIEWPORT);miniMap.setCenter(MINICENTER);          //初始化miniMapminiMap.setSize(MINIVIEWSIZE);miniMap.setViewport(MINIVIEWPORT);
}float limit_float(float x, float min, float max)
{//限制x与[min,max]if (x < min)return min;else if (x>max)return max;elsereturn x;
}int game_init()
{//windows初始化window.create(sf::VideoMode(WIDTH, HIGTH), "Snake");food.init();//游戏初始化initView();       //视角if (!font.loadFromFile("HanYiYanKaiW-2.ttf"))         //导入字体{cout << "导入字体失败" << endl;return -1;// error...   Adorable.TTF   Times New Roman Bold.ttf}//导入精灵texture.loadFromFile("image\\map.jpg");sprite.setScale(sf::Vector2f(ZOOM, ZOOM));sprite.setTexture(texture);texture.setSmooth(true);//初始化文本gameMsg.setString("Initing...");gameMsg.setFont(font);gameMsg.setCharacterSize(20);gameMsg.setPosition(sf::Vector2f(0.02*WIDTH, 0.8*HIGTH));//Main边界border.setFillColor(sf::Color(0, 0, 0, 0));border.setOutlineThickness(4);border.setOutlineColor(sf::Color::Black);border.setSize(sf::Vector2f(WIDTH*MAINSCALE + 20, HIGTH*MAINSCALE + 20));border.setPosition(sf::Vector2f(WIDTH*PWIDTH+10, +10));
}void draw(bool flag)
{//绘制window.draw(sprite);parametertext.draw();snake.draw();food.draw();if (snake.dead){//小蛇死亡gameMsg.setString("Game Over\nPress Enter");}window.draw(gameMsg);if(flag)window.draw(border);
}bool checkBorderCrash(sf::Vector2f port)
{if (port.x<LEFTMAP || port.x>RIGHTMAP || port.y<TOPMAP || port.y>BOTTOMMAP)return 1;elsereturn 0;
}void setDifficulty(int d)
{char buff[10] = { 0 };Difficulty = d;sprintf_s(buff, "%d", d);parametertext.difficulty.setString(buff);if (snake.dead || pauseFlag)snake.speed = 0;elsesnake.speed = BASESPEED*Difficulty;
}
  • parameter.h
#include <iostream>
#include <thread>
#include <string>
#include <vector>
#include <fstream>
#include <stdlib.h>
#include <SFML\Window.hpp>
#include <SFML\Graphics.hpp>
using namespace std;//游戏参数
#define ZOOM 0.6                    //缩放比例
#define WIDTH (1920*ZOOM)           //窗口宽度
#define HIGTH (1080*ZOOM)           //窗口高度
#define PWIDTH 0.2                  //参数视角的宽度占比
#define MINISCALE 0.2               //小地图的占比
#define MAINSCALE 0.2               //主地图占比
#define SNAKESIZE 8.0               //蛇的尺寸
#define FOODSIZE  10.0              //食物尺寸
#define LEFTMAP (PWIDTH*WIDTH)              //左边界
#define RIGHTMAP (WIDTH-2*SNAKESIZE)        //右边界
#define TOPMAP 0                            //上边界
#define BOTTOMMAP (HIGTH-2*SNAKESIZE)       //下边界
#define GAP 0.1                             // 行间距
#define ORIGINPOSITION (sf::Vector2f(WIDTH*PWIDTH+20, 20))     //小蛇的复活点
#define WORDSIZE 25                         //字号
#define TESTCOLOR   (sf::Color::Black)      //测试颜色
#define GROWFACTOR 100                      //生长系数
#define BASESPEED 0.4                       //基础速度
#define TESTCOLOR   (sf::Color::Black)      //测试颜色
#define SNAKECOLOR (sf::Color(165,180,124))         //蛇的颜色#define MAINCENTER (sf::Vector2f(WIDTH*(PWIDTH + MAINSCALE/2), HIGTH*MAINSCALE/2))       //主视图的参数,视图中心
#define MAINVIEWSIZE (sf::Vector2f(WIDTH*MAINSCALE, HIGTH*MAINSCALE))   //视图在window中的尺寸
#define MAINVIEWPORT (sf::FloatRect(0.2, 0, 0.8f, 1.f))     //视图显示在window中位置及大小#define PCENTER (sf::Vector2f(WIDTH*PWIDTH/2, HIGTH*0.5))        //参数视图的参数
#define PVIEWSIZE (sf::Vector2f(WIDTH*0.2, HIGTH))
#define PVIEWPORT (sf::FloatRect(0, 0, 0.2f, 1.f))#define MINICENTER (sf::Vector2f(WIDTH*(PWIDTH+(1-PWIDTH)/2), HIGTH*0.5))    //小地图视图参数
#define MINIVIEWSIZE (sf::Vector2f(WIDTH*(1-PWIDTH), HIGTH))
#define MINIVIEWPORT (sf::FloatRect(1-MINISCALE, 0, MINISCALE, MINISCALE))//函数声明
sf::View getView();
float limit_float(float x, float min, float max);
int game_init();
sf::Text getTimeText();
bool checkBorderCrash(sf::Vector2f port);
void draw(bool flag);
void setDifficulty(int d);//类声明
class Snake;
class ParameterText;
class Food;//全局变量声明
extern sf::RenderWindow window;
extern sf::Font font;
extern sf::Clock clock_sys;
extern sf::View mainView;
extern sf::View ParameterView;
extern sf::View miniMap;
extern sf::Texture texture;
extern sf::Sprite sprite;
extern sf::Text gameMsg;
extern sf::RectangleShape border;
extern int Difficulty;
extern ParameterText parametertext;
extern Snake snake;
extern Food food;
extern int Highest_score;
extern bool pauseFlag;
extern const double PI;class Snake
{
public:int lenth;       //长度float speed;    //速度bool dead;      //是否死亡sf::Vector2f vector;  //蛇头运动方向sf::Vector2f head;      //蛇头std::vector<sf::Vertex> vertices_snake;   //顶点队列static float sensitivity; //转向灵敏度static float crawling_distance;  //每次爬行距离static int growFactor;      //生长系数Snake(){this->restart();}void restart(){//重新开始游戏this->lenth = 0;this->dead = false;this->speed = BASESPEED*Difficulty;this->vector = sf::Vector2f(1, 0);this->head = ORIGINPOSITION;std::vector<sf::Vertex> v;   //创建队列this->vertices_snake = v;gameMsg.setString("Playing...");cout << "Restart" << endl;}sf::Vector2f getSnakeHeadPosition(){return this->head;}void updataQueue(sf::Time T){//去头压尾,更新整个队列if (snake.dead || pauseFlag)this->speed = 0;elsethis->speed = BASESPEED*Difficulty;sf::Vector2f headp;sf::Vertex vtemp;vtemp.color = TESTCOLOR;std::vector<sf::Vertex>::iterator iter;if (this->vertices_snake.size() > 0){//非空队列for (int i = 0; i < (int)(this->speed*T.asMilliseconds()); i++){headp = this->vertices_snake.back().position;headp = headp + this->vector*this->crawling_distance;  //每次爬行后头的位置vtemp.position = headp;this->vertices_snake.push_back(vtemp);    //压入列尾iter = this->vertices_snake.begin();  //迭代器this->vertices_snake.erase(iter++);   //去掉头部this->head = this->head + this->vector*this->crawling_distance;}}else{for (int i = 0; i < (int)(this->speed*T.asMilliseconds()); i++){headp = this->head;headp = headp + this->vector*this->crawling_distance; //每次爬行后头的位置this->head = headp;}}}void draw(){//遍历队列元素,完成窗口绘制sf::CircleShape Ctmp(SNAKESIZE);Ctmp.setPosition(this->head);Ctmp.setFillColor(SNAKECOLOR);Ctmp.setScale(sf::Vector2f(1.f, 0.8f));window.draw(Ctmp);for (int i = 0; i < this->vertices_snake.size(); i++){if (i == 0)continue;if (i % GROWFACTOR == 0){Ctmp.setPosition(this->vertices_snake[i].position);window.draw(Ctmp);}}    }void grow(){//生长,压入队尾诺干顶点float x, y;sf::Vector2f vtmp1;sf::Vector2f vtmp2;sf::Vertex vtemp; vtemp.color = TESTCOLOR;for (int i = 0; i < this->growFactor; i++){vtmp1 = this->head;vtmp2 = vtmp1 + this->vector*this->crawling_distance;   //每次爬行后头的位置this->head = vtmp2;vtemp.position = vtmp2;this->vertices_snake.push_back(vtemp); //压入列尾}this->lenth++;cout << "小蛇生长.." << endl;}bool isCapture(sf::RectangleShape rec){//判断小蛇是否能捕获食物sf::CircleShape Ctemp(SNAKESIZE);Ctemp.setPosition(this->head);sf::FloatRect box1 = rec.getGlobalBounds();sf::FloatRect box2 = Ctemp.getGlobalBounds();return box1.intersects(box2);}bool isCrashBorder(){//判断小蛇(头)是否碰撞到边界sf::Vector2f port;port = this->head;return checkBorderCrash(port);}
};class ParameterText
{
public:sf::Text game_name;sf::Text run_time;sf::Text lenth;sf::Text speedText;sf::Text difficulty;      //难度有1..9级,数越大,难度越大sf::Text Highest_score_in_history;sf::Text run_time_Text;sf::Text lenth_Text;sf::Text speed_Text;sf::Text difficulty_Text;sf::Text Highest_score_Text;ParameterText(){this->game_name = sf::Text("Snake", font);this->game_name.setPosition(sf::Vector2f(0.02*WIDTH, 0.03*HIGTH));this->run_time_Text = sf::Text("Run Time:", font, WORDSIZE);this->run_time_Text.setPosition(sf::Vector2f(0.02*WIDTH, 0.08*HIGTH + 1 * HIGTH*GAP));this->run_time = sf::Text("0.00", font, WORDSIZE);this->run_time.setPosition(sf::Vector2f(0.125*WIDTH, 0.08*HIGTH + 1 * HIGTH*GAP));this->lenth_Text = sf::Text("Score: ", font, WORDSIZE);this->lenth_Text.setPosition(sf::Vector2f(0.02*WIDTH, 0.08*HIGTH + 2 * HIGTH*GAP));this->lenth = sf::Text("1", font, WORDSIZE);this->lenth.setPosition(sf::Vector2f(0.09*WIDTH, 0.08*HIGTH + 2 * HIGTH*GAP));this->speed_Text = sf::Text("Speed: ", font, WORDSIZE);this->speed_Text.setPosition(sf::Vector2f(0.02*WIDTH, 0.08*HIGTH + 3 * HIGTH*GAP));this->speedText = sf::Text("0.00", font, WORDSIZE);this->speedText.setPosition(sf::Vector2f(0.09*WIDTH, 0.08*HIGTH + 3 * HIGTH*GAP));this->difficulty_Text = sf::Text("Difficulty: ", font, WORDSIZE);this->difficulty_Text.setPosition(sf::Vector2f(0.02*WIDTH, 0.08*HIGTH + 4 * HIGTH*GAP));this->difficulty = sf::Text("1", font, WORDSIZE);this->difficulty.setPosition(sf::Vector2f(0.13*WIDTH, 0.08*HIGTH + 4 * HIGTH*GAP));this->Highest_score_Text = sf::Text("Highest Score: ", font, WORDSIZE);this->Highest_score_Text.setPosition(sf::Vector2f(0.02*WIDTH, 0.08*HIGTH + 5 * HIGTH*GAP));this->Highest_score_in_history = sf::Text("0", font, WORDSIZE);this->Highest_score_in_history.setPosition(sf::Vector2f(0.17*WIDTH, 0.08*HIGTH + 5 * HIGTH*GAP));cout << "创建参数文本" << endl;}void upData(){//更新参数char buff1[15] = { 0 };sprintf_s(buff1, "%.2fs", clock_sys.getElapsedTime().asSeconds());this->run_time.setString(buff1);char buff2[10] = { 0 };sprintf_s(buff2, "%d", snake.lenth);this->lenth.setString(buff2);char buff3[10] = { 0 };sprintf_s(buff3, "%.2f", snake.speed);this->speedText.setString(buff3);char buff4[10] = { 0 };sprintf_s(buff4, "%d", Difficulty);this->difficulty.setString(buff4);if (Highest_score < snake.lenth){Highest_score = snake.lenth;char buff5[10] = { 0 };sprintf_s(buff5, "%d", Highest_score);this->Highest_score_in_history.setString(buff5);}}void draw(){//绘制textwindow.draw(this->game_name);window.draw(this->run_time_Text);window.draw(this->run_time);window.draw(this->lenth_Text);window.draw(this->lenth);window.draw(this->speed_Text);window.draw(this->speedText);window.draw(this->difficulty_Text);window.draw(this->difficulty);window.draw(this->Highest_score_Text);window.draw(this->Highest_score_in_history);}
};class Food
{
public:sf::RectangleShape rec;Food(){}void init(){this->createFood();}void createFood(){//创建食物sf::Vector2f Vtmp(0, 0);srand((unsigned int)time(0));  //随机数种子this->rec.setSize(sf::Vector2f(FOODSIZE, FOODSIZE));this->rec.setFillColor(sf::Color::Blue);this->rec.setScale(sf::Vector2f(1.f, 0.8f));Vtmp = sf::Vector2f(rand() % (int)((1- PWIDTH)*WIDTH) + PWIDTH*WIDTH, rand() % (int)HIGTH);Vtmp.x = limit_float(Vtmp.x, WIDTH*PWIDTH+30, WIDTH-30);Vtmp.y = limit_float(Vtmp.y, 30, HIGTH-30);this->rec.setPosition(Vtmp);cout << "创建food" << endl;}void draw(){window.draw(this->rec);}};

游戏效果

  • 运行效果
     
     

SFML(C++)实现贪吃蛇(带小地图、视角等)相关推荐

  1. 用python自带的tkinter做游戏(一)—— 贪吃蛇 篇

    用python自带的tkinter做游戏(一)-- 贪吃蛇 篇 本人新手,刚自学python满半年,现分享下心得,希望各位老手能指点一二,也希望和我一样的新手能共勉,谢谢~ 大家都知道用python做 ...

  2. 【SFML 贪吃蛇】 FDU_OOP 大作业报告

    面向对象C++大作业报告 193XXXXXXXX 聂XX 作业简介:修改github上的一个snake游戏项目,添加一些特性和功能,需要满足下面的需求. 贪食蛇的控制 源代码只支持 4 个方向的运行, ...

  3. 贪吃蛇—C—基于easyx图形库(下):从画图程序到贪吃蛇【自带穿墙术】

    上节我们用方向控制函数写了个小画图程序,它虽然简单好玩,但我们不应该止步于此.革命尚未成功,同志还需努力. 开始撸代码之前,我们先理清一下思路.和前面画图程序不同,贪吃蛇可以有很多节,可以用一个足够大 ...

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

    运行截图 等待开始界面 运行过程 失败界面截图 SFML配置 csdn上面已经有很多SFML配置的blog,随便就能搜到.正常配置好SFML后,还需要将字体ttf文件放在源代码同一目录和exe同一目录 ...

  5. Qt小游戏教程之贪吃蛇(带源码)

    #1.内容介绍 Qt小游戏开发系列将为大家带来几个用Qt设计可发的几款简单小游戏(贪吃蛇.俄罗斯方块.黑白棋.扫雷).今天将为大家带来的是贪吃蛇游戏的设计思路详解以及代码实现,本博客适用于有一定Qt基 ...

  6. java贪吃蛇博客带图片_java课程设计--贪吃蛇小队博客

    一.团队名称.团队成员介绍.任务分配,团队成员课程设计博客链接(以表格形式呈现) 学号 班级 姓名 任务 201721123103 网络1714 凌俊霄(组长) 蛇体.排行榜(数据库).排错.整体代码 ...

  7. 【Java】Java实现贪吃蛇小游戏(带详细注释)

    源码 源码来源:Java swing 写的贪吃蛇代码200行 前段时间在博客上看到了这段源码,由于自己没有用Java做过小游戏,于是就copy了一下,然后在自己电脑上运行,顺便加上了注释. 代码 gr ...

  8. 用带遗传算法的神经网络解决贪吃蛇问题,看完这篇,从游戏AI角度理解神经网络!(一)

    Designing AI: Solving Snake with Evolution--AI设计:用进化算法解决贪吃蛇问题 前言 The Game of Snake Choosing a Method ...

  9. 前端三小时用html和js写一个贪吃蛇游戏,非常简单带讲解,代码可直接用,功能完整

    目录 游戏主体部分--普通模式 游戏主体部分--地狱模式 游戏主页入口 预览图 游戏入口代码 1.html 2.css 3.js 注册页面代码 游戏实现很简单,只写游戏主体的话只要三小时就够了. 话不 ...

最新文章

  1. Ubuntu恢复默认的字体
  2. JavaScript判断是否是手机mobile登录
  3. 1020 月饼 (25 分)(c语言)
  4. resultset需要关闭吗_旧电脑福音!关闭Windows这些没用的设置,电脑性能至少提升50%!...
  5. 提高速度 - MyEclipse配置
  6. android开发之 SQLite(数据库)
  7. Oracle 导出部分表结构,以及导入
  8. 我,27岁,程序员,今年无情被辞:该转行还是降薪和年轻人抢饭碗?
  9. python求职意向怎么写_软件测试求职意向怎么写(附样本)最新精美简历模板
  10. Python数据分析的几种绘图方式——数据可视化(附源码)
  11. Latex写科技论文小技巧--修改稿件
  12. idea 关闭检查更新_intellij idea怎么关闭自动更新
  13. 企业内部知识共享平台的搭建和应用
  14. Excel VBA高级编程-微信群发消息工具
  15. 数据分析 --- 收集数据的技巧
  16. 影响计算机关键性能参数测试研究,【计算机病毒论文】谈灯光告警计算机测试系统设计(共3104字)...
  17. haproxy负载均衡+pcs高可用+fence
  18. linux 命令学习大全,初学者必备
  19. Node.js学习(express+node项目实战)
  20. 飞蛾云小票打印API,以及小票模板函数

热门文章

  1. linux系统优化,以及jvm优化
  2. YOLO是什么意思?
  3. MUI+H5开发移动APP/网易邮箱大师项目实战/Android、IOS跨平台应用开发-王翠英-专题视频课程...
  4. storyline发布方法_【微课制作】互动式微课怎么搞?Storyline给你“四大招”
  5. 扫黄打非办通报寒假7起典型案件 涉学习及阅读类App
  6. 外贸三个月不出单就没工资,手里都是长线客户,是离职还是熬
  7. WebService详解
  8. 基于OMAP平台的声源定位系统设计与实现
  9. 用计算机无法解决打印所有奇数的问题,浙江省温州市苍南县巨人中学2014-2015学年高二信息技术下学期期中试题...
  10. Redis 大量数据插入