c語言貪吃蛇課程設計
㈠ c語言實訓貪吃蛇報告書
《高級語言程序設計》課程設計 實驗報告
題目:貪吃蛇
專業:計算機
班級: 軟體
姓名:
成績:
指導教師:
完成日期:2008年09月23日
一、目的
1. 進一步掌握和利用C語言進行程設計的能力;
2、 進一步理解和運用結構化程設計的思想和方法;
3、 初步掌握開發一個小型實用系統的基本方法;
4、 學會調試一個較長程序的基本方法;
5、 學會利用流程圖或N-S圖表示演算法;
6、 掌握書寫程設計開發文檔的能力(書寫課程設計報告);
二、內容與設計思想。
(1).系統功能與分析(填寫你所設計的菜單及流程圖)。
功能:進行貪食蛇游戲
分析:定義鍵盤方向鍵操作,隨機數發生器產生食物,並分別利用函數判斷貪食蛇的長度及游戲是否成功等.
並能夠輸入游戲成績.
(2).數據結構
struct Food
{
int x;/*食物的橫坐標*/
int y;/*食物的縱坐標*/
int yes;/*判斷是否要出現食物的變數*/
}food;/*食物的結構體*/
struct Snake
}
int x[N];
int y[N];
int node;/*蛇的節數*/
int direction;/*蛇移動方向*/
int life;/* 蛇的生命,0活著,1死亡*/
}snake;
(3).模塊設計
根據功能需要:
源文件 :#include <stdio.h>
#include <graphics.h>
#include <stdlib.h>
#include <dos.h>
函數名 功能
void main() 游戲主程序
void Init(void); 圖形驅動
void Close(void); 圖形結束
void DrawK(void); 開始畫面
void GameOver(void); 結束游戲
void GamePlay(void); 玩游戲具體過程
void PrScore(void); 輸出成績
(3)總體設計思想:
利用圖形驅動,製作美觀的游戲界面.
通過隨機函數產生隨機數,控制游戲過程食物的出現.
定義鍵盤操作,控制游戲過程蛇的移動方向.
畫出邊界,並判斷游戲是否結束.
統計游戲過程蛇吃的食物數量,計算並輸出遊戲成績.
(4)調試過程: 測試數據及結果,出現了哪些問題,如何修改的
這里,你就寫一下你平時出錯的地方,與如何修改的.這里我也不好幫你寫.
(5)程序有待改進的地方及本次實習的收獲和建議
收獲:加深認識了程序編譯過程的中團隊合作的重要性.
提高了自己的編程能力
(7)源程序清單(主要代碼)
清單只要將上面的程序全部粘帖就可以了.
㈡ 用c語言設計貪吃蛇游戲
//<Copyrightliaoqb>
#include<windows.h>
#include<stdlib.h>
#include<time.h>
constintLENGTH=40;
constintWIDTH=10;
constintRANGE=50;
constintBeginLength=5;
constintspeed=300;
#defineSNAKE_COLORRGB(176,196,222)
#defineBACKGROUND_COLORRGB(255,255,0)
#defineDRAW_SNAKE(x)(x)*WIDTH
enumIsSnake{isSnake,isNotSnake,isFood};
IsSnakemap[LENGTH][LENGTH];
structsnake{
intx;
inty;
snake*next;
snake(intx,inty,snake*n=NULL){
this->x=x;
this->y=y;
next=n;
}
};//snake
typedefstructsnakeSnake;
Snake*head=NULL;//queue
Snake*tail=NULL;//queue
intdirect=0;//direction
RECTplayground;//district
TCHARszAppName[]=TEXT("-*-snakegame-*");//Theprojectname
LRESULTCALLBACKWndProc(HWND,UINT,WPARAM,LPARAM);//messagefunction
voidInitializer();
voidController(Snake*,LPVOID);//controlthesnake
voidMove(HWND);
voidPutFood();
intWINAPIWinMain(HINSTANCEhInstance,HINSTANCEhPreInstance,PSTRszCmdLine,intiCmdShow){
MSGmsg;
HWNDhwnd;
WNDCLASSwndclass;
while(TRUE){
wndclass.cbClsExtra=0;
wndclass.cbWndExtra=0;
wndclass.hbrBackground=CreateSolidBrush(RGB(255,255,255));
wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);
wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
wndclass.hInstance=hInstance;
wndclass.lpfnWndProc=WndProc;
wndclass.lpszClassName=szAppName;
wndclass.lpszMenuName=NULL;
wndclass.style=CS_HREDRAW|CS_VREDRAW;
if(!RegisterClass(&wndclass)){
MessageBox(NULL,TEXT("Pleasetryagain!!!"),szAppName,MB_ICONERROR);
return0;
}
break;
}
hwnd=CreateWindow(szAppName,TEXT("<^_^>SnakeGame<^_^>"),WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
NULL,NULL,hInstance,NULL);
ShowWindow(hwnd,SW_NORMAL);
UpdateWindow(hwnd);
while(TRUE){
if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)){
if(msg.message==WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}else{
Move(hwnd);
}
}
returnmsg.wParam;
}
LRESULTCALLBACKWndProc(HWNDhwnd,UINTmessage,WPARAMwParam,LPARAMlParam){
HDChdc;
PAINTSTRUCTps;
HBRUSHhBrush;
switch(message){
caseWM_DESTROY:
PostQuitMessage(0);
return0;
caseWM_CREATE:
Initializer();
MoveWindow(hwnd,RANGE,RANGE,WIDTH*LENGTH+RANGE*3,WIDTH*LENGTH+RANGE*3,TRUE);
return0;
caseWM_KEYDOWN:
switch(wParam){
caseVK_LEFT:
if(direct!=VK_RIGHT)
direct=VK_LEFT;
break;
caseVK_RIGHT:
if(direct!=VK_LEFT)
direct=VK_RIGHT;
break;
caseVK_UP:
if(direct!=VK_DOWN)
direct=VK_UP;
break;
caseVK_DOWN:
if(direct!=VK_UP)
direct=VK_DOWN;
break;
default:
break;
}
return0;
caseWM_PAINT:
hdc=BeginPaint(hwnd,&ps);
SetViewportOrgEx(hdc,RANGE,RANGE,NULL);
hBrush=CreateSolidBrush(BACKGROUND_COLOR);
SelectObject(hdc,hBrush);
Rectangle(hdc,playground.left,playground.top,playground.right,playground.bottom);
DeleteObject(hBrush);
hBrush=CreateSolidBrush(SNAKE_COLOR);
SelectObject(hdc,hBrush);
for(inti=0;i<LENGTH;++i){
for(intj=0;j<LENGTH;++j){
if(map[i][j]==isSnake||map[i][j]==isFood){
Rectangle(hdc,DRAW_SNAKE(i),DRAW_SNAKE(j),DRAW_SNAKE(i+1),DRAW_SNAKE(j+1));
}
}
}
DeleteObject(hBrush);
EndPaint(hwnd,&ps);
}
returnDefWindowProc(hwnd,message,wParam,lParam);
}
voidInitializer(){
for(inti=0;i<LENGTH;++i){
for(intj=0;j<LENGTH;++j){
map[i][j]=isNotSnake;
}
}
for(i=0;i<BeginLength;++i){
if(i==0){
head=tail=newsnake(i,0);
}else{
snake*temp=newsnake(i,0);
tail->next=temp;
tail=temp;
}
map[i][0]=isSnake;
}
playground.left=playground.top=0;
playground.right=playground.bottom=WIDTH*LENGTH;
direct=VK_RIGHT;
PutFood();
}
voidPutFood(){
srand(static_cast<unsigned>(time(NULL)));
intx,y;
do{
x=rand()%LENGTH;
y=rand()%LENGTH;
}while(map[x][y]==isSnake);
map[x][y]=isFood;
}//putfood
voidMove(HWNDhwnd){
snake*temp;
switch(direct){
caseVK_LEFT:
temp=newsnake(tail->x-1,tail->y);
break;
caseVK_RIGHT:
temp=newsnake(tail->x+1,tail->y);
break;
caseVK_UP:
temp=newsnake(tail->x,tail->y-1);
break;
caseVK_DOWN:
temp=newsnake(tail->x,tail->y+1);
break;
}
Controller(temp,hwnd);
//InvalidateRect(hwnd,NULL,FALSE);
Sleep(speed);//controlspeed
}//snakemoving
voidController(Snake*temp,LPVOIDlParam){
HWNDhwnd;
hwnd=(HWND)lParam;
if(temp->x<0||temp->x>=LENGTH||temp->y<0||temp->y>=LENGTH
||map[temp->x][temp->y]==isSnake){//thesnakeisdied
MessageBox(NULL,TEXT("<Copyrightliaoqb>Sorry!!!GameOver!!!<Copyrightliaoqb>"),szAppName,0);
deletetemp;
while(head!=NULL){
Snake*ptr=head;
head=head->next;
deleteptr;
}
head=tail=temp=NULL;
Initializer();
return;
}elseif(map[temp->x][temp->y]==isNotSnake){//move
map[temp->x][temp->y]=isSnake;
map[head->x][head->y]=isNotSnake;
snake*ptr=head;
head=head->next;
deleteptr;
tail->next=temp;
tail=temp;
InvalidateRect(hwnd,NULL,FALSE);
}else{//ifeatfood
map[temp->x][temp->y]=isSnake;
tail->next=temp;
tail=temp;
PutFood();
//InvalidateRect(hwnd,NULL,FALSE);
}
}
㈢ 誰有用c語言製作貪吃蛇的代碼,及使用方法,用VC打
/*
C/C++貪吃蛇游戲,zjlj,2015.3.16
*/
#define DEBUG 0 //當程序在調試階段時 DEBUG為 1
#include<iostream>
#include<windows.h>
#include<time.h>
#include<conio.h>
using namespace std;
void readini(FILE **fphead, int *score, char *argv[]) //創建或打開一個和運行文件對應的ini文件,讀取最高紀錄
{
char filename[200],*pfilename;
int flag=-1,i;
strcpy(filename,argv[0]);
for(i=0;filename[i]!='\0';i++)
{
if ('.'==filename[i])flag=1;
}
if(1==flag)
{
filename[i-1]='i';
filename[i-2]='n';
filename[i-3]='i';
}
else
{
filename[i]='.';
filename[i+1]='i';
filename[i+2]='n';
filename[i+3]='i';
filename[i+4]='\0';
}
for(;filename[i]!='\\'&&i>=0;i--)pfilename=&filename[i];
if ( (*fphead=fopen(pfilename, "rb+"))==NULL)
{
if ( (*fphead=fopen(pfilename, "wb+"))==NULL)
{
printf("無法創建或打開\"%s\"文件\n",pfilename);
system("pause");
exit(0);
}
}
else
{
fread(score,sizeof(int),1,*fphead);
}
}
void writeini(FILE **fphead, int *score, char *argv[]) //打開一個和運行文件對應的ini文件,寫入最高紀錄
{
char filename[200],*pfilename;
int flag=-1,i;
strcpy(filename,argv[0]);
for(i=0;filename[i]!='\0';i++)
{
if ('.'==filename[i])flag=1;
}
if(1==flag)
{
filename[i-1]='i';
filename[i-2]='n';
filename[i-3]='i';
}
else
{
filename[i]='.';
filename[i+1]='i';
filename[i+2]='n';
filename[i+3]='i';
filename[i+4]='\0';
}
for(;filename[i]!='\\'&&i>=0;i--)pfilename=&filename[i];
if ( (*fphead=fopen(pfilename, "wb+"))==NULL)
{
printf("無法寫入\"%s\"文件,磁碟防寫!\n",pfilename);
system("pause");
exit(0);
}
else
{
rewind(*fphead);
fwrite(score,sizeof(int),1,*fphead);
fclose(*fphead);
}
}
void gotoxy(int x,int y)//游標定位,游標定位函數SetConsoleCursorPosition是左上角位置是0,0然後向左向下延伸
{
COORD pos;
pos.X=2*y;
pos.Y=x;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),pos);
}
void color(int a)//顏色函數
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),a);
}
void Refresh(int q[][22], int grade, int gamespeed, int length,int score) // 輸出貪吃蛇棋盤
{
int i,j;
for(i=0;i<22;i++)
{
for(j=0;j<22;j++)
{
if(q[i][j]==0)//輸出棋盤空白
{
gotoxy(i,j);
color(11);
cout<<"■";
}
if(q[i][j]==1||q[i][j]==2)//輸出棋盤牆壁
{
gotoxy(i,j);
color(11);
cout<<"□";
}
if(q[i][j]==3)//輸出蛇頭
{
gotoxy(i,j);
color(14);
cout<<"★";
}
if(q[i][j]==4)//輸出蛇身
{
gotoxy(i,j);
color(12);
cout<<"◆";
}
if(q[i][j]==5)//輸出果子
{
gotoxy(i,j);
color(12);
cout<<"●";
}
}
if(i==0) cout << "\t***********************";
if(i==1) cout << "\t等級為:" << grade;//顯示等級
if(i==3) cout << "\t自動前進時間";
if(i==4) cout << "\t間隔為:" << gamespeed << "ms";//顯示時間
if(i==6) cout << "\t歷史最高分為:" << score << "分";
if(i==7) cout << "\t你現在得分為:" << (length+(grade-1)*8)*10 << "分";
if(i==8) cout << "\t**********************";
if(i==9) cout << "\t游戲說明:";
if(i==10) cout << "\t(1)用小鍵盤方向鍵控制";
if(i==11) cout << "\t蛇頭運動方向;";
if(i==12) cout << "\t(2)蛇每吃一個果子蛇身";
if(i==13) cout << "\t增加一節;";
if(i==14) cout << "\t(3)蛇咬到自己或碰到牆";
if(i==15) cout << "\t壁游戲結束。";
if(i==18) cout << "\t**********************";
if(i==19) cout << "\tC/C++語言作業:";
if(i==20) cout << "\tzjlj,2015.03.16 ";
}
}
int main(int argc, char *argv[]){
int tcsQipan[22][22]; // 貪吃蛇棋盤是一個二維數組(如22*22,包括牆壁)
int i,j,score,directiontemp;
FILE *fpini;//*fpini 信息文件
readini(&fpini, &score, argv);//讀取ini文件的最高紀錄
if (score<0)//最高成績小於零設置為零,初建文件會是負數
score=0;
while(1)
{
for(i=1;i<=20;i++)
for(j=1;j<=20;j++)
tcsQipan[i][j]=0; //貪吃蛇棋盤相應坐標標上中間空白部分的標志0
for(i=0;i<=21;i++)
tcsQipan[0][i] = tcsQipan[21][i] = 1; //貪吃蛇棋盤相應坐標標上上下牆壁的標志1
for(i=1;i<=20;i++)
tcsQipan[i][0] = tcsQipan[i][21] = 2; //貪吃蛇棋盤相應坐標標上左右牆壁的標志2
int tcsZuobiao[2][500]; //蛇的坐標數組
for(i=0; i<4; i++)
{
tcsZuobiao[0][i] = 1;//蛇身和蛇頭的x坐標
tcsZuobiao[1][i] = i + 1;//蛇身和蛇頭的y坐標
}
int head = 3,tail = 0;//標示蛇頭和蛇尾的數組偏移量
for(i=1;i<=3;i++)
tcsQipan[1][i]=4; //蛇身
tcsQipan[1][4]=3; //蛇頭
int x1, y1; // 隨機出果子
srand(time(0));//設置隨機種子
do
{
x1=rand()%20+1;
y1=rand()%20+1;
}
while(tcsQipan[x1][y1]!=0);//如果不是在空白處重新出果子
tcsQipan[x1][y1]=5;//貪吃蛇棋盤相應坐標標上果子的標志5
color(12);
cout<<"\n\n\t\t\t\t貪吃蛇游戲即將開始 !"<<endl;//准備開始
long start,starttemp;
int grade = 1, length = 4; //設置初始等級和蛇的初始長度
int gamespeed = 500; //設置初始前進時間間隔
for(i=3;i>=0;i--)
{
start=clock();
while(clock()-start<=1000);
system("cls");
if(i>0)
cout << "\n\n\t\t\t\t進入倒計時:" << i << endl; //倒計時顯示
else
Refresh(tcsQipan,grade,gamespeed,length,score); //初始棋盤顯示
}
int timeover=1,otherkey=1;//初始化超時時間和按鍵判斷參數
char direction = 77; // 設置初始情況下,向右運動
int x=tcsZuobiao[0][head],y=tcsZuobiao[1][head];//保存蛇頭坐標到x,y變數
while(1)//運行一局游戲
{
start = clock();
while((timeover=((starttemp=clock())-start<=gamespeed))&&!kbhit());//如果有鍵按下或時間超過自動前進時間間隔則終止循環
if(direction==72||direction==80||direction==75 ||direction==77)
directiontemp=direction;//保留上一次方向按鍵
//starttemp=gamespeed+start-starttemp;//保留停留時間
if(timeover)
{
#if (DEBUG==1)
direction = getch();//調試代碼
#else
if((direction =getch())==-32)
direction = getch();
#endif
}
#if (DEBUG==1)//調試代碼
start=clock();
while(clock()-start<=2000);
gotoxy(24,4);
cout << "\t按鍵ASCII代碼"<<(int)direction<<" "<<endl;
#endif
if(!(direction==72||direction==80||direction==75 ||direction==77))
{
otherkey=0;// 按鍵非方向鍵,otherkey設置為0
}
else
{
otherkey=1;// 按鍵為方向鍵,otherkey設置為1
}
if(direction==72 && directiontemp==80)//忽略反方向按鍵
{
direction=32;
otherkey=0;
//start = clock();
//while(clock()-start<=starttemp);
}
else if(direction==80 && directiontemp==72)
{
direction=32;//設置按鍵為非方向鍵
otherkey=0;// 按鍵為非方向鍵,otherkey設置為0
// start = clock();
//while(clock()-start<=starttemp);//補償等待時間
}
else if(direction==75 && directiontemp==77)
{
direction=32;
otherkey=0;
//start = clock();
//while(clock()-start<=starttemp);
}
else if(direction==77 && directiontemp==75)
{
direction=32;
otherkey=0;
//start = clock();
//while(clock()-start<=starttemp);
}
switch(direction)//判斷方向鍵
{
case 72: x= tcsZuobiao[0][head]-1; y= tcsZuobiao[1][head];break; // 向上
case 80: x= tcsZuobiao[0][head]+1; y= tcsZuobiao[1][head];break; // 向下
case 75: x= tcsZuobiao[0][head]; y= tcsZuobiao[1][head]-1;break; // 向左
case 77: x= tcsZuobiao[0][head]; y= tcsZuobiao[1][head]+1;break; // 向右
default: break;
}
if(x==0 || x==21 ||y==0 || y==21) // 蛇頭碰到牆壁,結束本局游戲
{
gotoxy(22,12);
cout << "\t游戲已結束!" << endl;
if(score>=(length+(grade-1)*8)*10)//判斷是否破記錄
{
gotoxy(10,7);
color(12);
cout << "闖關失敗 加油耶!" << endl;
fclose(fpini);//關閉ini文件
}
else
{
gotoxy(10,7);
color(12);
cout << "恭喜您打破記錄" << endl;
score=(length+(grade-1)*8)*10;
writeini(&fpini, &score, argv);//寫入ini文件的最高紀錄
}
gotoxy(23,12);
cout << "按回車鍵重新開始,按ESC退出遊戲" << endl;//顯示的提示
break;//退出該局游戲
}
if(tcsQipan[x][y]!=0&&!(x==x1&&y==y1)&&tcsQipan[x][y]!=3) // 蛇頭碰到蛇身,結束本局游戲
{
gotoxy(22,12);
cout << "\t游戲已結束!" << endl;
if(score>=(length+(grade-1)*8)*10)//判斷是否破記錄
{
gotoxy(10,7);
color(12);
cout << "闖關失敗 加油耶!" << endl;
fclose(fpini);//關閉ini文件
}
else
{
gotoxy(10,7);
color(12);
cout << "恭喜您打破記錄" << endl;
score=(length+(grade-1)*8)*10;
writeini(&fpini, &score, argv);//寫入ini文件的最高紀錄
}
gotoxy(23,12);
cout << "按回車鍵重新開始,按ESC退出遊戲" << endl;//顯示的提示
break;//退出該局游戲
}
/*
游戲運行時的核心演算法開始
*/
if(x==x1 && y==y1) // 吃果子,長度加1
{
length ++;
if(length>=8)//長度大於等於8重新計算長度,等級加1
{
length -= 8;//重新計算長度
grade ++;//等級加1
if(gamespeed>50)//控制最快速度為50
gamespeed = 550 - grade * 50; // 改變自動前進時間間隔
}
tcsQipan[x][y]= 3;//貪吃蛇棋盤相應坐標現在蛇頭標志改為蛇頭標志3
tcsQipan[tcsZuobiao[0][head]][tcsZuobiao[1][head]] = 4;//貪吃蛇棋盤相應坐標原來蛇頭標志改為蛇身標志4
head = (head+1)%400;//防止數組越界
tcsZuobiao[0][head] = x;//蛇頭的x坐標
tcsZuobiao[1][head] = y;//蛇頭的y坐標
do//隨機出果子
{
x1=rand()%20+1;
y1=rand()%20+1;
}
while(tcsQipan[x1][y1]!=0);//如果不是在空白處重新出果子
tcsQipan[x1][y1]=5;//貪吃蛇棋盤相應坐標標上果子的標志5
gotoxy(22,12);
cout << "\t游戲進行中!" << endl;
Refresh(tcsQipan,grade,gamespeed,length,score);
}
else // 不吃果子
{
if(otherkey)
{
tcsQipan [tcsZuobiao[0][tail]][tcsZuobiao[1][tail]]=0;
tail=(tail+1)%400;//防止數組越界
tcsQipan [tcsZuobiao[0][head]][tcsZuobiao[1][head]]=4;
head=(head+1)%400;//防止數組越界
tcsZuobiao[0][head]=x;//蛇頭的x坐標
tcsZuobiao[1][head]=y;//蛇頭的y坐標
tcsQipan[tcsZuobiao[0][head]][tcsZuobiao[1][head]]=3;
gotoxy(22,12);
cout << "\t游戲進行中!" << endl;
Refresh(tcsQipan,grade,gamespeed,length,score);
}
else
{
gotoxy(22,12);
cout << "\t游戲暫停中!" << endl;
}
}
/*
游戲運行時的核心演算法結束
*/
}
while(1)
{
while(!kbhit());
if((direction =getch())==13)//按回車鍵開始下一局
break;
if(direction ==27)//按ESC退出遊戲
exit(0);
}
system("cls");//清除屏幕重新開始
}
return 0;
}
㈣ 如何用C語言寫貪吃蛇
p->x和p->y都是指向int的指針,不是數組,所以x[1]、y[1]等數據,使用的全是未申請的內存。
你應該定將他們成一個整型數組,大小足夠大,或者乾脆使用鏈表。
㈤ C語言課程設計,貪吃蛇應該怎麼做
2.1程序功能介紹
貪吃蛇游戲是一個經典小游戲,一條蛇在封閉圍牆里,圍牆里隨機出現一個食物,通過按鍵盤四個游標鍵控制蛇向上下左右四個方向移動,蛇頭撞倒食物,則食物被吃掉,蛇身體長一節,同時記10分,接著又出現食物,等待蛇來吃,如果蛇在移動中撞到牆或身體交叉蛇頭撞倒自己身體游戲結束。
2.2程序整體設計說明
一個游戲要有開始部分,運行部分,結束部分(實際上開始部分與運行部分是一體的)。
2.2.1設計思路
這個程序的關鍵是表示蛇的圖形以及蛇的移動。用一個小矩形表示蛇的一節身體,身體每長一節,增加一個矩形塊,蛇頭用兩節表示。移動時必須從蛇頭開始,所以蛇不能向相反方向移動,也就是蛇尾不能改作蛇頭。如果不按任何鍵,蛇自行在當前方向上前移,當游戲者按了有效的方向鍵後,蛇頭朝著指定的方向移動,一步移動一節身體,所以當按了有效的方向鍵後,先確定蛇頭的位置,然後蛇身體隨著蛇頭移動,圖形的實現是從蛇頭的新位置開始畫出蛇,這時由於沒有慶平的原因,原來蛇的位置和新蛇的位置差一個單位,所以看起來社會多一節身體,所以將蛇的最後一節用背景色覆蓋。食物的出現和消失也是畫矩形塊和覆蓋矩形塊
2.2.2數據結構設計及用法說明
開始部分:
游戲是運行在圖形模式下的,所以第一步一定是初始化圖形模式,接著要有開始的界面,就像書有封面一樣,我設置了一個游戲的標題畫面,除了游戲標題畫面我還設置了一個歡迎畫面。標題畫面以後,還要為游戲的運行部分作初始化,包括繪制游戲運行時的背景,對游戲某些重 要變數的初始化。
運行部分:
作為游戲的核心部分,這里包括的函數比較多,也就是模塊比較多,首先讓我模擬一下貪吃蛇的游戲模式:某個世界上突然出現一條蛇,它很短,它的運動神經異常,它沒法停止自己的多動症在它的世界裡就只有食物,它很餓,也很貪吃;同樣在不明原因的情況下,食物從天而降,可惜的是沒有落到嘴邊;飢餓的主人公,不管它有沒有毒,也不問食物的來歷,徑直向食物爬去;它吃到食物啦,它超出想像的同化能力讓食物很快的成為自己身體的一部分,它的身子變長啦。當它吃到第一顆食物時,上帝有給它第二顆,於是它吃了第二顆,於是又變長了,於是又有第三顆??它的身子是一直的加長,它不管自己過長身體的麻煩——轉身不便,繼續吃下去,現在它是直接把巴張大,好讓食物有個綠色通道。但是在某天的下午,它咬到了自己,它才想起自己是一條毒蛇,於是暈死過去(不是毒死);又或者它往食物沖鋒的時候,它失去控制,撞到了牆上。
第一輪循環:第一步,出現食物;第二步,蛇不停運動;第三步,檢查蛇是撞到自己或牆壁;由第四步起游戲有兩條支線(A、B):
A :第四步,蛇沒有碰到自己或牆壁,蛇繼續前進,繪制蛇的動作;第五步,判斷蛇是否吃到食物,如果蛇吃到食物,身子變長,原來的食物消失;第六步,讓玩家輸入控制指令,讓蛇在下一輪循環的第二步改變運動方向;第七步,第二輪循環的第一步,重復第一輪的步驟;
B:第四步,蛇碰到自己或牆壁,終止游戲。
結束部分:
游戲結束時,顯示「GAME OVER」,已經是約定俗成的規律了,我的游戲也不例外。除了游戲結束畫面外,我還設置了一個游戲退出畫面,「善始善終」嘛。
有了上述的大致劃分,我把整個程序劃分成(13+2)個模塊(其實就是函數)
2.2.3程序結構(流程圖)
圖2.1流程圖
依據所需要處理的任務要求,規劃輸入數據和輸出結果,決定存放數據的數據結構。
C語言中數據結構集中體現在數據類型上,因此在進行C語言程序設計時,應統籌規劃程序中所使用的變數,數組,指針等,以及它們的類型等。這點是很重要的,如果在此期間選擇不合適的變數或者數組,將來修改就十分困難。
現在分析一下貪吃蛇游戲中的元素,繼而得出與它們對應的在程序中的描述:
蛇:
基本描述:長度,顏色,位置。
對應數據與數據類型:長度—雖然可以用坐標表示,但是這樣的話,運算量將很大,所以換算成較大的單位—節數,以固定長度的每節描述;坐標--整型;顏色--整型; 位置--X,Y坐標。
增加的描述:蛇運動的方向,蛇的生命。
對應數據與數據類型:這些描述是為了與程序的按鍵的輸入部分與判斷游戲結束部分相聯系而設的。方向只有四個方向:上下左右。可以設置與之對應的四個整型數:3、4、2、1。生命就只有兩種情況:死或生,對應0或1。
食物:
基本描述:顏色,位置。
對應數據與數據類型:由於顏色設成固定的,所以不再討論。位置—X、Y坐標。
增加的描述:食物的存在。
對應數據與數據類型:這是為了避免重復出現食物而設置的,與繪制食物的函數有聯系。只有兩個值:0或1(沒有食物或有食物)
其他的元素:牆,由於它在顯示上是作為背景而存在的,所以並沒有什麼說明實際的牆壁就是四條直線組成的邊框,由坐標描述。
還需要的變數:鍵盤鍵入的鍵值(作為全局變數,整型);經常要使用的循環變數;自定義的填充圖案;說明文字的字元數組;游戲的記分;游戲的速度(蛇的速度)。
圖2.2蛇的不停運動的關鍵演算法的流程圖
2.2.4各模塊的功能及程序說明
主要模塊的實現思路和演算法的流程圖說明:
關鍵所在——蛇不停移動的Snakemove():
蛇的不停移動,就是蛇的下一節取代前一節的位置,在計算機中就是蛇下一節的位置坐標變成前一節的位置坐標。在上文中,已定義蛇的位置坐標為數組類型,一組坐標對應一節的位置,假設有i+1節,由0到i節,第i節的坐標取第i-1節的坐標,第i-1節的坐標取第i-2節的坐標??直到第1節取第0節的坐標。而第0節的坐標,即蛇頭的坐標要往某個方向變化,變化量為蛇每節的長度。蛇的這種坐標輪換需要循環語句使其繼續下去。
2.2.5程序結果
運行程序得到如下初始界面圖:
圖2.3程序結果圖
用一個小矩形表示蛇的一節身體,身體每長一節,增加一個矩形塊,蛇頭用兩節表示:
圖2.4程序結果圖
蛇沒有碰到自己或牆壁,蛇繼續前進:
圖2.5程序結果圖
游戲結束時,顯示「GAME OVER」
圖2.6程序結果圖
2.3程序源代碼及注釋
#define N 200
#include <graphics.h>
#include <stdlib.h>
#include <dos.h>
#define LEFT 0x4b00
#define RIGHT 0x4d00
#define DOWN 0x5000
#define UP 0x4800
#define ESC 0x011b
int i,key;
int score=0;/*得分*/
int gamespeed=50000;/*游戲速度自己調整*/
struct Food{
int x;/*食物的橫坐標*/
int y;/*食物的縱坐標*/
int yes;/*判斷是否要出現食物的變數*/
}food;/*食物的結構體*/
struct Snake{
int x[N];
int y[N];
int node;/*蛇的節數*/
int direction;/*蛇移動方向*/
int life;/* 蛇的生命,0活著,1死亡*/
}snake;
void Init(void);/*圖形驅動*/
void Close(void);/*圖形結束*/
void DrawK(void);/*開始畫面*/
void GameOver(void);/*結束游戲*/
void GamePlay(void);/*玩游戲具體過程*/
void PrScore(void);/*輸出成績*/
/*主函數*/
void main(void){
Init();/*圖形驅動*/
DrawK();/*開始畫面*/
GamePlay();/*玩游戲具體過程*/
Close();/*圖形結束*/}
/*圖形驅動*/
void Init(void){
int gd=DETECT,gm;
registerbgidriver(EGAVGA_driver);
initgraph(&gd,&gm,"c:\program files\winyes\tc20h\bgi");
cleardevice();}
/*開始畫面,左上角坐標為(50,40),右下角坐標為(610,460)的圍牆*/
void DrawK(void){
/*setbkcolor(LIGHTGREEN);*/
setcolor(11);
setlinestyle(SOLID_LINE,0,THICK_WIDTH);/*設置線型*/
for(i=50;i<=600;i+=10)/*畫圍牆*/ {
rectangle(i,40,i+10,49); /*上邊*/
rectangle(i,451,i+10,460);/*下邊*/ }
for(i=40;i<=450;i+=10) {
rectangle(50,i,59,i+10); /*左邊*/
rectangle(601,i,610,i+10);/*右邊*/ }}
/*玩游戲具體過程*/
void GamePlay(void){
randomize();/*隨機數發生器*/
food.yes=1;/*1表示需要出現新食物,0表示已經存在食物*/
snake.life=0;/*活著*/
snake.direction=1;/*方嚮往右*/
snake.x[0]=100;snake.y[0]=100;/*蛇頭*/
snake.x[1]=110;snake.y[1]=100;
snake.node=2;/*節數*/
PrScore();/*輸出得分*/
while(1)/*可以重復玩游戲,壓ESC鍵結束*/ {
while(!kbhit())/*在沒有按鍵的情況下,蛇自己移動身體*/ {
if(food.yes==1)/*需要出現新食物*/ {
food.x=rand()%400+60;
food.y=rand()%350+60;
while(food.x%10!=0)/*食物隨機出現後必須讓食物能夠在整格內,這樣才可以讓蛇吃到*/
food.x++;
while(food.y%10!=0)
food.y++;
food.yes=0;/*畫面上有食物了*/ }
if(food.yes==0)/*畫面上有食物了就要顯示*/ {
setcolor(GREEN);
rectangle(food.x,food.y,food.x+10,food.y-10); }
for(i=snake.node-1;i>0;i--)/*蛇的每個環節往前移動,也就是貪吃蛇的關鍵演算法*/ {
snake.x[i]=snake.x[i-1];
snake.y[i]=snake.y[i-1]; }
/*1,2,3,4表示右,左,上,下四個方向,通過這個判斷來移動蛇頭*/
switch(snake.direction) {
case 1:snake.x[0]+=10;break;
case 2: snake.x[0]-=10;break;
case 3: snake.y[0]-=10;break;
case 4: snake.y[0]+=10;break; }
for(i=3;i<snake.node;i++)/*從蛇的第四節開始判斷是否撞到自己了,因為蛇頭為兩節,第三節不可能拐過來*/ {
if(snake.x[i]==snake.x[0]&&snake.y[i]==snake.y[0]) {
GameOver();/*顯示失敗*/
snake.life=1;
break; } }
if(snake.x[0]<55||snake.x[0]>595||snake.y[0]<55||
snake.y[0]>455)/*蛇是否撞到牆壁*/ {
GameOver();/*本次游戲結束*/
snake.life=1; /*蛇死*/ }
if(snake.life==1)/*以上兩種判斷以後,如果蛇死就跳出內循環,重新開始*/
break;
if(snake.x[0]==food.x&&snake.y[0]==food.y)/*吃到食物以後*/ {
setcolor(0);/*把畫面上的食物東西去掉*/
rectangle(food.x,food.y,food.x+10,food.y-10);
snake.x[snake.node]=-20;snake.y[snake.node]=-20;
/*新的一節先放在看不見的位置,下次循環就取前一節的位置*/
snake.node++;/*蛇的身體長一節*/
food.yes=1;/*畫面上需要出現新的食物*/
score+=10;
PrScore();/*輸出新得分*/ }
setcolor(4);/*畫出蛇*/
for(i=0;i<snake.node;i++)
rectangle(snake.x[i],snake.y[i],snake.x[i]+10,
snake.y[i]-10);
delay(gamespeed);
setcolor(0);/*用黑色去除蛇的的最後一節*/
rectangle(snake.x[snake.node-1],snake.y[snake.node-1],
snake.x[snake.node-1]+10,snake.y[snake.node-1]-10); } /*endwhile(!kbhit)*/
if(snake.life==1)/*如果蛇死就跳出循環*/
break;
key=bioskey(0);/*接收按鍵*/
if(key==ESC)/*按ESC鍵退出*/
break;
else
if(key==UP&&snake.direction!=4)
/*判斷是否往相反的方向移動*/
snake.direction=3;
else
if(key==RIGHT&&snake.direction!=2)
snake.direction=1;
else
if(key==LEFT&&snake.direction!=1)
snake.direction=2;
else
if(key==DOWN&&snake.direction!=3)
snake.direction=4;
}/*endwhile(1)*/}
/*游戲結束*/
void GameOver(void){
cleardevice();
PrScore();
setcolor(RED);
settextstyle(0,0,4);
outtextxy(200,200,"GAME OVER");
getch();}
/*輸出成績*/
void PrScore(void){
char str[10];
setfillstyle(SOLID_FILL,YELLOW);
bar(50,15,220,35);
setcolor(6);
settextstyle(0,0,2);
sprintf(str,"score:%d",score);
outtextxy(55,20,str);}
/*圖形結束*/
void Close(void){
getch();
closegraph();
}