c语言小游戏 flybird Easyx编程 项目源码讲解
程序员文章站
2024-03-18 14:59:10
...
分享一个c语言小游戏可以帮助大家更好的熟悉c语言
这个就是前几年很火的手机小游戏飞行的小鸟
1.游戏流程:小鸟不断下落使用按键让其飞起来不断的穿过两个管子。
2.游戏框架:采用老师提供的框架和重要模块分开编写,使用easyx图形系统。
a.核心算法:使用了坐标的判断,和判断语句的熟练运用。
b.程序调度。
c.透明贴图消除图片的背景方框
d.文件的使用
3.代码优化。
先看一下游戏效果
现在开始上代码
先上流程图
//
//
//flybrid小游戏
// 主要玩法:
// 使用空格键让不断下落的小鸟在管子中间穿梭
// 若碰到了地板,顶部,管子游戏结束
// 保存最高分数
#include"head.h"
int x = 0;//分数
int max;//最高分
IMAGE back;//背景图
IMAGE per;//小鸟图
IMAGE bird1;//小鸟底图
IMAGE up;//管子图
IMAGE down;//管子图
IMAGE lend;//地板图
IMAGE over;//游戏结束图
IMAGE over1;//游戏结束底图
IMAGE began;//开始游戏图
IMAGE began1;//开始游戏底图
IMAGE diff;//困难模式游戏图
IMAGE again1;//重新开始游戏图
IMAGE out;//退出图
IMAGE open;//开机动画的图
//IMAGE again;
MOUSEMSG k;
//小鸟的结构体
struct Bird {
int x; //小鸟的横坐标
int y; //小鸟的纵坐标
int speed; //小鸟下坠的高度
}bird = { 100,250,30 }; //初始化
//管子的结构体
struct pipe {
int x; //管子的横坐标
int y; //管子的纵坐标
int h; //管子的高度
};
//加载资源
void loadRescue() {
loadimage(&back, "bg_night.png"); //加载背景图
loadimage(&per, "bird.png",30,30); //加载小鸟图
loadimage(&bird1, "bird1_1.png", 30, 30);
loadimage(&lend, "land.png"); //加载地板图
loadimage(&over, "game_over.png"); //加载游戏结束图
loadimage(&over1, "text_game_over_1.png"); //加载游戏结束图
loadimage(&down, "down.png"); //加载管子图
loadimage(&up, "up.png");//加载上管子图
loadimage(&began, "button_play.png");//简单模式游戏图
//loadimage(&again, "again.png");
loadimage(&again1, "again1.png");//重新开始图
loadimage(&began, "button_play.png");
loadimage(&began1, "button_play_1.png");
loadimage(&out, "back.png");
}
//开始的按钮
void Booton() {
Startmove();
MOUSEMSG m;//鼠标定义
MOUSEMSG g;//
loadimage(&back, "bg_night.png"); //加载背景图
putimage(0, 0, &back);
rectangle(120, 210, 200, 250);//简单模式
rectangle(120, 310, 200, 350);//困难模式
loadimage(&began, "button_play.png",80,40);
loadimage(&diff, "diff.png",80,40);
putimage(120, 310, &diff);
putimage(120,210, &began);
while (1) {
m = GetMouseMsg();//获取鼠标
if (m.uMsg == WM_LBUTTONDOWN /*|| _kbhit()*/) {
if (((m.x > 100 && m.x < 216) && (m.y > 200 && m.y < 270))//简单模式范围
/*|| _getch() == 'e'*/) {
Begin();
}
}
g = GetMouseMsg();
if (g.uMsg == WM_LBUTTONDOWN /*|| _kbhit()*/) {
if (((g.x > 120 && g.x < 216) && (g.y > 300 && g.y < 370))//困难模式范围
/*|| _getch() == 'd'*/) {
Diffcult_Began();
}
}
if (_kbhit()) {
if (_getch() == 'e') {
Begin();
}
else if (_getch() == 'd') {
Diffcult_Began();
}
}
}
return;
}
//设定鸟
void drawperson(int x, int y) {
putimage(x,y,&per,SRCAND);//底图
putimage(x, y, &bird1, SRCPAINT);//正图
bird.y += 5; //鸟一直往下坠落5
}
//多线程 否则会卡顿
//加载按键音乐
DWORD WINAPI playMusic(LPVOID IpParamer) {
mciSendString("open correct.mp3", 0, 0, 0);
mciSendString("play correct.mp3 wait", 0, 0, 0);
mciSendString("close correct.mp3", 0, 0, 0);
return 0;
}
//加载游戏结束音乐
DWORD WINAPI OverMusic(LPVOID IpParamer) {
mciSendString("open 12321.mp3", 0, 0, 0);
mciSendString("play 12321.mp3 wait", 0, 0, 0);
mciSendString("close 12321.mp3", 0, 0, 0);
return 0;
}
//加载地板
void drawland() {
putimage(0,414, &lend, SRCAND);
putimage(0,414, &lend, SRCPAINT);
}
//鸟的按键处理
void Down() {
char userkey = _getch();
switch (userkey) {
//按下空格键时鸟向上弹跳
case ' ':
bird.y -= bird.speed;
CreateThread(NULL,NULL,playMusic,NULL,NULL,NULL); //按下空格键时的音效
break;
default:
break;
}
}
//撞击地板后
int hitland() {
if (bird.y <= 0 || bird.y >= (512 - 96)) {
return 1;
}
return 0;
}
//游戏死亡后的弹出的图标
void GameOver() {
//图标的坐标
int x = 50;
int y = 512;
//图标从底层出现 提留在中间层5s
while (y >= 200) {
putimage(0, 0, &back);
putimage(x, y, &over1, SRCAND);
putimage(x, y, &over, SRCPAINT);
y -= 30;
Sleep(100);
}
CreateThread(NULL, NULL, OverMusic, NULL, NULL, NULL); //游戏结束后的音效
Again();//重新开始游戏图标选项
Sleep(5000);
}
//定义管子
void printpipe(struct pipe pip[], int i) {
pip[i].h = rand() % 100 + 130; //管子在屏幕的高度 随机显示在130—230之间
pip[i].x = 288;
pip[i].y = 0;
}
//画出管子
void drawpip(struct pipe pip) {
//上方的管子
putimage(pip.x, 0, 52, pip.h, &down, 0, 320 - pip.h);// xy轴坐标 长框 图片指针名 图片开始从哪画的xy轴
//下方的管子
putimage(pip.x, 412-(320-pip.h), 52, 320 - pip.h, &up, 0, 0);
}
//简单模式管子的移动和刷新
void Movetube(struct pipe pip[], int i) {
pip[i].x -= 5;
//当管子被刷出屏幕外时加载新管子
if (pip[i].x < (-52 - 150)) //第一个出去150后 重新载第四跟管子 屏幕永远都有两个管子
{
printpipe(pip, i);
}
return;
}
//困难模式下管子的移动和刷新
void Diff_Movetube(struct pipe pip[], int i) {
pip[i].x -= 10;
//当管子被刷出屏幕外时加载新管子
if (pip[i].x < (-52 - 150))
{
printpipe(pip, i);
}
return;
}
//是否碰撞到了上面的柱子
int HItUp(struct pipe pip[],int i) {
//判断鸟的坐标与上方柱子坐标之间的关系
if ((bird.y <= pip[i].h) && (bird.x + 30 >= pip[i].x) && (pip[i].x <= pip[i].x + 52)) {
return 1;//1表示撞到了
}
return 0;
}
//是否碰撞到了下面的柱子
int HItDown(struct pipe pip[], int i) {
//判断鸟的坐标与下方柱子坐标之间的关系
if ((bird.y + 30 >= 412 - (320 - pip[i].h)) && (bird.x + 30 >= pip[i].x) && (pip[i].x <= pip[i].x + 52)) {
return 1;
}
return 0;
}
//是否撞到管子
void Hittube(struct pipe pip[], int i) {
//判断鸟穿过当前这个管子
if (pip[i].x + 52 <= bird.x) {
return;
}
//与下一个管子比较
else if (HItUp(pip, i) == 1) {
GameOver();
return;
}
else if (HItDown(pip, i) == 1) {
GameOver();
return;
}
}
//记录分数
void Score(struct pipe pip[], int i){
char s[10];
sprintf_s(s, " %d", x);//将整型数字转成字符保存在s中
//settextcolor(RED);
outtextxy(72, 0, s);
outtextxy(0, 0, "你的分数: ");
if (pip[i].x + 52 == bird.x){ //判断鸟是否串过管子了
x++;
sprintf_s(s, " %d", x);
outtextxy(0, 0, "你的分数: ");
outtextxy(72, 0, s);
}
}
//简单分数管理
void ChangeMaxScore(int x) {
FILE* fp = fopen("Score.txt", "r+"); //存放普通模式下的最高分文件
fscanf(fp, "%d", &max); //取出保存在max中
char s1[10];
sprintf_s(s1, " %d", max);//转换类型 用outtextxy输出到游戏界面
outtextxy(72, 16, s1);
outtextxy(0, 16, "最高分数: ");
FlushBatchDraw();
fclose(fp);
if (x > max) {//在数据库中存入最高分
FILE* fp = fopen("Score.txt", "w+");
fprintf(fp, "%d", x);
fclose(fp);
}
}
//困难模式分数管理
void Diff_ChangeMaxScore(int x) {
FILE* fp = fopen("Diff_Score.txt", "r+");//困难模式最高分的文件
fscanf(fp, "%d", &max);
char s1[10];
sprintf_s(s1, " %d", max);
outtextxy(72, 16, s1);
outtextxy(0, 16, "最高分数: ");
fclose(fp);
if (x > max) {//在数据库中存入最高分
FILE* fp = fopen("Diff_Score.txt", "w+");
fprintf(fp, "%d", x);
fclose(fp);
}
}
//游戏开始
void Begin() {
struct pipe pip[3];//三个管子
//初始化三个管子
for (int i = 0; i < 3; i++) {
printpipe(pip, i);//在屏幕中显示管子
pip[i].x = 288 + i * 150;//每个管子之间的间隔150
}
loadRescue(); //加载资源
while (1) {
putimage(0, 0, &back); //画出背景图
drawland(); //画出地板
drawperson(bird.x, bird.y); //画出鸟
for (int i = 0; i < 3; i++) {
drawpip(pip[i]);//画出管子
Movetube(pip, i);
}
FlushBatchDraw();
//判断是否撞上了管子
for (int i = 0; i < 3; i++) {
Hittube(pip, i);
Score(pip, i); //显示当前分数
}
//MaxScore();//显示最高分
ChangeMaxScore(x);
//判断按键是否按下
if (_kbhit()) {
Down();
}
//判断是否撞击地板
if (hitland()) {
GameOver();
break;
}
Sleep(100);
}
}
void Diffcult_Began() {
struct pipe pip[3];//三个管子
//初始化三个管子
for (int i = 0; i < 3; i++) {
printpipe(pip, i);//在屏幕中显示管子
pip[i].x = 288 + i * 150;//每个管子之间的间隔150
}
loadRescue(); //加载资源
while (1) {
putimage(0, 0, &back); //画出背景图
drawland(); //画出地板
drawperson(bird.x, bird.y); //画出鸟
for (int i = 0; i < 3; i++) {
drawpip(pip[i]);//画出管子
Diff_Movetube(pip, i);
}
FlushBatchDraw();
//判断是否撞上了管子
for (int i = 0; i < 3; i++) {
Hittube(pip, i);
Score(pip, i); //显示当前分数
}
//MaxScore();//显示最高分
Diff_ChangeMaxScore(x);
//判断按键是否按下
if (_kbhit()) {
Down();
}
//判断是否撞击地板
if (hitland()) {
GameOver();
break;
}
Sleep(100);
}
}
//重新开始
void Again() {
rectangle(70, 310,240, 380);
putimage(70, 310, &again1);
putimage(100, 100, &out);
//putimage(80, 310, &again, SRCPAINT);
MOUSEMSG k;
while (1) {
k = GetMouseMsg();
if (k.uMsg == WM_LBUTTONDOWN) {
if (((k.x > 80 && k.x < 240) && (k.y > 300 && k.y < 380))
) {
x = 0;
bird.y = 250;
Begin();//重新开始游戏
}
}
if (_kbhit()) {
if (_getch() == 'k') {
x = 0;
Begin();//重新开始游戏
}
else if (_getch() == 'q') {
Endmove();
}
}
}
}
void Startmove() {//开机动画
clearrectangle(0, 0, 288, 512);
setbkcolor(BLACK);
int i;
for (i = 0; i < 5; i++) {
//随机出现图画
int x = rand() % 180;
int y = rand() % 480;
loadimage(&open, "open.png");
putimage(x, y, &open);
Sleep(50);
}
}
void Endmove() { //关机动画
clearrectangle(0, 0, 288, 512);//清屏
setbkcolor(BLACK);//背景颜色
int y = 100;
for (int x = 50; x < 288; x += 20) {
settextcolor(BLUE);
settextstyle(32, 0, NULL);//高度 宽度0自适应 字体样式无
outtextxy(100, y,"GOOD BYE");
y += 52;//下移
setcolor(YELLOW);
setfillstyle(BLUE);
fillellipse(x, 50, 10, 10);
Sleep(500);
setcolor(GREEN);
setfillstyle(RED);
fillellipse(x, 50, 10, 10);
}
closegraph();
}
//头文件
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<graphics.h> //图形库文件
#include<conio.h> //按键头文件
#include<time.h>
#include<mmsystem.h>//调用音乐的头文件
#pragma comment(lib,"winmm.lib")
/*全局变量*/
extern int x;//分数
extern int max;//最高分
/*游戏资源的加载初始化*/
void loadRescue();//加载资源
void drawperson(int x, int y);//画鸟
void Booton();//开始的按钮
DWORD WINAPI playMusic(LPVOID IpParamer);//加载按键音乐 多线程 否则会卡顿
DWORD WINAPI OverMusic(LPVOID IpParamer);//加载游戏结束音乐
void drawland();//加载地板
void printpipe(struct pipe pip[], int i);//定义管子
void drawpip(struct pipe pip);//画出管子
/*游戏过程的处理*/
void Down();//鸟的按键处理
int hitland();//撞击地板后
void Movetube(struct pipe pip[], int i);//管子的移动和刷新
int HItUp(struct pipe pip[], int i);//是否碰撞到了上面的柱子
int HItDown(struct pipe pip[], int i);//是否碰撞到了下面的柱子
void Hittube(struct pipe pip[], int i);//是否撞到管子
void Diff_Movetube(struct pipe pip[], int i);//困难模式下的管子移动
/*分数管理*/
void Diff_ChangeMaxScore(int x);//最高分的记录
void Score(struct pipe pip[], int i);//记录分数
void ChangeMaxScore(int x);//分数管理
/*游戏的几种模式*/
void Diffcult_Began();//困难模式
void Begin();//游戏开始
void Again();//重新开始
void GameOver();//游戏死亡后的弹出的图标
/*开关机动画*/
void Endmove();//关机动画
void Startmove();//开机动画
//主函数
#include"head.h"
int main() {
initgraph(288, 512);//初始化图形系统
setbkcolor(BLACK);
Booton(); //开始按钮 点击开始后进入游戏
return 0;
}
//刚刚学的c语言如果有不对的地方欢迎大家给我提出
//不懂的地方可以评论提问 我尽量解答
//需要图片资源的可以留下邮箱
上一篇: java各种进制之间的相互转化
下一篇: 2020年请坚持这22件事!