console下纯字符实现的贪吃蛇
最近简直超级无聊……
code blocks win7 64编译运行无问题,应该其他编译器也不会有问题。
w:上
s:下
a:左
d:右
CS标准方向控制,AK47和M4这种高级货是没有滴……
废话不多说,直接上代码。
#include "stdio.h" #include "stdlib.h" #include "windows.h" #include "time.h" // ---------------------------------------------------------------------------- // definition // ---------------------------------------------------------------------------- // basic char node #define _FOOD "#" #define _SNAKE_NODE "O" #define _SNAKE_END "+" #define _SNAKE_HEAD "@" #define _MAP_NODE " " #define _MAP_EDGE "O" // area pos and range #define _AREA_X_OFFSET 10 #define _AREA_Y_OFFSET 5 #define _AREA_X_LINE_MAX 30 // max line num in x direction #define _AREA_Y_LINE_MAX 20 // max line num in y direction #define _SNAKE_LENGTH_MAX 30 // key val defintion #define _KEY_UP 'w' #define _KEY_DOWN 's' #define _KEY_LEFT 'a' #define _KEY_RIGHT 'd' // default snake speed #define _DEFAULT_SNAKE_SPEED 300 // 1 step per second // ---------------------------------------------------------------------------- // type // ---------------------------------------------------------------------------- // basic type typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned long DWORD; typedef unsigned char * PBYTE; typedef unsigned short * PWORD; typedef unsigned long * PDWORD; // element type typedef enum { _ET_MAP_NODE, _ET_MAP_EDGE, _ET_FOOD, _ET_SNAKE_HEAD, _ET_SNAKE_NODE, _ET_SNAKE_END }E_ET; // snake node type typedef enum { _ESNT_HEAD = _ET_SNAKE_HEAD, _ESNT_NODE = _ET_SNAKE_NODE, _ESNT_END = _ET_SNAKE_END }E_SNT; // node pos typedef struct { BYTE by_x; BYTE by_y; }T_Pos, *PT_Pos; // snake node typedef struct { E_SNT e_type; T_Pos t_pos; //BOOL b_valid; }T_Snake_Node; // direction typedef enum { _UP, _DOWN, _LEFT, _RIGHT }E_DRCT; // snake typedef struct { DWORD dw_speed; E_DRCT e_direction; BYTE by_node_num; T_Snake_Node at_node[_SNAKE_LENGTH_MAX]; }T_Snake; // food typedef struct { BOOL b_eaten; T_Pos t_pos; }T_Food; // key type typedef enum { _E_KT_NONE, _E_KT_UP, _E_KT_DOWN, _E_KT_LEFT, _E_KT_RIGHT, _E_KT_SIZE }E_KEY_TYPE; // ---------------------------------------------------------------------------- // local para // ---------------------------------------------------------------------------- // range buffer E_ET l_ae_area[_AREA_Y_LINE_MAX][_AREA_X_LINE_MAX]; // snake T_Snake l_t_snake; BOOL l_b_key_lock = FALSE; T_Food l_t_food = {.b_eaten = TRUE}; // ---------------------------------------------------------------------------- // function // ---------------------------------------------------------------------------- // ------------------------------------ // pos jump // ------------------------------------ void Pos_Jump(int x, int y) { COORD pos = {_AREA_X_OFFSET + x, _AREA_Y_OFFSET + y}; HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleCursorPosition(hOut, pos); } // ------------------------------------ // draw rect element // ------------------------------------ void Rect_Elem_Draw(E_ET e_et) { switch(e_et) { case _ET_FOOD: printf(_FOOD); break; case _ET_SNAKE_NODE: printf(_SNAKE_NODE); break; case _ET_SNAKE_HEAD: printf(_SNAKE_HEAD); break; case _ET_SNAKE_END: printf(_SNAKE_END); break; case _ET_MAP_EDGE: printf(_MAP_EDGE); break; case _ET_MAP_NODE: default: printf(_MAP_NODE); break; } } // ------------------------------------ // draw map // ------------------------------------ void Area_Refresh( void ) { BYTE i, j, k; // make Y offset for(i=0 ; i<_AREA_Y_OFFSET ; i++) { printf("\r\n"); } // refresh rect line by line for(i=0 ; i<_AREA_Y_LINE_MAX ; i++) { // make X offset for(k=0 ; k<_AREA_X_OFFSET ; k++) { printf(" "); } // draw line for(j=0 ; j<_AREA_X_LINE_MAX ; j++) { Rect_Elem_Draw(l_ae_area[i][j]); } printf("\r\n"); } } // ------------------------------------ // snake init // ------------------------------------ void Snake_Init() { l_t_snake.dw_speed = _DEFAULT_SNAKE_SPEED; l_t_snake.e_direction = _RIGHT; l_t_snake.by_node_num = 3; //l_t_snake.at_node[0].b_valid = TRUE; l_t_snake.at_node[0].e_type = _ESNT_END; l_t_snake.at_node[0].t_pos.by_x = 2; l_t_snake.at_node[0].t_pos.by_y = 1; //l_t_snake.at_node[0].b_valid = TRUE; l_t_snake.at_node[1].e_type = _ESNT_NODE; l_t_snake.at_node[1].t_pos.by_x = 2; l_t_snake.at_node[1].t_pos.by_y = 2; //l_t_snake.at_node[0].b_valid = TRUE; l_t_snake.at_node[2].e_type = _ESNT_HEAD; l_t_snake.at_node[2].t_pos.by_x = 2; l_t_snake.at_node[2].t_pos.by_y = 3; } // ------------------------------------ // area init // notice: should be called after snake // init // ------------------------------------ void Area_Init() { BYTE by_i, by_j; // set area default value for(by_i=0 ; by_i<_AREA_X_LINE_MAX ; by_i++) { for(by_j=0 ; by_j<_AREA_Y_LINE_MAX ; by_j++) { l_ae_area[by_i][by_j] = _ET_MAP_NODE; } } // set area edge value for(by_i=0 ; by_i<_AREA_X_LINE_MAX ; by_i++) { l_ae_area[0][by_i] = _ET_MAP_EDGE; l_ae_area[_AREA_Y_LINE_MAX - 1][by_i] = _ET_MAP_EDGE; } for(by_j=0 ; by_j<_AREA_Y_LINE_MAX ; by_j++) { l_ae_area[by_j][0] = _ET_MAP_EDGE; l_ae_area[by_j][_AREA_X_LINE_MAX - 1] = _ET_MAP_EDGE; } } void Show_Game_Over() { Pos_Jump(_AREA_X_LINE_MAX/4, _AREA_X_LINE_MAX+1); printf("Game Over!"); Pos_Jump(_AREA_X_LINE_MAX/4, _AREA_X_LINE_MAX+2); printf("Press Anykey to Exit..."); } BOOL Snake_Is_Dead() { T_Pos t_head_pos = l_t_snake.at_node[l_t_snake.by_node_num-1].t_pos; BYTE i; // touch area ---------------- if( t_head_pos.by_x == 0 || t_head_pos.by_x >= _AREA_X_LINE_MAX-1 || t_head_pos.by_y == 0 || t_head_pos.by_y >= _AREA_Y_LINE_MAX-1) { Show_Game_Over(); return TRUE; } // touch body -------- for(i=0 ; i<l_t_snake.by_node_num-1 ; i++) { if( t_head_pos.by_x == l_t_snake.at_node[i].t_pos.by_x &&t_head_pos.by_y == l_t_snake.at_node[i].t_pos.by_y) { return TRUE; } } return FALSE; } // ------------------------------------ // on snake moving // ------------------------------------ On_Snake_Moving() { static DWORD dw_time_cur = 0; static DWORD dw_time_last = 0; BYTE by_i = 0; T_Pos t_end_pos_before_moving; BYTE by_neck_index, by_head_index; // check speed dw_time_cur = GetTickCount(); if(dw_time_cur < dw_time_last + l_t_snake.dw_speed) { return; } l_b_key_lock = FALSE; dw_time_last = dw_time_cur; // move by_head_index = l_t_snake.by_node_num - 1; by_neck_index = l_t_snake.by_node_num - 2; if( l_t_snake.at_node[by_neck_index].t_pos.by_x != l_t_snake.at_node[by_head_index].t_pos.by_x ||l_t_snake.at_node[by_neck_index].t_pos.by_y != l_t_snake.at_node[by_head_index].t_pos.by_y) // last step not eat food { t_end_pos_before_moving = l_t_snake.at_node[0].t_pos; for(by_i=1 ; by_i<l_t_snake.by_node_num ; by_i++) { l_t_snake.at_node[by_i - 1].t_pos = l_t_snake.at_node[by_i].t_pos; } // refresh snake Pos_Jump(t_end_pos_before_moving.by_x, t_end_pos_before_moving.by_y); Rect_Elem_Draw(_ET_MAP_NODE); } switch(l_t_snake.e_direction) { case _UP: l_t_snake.at_node[by_head_index].t_pos.by_y--; break; case _DOWN: l_t_snake.at_node[by_head_index].t_pos.by_y++; break; case _LEFT: l_t_snake.at_node[by_head_index].t_pos.by_x--; break; case _RIGHT: l_t_snake.at_node[by_head_index].t_pos.by_x++; break; } for(by_i=0 ; by_i<l_t_snake.by_node_num ; by_i++) { Pos_Jump(l_t_snake.at_node[by_i].t_pos.by_x, l_t_snake.at_node[by_i].t_pos.by_y); Rect_Elem_Draw(l_t_snake.at_node[by_i].e_type); } // eat food if( l_t_snake.at_node[by_head_index].t_pos.by_x == l_t_food.t_pos.by_x &&l_t_snake.at_node[by_head_index].t_pos.by_y == l_t_food.t_pos.by_y) { l_t_snake.at_node[by_head_index+1] = l_t_snake.at_node[by_head_index]; l_t_snake.at_node[by_head_index].e_type = _ESNT_NODE; l_t_snake.by_node_num++; l_t_food.b_eaten = TRUE; } } // ------------------------------------ // key detect // ------------------------------------ E_KEY_TYPE Key_Detect() { BYTE by_key_value; E_KEY_TYPE e_kt; if(0 == kbhit()) { return _E_KT_NONE; } by_key_value = (BYTE)(getch()); if(l_b_key_lock) { return _E_KT_NONE; } switch(by_key_value) { case _KEY_UP: e_kt = _E_KT_UP; break; case _KEY_DOWN: e_kt = _E_KT_DOWN; break; case _KEY_LEFT: e_kt = _E_KT_LEFT; break; case _KEY_RIGHT: e_kt = _E_KT_RIGHT; break; default: e_kt = _E_KT_NONE; break; } return e_kt; } // ------------------------------------ // changing snake direction // ------------------------------------ void On_Changing_Snake_Drctn(E_KEY_TYPE e_kt) { switch(e_kt) { case _E_KT_UP: if( (_LEFT == l_t_snake.e_direction) ||(_RIGHT == l_t_snake.e_direction)) { l_t_snake.e_direction = _UP; } break; case _E_KT_DOWN: if( (_LEFT == l_t_snake.e_direction) ||(_RIGHT == l_t_snake.e_direction)) { l_t_snake.e_direction = _DOWN; } break; case _E_KT_LEFT: if( (_UP == l_t_snake.e_direction) ||(_DOWN == l_t_snake.e_direction)) { l_t_snake.e_direction = _LEFT; } break; case _E_KT_RIGHT: if( (_UP == l_t_snake.e_direction) ||(_DOWN == l_t_snake.e_direction)) { l_t_snake.e_direction = _RIGHT; } break; } } // ------------------------------------ // On key down // ------------------------------------ void On_Key_Down() { E_KEY_TYPE e_kt; e_kt = Key_Detect(); if(_E_KT_NONE != e_kt) { // lock keyboard l_b_key_lock = TRUE; // changing snake direction On_Changing_Snake_Drctn(e_kt); // system operation } } void Refresh_Food() { T_Pos t_food_pos; if(l_t_food.b_eaten) { srand(time(0)); t_food_pos.by_x = rand()%(_AREA_X_LINE_MAX-1-1)+1; t_food_pos.by_y = rand()%(_AREA_Y_LINE_MAX-1-1)+1; l_t_food.t_pos = t_food_pos; Pos_Jump(l_t_food.t_pos.by_x, l_t_food.t_pos.by_y); Rect_Elem_Draw(_ET_FOOD); l_t_food.b_eaten = FALSE; } } // ------------------------------------ // main // ------------------------------------ int main() { int i_tmp = 0; Area_Init(); Area_Refresh(); Snake_Init(); while(1) { On_Key_Down(); On_Snake_Moving(); Refresh_Food(); if(TRUE == Snake_Is_Dead()) { break; } } getch(); return 0; }
上张截图