《計算機程序設計》課程設計報告
課 題 名 稱 貪喫蛇遊戲
班 級 軟件1班
姓 名 neolone
目錄
1 需求分析
【闡述課程設計應該完成的功能】
使用鍵盤的上下左右,來控制蛇的運動方向,ESC鍵退出,並顯示得分。
2 系統分析和設計
2.1 數據結構的設計和選擇的理由
本遊戲中涉及的主要數據結構是如何表示運動的蛇、食物狀態等問題。
2.1.1 從遊戲參考畫面中我們可以看到,貪喫蛇的身體是一節節的,由一個個大小相同的方塊組成,那麼我們可以用一個(x,y)座標爲左上角的、固定寬度的正方形來表示一節蛇身。爲表示連續的多節身體,那麼我們可以採用數組(或鏈表,或線性表)等數據結構來表示。下面以數組方式爲例:
struct Point {
int x, y;
}
struct Point nodes[MAX_LENGTH]; //蛇身數組,MAX_LENGTH爲最大蛇長
貪喫蛇是在不斷的運動的,我們研究蛇的運動可以發現這樣的特點:
1. 蛇頭由鍵盤控制,鍵盤不操作時,保持原有方向運動;(用 intdirection;表示)
2. 運動時,蛇身後面一節移動到前面一節的位置。當我們用nodes[0]表示蛇頭的時候,nodes[1]運動到nodes[0]處;nodes[2]運動到nodes[1]處...。
3. 喫到一個食物以後,蛇身會增加一節。即該數組中的有效數據個數加一。(用int length;表示)
根據上面的情況,我們可以設計蛇的數據結構如下:
struct Snake {
struct Point nodes[MAX_LENGTH]; //蛇身數組,保存每節蛇身的座標。MAX_LENGTH爲最大蛇長
int length; //當前蛇長
int direction; //蛇頭運動方向
int live; //蛇活的,還是已經死了?
}
2.1.2 關於食物,有兩個屬性:
1. 座標位置
2. 狀態:存在,或被喫。
故我們用以下結構表示:
struct Food {
struct Point position; //食物的位置
int exist; //存在?還是被喫?
}
2.2 系統模塊劃分和模塊結構
void main() {
init(); /*初始化*/
l=1;
while(l) /*循環遊戲*/
{
select(); /*遊戲速度和結束的選擇菜單*/
gamePlay(); /*遊戲主程序*/
}
close(); /*關閉遊戲*/
}
2.3 流程圖
2.4 數據類型、全局變量和函數說明
2.4.1數據類型
struct Point { /*一個存放點座標的結構體*/
intx, y; /*被多個結構體調用的基本參數,所以統一用point結構體來表示*/
};
struct Snake { /*用來模擬蛇狀態的結構體*/
structPoint nodes[MAX_LENGTH]; /*用來存放蛇每一節的位置*/
intlength; /*蛇長*/
intdirection; /*蛇移動的方向*/
intlive; /*蛇是否活着*/
} snake;
/*比較形象的把蛇抽象爲一個數據類型*/
struct Food { /*用來模擬食物狀態的結構體*/
structPoint position; /*食物的位置*/
intexist; /*食物是否存在*/
} food;
2.4.2全局變量
Score \\得分
left,top,right,bottom \\遊戲區域範圍
lastx,lasty \\用來保存最後一節蛇的位置
keyCode \\用來保存按下的鍵
2.4.3函數說明
void init(void); \\初始化程序,給一些初始值賦值
void gamePlay(void); \\遊戲主循環
void close(void); \\關閉遊戲
void drawWall(void); \\畫牆
void createFood(void); \\創造一個食物
void drawFood(void); \\畫出食物
void drawSnake(void); \\畫出蛇
void drawScore(void); \\畫出分數
int touchWall(void); \\判斷是否碰到牆
int touchSelf(void); \\判斷是否碰到自己
void gameOver(void); \\遊戲結束
void moveSnake(void); \\移動蛇
int oppositeDirection(int keyCode); \\判斷是否方向有誤
int foodEat(void); \\判斷是否喫到食物
void expandSnake(void); \\把蛇增長一節
3 程序測試和運行結果
----------------------------------------------------------------------------選擇速度開始或退出
----------------------------------------------------------------------------------------遊戲運行中
--------------------------------------------------------------------------------------------------------遊戲結束
4 課程報告小結
【遇到的問題及解決方法分析等】
4.1分數重疊顯示
解決方法:每次都用一塊黑的矩形覆蓋
setfillstyle(1,16);
bar(45,45,150,80);
4.2速度太快
解決方法:循環delay
for(d=0;d<4;d++)
delay(GAME_SPEED);
4.3食物可能出現在蛇身上
解決方法:依次判斷,若重疊則重新生成食物
void createFood() {
inti;
label:
food.position.x=left+10*((int)rand()%11);
food.position.y=top+10*((int)rand()%11);
for(i=0;i<=snake.length-1;i++){
if(snake.nodes[i].x==food.position.x&&snake.nodes[i].y==food.position.y)
gotolabel;
}
附錄A:程序源代碼
/*writer: neolone*/
#include<graphics.h>
#include<stdlib.h>
#include<time.h>
#include<stdio.h>
#include<dos.h>
#include<conio.h>
#include<bios.h>
#define TRUE 1
#define FALSE 0
#define UP0x4800
#define DOWN0x5000
#define LEFT0x4B00
#define RIGHT0x4D00
#define ESC0x011B
#define SPEED10x0231
#define SPEED20x0332
#define SPEED30x0433
#defineQUIT 0x0B30
#define ENTER 0x1C0D
#defineMAX_LENGTH 100 /* max length ofsnake nodess */
#defineGAME_SPEED 100 /* game speed */
/* datastructure */
struct Point {
int x, y;
};
struct Snake {
struct Pointnodes[MAX_LENGTH];
int length;
int direction;
int live;
} snake;
struct Food {
struct Pointposition;
int exist;
} food;
intscore=0,max,max1,max2,max3,left=200,top=200,right=300,bottom=300,lastx,lasty,keyCode,keyCode2,sp,l,sel,times=1;
char text[80];
/* functionsdeclaration */
void init(void);
voidgamePlay(void);
voidclose(void);
voiddrawWall(void);
voidcreateFood(void);
voiddrawFood(void);
voiddrawSnake(void);
voiddrawScore(void);
inttouchWall(void);
inttouchSelf(void);
voidgameOver(void);
void moveSnake(void);
intoppositeDirection(int keyCode);
intfoodEat(void);
voidexpandSnake(void);
voidselect(void);
/*------------------------*/
void main() {
init();
l=1;
while(l)
{
select();
gamePlay();
}
close();
}
void init() {
int gdriver=VGA ,gmode=VGAHI ;
snake.nodes[0].x=250;
snake.nodes[0].y=250;
snake.nodes[1].x=250;
snake.nodes[1].y=260;
snake.length=2;
snake.live=1;
snake.direction=UP;
score=0;
food.exist=0;
initgraph(&gdriver,&gmode,"C:\\tc20\\BGI");
randomize();/*sui ji shu fa sheng qi*/
drawWall();
}
void close() {
FILE *fp;
closegraph();
if((fp=fopen("data.txt","w"))==NULL) /*關閉時保存最高分*/
{
exit(0);
}
else
{
fprintf(fp,"%d,%d,%d",max1,max2,max3);
fclose(fp);
}
printf("pessany key to continue");
}
void gamePlay() {
int keyCode,d;
getch();
while(TRUE) {
drawScore();
drawWall();
if(touchWall() || touchSelf()) {
gameOver();
return;
}
if(!food.exist) createFood();
food.exist=1;
drawFood();
drawSnake();
for(d=0;d<sp;d++)
delay(GAME_SPEED);
if(bioskey(1) != 0) {
keyCode= bioskey(0);
switch(keyCode){
caseESC:
gameOver();
return;
default:
lastx=snake.nodes[snake.length-1].x;
lasty=snake.nodes[snake.length-1].y;
if(!oppositeDirection(keyCode)) {
snake.direction= keyCode;
}
}
}
moveSnake();
if(foodEat()) {
food.exist= FALSE;
score+= 10;
expandSnake();
}
}
}
void drawWall(){
rectangle(left,top,right+10,bottom+10);
}
voidcreateFood() {
int i;
label:
food.position.x=left+10*((int)rand()%11);
food.position.y=top+10*((int)rand()%11);
for(i=0;i<=snake.length-1;i++){
if(snake.nodes[i].x==food.position.x&&snake.nodes[i].y==food.position.y)
goto label;
}
}
void drawFood(){
setfillstyle(1,2);
bar(food.position.x,food.position.y,food.position.x+10,food.position.y+10);
}
void drawSnake(){
int j;
setfillstyle(1,4);
for(j=0;j<=snake.length-1;j++)
{
bar(snake.nodes[j].x,snake.nodes[j].y,snake.nodes[j].x+10,snake.nodes[j].y+10);
}
}
voiddrawScore(void) {
setfillstyle(1,16);
bar(45,45,150,80);
setcolor(WHITE);
sprintf(text,"writer:neolone");
outtextxy(170,50,text);
sprintf(text,"score:%5d",score);
outtextxy(50,50,text);
}
int touchWall(){
int x1=snake.nodes[0].x;
int y1=snake.nodes[0].y;
if(x1<left||x1>right||y1<top||y1>bottom)
return TRUE;
else
return FALSE;
}
int touchSelf(){
int i;
for (i=3;i<snake.length-1;i++)
{
if(snake.nodes[0].x==snake.nodes[i].x&&snake.nodes[0].y==snake.nodes[i].y)
return TRUE;
}
return FALSE;
}
void gameOver(){
FILE *fp;
int x2,y2;
x2=180;
y2=250;
setcolor(WHITE);
sprintf(text,"Gameover !!your score is %d,%d",score,sel);
outtextxy(x2,y2,text);
delay(1000);
getch();
switch(sel%4)
{
case 1:
if(score>max1)
{
max1=score;
}
break;
case 2:
if(score>max2)
{
max2=score;
}
break;
case 3:
if(score>max3)
{
max3=score;
}
break;
default :
{
break;
}
}
}
void moveSnake(){
int k;
setfillstyle(1,16);
lastx=snake.nodes[snake.length-1].x;
lasty=snake.nodes[snake.length-1].y;
bar(snake.nodes[snake.length-1].x,snake.nodes[snake.length-1].y,snake.nodes[snake.length-1].x+10,snake.nodes[snake.length-1].y+10);
for(k=snake.length-2;k>=0;k--)
{
snake.nodes[k+1].x=snake.nodes[k].x;
snake.nodes[k+1].y=snake.nodes[k].y;
}
if(snake.direction==UP)
snake.nodes[0].y-=10;
else if(snake.direction==DOWN)
snake.nodes[0].y+=10;
else if(snake.direction==LEFT)
snake.nodes[0].x-=10;
else if(snake.direction==RIGHT)
snake.nodes[0].x+=10;
else
;
}
intoppositeDirection(int keyCode) {
if(keyCode==UP&&snake.direction==DOWN){
return 1;
}
elseif(keyCode==DOWN&&snake.direction==UP) {
return 1;
}
elseif(keyCode==LEFT&&snake.direction==RIGHT){
return 1;
}
elseif(keyCode==RIGHT&&snake.direction==LEFT){
return 1;
}
else
return 0;
}
int foodEat() {
if(snake.nodes[0].x==food.position.x&&snake.nodes[0].y==food.position.y)
return 1;
else
return 0;
}
voidexpandSnake() {
if(keyCode==UP){
lastx-=10;
}
else if(keyCode==DOWN) {
lastx+=10;
}
else if(keyCode==LEFT){
lasty-=10;
}
else if(keyCode==RIGHT){
lasty+=10;
}
else
;
snake.nodes[snake.length].x=lastx;
snake.nodes[snake.length].y=lasty;
snake.length++;
}
void select()
{
setfillstyle(1,7); /*實現選擇速度的可視化菜單*/
bar(420,220,490,310);
setfillstyle(1,9);
bar(430,230,480,240);
setfillstyle(1,5);
setcolor(WHITE);
sprintf(text,"speed1");
outtextxy(430,230,text);
bar(430,250,480,260);
sprintf(text,"speed2");
outtextxy(430,250,text);
bar(430,270,480,280);
sprintf(text,"speed3");
outtextxy(430,270,text);
bar(430,290,480,300);
sprintf(text," quit ");
outtextxy(430,290,text);
sel=1;
t=1;
while(t){
delay(10);
if (bioskey(1) != 0) {
keyCode =bioskey(0);
switch(keyCode){
caseUP:
sel--;break;
caseDOWN:
sel++;break;
caseENTER:
t=0;break;
default :
break;
}
switch(sel%4) {
case0:
setfillstyle(1,9);
bar(430,290,480,300);
setcolor(WHITE);
setfillstyle(1,5);
bar(430,230,480,240);
sprintf(text,"speed1");
outtextxy(430,230,text);
bar(430,250,480,260);
sprintf(text,"speed2");
outtextxy(430,250,text);
bar(430,270,480,280);
sprintf(text,"speed3");
outtextxy(430,270,text);
sprintf(text,"quit ");
outtextxy(430,290,text);
break;
case1:
setfillstyle(1,9);
bar(430,230,480,240);
setfillstyle(1,5);
setcolor(WHITE);
sprintf(text,"speed1");
outtextxy(430,230,text);
bar(430,250,480,260);
sprintf(text,"speed2");
outtextxy(430,250,text);
bar(430,270,480,280);
sprintf(text,"speed3");
outtextxy(430,270,text);
bar(430,290,480,300);
sprintf(text,"quit ");
outtextxy(430,290,text);
break;
case2:
setfillstyle(1,9);
bar(430,250,480,260);
setfillstyle(1,5);
bar(430,230,480,240);
setcolor(WHITE);
sprintf(text,"speed1");
outtextxy(430,230,text);
sprintf(text,"speed2");
outtextxy(430,250,text);
bar(430,270,480,280);
sprintf(text,"speed3");
outtextxy(430,270,text);
bar(430,290,480,300);
sprintf(text,"quit ");
outtextxy(430,290,text);
break;
case3:
setfillstyle(1,9);
bar(430,270,480,280);
setfillstyle(1,5);
bar(430,230,480,240);
setcolor(WHITE);
sprintf(text,"speed1");
outtextxy(430,230,text);
bar(430,250,480,260);
sprintf(text,"speed2");
outtextxy(430,250,text);
sprintf(text,"speed3");
outtextxy(430,270,text);
bar(430,290,480,300);
sprintf(text,"quit ");
outtextxy(430,290,text);
break;
default:
break;
}
}
}
/*ch=getch();*/
if(times==1) /*讀取歷史最高分*/
{
if((fp=fopen("data.txt","r"))==NULL)
{
sprintf(text,"Can not open thefile");
exit(0);
}
else
{
fscanf(fp,"%d,%d,%d",&max1,&max2,&max3);
}
fclose(fp);
times=0;
}
switch(sel%4) { /*選擇速度*/
case0:
l=0;
gameOver();
close();
break;
case1:
sp=5;
init();
sprintf(text,"Hightestscore:%d",max1);
outtextxy(50,90,text);
break;
case2:
sp=3;
init();
sprintf(text,"Hightestscore:%d",max2);
outtextxy(50,90,text);
break;
case3:
sp=1;
init();
sprintf(text,"Hightestscore:%d",max3);
outtextxy(50,90,text);
break;
default:
break;
}
}
這是資源地址,源代碼http://download.csdn.net/source/3483954
設計報告http://download.csdn.net/source/3483963