Advertisement

基于Easyx的打字游戏

阅读量:

一、效果展示

1.游戏开始时的界面:

2.游戏中的画面

3.游戏失败后的界面

二、准备开发环境

  • 在官网上下载Easyx安装包文件(https://easyx.cn/)
  • 双击exe文件,点击下一步
在这里插入图片描述
  • 选择VC++2022
在这里插入图片描述
  • 弹出安装成功提示
在这里插入图片描述
  • 在VS2022上新建一个空项目工程

二、实现思路

1.引入库头文件

代码如下:

复制代码
    #include<easyx.h>
    
    AI生成项目c

2.游戏对象类的创立

类声明

复制代码
 class Letter

    
 {
    
 private:
    
 	int x;
    
 	int y;
    
 	int speed;
    
 	char ch;
    
 public:
    
 	//字母偏移量
    
 	static int dx[26];
    
 	//获取字母接口
    
 	char get_ch();
    
 	//获取纵坐标接口
    
 	int get_y();
    
 	//指向下一个结点
    
 	Letter* next;
    
 	//构造函数
    
 	Letter(Letter* LetterList);
    
 	//渲染自己
    
 	void drawLetter();
    
 	//更新自身坐标
    
 	void modifyPos();
    
 };
    
    
    
    
    AI生成项目cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-13/eoACawyZh4K38RuY9VMzLSrlImE5.png)

类成员函数实现

复制代码
 #include<iostream>

    
 #include "Letter.h"
    
 #define FPS 90//帧率不能超过90
    
  
    
 int Letter::dx[26] = { 22, 22, 22, 22, 24, 24, 21, 20, 26, 22, 22, 24, 17,
    
 				  20, 20, 23, 21, 22, 24, 22, 20, 21, 16, 21, 22, 22 };
    
 extern IMAGE LetterImg;
    
 char Letter::get_ch() {
    
 	return this->ch;
    
 }
    
  
    
 int Letter::get_y() {
    
 	return this->y;
    
 }
    
  
    
 Letter::Letter(Letter* LetterList) {
    
 	this->y = 0;
    
 	this->speed = rand() % 2 + 1;
    
 	//不允许创建对象时字母一样以及萝卜重合
    
 end:
    
 	this->ch = 'A' + rand() % 26;
    
 	this->x = rand() % (900 - 40) + 40;
    
 	for (Letter* p = LetterList; p; p = p->next) {
    
 		if (p->ch == this->ch || fabs(p->x - this->x) <= 50) {
    
 			goto end;
    
 		}
    
 	}
    
 }
    
  
    
 void Letter::drawLetter() {
    
 	//绘制字体
    
 	DWORD* dst = GetImageBuffer();
    
 	DWORD* draw = GetImageBuffer();
    
 	DWORD* src = GetImageBuffer(&LetterImg);
    
 	int picture_width = (&LetterImg)->getwidth();
    
 	int picture_height = (&LetterImg)->getheight();
    
 	int graphWidth = getwidth();
    
 	int graphHeight = getheight();
    
 	int dstX = 0;
    
 	for (int iy = 0; iy < picture_height; iy++)
    
 	{
    
 		for (int ix = 0; ix < picture_width; ix++)
    
 		{
    
 			int srcX = ix + iy * picture_width;
    
 			int sa = ((src[srcX] & 0xff000000) >> 24);
    
 			int sr = ((src[srcX] & 0xff0000) >> 16);
    
 			int sg = ((src[srcX] & 0xff00) >> 8);
    
 			int sb = src[srcX] & 0xff;
    
 			if (ix >= 0 && ix <= graphWidth && iy >= 0 && iy <= graphHeight && dstX <= graphWidth * graphHeight)
    
 			{
    
 				dstX = (ix + this->x) + (iy + this->y) * graphWidth;
    
 				int dr = ((dst[dstX] & 0xff0000) >> 16);
    
 				int dg = ((dst[dstX] & 0xff00) >> 8);
    
 				int db = dst[dstX] & 0xff;
    
 				draw[dstX] = ((sr * sa / 255 + dr * (255 - sa) / 255) << 16)
    
 					| ((sg * sa / 255 + dg * (255 - sa) / 255) << 8)
    
 					| (sb * sa / 255 + db * (255 - sa) / 255);
    
 			}
    
 		}
    
 	}
    
 	//绘制字母
    
 	LOGFONT f1;//设置字体
    
 	gettextstyle(&f1);
    
 	f1.lfHeight = 40;
    
 	f1.lfWeight = 30;
    
 	strcpy(f1.lfFaceName, "Segoe UI Black");  //字体名字
    
 	f1.lfQuality = ANTIALIASED_QUALITY;       //抗锯齿
    
 	settextstyle(&f1);
    
 	setbkmode(TRANSPARENT);                  //字体的背景透明
    
 	settextcolor(BLACK);                     //字体颜色
    
 	outtextxy(this->x + dx[this->ch - 'A'], this->y + 40, this->ch);
    
 }
    
  
    
 void Letter::modifyPos() {
    
 	this->y += this->speed * 90 / FPS;
    
 }
    
    
    
    
    AI生成项目cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-13/DXeqmcbCj7KtHLQh8Ndy1fzrvoVU.png)

成员变量:

1、int x,y 用于定位萝卜在游戏界面上的坐标

2、int speed 是萝卜往下掉落的速度

3、char ch 是用来决定生成萝卜上的字母

本项目使用链表数据结构对对象进行组织与管理,并在类中的每个对象中分配一个Letter指针next成员变量用于指向下一个结点

成员函数:

static int dx[26]:以确保各字母在萝卜模型中居中显示,并需测定各字母相对于萝卜模型横向坐标轴的最佳偏移量;以便各对象均基于此固定偏移量进行创建

经过测试得到26个字母每个的最佳偏移值:

将变量x、y和speed设为私有属性以防止外界访问,并为此实现了int get_x()以及char get_ch()的接口以供外界进行读取操作

3、调用drawLetter()接口时程序会在(x, y)处渲染出萝卜

4、每次调用modifyPos()时都会更新萝卜的位置坐标

3.程序入口

复制代码
 int main() {

    
 	initgraph(1000, 600);
    
 	gameInit();//初始化
    
 	gameLoop();//进入游戏循环
    
 	closegraph();//关闭绘图窗口
    
 	return 0;
    
 }
    
    
    
    
    AI生成项目cpp

通过initgraph()函数创建一个1000×600像素的游戏界面

4.游戏数据初始化

复制代码
 IMAGE bg;

    
 IMAGE gameover;
    
 IMAGE sta;
    
 IMAGE LetterImg;
    
 //游戏初始化
    
 void gameInit() {
    
 	loadimage(&bg, "./bg.jpg", 1000, 600);
    
 	loadimage(&gameover, "./gameover.jpeg", 1000, 600);
    
 	loadimage(&sta, "./sta.jpeg", 1000, 600);
    
 	loadimage(&LetterImg, "./letter.png", 60, 90);
    
 	putimage(0, 0, &sta);
    
 	srand((unsigned)time(NULL));
    
 }
    
    
    
    
    AI生成项目cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-13/DnySPIWrOhXtflQsGpvELT8aogm5.png)

利用IMAGE变量类型构建了背景图景、游戏结局画面、游戏启动界面画面以及角色图像

loadimage()函数可以加载指定路径上的图片到IMAGE类型的变量当中

游戏初始化时通过putimage()函数将游戏开始时的界面渲染出

5.游戏循环

1.按键监听部分

复制代码
 //按键消息处理

    
 bool Key(Letter* LetterList, int& Score) {
    
 	if (_kbhit()) {
    
 		bool isDownError = true;
    
 		char dowsKey = _getch();
    
 		//删除萝卜
    
 		deleteNode(LetterList, dowsKey, isDownError);
    
 		//删除后又创建萝卜增加可玩性
    
 		getLetter(LetterList);
    
 		if (!isDownError) {
    
 			Score++;
    
 		}
    
 		return isDownError;
    
 	}
    
 	return false;
    
 }
    
    
    
    
    AI生成项目cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-13/15KVNu8pnM06yZhF7wgYvRmWjtOS.png)

该函数用来检测用户按下输入的字母是否存在于当前画面上。如果在当前画面上找到了该字母,则会删除对应的对象并返回false;否则则会返回true并结束游戏流程。

删除萝卜对象代码

复制代码
 //删除对象

    
 void deleteNode(Letter* LetterList, char key, bool& isDownError) {
    
 	Letter* current = LetterList;
    
 	Letter* prev = nullptr;
    
  
    
 	while (current) {
    
 		if (current->get_ch() == key) {
    
 			isDownError = false;
    
 			if (prev) {
    
 				prev->next = current->next;
    
 			}
    
 			else {
    
 				LetterList = current->next;
    
 			}
    
 			Letter* temp = current;
    
 			current = current->next;
    
 			delete temp;
    
 		}
    
 		else {
    
 			prev = current;
    
 			current = current->next;
    
 		}
    
 	}
    
 }
    
    
    
    
    AI生成项目cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-13/3Ra0OkIYiob1s9WcGEKzXqv2xM74.png)

2.鼠标信息监听部分

复制代码
 //处理鼠标点击事件

    
 void Message_processing() {
    
 	ExMessage msg;
    
 	static bool isRun = false;//游戏是否
    
 	static int cout = 5;//暂停次数
    
 	//没有产生鼠标消息
    
 	while (!isRun) {
    
 		//鼠标左键按下
    
 		if (peekmessage(&msg) && msg.message == WM_LBUTTONDOWN) {
    
 			//鼠标点击了开始按钮
    
 			if (msg.x > 1 && msg.x < 139 && msg.y>530 && msg.y < 568) {
    
 				isRun = true;
    
 			}
    
 		}
    
 	}
    
 	if (peekmessage(&msg) && msg.message == WM_LBUTTONDOWN) {
    
 		//鼠标点击了暂停游戏
    
 		if (msg.x > 193 && msg.x < 324 && msg.y>535 && msg.y < 566 && cout) {
    
 			cout--;
    
 			isRun = false;
    
 		}
    
 	}
    
 }
    
    
    
    
    AI生成项目cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-13/KrhBVn4mApFdX0ayNHQw9Cz5LITs.png)

监听用户是否按了暂停键或者开始键

3.游戏数据更新

复制代码
 //游戏数据更新

    
 void update(Letter* LetterList) {
    
 	//生成萝卜
    
 	getLetter(LetterList);
    
 	//更新萝卜
    
 	for (Letter* p = LetterList->next; p; p = p->next) {
    
 		p->modifyPos();
    
 	}
    
 }
    
    
    
    
    AI生成项目cpp

用于创建新对象以及更新现有对象的坐标

getLetter():

复制代码
 //创建萝卜

    
 void getLetter(Letter* LetterList) {
    
 	static int timer = 0;
    
 	static int randTime = rand() % (200 * FPS / 90);
    
 	Letter* p = LetterList;
    
 	if (timer == randTime) {//200 * 10 ms = 2秒   //每间隔 2-3秒 之间生成一个对象
    
 		timer = 0;
    
 		randTime = rand() % (100 * FPS / 90) + (100 * FPS / 90);
    
 		for (int i = 0; i < NUM; i++) {
    
 			while (p->next) {
    
 				p = p->next;
    
 			}
    
 			Letter* LetterTemp = new Letter(LetterList);
    
 			p->next = LetterTemp;
    
 			p = p->next;
    
 			p->next = NULL;
    
 		}
    
 	}
    
 	timer++;
    
 }
    
    
    
    
    AI生成项目cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-13/4ip60lhZKULnyrbkAIDuQvdRfO31.png)

声明静态变量timer用于计数。每当函数update()被调用时,计数值将增加1次。当计数值达到预定值randTime时,则会生成一个萝卜并清空计数器;此时会将该值重置为新的随机数randTime以准备下次循环。

此游戏运行时每秒可执行90次更新操作(实现原理在后面),即每次update()函数被调用的时间间隔约为1/90秒,在每次更新操作中都会基于当前状态计算出下一状态的数据。通常情况下,在大约每隔2秒的时间段内会生成3个萝卜(其中宏NUM决定了生成的数量)。

4.检测萝卜是否越界

复制代码
 //检测萝卜是否越界

    
 bool detection(Letter* LetterList) {
    
 	for (Letter* p = LetterList->next; p; p = p->next) {
    
 		if (p->get_y() >= 510) {
    
 			return true;
    
 		}
    
 	}
    
 	return false;
    
 }
    
    
    
    
    AI生成项目cpp

依次访问萝卜对象的列表结构,并对其中是否存在纵坐标超过510的萝卜进行检查;如果发现存在,则导致游戏结束。

5.渲染游戏界面

复制代码
 //渲染画面

    
 void draw(Letter* LetterList, const int& Score) {
    
 	BeginBatchDraw();
    
 	cleardevice();
    
  
    
 	//背景图片
    
 	putimage(0, 0, &bg);
    
  
    
 	//渲染得分
    
 	drawScore(Score);
    
  
    
 	//绘制萝卜
    
 	for (Letter* p = LetterList->next; p; p = p->next) {
    
 		p->drawLetter();
    
 	}
    
  
    
 	FlushBatchDraw();
    
 }
    
    
    
    
    AI生成项目cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-13/l7XbNGnWQH2cC8dVt6MBr4goJISy.png)

循环遍历萝卜对象链表,并依次调用每个萝卜对象的drawLetter()方法来绘制自身,并同时生成相应的分数结果

该函数也是1秒钟调用90次(90帧),每帧调用更新当前帧画面

6.游戏循环部分完整代码

复制代码
 //游戏循环

    
 void gameLoop() {
    
 end:
    
 	int timer = 0;
    
 	int Score = 0;
    
 	Letter* LetterList = new Letter(NULL);//创建萝卜链表
    
 	LetterList->next = NULL;
    
 	while (1) {
    
 		//按的字母屏幕上没有
    
 		if (Key(LetterList, Score)) {
    
 			break;
    
 		}
    
 		Message_processing();//处理鼠标点击事件
    
 		if (timer > 1000 / FPS) {
    
 			timer = 0;
    
 			update(LetterList);
    
 			if (detection(LetterList)) {
    
 				break;
    
 			}
    
 			draw(LetterList, Score);
    
 		}
    
 		timer += getDelay();
    
 	}
    
 	//游戏结束
    
 	BeginBatchDraw();
    
 	cleardevice();
    
 	putimage(0, 0, &gameover);
    
 	drawScore(Score);//渲染得分
    
 	FlushBatchDraw();
    
 	while (1) {
    
 		if (_getch() == 32) {
    
 			goto end;
    
 		}
    
 	}
    
 }
    
    
    
    
    AI生成项目cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-13/b20AEGcp689f3lsdkTPZmzvLyWFI.png)

getDelay()返回上一次调用与当前调用的时间差(ms)

通过定期计数器timer每次运行时累加一次的时间差值,在累计值超过每秒(即1秒=1000/FPS)时触发执行一帧的操作,并最终使update()与draw()函数每秒可完成90次调用(生成90帧)

6.游戏得分渲染

复制代码
 BeginBatchDraw();

    
 cleardevice();
    
 putimage(0, 0, &gameover);
    
 drawScore(Score);//渲染得分
    
 FlushBatchDraw();
    
 while (1) {
    
 	if (_getch() == 32) {
    
 		goto end;
    
 	}
    
 }
    
    
    
    
    AI生成项目cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-13/m4RXd6reE9HvxCnPiAgl3215hUtb.png)

游戏结束后退出游戏循环,渲染得分,若按空格则重新开始游戏


三、完整代码

main.cpp

复制代码
 #include<easyx.h>

    
 #include<iostream>
    
 #include<conio.h>
    
 #include<ctime>
    
 #include<string>
    
 #include "Letter.h"
    
 #define FPS 90//帧率不能超过90
    
 #define NUM 3  //每次往下掉的数量
    
 using namespace std;
    
  
    
 IMAGE bg;
    
 IMAGE gameover;
    
 IMAGE sta;
    
 IMAGE LetterImg;
    
  
    
 //定时器
    
 int getDelay()
    
 {
    
 	static unsigned long long lasttime = 0;
    
 	unsigned long long curr = GetTickCount();
    
 	if (lasttime == 0)
    
 	{
    
 		lasttime = curr;
    
 		return 0;
    
 	}
    
 	else
    
 	{
    
 		int ret = curr - lasttime;
    
 		lasttime = curr;
    
 		return ret;
    
 	}
    
 }
    
  
    
 //游戏初始化
    
 void gameInit() {
    
 	loadimage(&bg, "./bg.jpg", 1000, 600);
    
 	loadimage(&gameover, "./gameover.jpeg", 1000, 600);
    
 	loadimage(&sta, "./sta.jpeg", 1000, 600);
    
 	loadimage(&LetterImg, "./letter.png", 60, 90);
    
 	putimage(0, 0, &sta);
    
 	srand((unsigned)time(NULL));
    
 }
    
  
    
 //删除对象
    
 void deleteNode(Letter* LetterList, char key, bool& isDownError) {
    
 	Letter* current = LetterList;
    
 	Letter* prev = nullptr;
    
  
    
 	while (current) {
    
 		if (current->get_ch() == key) {
    
 			isDownError = false;
    
 			if (prev) {
    
 				prev->next = current->next;
    
 			}
    
 			else {
    
 				LetterList = current->next;
    
 			}
    
 			Letter* temp = current;
    
 			current = current->next;
    
 			delete temp;
    
 		}
    
 		else {
    
 			prev = current;
    
 			current = current->next;
    
 		}
    
 	}
    
 }
    
  
    
 //创建萝卜
    
 void getLetter(Letter* LetterList) {
    
 	static int timer = 0;
    
 	static int randTime = rand() % (200 * FPS / 90);
    
 	Letter* p = LetterList;
    
 	if (timer == randTime) {//200 * 10 ms = 2秒   //每间隔 2-3秒 之间生成一个对象
    
 		timer = 0;
    
 		randTime = rand() % (100 * FPS / 90) + (100 * FPS / 90);
    
 		for (int i = 0; i < NUM; i++) {
    
 			while (p->next) {
    
 				p = p->next;
    
 			}
    
 			Letter* LetterTemp = new Letter(LetterList);
    
 			p->next = LetterTemp;
    
 			p = p->next;
    
 			p->next = NULL;
    
 		}
    
 	}
    
 	timer++;
    
 }
    
  
    
 //按键消息处理
    
 bool Key(Letter* LetterList, int& Score) {
    
 	if (_kbhit()) {
    
 		bool isDownError = true;
    
 		char dowsKey = _getch();
    
 		//删除萝卜
    
 		deleteNode(LetterList, dowsKey, isDownError);
    
 		//删除后又创建萝卜增加可玩性
    
 		getLetter(LetterList);
    
 		if (!isDownError) {
    
 			Score++;
    
 		}
    
 		return isDownError;
    
 	}
    
 	return false;
    
 }
    
  
    
 //游戏数据更新
    
 void update(Letter* LetterList) {
    
 	//生成萝卜
    
 	getLetter(LetterList);
    
 	//更新萝卜
    
 	for (Letter* p = LetterList->next; p; p = p->next) {
    
 		p->modifyPos();
    
 	}
    
 }
    
  
    
 //检测萝卜是否越界
    
 bool detection(Letter* LetterList) {
    
 	for (Letter* p = LetterList->next; p; p = p->next) {
    
 		if (p->get_y() >= 510) {
    
 			return true;
    
 		}
    
 	}
    
 	return false;
    
 }
    
  
    
 //渲染得分
    
 void drawScore(const int& Score) {
    
 	LOGFONT f1;//设置字体
    
 	gettextstyle(&f1);
    
 	f1.lfHeight = 100;
    
 	f1.lfWeight = 80;
    
 	strcpy(f1.lfFaceName, "Segoe UI Black");  //字体名字
    
 	f1.lfQuality = ANTIALIASED_QUALITY;       //抗锯齿
    
 	settextstyle(&f1);
    
 	setbkmode(TRANSPARENT);                  //字体的背景透明
    
 	settextcolor(BLACK);                     //字体颜色
    
 	char scoreStr[8];
    
 	sprintf_s(scoreStr, "%d", Score);
    
 	if (Score >= 100) {
    
 		outtextxy(835, 420, scoreStr);
    
 	}
    
 	if (Score >= 10 && Score < 100) {
    
 		outtextxy(855, 420, scoreStr);
    
 	}
    
 	else {
    
 		outtextxy(875, 420, scoreStr);
    
 	}
    
  
    
 }
    
  
    
 //渲染画面
    
 void draw(Letter* LetterList, const int& Score) {
    
 	BeginBatchDraw();
    
 	cleardevice();
    
  
    
 	//背景图片
    
 	putimage(0, 0, &bg);
    
  
    
 	//渲染得分
    
 	drawScore(Score);
    
  
    
 	//绘制萝卜
    
 	for (Letter* p = LetterList->next; p; p = p->next) {
    
 		p->drawLetter();
    
 	}
    
  
    
 	FlushBatchDraw();
    
 }
    
  
    
 //处理鼠标点击事件
    
 void Message_processing() {
    
 	ExMessage msg;
    
 	static bool isRun = false;//游戏是否
    
 	static int cout = 5;//暂停次数
    
 	//没有产生鼠标消息
    
 	while (!isRun) {
    
 		//鼠标左键按下
    
 		if (peekmessage(&msg) && msg.message == WM_LBUTTONDOWN) {
    
 			//鼠标点击了开始按钮
    
 			if (msg.x > 1 && msg.x < 139 && msg.y>530 && msg.y < 568) {
    
 				isRun = true;
    
 			}
    
 		}
    
 	}
    
 	if (peekmessage(&msg) && msg.message == WM_LBUTTONDOWN) {
    
 		//鼠标点击了暂停游戏
    
 		if (msg.x > 193 && msg.x < 324 && msg.y>535 && msg.y < 566 && cout) {
    
 			cout--;
    
 			isRun = false;
    
 		}
    
 	}
    
 }
    
  
    
 //游戏循环
    
 void gameLoop() {
    
 end:
    
 	int timer = 0;
    
 	int Score = 0;
    
 	Letter* LetterList = new Letter(NULL);//创建萝卜链表
    
 	LetterList->next = NULL;
    
 	while (1) {
    
 		//按的字母屏幕上没有
    
 		if (Key(LetterList, Score)) {
    
 			break;
    
 		}
    
 		Message_processing();//处理鼠标点击事件
    
 		if (timer > 1000 / FPS) {
    
 			timer = 0;
    
 			update(LetterList);
    
 			if (detection(LetterList)) {
    
 				break;
    
 			}
    
 			draw(LetterList, Score);
    
 		}
    
 		timer += getDelay();
    
 	}
    
 	//游戏结束
    
 	BeginBatchDraw();
    
 	cleardevice();
    
 	putimage(0, 0, &gameover);
    
 	drawScore(Score);//渲染得分
    
 	FlushBatchDraw();
    
 	while (1) {
    
 		if (_getch() == 32) {
    
 			goto end;
    
 		}
    
 	}
    
 }
    
 int main() {
    
 	initgraph(1000, 600);
    
 	gameInit();//初始化
    
 	gameLoop();//进入游戏循环
    
 	closegraph();//关闭绘图窗口
    
 	return 0;
    
 }
    
    
    
    
    AI生成项目cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-13/Chl8YmP2bTQo1e6RH4J7qXLziuUj.png)

Letter.h

复制代码
 #pragma once

    
 #include<easyx.h>
    
 class Letter
    
 {
    
 private:
    
 	int x;
    
 	int y;
    
 	int speed;
    
 	char ch;
    
 public:
    
 	//字母偏移量
    
 	static int dx[26];
    
 	//获取字母接口
    
 	char get_ch();
    
 	//获取纵坐标接口
    
 	int get_y();
    
 	//指向下一个结点
    
 	Letter* next;
    
 	//构造函数
    
 	Letter(Letter* LetterList);
    
 	//渲染自己
    
 	void drawLetter();
    
 	//更新自身坐标
    
 	void modifyPos();
    
 };
    
    
    
    
    AI生成项目cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-13/w4V3ncY0m97Z6JXpWQRkfqdLMGls.png)

Letter.cpp

复制代码
 #include<iostream>

    
 #include "Letter.h"
    
 #define FPS 90//帧率不能超过90
    
  
    
 int Letter::dx[26] = { 22, 22, 22, 22, 24, 24, 21, 20, 26, 22, 22, 24, 17,
    
 				  20, 20, 23, 21, 22, 24, 22, 20, 21, 16, 21, 22, 22 };
    
 extern IMAGE LetterImg;
    
 char Letter::get_ch() {
    
 	return this->ch;
    
 }
    
  
    
 int Letter::get_y() {
    
 	return this->y;
    
 }
    
  
    
 Letter::Letter(Letter* LetterList) {
    
 	this->y = 0;
    
 	this->speed = rand() % 2 + 1;
    
 	//不允许创建对象时字母一样以及萝卜重合
    
 end:
    
 	this->ch = 'A' + rand() % 26;
    
 	this->x = rand() % (900 - 40) + 40;
    
 	for (Letter* p = LetterList; p; p = p->next) {
    
 		if (p->ch == this->ch || fabs(p->x - this->x) <= 50) {
    
 			goto end;
    
 		}
    
 	}
    
 }
    
  
    
 void Letter::drawLetter() {
    
 	//绘制字体
    
 	DWORD* dst = GetImageBuffer();
    
 	DWORD* draw = GetImageBuffer();
    
 	DWORD* src = GetImageBuffer(&LetterImg);
    
 	int picture_width = (&LetterImg)->getwidth();
    
 	int picture_height = (&LetterImg)->getheight();
    
 	int graphWidth = getwidth();
    
 	int graphHeight = getheight();
    
 	int dstX = 0;
    
 	for (int iy = 0; iy < picture_height; iy++)
    
 	{
    
 		for (int ix = 0; ix < picture_width; ix++)
    
 		{
    
 			int srcX = ix + iy * picture_width;
    
 			int sa = ((src[srcX] & 0xff000000) >> 24);
    
 			int sr = ((src[srcX] & 0xff0000) >> 16);
    
 			int sg = ((src[srcX] & 0xff00) >> 8);
    
 			int sb = src[srcX] & 0xff;
    
 			if (ix >= 0 && ix <= graphWidth && iy >= 0 && iy <= graphHeight && dstX <= graphWidth * graphHeight)
    
 			{
    
 				dstX = (ix + this->x) + (iy + this->y) * graphWidth;
    
 				int dr = ((dst[dstX] & 0xff0000) >> 16);
    
 				int dg = ((dst[dstX] & 0xff00) >> 8);
    
 				int db = dst[dstX] & 0xff;
    
 				draw[dstX] = ((sr * sa / 255 + dr * (255 - sa) / 255) << 16)
    
 					| ((sg * sa / 255 + dg * (255 - sa) / 255) << 8)
    
 					| (sb * sa / 255 + db * (255 - sa) / 255);
    
 			}
    
 		}
    
 	}
    
 	//绘制字母
    
 	LOGFONT f1;//设置字体
    
 	gettextstyle(&f1);
    
 	f1.lfHeight = 40;
    
 	f1.lfWeight = 30;
    
 	strcpy(f1.lfFaceName, "Segoe UI Black");  //字体名字
    
 	f1.lfQuality = ANTIALIASED_QUALITY;       //抗锯齿
    
 	settextstyle(&f1);
    
 	setbkmode(TRANSPARENT);                  //字体的背景透明
    
 	settextcolor(BLACK);                     //字体颜色
    
 	outtextxy(this->x + dx[this->ch - 'A'], this->y + 40, this->ch);
    
 }
    
  
    
 void Letter::modifyPos() {
    
 	this->y += this->speed * 90 / FPS;
    
 }
    
    
    
    
    AI生成项目cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-13/NTHqm8vC4XS7lZzV2dkLbRpDf1gP.png)

创建下图所示的文件夹名称

将游戏素材放到项目文件夹目录下(图片名称要和我一致)

必须确保字符集设置与我的配置一致以便正常运行代码。将导航栏属性中的高级选项中的字符集字段更改为多字节编码,并将编程语言从c/c++更改为SDL库。

素材地址可通过百度网盘下载的电子资料包名称为"打字游戏"获取 下载页面链接为 https://pan.baidu.com/s/19j9pKwLlNUN1j7ST7RlQTw?pwd=9dn4 并在跳出页面中输入提取编码 [此处填写字符] 即可下载

四、总结

以链表为数据结构设计的类,在接收到玩家交互返回的指令时会对链表上的萝卜对象进行增减,并具体实现萝卜对象的行为。

全部评论 (0)

还没有任何评论哟~