C语言书写羊了个羊第一关(详解版)

在这里插入图片描述

游戏效果展示

在这里插入图片描述

**C语言写羊了个羊第一关

前言

学了C语言,也尝试自己做一些小游戏,当然因水平有限,这只是第一关,还是简化版的,也非常希望大家学了C语言,能够去学习,然后做一些有趣的小游戏,进一步来提高自己的开发能力。

游戏运用的知识点(必看)

1.首先,制作相对较高体验的游戏,肯定都要摆脱黑窗口,对于初学者来说,学会easyx库的使用,必不可少, 如果有不懂的可以去看我之前写的一篇讲解 easyx的使用。
2.制作游戏,数组的运用肯定少不了,大部分游戏都需要数组来绘制地图
3.这是一款类似消消乐的游戏, 那么要让每次出现的都不一样,我就采用了随机数的运用(随机数种子以及随机数)
4.当然,游戏也运用了, 函数,指针,结构体
5.最后也运用了 , bool类型(布尔类型), C++中会介绍,当然也不用感到会怕,这类似于(int char),它有两种返回值 (return true 和 return false),这一般用于,来判断游戏是否结束, 游戏结束肯定就 return true

以上所说的运用的知识点,如果有不知道的,可以先在csdn上了解下不会也别急,见得多了自然就会了

代码讲解

游戏界面

void initmenu()
{
	mciSendString("open ./res/封面.mp3", 0, 0, 0);
	mciSendString("play ./res/封面.mp3", 0, 0, 0);
	
	loadimage(&MENU1, "./res/新建文件夹/1.png");
	putimage(0, 0, &MENU1);
	_getch();

	char arr2[30];
	for (int i = 0; i < 4; i++)
	{
		BeginBatchDraw();

		sprintf_s(arr2, sizeof(arr2), "./res/新建文件夹/%d.png", i + 2);
		loadimage(&MENU2[i], arr2);
		putimage(0, 0, &MENU2[i]);
		Sleep(1050);

		EndBatchDraw();

	}

	loadimage(&MENU3, "./res/新建文件夹/11.png");

	putimage(0, 0, &MENU3);
	Sleep(1050);

}

这游戏的界面的设计很简答,主要是运用easyx库,放一些游戏界面的图片,和游戏界面的音乐,
最后那个Sleep()函数,起到个延迟的作用,参数是延迟的时间(以毫秒为单位
不知道怎么使用easy库,建议去看下我之前写的博客关于easyx库的使用,再来学习这个

游戏的初始化(包括地图)

void initgame()
{
	mciSendString("open ./res/sheep.mp3", 0, 0, 0);
	mciSendString("play ./res/sheep.mp3", 0, 0, 0);

	mciSendString("close ./res/封面.mp3", 0, 0, 0);

	loadimage(&BG, "./res/bg.png");
	                                     
	for (int i = 0; i < 3; i++)
	{
		char arr[100];
		sprintf_s(arr, sizeof(arr), "./res/%d.png", i + 1);  // sprintf 打印字符串
		loadimage(&Role[i], arr);
	}
	srand(time(NULL));

	initMap();

	for (int i = 0; i < 7; i++)
	{
		cao[i] = 0;
	}
}

这里进入游戏中,
1.先关闭游戏界面的音乐,然后播放游戏的音乐
2.加载游戏的背景图片
3.产生随机种子(srand(time(NULL))),便于后面产生随机数
4.当然,我这里也调用了一个我构造的函数,游戏的地图初始化的函数
下一步讲解
5.对羊槽就行初始化(游戏中的棕色部分),地图最初都是以数组的形式存在的

游戏的地图初始化(重点)

void initMap()
{
	 // 1  1  1
    //  2  2  2
    //  3  3  3
	for (int i = 0; i < 3; i++)            
	{
		for (int j = 0; j < 3; j++)
		{
			map[i][j] = i + 1;
		}
	}

	for (int i = 0; i < 20; i++)
	{
		int x1 = rand() % 3;
		int y1 = rand() % 3;
		int x2 = rand() % 3;
		int y2 = rand() % 3;

		int tmp = map[x1][y1];
		map[x1][y1] = map[x2][y2];
		map[x2][y2] = tmp;
	}
}

这个函数,主要用来绘制游戏的地图,
当然这个游戏地图,只是简化版的
思路:用一个三维数组来绘制的,因为3个就消掉,肯定要确保有3组3个一样的,我用数组中元素的值1,2,3,分别代表着一张图片,然后打印照片,如果数组中的值被改为0的话,就不打印照片,意思就是被消掉了
1.先对数组进行会初始化
1 1 1
2 2 2
3 3 3
2.因为游戏中,照片都是打乱的,就让数组中的2个元素对调,用一个循环,循环次数可以自己随便设置,我这里用了20次,至于哪2个元素对调,我这里用的随机数,随机的

加载游戏图片(重点)

void updategame()
{
	BeginBatchDraw();               // 双缓冲区, 加载图片的时候, 防止闪烁
	putimage(0, 0, &BG);

	int distanceX = (504 - 61 * 3 - 15 * 2) / 2;
	int distanceY = 270;

	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			if (map[i][j] == 0)      //
			{
				continue;
			}
			else
			{
				int x = distanceX + j * (61 + 15);
				int y = distanceY + i * (68 + 15);

				putimage(x, y, &Role[map[i][j] - 1]);
			}
		}
	}

	for (int i = 0; i < 7; i++)
	{
		if (cao[i] != 0)
		{
			int x = 26 + 64.7 * i;
			int y = 696;

			putimage(x, y, &Role[cao[i] - 1]);

		}
	}

	EndBatchDraw();
}

1.在加载图片的过程中,可能会出现图片的闪烁
解决办法:建立一个双缓冲区

用BeighBatchDraw()函数和EedBatchDraw()函数。
将加载图片的步骤,放在两个函数的中间。

2.放置背景图片

3… 放置游戏图片 , 数组中 1代表的是 第一张图片, 2代表的是第二张图片, 3代表的是第三张图片, 0则不打印图片(即直接continue)
这里需要做一些简单的计算, 通过背景图片的大小和游戏图片的大小,,计算出相对应的距离,让图片放在相应的位置

distancex是图片离,游戏左框框的位置(初始值需要具体计算)
distancey是图片离, 游戏上框框的位置(图片没在中间, 初始值随便恰当给个距离)
15(可以自己随便设置) 为2张图片的间隔距离

4.放置羊槽的图片,羊槽中最多可以放置7张图片, 这里需要在画图工具,用刻度尺,自己量一下羊槽的总距离,在根据元游戏图片的大小,进行一个简单的计算。
羊槽的元素最开始初始化为0, 打印图片,
肯定是cao[i] ! = 0;

图片的点击

typedef struct location
{
	int row;
	int col;
}LO;

bool userClick(LO* Location)
{
	ExMessage m;
	
	if (peekmessage(&m) && m.message == WM_LBUTTONDOWN)	  //检查是否有鼠标左键的消息
	{
		int distanceX = (504 - 61 * 3 - 15 * 2) / 2;
		int distanceY = 270;

		int col = (m.x - distanceX) / (61 + 15);
		int row = (m.y - distanceY) / (68 + 15);

		if (row >= 0 && row < 3 && col >= 0 && col < 3)
		{
			Location->row = row;
			Location->col = col;

			return true;
		}

		printf("%d %d\n", col, row);
	}

	return false;
}

函数作用:通过鼠标的左键点击图片,并且记录鼠标点击位置

这里使用了结构体(int row int col 分别代表行和列), 通过指针传递,同时函数用的是bool类型,为真肯定句调用,为假就不调用。

1.先定义一个结构体。
2.用easxy库, 检查有无鼠标左键的消息。
3.鼠标点击的范围的设置(只能在游戏那个三维数组中才能够生效)。
4.这里也需要做一些计算,算出三维数组的位置,而结构体记录鼠标点击的位置。

游戏图片的删除,消掉与转移(重点)

void work(LO* Location)
{
	int index = map[Location->row][Location->col];

	int i = 0;
	//for (; i < 7 && cao[i]; i++); //如果第一个槽为0,结束, 如果第一个槽不为0, 就继续++,直到找到槽为0的时候,此时i的值结束。
	
	//if (i < 7)
	//{
	//	cao[i] = index;
	//
	//}

	for (int i = 0; i < 7; i++)
	{
		if (cao[i] == 0)
		{
			cao[i] = index;
			break;
		}
	}

	int cout = 0;
	for (int i = 0; i < 7; i++)
	{
		if (cao[i] == map[Location->row][Location->col])
		{
			cout++;
		}
	}
	if (cout == 3)
	{
		for (int i = 0; i < 7; i++)
		{
			if (cao[i] == map[Location->row][Location->col])
			{
				cao[i] = 0;
			}
		}
	}
	map[Location->row][Location->col] = 0;
}

1.这里用 int index 来接受 鼠标点击数组元素的大小(通过结构体记录鼠标点击的位置)

2.图片的转移, 图片转移到羊槽上去,就如果羊槽中的元素为0,
就让它 = index,让它从左到右,挨个打印照片, 具体操作这里写了2种方法,代码注释读的部分是方法二

3.图片的消除,在羊槽中3个一样的便会消除, 这里我用cout这个变量来记录的图片重复出现的次数, (用循环)如果羊槽中数组的值等于游戏三维数组的值,那么cout++。 (用循环)if cout == 3, 那么羊槽中 这个元素与三维数组元素相等的,cao[i] = 0;,消掉
4.图片的删除,就让鼠标点击的那个三维数组的值

游戏结束

bool gameover()
{

for (int i = 0; i < 3; i++)
{
	for (int j = 0; j < 3; j++)
		if (map[i][j] == 1)
		{
			return false;
		}
		else if (map[i][j] == 2)
		{
			return false;
		}
		else if (map[i][j] == 3)
		{
			return false;
		}

}

return true;

}

游戏结束,也是用bool 类型来判断,结束的话就返回 true

游戏结束的标志:,三维数组中的值 不等于1,不等于2,不等于3(都不等于的话,代表着,三维数组值都为0,没有了图片,都在羊槽中被消掉了)

主函数

int main()
{
	initgraph(504, 900);
	
	initmenu();

	initgame();
	LO Location;

	while (1)
	{   
		if (userClick(&Location))
		{
			work(&Location);
		}
		updategame();

		if (gameover())
		{
			setbkmode(TRANSPARENT);
			settextcolor(YELLOW);

			settextstyle(50, 0, "楷体");
			outtextxy(30, 300, "不愧是你!!");
			outtextxy(100, 400, "恭喜通关!!");
			outtextxy(200, 500, "你赢了!!");
			break;

		}
	}

	system("pause");

	return 0;
}

当然主函数中,调用游戏结束那部分,后面也用了easyx库的东西,打印字,以及字体的颜色,模式,大小。
注意:别忘了用initgraph()函数,创建一个窗口。

头文件和定义的变量,以及函数的声明

#include<stdio.h>
#include<graphics.h>
#include<mmsystem.h>
#pragma comment(lib, "winmm.lib")
#include<time.h>
#include<stdlib.h>
#include<conio.h>

IMAGE MENU1;
IMAGE MENU2[4];
IMAGE MENU3;
IMAGE BG;
IMAGE Role[3];
int map[3][3];
int cao[7];

void initmenu();
void initgame();
void initMap();
void updategame();
bool gameover();

typedef struct location
{
	int row;
	int col;
}LO;

bool userClick(LO* location);
void work(LO* Location);

这部分代码,很简单,有的就是一些固定的格式,就不在讲解了

源码和图片素材领取(百度网盘)

百度网盘图片素材和源码链接
提取码:1111
老铁们,这是压缩包,下载后,直接解压就行。

点个关注,点个赞。
你们的关注和点赞以及收藏真的对我很重要, 后续会与大家分享更多优质的博客

在这里插入图片描述

  • 16
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 15
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

温柔了岁月.c

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

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

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

打赏作者

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

抵扣说明:

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

余额充值