IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 用纯C++代码写一款精美的FlappyBird -> 正文阅读

[C++知识库]用纯C++代码写一款精美的FlappyBird

先上效果图。

游戏的实现主要基于EasyX图形库,有暂停界面、结束界面、游戏音效、游戏存档,并最终集成为一个exe文件。可谓麻雀虽小,五脏俱全?。这里先放出源代码和下载链接,以后有时间会以此为例写一个C++小游戏开发教程系列。

链接:https://pan.baidu.com/s/1sBPD-LTGCTa7bfkI1RloXg?
提取码:8848

组件类及其定义:

#pragma once
#include<graphics.h>
#include<utility>
using namespace std;
typedef pair<double, double> BVec;

class Object
{
	int _x;
	int _y;			//组件基类的四个成员,逻辑坐标(x,y),运动速度v,加速度g,贴图ptr、掩码ym_ptr
	int _width;
	int _height;
	BVec _v;
	BVec _g;
	IMAGE _ptr;
	IMAGE ym_ptr;
public:
	Object(LPCTSTR path, LPCTSTR ympath, int width, int height, int posx= 0, int posy= 0);//构造函数
	Object(LPCTSTR path,  int width, int height, int posx = 0, int posy = 0);
	Object(LPCTSTR path);
	Object():_x(0),_y(0),_width(0),_height(0),_v(make_pair(0,0)),_g(make_pair(0,0)){}
	int x()const{ return _x; };
	int y()const { return _y; };
	BVec v()const { return _v; };   //数据成员操作接口
	BVec g()const { return _g; }
	int width()const { return _width; };
	int height()const { return _height; };
	void setx(int newx) { _x = newx; };
	void sety(int newy) { _y = newy; };
	void setv(int x, int y) { _v.first = x; _v.second = y; };
	void setvx(int x) { _v.first = x; };
	void setvy(int y) { _v.second = y; }
	void setg(BVec newg) { _g = newg; };
	void setptr(IMAGE newptr) { _ptr = newptr; }
	void setptr_ym(IMAGE newptr_ym) { ym_ptr = newptr_ym; }
	void setwidth(int newwidth) { _width = newwidth; }
	void setheight(int newheight) { _height = newheight; }
    void move();//此方法更新组件位置。
	void show_n()const; //显示组件,不显示掩码
	void show()const;  //显示组件和掩码
	~Object() { };
	
};

#include "Object.h"
Object::Object(LPCTSTR path,LPCTSTR ympath, int width, int height, int posx , int posy )
{
	loadimage(&_ptr, _T("PNG"), path, width, height);
	loadimage(&ym_ptr,_T("PNG"), ympath, width, height);
	_x = posx;
	_y = posy;
	_width = width;
	_height = height;
	_v.first = 0;
	_v.second = 0;
	_g.first = 0;
	_g.second = 0;
}
Object::Object(LPCTSTR path, int width, int height, int posx , int posy )
{
	loadimage(&_ptr, _T("PNG"),path, width, height);
	_x = posx;
	_y = posy;
	_width = width;
	_height = height;
	_v.first = 0;
	_v.second = 0;
	_g.first = 0;
	_g.second = 0;
}
Object::Object(LPCTSTR path)
{
	loadimage(&_ptr, path);
	_x = 0;
	_y = 0;
	_width = _ptr.getwidth();
	_height = _ptr.getheight();
	_v.first = 0;
	_v.second = 0;
	_g.first = 0;
	_g.second = 0;
}
void Object::move()
{
	_x += _v.first;
	_y += _v.second;
	_v.first += _g.first;
	_v.second += _g.second;
}
void Object::show_n()const
{
	putimage(_x, _y, &_ptr); 
}
void Object::show()const
{
	putimage(_x, _y, &ym_ptr, SRCAND);
	putimage(_x, _y, &_ptr, SRCPAINT);
}

?角色类及其定义

#pragma once
#include "Object.h"
#include<vector>
class bird :        //角色类继承组件类(游戏角色只有小鸟,故名为小鸟类)
    public Object   //添加动作序列、死亡贴图
{
    vector<IMAGE> seq;
    vector<IMAGE> seq_ym;
    IMAGE die;
    IMAGE die_ym;
    int index = 0;
public:
    bird();
    void add_seq(LPCTSTR path,LPCTSTR ympath);//添加动作序列
    void add_die(LPCTSTR path, LPCTSTR ympath);//添加死亡贴图
    void select_next();//切换动作
    IMAGE& getdie() { return die; }
    IMAGE& getdie_ym() { return die_ym; }
 };
#include "bird.h"
#include "GamePragma.h"
#include<utility>
using std::make_pair;
void bird::add_seq(LPCTSTR path,LPCTSTR ympath)
{
	IMAGE img,ym;
	loadimage(&img,_T("PNG"), path);
	loadimage(&ym, _T("PNG"),ympath);
	seq.push_back(img);
	seq_ym.push_back(ym);
	setptr(seq.back());
	setptr_ym(seq_ym.back());
	setwidth(img.getwidth());
	setheight(img.getheight());
}
void bird::select_next()
{
	int len = seq.size();
	if (index == len - 1)
	{
		index = 0;
	}
	else index++;
	setptr(seq[index]);
	setptr_ym(seq_ym[index]);
}
bird::bird()
{
	setg(make_pair(0, gravity));
	setx(100);
	sety(200);
}
void bird::add_die(LPCTSTR path, LPCTSTR ympath)
{
	loadimage(&die, _T("PNG"), path);
	loadimage(&die_ym,_T("PNG"), ympath);
}

障碍物类及其实现

#pragma once
#include "Object.h"
class Tube :        //管道类继承组件类,添加方向、和小鸟是否通过。
    public Object
{
    int direction;
    bool if_pass ;
public:
    Tube(LPCTSTR path, LPCTSTR ympath, int width, int height, int posx, int posy,int d);
    int getd()const { return direction; }
    bool getp() { return if_pass; }
    void setp(bool p) { if_pass = p; }
};

#include "Tube.h"
Tube::Tube(LPCTSTR path, LPCTSTR ympath, int width, int height, int posx, int posy, int d) :
	Object(path, ympath, width, height, posx, posy)
{
	direction = d;
	if_pass = false;
}

?游戏参数定义

#pragma once
#define WinWidth 800
#define WinHeight 600
#define gravity 0.5
#define BirdUpdate 5
#define TubeWidth 90
#define TubeSpeed -3.5
#define BirdJump -9
#define TubeGenerateSpeed 85
#define CloudSpeed -5

用到的函数

含游戏运作需要的函数
#pragma once
#include "Object.h"
#include "GamePragma.h"
#include<vector>
#include<cmath>
#include "bird.h"
#include"Tube.h"
#include<ctime>
#include<random>
#include<iostream>
using namespace std;
void PlayBg(Object& bg1,Object& bg2)//播放背景
{
	bg1.show_n();
	bg2.setx(bg1.x() + WinWidth);
	bg2.show_n();
	bg1.move();
	bg2.move();
	if (bg1.x() == -WinWidth)bg1.setx(0);
}
void PlayCloud(vector<Object>& cloud,int& count,long double runtime)//播放云
{
	if (!count)
	{
		cloud.push_back(Object(_T("cloud"), _T("cloud_ym"), 0, 0, 800, rand()%400));
		cloud.back().setvx(CloudSpeed);
	}
	for (auto& c : cloud)
	{
		c.show();
		c.move();
	}
	if (count == 130)count = 0;
	else count++;
	if (cloud.front().x() <= -200)
	{
		cloud.erase(cloud.begin());
	}
}
void PlayBird(bird& b,int& flyfreq,bool start)//播放鸟
{
	b.show();
	if(start)
	b.move();


	if (flyfreq == 8)
	{
		b.select_next();
		flyfreq = 0;
	}
	else flyfreq++;
	
}
int TubeGenerator()//生成障碍物高度。所用的分布与正态分布图像关于x轴对称
{
	mt19937 rng;
	rng.seed(std::random_device()());
	std::uniform_int_distribution<int> dist(30, 390);
	int h = dist(rng);
	if (h >= 210)h -= 180;
	else h += 180;
	return h;
}
void PlayTube(vector<Tube>& tube, int& count)//播放障碍物
{
	if (!count)
	{
		int h = TubeGenerator();
		tube.push_back(Tube(_T("tube"), _T("tube_ym"), TubeWidth, h, 800, 0,0));
		tube.back().setvx(TubeSpeed);
		tube.push_back(Tube(_T("rtube"), _T("rtube_ym"), TubeWidth, 400-h, 800, 200+h, 1));
		tube.back().setvx(TubeSpeed);

	}
	if (count == TubeGenerateSpeed)count = 0;
	else count++;
	for (auto& t : tube)
	{
		t.show();
		t.move();
	}
	
	if (!tube.empty()&&tube.front().x() <= -100)
	{
		tube.erase(tube.begin());
		tube.erase(tube.begin());
	}
}
int CheckColid(const vector<Tube>& tube,const bird& b)//碰撞检测
{
	int bx1 = b.x();
	int by1 = b.y();
	int bx2 = bx1 + b.width();
	int by2 = by1 + b.height();
	for (int i =0; i < tube.size(); i++)
	{
		int d = tube[i].getd();
		int tx1 = tube[i].x();
		int ty1 = tube[i].y();
		int tx2 = tx1 + tube[i].width();
		int ty2 = ty1 + tube[i].height();
		bool s1 = (d == 0 && tx1 <= bx1 && bx1 <= tx2 && (by1+20) <= ty2);
		bool s2= (d == 0 && tx1 <= bx2-5 && bx2-5 <= tx2 && by1 <= ty2);
		bool s3= (d == 1 && tx1 <= bx1+20 && bx1+20 <= tx2 && by2-5 >= ty1);
		bool s4= (d == 1 && tx1 <= bx2-20 && bx2-20 <= tx2 && by2-5 >= ty1);
		if (s1 || s2 || s3 || s4)return true;
	}
	return false;
}
void PlayBirdDie(bird& b)//播放鸟死亡动画
{
	b.setvy(5);
	b.setptr(b.getdie());
	b.setptr_ym(b.getdie_ym());
	b.show();
	b.move();
}
void add_score(vector<Tube>&tube, long int& score)//计分器
{
	for (auto it = tube.begin(); it != tube.end(); it++)
	{
		if ((*it).getp() == false)
		{
			if ((*it).x() <= 20)
			{
				(*it).setp(true);
				score++;
				it++;
				(*it).setp(true);
				break;
			}
		}
	}
}
int GetPauseMenuAct(ExMessage& p)//获取玩家在用户界面的操作
{
	if (329 <= p.x && p.x <= 468 && 147 <= p.y && p.y <= 186)return 1;
	if (329 <= p.x && p.x <= 468 && 260 <= p.y && p.y <= 300)return 2;
	if (329 <= p.x && p.x <= 468 && 375 <= p.y && p.y <= 413)return 3;
	return 0;
}
int GetOverMenuAct(ExMessage& p)//获取玩家在结束界面的操作
{
	if (330 <= p.x && p.x <= 470 && 320 <= p.y && p.y <= 360)return 1;
	if (330 <= p.x && p.x <= 470 && 395 <= p.y && p.y <= 435)return 2;
	return 0;
}

主函数

#include<graphics.h>
#include<conio.h>
#include<windows.h>
#include "Object.h"
#include "function.h"
#include<vector>
#include<ctime>
#include<windows.h>
#include"Tube.h"
#include<string>
#include<fstream>
#include<Mmsystem.h>
#include<dsound.h>
#include<stdio.h>
#pragma comment(lib,"WINMM.LIB")
#define KEY_DOWN(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000) ? 1:0)
using namespace std;
int main()
{
	

	initgraph(800, 600);
	BEGIN:
	Object Background1(_T("Background"), 800, 600);             //加载贴图资源及相关变量
	Object Background2(_T("Background"), 800, 600);
	
	Background1.setv(-1, 0);
	Background2.setv(-1, 0);
	
	Object pausemenu(_T("pausemenu"), _T("pausemenu_ym"),400,450,200,50);
	Object overmenu(_T("overmenu"), _T("overmenu_ym"), 400, 450, 200,-500);
	Object startflag(_T("startflag"), _T("startflag_ym"), 0, 0, 200, 200);
	bird b;
	b.add_seq(_T("bird1"), _T("bird1_ym"));
	b.add_seq(_T("bird2"), _T("bird2_ym"));
	b.add_seq(_T("bird3"), _T("bird3_ym"));
	b.add_seq(_T("bird4"), _T("bird4_ym"));
	b.add_die(_T("bird_die"), _T("bird_die_ym"));
	vector<Tube> tube;
	vector<Object> cloud;
	int cloudcount = 0;
	int tubecount = 0;
	int flyfreq = 0;
	int birdcount = 0;
	
	
	time_t begin, now;
	double runtime;
	begin = clock();
	bool start = false;
	
	long int score = 0;
	settextstyle(50, 0, _T("JandaManateesolid"));
	
	setbkmode(TRANSPARENT);
	BeginBatchDraw();
	bool firstflag = true;
	bool LASTKEYDOWN = false;
	
    GAMING:
	while (true)//主循环
	{
		
		if (_kbhit())         //检测是否按下ESC键暂停
		{
			int a = _getch();
			if (a == 27)
			{
				
				pausemenu.show();
				FlushBatchDraw();
				ExMessage m;
				while (1)
				{
					peekmessage(&m);
					if (KEY_DOWN(VK_LBUTTON))  //检测选择
					{					
						
							int selection = GetPauseMenuAct(m);
							switch (selection)
							{
							case 0:break;
							case 1:
								PlaySound(TEXT("click"), NULL, SND_RESOURCE | SND_ASYNC );//播放点击音效
								Sleep(100);
								goto GAMING;  //选择Resume,回到主循环
	
							case 2:
								PlaySound(TEXT("click"), NULL, SND_RESOURCE | SND_ASYNC );
								goto BEGIN;   //选择Restart,跳转到开始
							case 3:
								PlaySound(TEXT("click"), NULL, SND_RESOURCE | SND_ASYNC );
								Sleep(100);   //选择Exit退出游戏
								exit(1);
							}
						
					}
				
				}
	
			}
		}	
		now = clock();
		runtime = (now - begin) / CLOCKS_PER_SEC;   //记录游戏运行时间
		PlayBg(Background1, Background2);		
		PlayCloud(cloud, cloudcount, runtime);	//使各贴图运动
		PlayBird(b, flyfreq,start);
	
		if (start)
		{
			PlayTube(tube, tubecount);  //游戏进行过程加载障碍物和计分器
			add_score(tube, score);
			
		}
		TCHAR scorestr[10];
		_stprintf_s(scorestr, _T("%d"), score);
		
		outtextxy(380- 13 * (to_string(score).length() - 1), 20, scorestr); //打印分数
	
		if (KEY_DOWN(VK_LBUTTON))    //检测是否单击鼠标左键并松开。
		{
			if (!LASTKEYDOWN)
			{
				b.setvy(BirdJump);   //重设速度使小鸟跳跃
				start = true;
				LASTKEYDOWN = true;
				PlaySound(TEXT("plop"), NULL, SND_RESOURCE | SND_ASYNC );//播放音效
				
			}
					
		}
		else
		{
			LASTKEYDOWN = false;
		}
		
		FlushBatchDraw();//刷新帧
		if (CheckColid(tube, b) || b.y() >= 620||b.y()<=-50) //死亡检测
		{
			
			PlaySound(TEXT("die"), NULL, SND_RESOURCE | SND_ASYNC);//播放结束音乐及动画
			b.setvy(-5);
			b.setptr(b.getdie());
			b.setptr_ym(b.getdie_ym());
			ifstream f("data.dat", ios::binary | ios::in);
			long int best;
			if (!f.is_open())                             //更新最高分
			{
				f.close();
				ofstream fo("data.dat", ios::binary);
				fo.write((char*)&score, sizeof(long int));
				best = score;
				fo.close();
			}
			else
			{
				f.read((char*)&best, sizeof(long int));
				if (score > best)
				{
					best = score;
					f.close();
					ofstream fo("data.dat", ios::binary);
					fo.write((char*)&score,sizeof(score));
					fo.close();
				}
				f.close();
			}
			while (true)  //死亡动画次循环
			{
				PlayBg(Background1, Background2);
				for (auto& c : cloud)
				{
					c.show();
				}
				for (auto& t : tube)
				{
					t.show();
				}
				outtextxy(370 , 20, scorestr);
				b.show();
				b.move();			
				FlushBatchDraw();
				Sleep(1);
				if (b.y() >= 620)
				{
					ExMessage m;
					overmenu.setvy(10);
					TCHAR scorestr[10];
					_stprintf_s(scorestr, _T("%d"), score);
					
					TCHAR beststr[10];
					_stprintf_s(beststr, _T("%d"), best);
					while (true)  //结束菜单播放次循环
					{
						PlayBg(Background1, Background2);
						for (auto& c : cloud)
						{
							c.show();
						}
						for (auto& t : tube)
						{
							t.show();
						}
						overmenu.show();
						outtextxy(395-13*(to_string(score).length()-1), overmenu.y()+110, scorestr);
						outtextxy(395 - 13 * (to_string(best).length() - 1), overmenu.y() + 200, beststr);
						if (overmenu.y() < 50)
						{
							overmenu.move();
						}
						else
						{
	
							while (true)//等候操作次循环
							{
								peekmessage(&m);
								if (KEY_DOWN(VK_LBUTTON))
								{
									int selection = GetOverMenuAct(m);
									switch (selection)
									{
									case 1: 
										PlaySound(TEXT("click"), NULL, SND_RESOURCE | SND_ASYNC );
										goto BEGIN;
									case 2: 
										PlaySound(TEXT("click"), NULL, SND_RESOURCE | SND_ASYNC );
										Sleep(100);
										exit(1);
									default: break;
									}
								}
								
							}
							closegraph();
						}
						FlushBatchDraw();
						Sleep(1);
					}
					
				}
			}
			
		}
		Sleep(1);
	}
	
	EndBatchDraw();


	closegraph();
	return 0;
}
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-10-22 10:47:24  更:2021-10-22 10:48:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 3:14:16-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码