分享一個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語言如果有不對的地方歡迎大家給我提出
//不懂的地方可以評論提問 我儘量解答
//需要圖片資源的可以留下郵箱