自制贪吃蛇——会移动的蛇
上篇地址:http://www.cnblogs.com/chinxi/p/7184063.html
有了主场景,就要加一条蛇进去看看了。这条“蛇”的功能嘛,要有以下几个:
1、改变方向
2、新增一个节点
3、前进
首先,是枚举和结构体:
1 enum Direction 2 { 3 EN_DIR_UP = 0, 4 EN_DIR_DOWN, 5 EN_DIR_LEFT, 6 EN_DIR_RIGHT, 7 }; 8 9 struct Coordinate 10 { 11 int int_x; 12 int int_y; 13 }; 14 15 typedef struct Snake_Base 16 { 17 Snake_Base* pNext; 18 char char_icon; //图标 19 Coordinate coordinate_cur; //当前坐标 20 }SnakeBase; 21 22 typedef struct Snake_Head 23 { 24 char char_icon; //图标 25 int int_direction; //前进方向 26 int int_size; //当前长度 27 Coordinate coordinate_cur; //当前坐标 28 Snake_Base* pNext; //下一节 29 }SnakeHead;
1 /// 2 /// @file snake.h 3 /// @author marrs(chenchengxi993@gmail.com) 4 /// @date 2017-07-15 09:32:47 5 /// 6 7 #ifndef __SNAKE_H__ 8 #define __SNAKE_H__ 9 10 #include "define.h" 11 12 namespace marrs{ 13 14 class Snake 15 { 16 public: 17 Snake(); 18 ~Snake(); 19 20 public: 21 int init(char char_icon, int int_direction, int int_size, Coordinate coordinate); 22 int change_direction(int int_direction); 23 int add_new_node(Coordinate coordinate_new, char char_icon_new); 24 int forward(); 25 Snake_Base* get_snake_base(); 26 SnakeHead* get_snake_head(); 27 28 private: 29 SnakeHead _snake; 30 31 }; 32 33 } 34 35 #endif
改变方向其实很简单,改一下字段的值就行了。新增节点的话,如果不考虑场景,那么只要用头插法,向链表中插入一个新元素即可。至于前进,想到了两种植方法:
其一,“蛇”类中只处理头节点的坐标,其它坐标放在game.cc中处理,把前一个节点的坐标赋值给后一个节点,然后清除最后一个节点的原坐标在场景中的展示。这种方法需要进行多次拷贝,而且要定义多个临时变量,比较麻烦。
其二,“蛇”类中,如果“蛇”的长度大于1,则先调用一波add_new_node方法,再把最后一个节点删除,并返回这个节点的信息。如果size=1,则new一个节点出来,把头节点的原坐标赋值给它,之后game.cc中,直接清理返回的坐标,再设置头节点新坐标即可。
实际上,是先想到第一种方法,而且实现了,后来想到了第二种方法,直接就改了。
1 /// /// @file snake.cc 2 /// @author marrs(chenchengxi993@gmail.com) 3 /// @date 2017-07-15 11:02:32 4 /// 5 6 #include <string.h> 7 #include <iostream> 8 #include "snake.h" 9 10 namespace marrs{ 11 12 Snake::Snake() 13 { 14 } 15 16 Snake::~Snake() 17 { 18 } 19 20 int Snake::init(char char_icon, int int_direction, int int_size, Coordinate coordinate) 21 { 22 _snake.char_icon = char_icon; 23 _snake.int_direction = int_direction; 24 _snake.int_size = int_size; 25 _snake.coordinate_cur = coordinate; 26 _snake.pNext = NULL; 27 28 if (int_size > 1) 29 { 30 for (int int_idx = 0; int_idx < int_size; ++int_idx) 31 { 32 //todo add_new_node 33 } 34 } 35 return 0; 36 37 } 38 39 int Snake::change_direction(int int_direction) 40 { 41 _snake.int_direction = int_direction; 42 return int_direction; 43 } 44 45 int Snake::add_new_node(Coordinate coordinate_new, char char_icon_new) 46 { 47 Snake_Base* pNode = new Snake_Base; 48 memset(pNode, 0, sizeof(Snake_Base)); 49 pNode->coordinate_cur = _snake.coordinate_cur; 50 pNode->char_icon = _snake.char_icon; 51 52 if (_snake.pNext == NULL) 53 { 54 _snake.pNext = pNode; 55 }else{ 56 pNode->pNext = _snake.pNext; 57 _snake.pNext = pNode; 58 } 59 60 _snake.coordinate_cur = coordinate_new; 61 _snake.char_icon = char_icon_new; 62 ++_snake.int_size; 63 64 return 0; 65 } 66 67 Snake_Base* Snake::forward() 68 { 69 Snake_Base* pReturn = NULL; 70 if(_snake.int_size > 1) 71 { 72 add_new_node(_snake.coordinate_cur, _snake.char_icon); 73 Snake_Base* pCur = _snake.pNext; 74 while(pCur->pNext->pNext) 75 { 76 pCur = pCur->pNext; 77 } 78 pReturn = pCur->pNext; 79 pCur->pNext = NULL; 80 81 } 82 else 83 { 84 pReturn = new Snake_Base; 85 pReturn->coordinate_cur = _snake.coordinate_cur; 86 } 87 88 switch(_snake.int_direction) 89 { 90 case EN_DIR_UP: 91 _snake.coordinate_cur.int_x -= 1; 92 break; 93 case EN_DIR_DOWN: 94 _snake.coordinate_cur.int_x += 1; 95 break; 96 case EN_DIR_LEFT: 97 _snake.coordinate_cur.int_y -= 1; 98 break; 99 case EN_DIR_RIGHT: 100 _snake.coordinate_cur.int_y += 1; 101 break; 102 default:break; 103 104 } 105 return pReturn; 106 107 } 108 109 Snake_Base* Snake::get_snake_base() 110 { 111 return _snake.pNext; 112 113 } 114 115 SnakeHead* Snake::get_snake_head() 116 { 117 return &_snake; 118 119 } 120 }
然后,根据需要修改了game.h和game.cc
1 /// 2 /// @file game.h 3 /// @author marrs(chenchengxi993@gmail.com) 4 /// @date 2017-07-15 11:42:03 5 /// 6 7 #ifndef __GAME_H__ 8 #define __GAME_H__ 9 10 #include "map.h" 11 #include "snake.h" 12 13 namespace marrs{ 14 15 class Game 16 { 17 public: 18 int init(); 19 int output_map(); 20 int refresh_map(); 21 int gen_random_point(); 22 int reset_random_point(); 23 24 int forward(); 25 int check_collision(); 26 27 private: 28 Map _map; 29 Snake _snake; 30 Coordinate _random_point; 31 }; 32 33 } 34 35 #endif
新增了一些方法。
1 /// 2 /// @file game.cc 3 /// @author marrs(chenchengxi993@gmail.com) 4 /// @date 2017-07-15 18:05:24 5 /// 6 7 #include <iostream> 8 #include "game.h" 9 10 namespace marrs{ 11 12 int Game::init() 13 { 14 Coordinate coordinate = _map.get_map_center_pos(); 15 _snake.init('O', EN_DIR_DOWN, 1, coordinate); 16 17 MapBase map; 18 map.char_icon = 'O'; 19 map.int_type = EN_MAP_SNAKE; 20 _map.set_map_val(coordinate.int_x, coordinate.int_y, map); 21 22 reset_random_point(); 23 24 output_map(); 25 return 0; 26 27 } 28 29 int Game::output_map() 30 { 31 int int_map_x_size = _map.get_x_size(); 32 int int_map_y_size = _map.get_y_size(); 33 34 for (int int_idx = 0; int_idx < int_map_x_size; ++int_idx) 35 { 36 for (int int_idy = 0; int_idy < int_map_y_size; ++int_idy) 37 { 38 _map.output_map(int_idx, int_idy); 39 } 40 cout << endl; 41 } 42 return 0; 43 44 } 45 46 int Game::refresh_map() 47 { 48 int int_map_y_size = _map.get_y_size(); 49 printf("\033[%dA", int_map_y_size); 50 output_map(); 51 return 0; 52 53 } 54 55 int Game::gen_random_point() 56 { 57 while(_random_point.int_x == 0) 58 { 59 _random_point.int_x = random(_map.get_x_size()); 60 } 61 while(_random_point.int_x == 0) 62 { 63 _random_point.int_y = random(_map.get_y_size()); 64 } 65 return 0; 66 67 } 68 69 int Game::reset_random_point() 70 { 71 _random_point.int_x = 0; 72 _random_point.int_y = 0; 73 return 0; 74 } 75 76 int Game::forward() 77 { 78 int int_ret = check_collision(); 79 if(int_ret) 80 { 81 return int_ret; 82 } 83 84 Snake_Base* snake_tmp = _snake.forward(); 85 86 87 _map.reset_point(snake_tmp->coordinate_cur.int_x, snake_tmp->coordinate_cur.int_y); 88 delete snake_tmp; 89 MapBase map_tmp; 90 map_tmp.int_type = EN_MAP_SNAKE; 91 map_tmp.char_icon = _snake.get_snake_head()->char_icon; 92 _map.set_map_val(_snake.get_snake_head()->coordinate_cur.int_x, 93 _snake.get_snake_head()->coordinate_cur.int_y, 94 map_tmp); 95 96 return 0; 97 } 98 99 int Game::check_collision() 100 { 101 102 return 0; 103 } 104 105 }
可以测试一下
1 /// 2 /// @file main.cc 3 /// @author marrs(chenchengxi993@gmail.com) 4 /// @date 2017-07-15 18:20:18 5 /// 6 7 #include "game.h" 8 using namespace marrs; 9 10 int main() 11 { 12 Game game; 13 game.init(); 14 for(int int_idx = 0; int_idx < 5; ++int_idx) 15 { 16 game.forward(); 17 game.refresh_map(); 18 sleep(1); 19 } 20 21 22 23 24 return 0; 25 }
预期的结果,是“OO”向下移动了五个位置,一秒一次。
执行程序:
开始
1 [ccx@ubuntu ~/Retro_Snaker/bin]$>./game.exe 2 ++====================================++ 3 || || 4 || || 5 || || 6 || || 7 || || 8 || || 9 || || 10 || || 11 || || 12 || OO || 13 || || 14 || || 15 || || 16 || || 17 || || 18 || || 19 || || 20 || || 21 ++====================================++
结束
1 [ccx@ubuntu ~/Retro_Snaker/bin]$>./game.exe 2 ++====================================++ 3 || || 4 || || 5 || || 6 || || 7 || || 8 || || 9 || || 10 || || 11 || || 12 || || 13 || || 14 || || 15 || || 16 || || 17 || OO || 18 || || 19 || || 20 || || 21 ++====================================++ 22 [ccx@ubuntu ~/Retro_Snaker/bin]$>
可以看到,它从第12行,移到了第17行,符合预期。
未完待续....