由於使用了一些庫文件,上傳了下載還需要積分,所以我會把所以代碼都上傳,方便日後複習結構設計的方向希望能有所作用,如果有什麼缺點多謝點評
首先是文件的劃分
需要注意的是,在函數命名的時候要注意清晰明瞭,還有就是注意模塊的劃分要清晰,該是哪個模塊的任務就由哪個模塊去做,不要混亂結果,打個比方,如蛇身的繪畫,可以是snake模塊的任務,但是在實際設計上,繪畫並不是蛇本身的屬性,他應該是view模塊的任務,這樣這是爲了保證數據和操作相互隔離,分工明確。所以在整個程序中會有許多的函數去獲得,snake和food的指針,這樣看似麻煩。但卻是在解決問題時得到了方便。
另外還有注意的是,在編寫程序是要注意模塊劃分,儘可能減少全局變量的使用,如果非要用全局變量也要避免該變量被其他模塊直接操作,這樣就會使代碼安全性提升。
當然在後面的程序中有一處變量我使用了extern int去共享,這個設計其實不太好,但是由於那幾個窗口id屬性是庫函數調用的結果,所以我在這偷了個懶,希望大家不要學習
其次一點就是在跟新遊戲數據時,這裏採用了掩碼的方式去比對,選擇跟新的選項,這個技巧還是十分有用的
snake.h
我爲了方便給頭文件加了很多預編譯,這是個極差的方式,請勿模仿。再此只是爲了我調試的時候方便,是一個錯誤的做法
那麼接下來整個程序還是分爲四個模塊,snake,food,view,main
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include<assert.h>
#include<Windows.h>
#include <conio.h>
#include "glConsole.h"
typedef struct body
{
int x;
int y;
struct body *next;
}body;
typedef enum _tagDir
{
Left,
Right,
Up,
Down
} Movedir;
typedef struct Snake
{
body* head;
body* tail;
Movedir movedir;
Movedir newmovedir;//改變方向時,新的移動方向
int last_tx; // 存儲蛇尾最後位置
int last_ty;
}Snake;
typedef struct _tagFood
{
int x;
int y;
} Food;
//snake
body *body_make(int x, int y, body *next);
Snake* snake_init();
void snake_release();
bool snake_death();
void snake_grow();
void snake_update();
Snake *retrn_snake_info();
//food
void food_make();
bool food_eat_hit();
Food return_food_info();
//view
void window_init();
void window_release();
void window_show_about();
void window_show_gameinfo(int score, int level, int speed);
void window_draw_wall();
void snake_draw();
void snake_tail_empty();
void food_draw();
snake.c
#include"snake.h"
extern int about_window; // 關於窗口ID
extern int score_window; // 成績窗口ID
extern int snake_window; // 遊戲窗口ID
Snake* snake = NULL;//蛇的全局變量
body *body_make(int x, int y, body *next)
{
body *p = (body*)malloc(sizeof(body));
p->x = x;
p->y = y;
p->next = next;
return p;
}
Snake* snake_init()
{
snake = (Snake*)malloc(sizeof(Snake));
body *sn1 = body_make(17, 10, NULL);
body *sn2 = body_make(18, 10, sn1);
body *sn3 = body_make(19, 10, sn2);
body *sn4 = body_make(20, 10, sn3);
snake->head = sn4;
snake->tail = sn1;
snake->last_tx = sn1->x;
snake->last_ty = sn1->y;
snake->movedir = Right;
snake->newmovedir = Right;
return snake;
}
void snake_release()
{
body *p = snake->head;
while (p != NULL)
{
body *tmp = p->next;
free(p);
p = tmp;
}
free(snake);
}
void snake_update()
{
snake->movedir = snake->newmovedir;
snake->last_tx = snake->tail->x;
snake->last_ty = snake->tail->y;
body *prev = snake->head;
body *curr = snake->head->next;
int x = prev->x;
int y = prev->y;
while (curr != NULL)
{
int xx = curr->x;
int yy = curr->y;
curr->x = x;
curr->y = y;
prev = curr;
curr = curr->next;
x = xx;
y = yy;
}
int xxx = 0;
int yyy = 0;
switch (snake->movedir)
{
case Left:xxx = -1; break;
case Right:xxx = 1; break;
case Up:yyy = -1; break;
case Down:yyy = 1; break;
default:break;
}
snake->head->x += xxx;
snake->head->y += yyy;
}
void snake_grow()
{
body *p = (body*)malloc(sizeof(body));
p->x = snake->last_tx;
p->y = snake->last_ty;
snake->tail->next = p;
p->next = NULL;
snake->tail = p;
}
bool snake_death()
{
int x, y, w, h;
glmxConsole_GetWindowRect(snake_window, &x, &y, &w, &h);
if (snake->head->x == w || snake->head->x == 1 || snake->head->y == 0 || snake->head->y == h )
return true;
body *p = snake->head->next;
while (p->next != NULL)
{
if (snake->head->x == p->x&&snake->head->y == p->y)
return true;
else p = p->next;
}
return false;
}
Snake *retrn_snake_info()
{
assert(snake!=NULL);
return snake;
}
food.c
#include"snake.h"
extern int about_window; // 關於窗口ID
extern int score_window; // 成績窗口ID
extern int snake_window; // 遊戲窗口ID
Food food;
void food_make()
{
int x, y, w, h;
glmxConsole_GetWindowRect(snake_window, &x, &y, &w, &h);
food.x= rand() % (w-1) + 1;
food.y= rand() % (h-1) + 1;
}
bool food_eat_hit()
{
Snake *snake = retrn_snake_info();
if (food.x == snake->head->x&&food.y == snake->head->y)
return true;
else return false;
}
Food return_food_info()
{
return food;
}
view.c
#include"snake.h"
int about_window = -1; // 關於窗口ID
int score_window = -1; // 成績窗口ID
int snake_window = -1; // 遊戲窗口ID
void window_init()
{
int main_window;
int bottom_window1;
main_window = glmxConsole_CreateWindow(60, 30, "Snake");
glmxConsole_SplitWindow(main_window, 3, WND_SPLIT_HORIZONTAL, '=', 9, &about_window, &bottom_window1);
glmxConsole_SplitWindow(bottom_window1, 2, WND_SPLIT_HORIZONTAL, '=', 9, &score_window, &snake_window);
}
void window_release()
{
}
void window_show_about()
{
glmxConsole_WndDrawFormatText(about_window, 0, 0, 12, "Snake Ver1.0", TEXT_ALIGN_CENTER);
glmxConsole_WndDrawFormatText(about_window, 0, 2, 12, "GLimix Studio - ZYF", TEXT_ALIGN_CENTER);
}
void window_show_gameinfo(int score,int level,int speed)
{
char buffer[32];
sprintf_s(buffer, 32, "SCORE: %d", score);
glmxConsole_WndDrawFormatText(score_window, 0, 0, 6, buffer, TEXT_ALIGN_LEFT);
sprintf_s(buffer, 32, "LEVEL: %d", level);
glmxConsole_WndDrawFormatText(score_window, 0, 1, 6, buffer, TEXT_ALIGN_LEFT);
sprintf_s(buffer, 32, "SPEED: %d", speed);
glmxConsole_WndDrawFormatText(score_window, 0, 1, 8, buffer, TEXT_ALIGN_RIGHT);
}
void window_draw_wall()
{
int x, y, w, h;
glmxConsole_GetWindowRect(snake_window, &x, &y, &w, &h);
for (int i = 0; i < w; i++)
{
glmxConsole_WndDrawTextEx(snake_window, i, 0, 82, " ");
glmxConsole_WndDrawTextEx(snake_window, i, h, 82, " ");
}
for (int i = 0; i < h; i++)
{
glmxConsole_WndDrawTextEx(snake_window, 0, i, 82, " ");
glmxConsole_WndDrawTextEx(snake_window, w, i, 82, " ");
}
}
void snake_draw()
{
Snake *snake = retrn_snake_info();
body *p = snake->head;
while (p->next != NULL)
{
if (p == snake->head)
glmxConsole_WndDrawTextEx(snake_window, p->x, p->y, 8, "@");
else
glmxConsole_WndDrawTextEx(snake_window, p->x, p->y, 8, "=");
p = p->next;
}
glmxConsole_WndDrawTextEx(snake_window, p->x, p->y, 8, "-");
}
void snake_tail_empty()
{
Snake *snake = retrn_snake_info();
glmxConsole_WndDrawTextEx(snake_window, snake->last_tx, snake->last_ty, 8, " ");
}
void food_draw()
{
Food food = return_food_info();
glmxConsole_WndDrawTextEx(snake_window, food.x, food.y, 4, "*");
}
main.c
#include"snake.h"
extern int about_window; // 關於窗口ID
extern int score_window; // 成績窗口ID
extern int snake_window; // 遊戲窗口ID
//更新掩碼
#define update_none 0x00
#define update_score 0x01
#define update_all 0x08
void update_info(int *score, int *level, int *speed, int update)
{
switch (update)
{
case update_none:break;
case update_score:*score += 1;break;
case update_all:
*score += 1;
*level += 1;
*speed += 1;
break;
}
}
int main()
{
system("cls");
glmxConsole_Init();
window_init();
int score = 0;
int level = 1;
int speed = 1;
window_show_about();
window_show_gameinfo(score, level, speed);
window_draw_wall();
Snake *snake = NULL;
snake=snake_init();
snake_draw();
int time_count = 20;//畫面更新計時器
int time = 10;
int update;
bool food_existence = false;
for (;;)
{
snake_death();
if (time_count-- == 0)
{
snake_update();
snake_tail_empty();
snake_draw();
glmxConsole_SetCursorPosition(59, 29);
if (food_eat_hit())
{
update_info(&score, &level, &speed, update_score);
window_show_gameinfo(score, level, speed);
if (score % 5 == 0)
{
update_info(&score, &level, &speed, update_all);
if (time != 0)
{
time -= 1;
}
}
food_existence = false;
snake_grow();
}
if (!food_existence)
{
food_make();
food_draw();
food_existence = true;
}
if (snake_death())
{
glmxConsole_WndDrawTextEx(snake_window, 25,8, 2, "GAME OVER \n");
break;
}
time_count = 20;
}
if (kbhit())
{
char move = getch();
switch (move)
{
case 'w':
case 'W':
if (snake->movedir != Down)
snake->newmovedir = Up;
break;
case 's':
case 'S':
if (snake->movedir != Up)
snake->newmovedir = Down;
break;
case 'd':
case 'D':
if (snake->movedir != Left)
snake->newmovedir = Right;
break;
case 'a':
case 'A':
if (snake->movedir != Right)
snake->newmovedir = Left;
break;
}
}
Sleep(time);
}
getch();
snake_release();
window_release();
glmxConsole_Release();
return 0;
}