自家製食いしん坊蛇——方向制御、初期長さ増加
51100 ワード
前のアドレス:http://www.cnblogs.com/chinxi/p/7185309.html
動く「蛇」があったら、方向を変える方法を書き始めます。
これはlinuxの下で実行されているので、windowsの下のgetchのような方法はなく、キーを入力したいです。リターンを入力しないと、プログラムに応答があります。
でも、このような方式を思い付くことができるなら、前にきっと一部の先輩も同じ問題に出会ったことがあります。案の定、解決策が見つかった。
http://blog.csdn.net/shawnkong/article/details/36658177
これはどういう意味ですか?今は分かりませんが、直接コードを拷問してテストしてみたらいいです。そのまま使ってください。
初期長がまだ1の場合は、まずその移動方向を制御してみよう。
game.hに新しい方法を追加します。
main.ccのサイクルもここに移転して、後期処理に便利です。
テストの結果は以下の通りです。
プログラムを実行
では、初期の長さが1でないとどうなりますか?
game.ccのinit方法を修正する:
この時、snake.hとsnake.cは修正されていません。そのinit方法の中で、add_new_nodeはまだtodoの状態なので、このパラメータが変更されたのも白です。
そこで私はこの方法を加えて、前の一つが蛇の長さが1より大きい場合、coreのbugになるということを発見しました。
そこで、snakeを修正しました。
はい、テストしてみます。
プログラムを実行
現在は衝突検査をしていませんので、ずっと右か下に移動すると「壁」を食べて外に出ます。ずっと左か上に行くと、プログラムがかかります。左右または上下を繰り返すと、2つだけに展示されます。
今は前進と方向制御を分離します。いろいろな方法を考えました。例えば、epollを使って、タイマーを書いたり、マルチスレッドを使ったり、プロセスをしたりします。比較的簡単な方法は、入力をサブスレッドで待つことです。メインスレッドはデッドループで、タイミングよく前進すればいいです。
game.hの増加方法
game.ccの中の変化も小さいです。
テスト結果はここでは送れません。
未完次号
github:https://github.com/ccx19930930/Retro_スナカー
動く「蛇」があったら、方向を変える方法を書き始めます。
これはlinuxの下で実行されているので、windowsの下のgetchのような方法はなく、キーを入力したいです。リターンを入力しないと、プログラムに応答があります。
でも、このような方式を思い付くことができるなら、前にきっと一部の先輩も同じ問題に出会ったことがあります。案の定、解決策が見つかった。
http://blog.csdn.net/shawnkong/article/details/36658177
これはどういう意味ですか?今は分かりませんが、直接コードを拷問してテストしてみたらいいです。そのまま使ってください。
初期長がまだ1の場合は、まずその移動方向を制御してみよう。
game.hに新しい方法を追加します。
1 ///
2 /// @file game.h
3 /// @author marrs([email protected])
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(); //todo
26
27 int input(); //add
28 int change_direction(); //add
29 int loop(); //add
30
31 private:
32 Map _map;
33 Snake _snake;
34 Coordinate _random_point;
35 bool _bool_is_need_exit; //add
36 };
37
38 }
39
40 #endif
main.ccのサイクルもここに移転して、後期処理に便利です。
1 int Game::input()
2 {
3 struct termios stored_settings;
4 struct termios new_settings;
5 tcgetattr (0, &stored_settings);
6 new_settings = stored_settings;
7 new_settings.c_lflag &= (~ICANON);
8 new_settings.c_cc[VTIME] = 0;
9 new_settings.c_cc[VMIN] = 1;
10 tcsetattr (0, TCSANOW, &new_settings);
11 char char_input = getchar();
12 putchar('\b');
13 tcsetattr (0, TCSANOW, &stored_settings);
14 switch(char_input)
15 {
16 case 'w':return EN_DIR_UP;
17 case 's':return EN_DIR_DOWN;
18 case 'a':return EN_DIR_LEFT;
19 case 'd':return EN_DIR_RIGHT;
20 default:break;
21
22 }
23
24 return -1;
25 }
26
27 int Game::change_direction()
28 {
29 int int_new_direction = input();
30 if (int_new_direction == -1)
31 {
32 _bool_is_need_exit = true;
33 }else
34 {
35 _snake.change_direction(int_new_direction);
36 }
37 return 0;
38 }
39
40 int Game::loop()
41 {
42 while(!_bool_is_need_exit)
43 {
44 change_direction();
45 forward();
46 refresh_map();
47
48 }
49 return 0;
50
51 }
今は簡単に作って、方向を入力して、蛇が前に進みます。テストのために、まず方向をコントロールして、他のものを実現したいです。テストの結果は以下の通りです。
プログラムを実行
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 ++====================================++
この時は進んでいません。「w」を押したら 1 [ccx@ubuntu ~/Retro_Snaker]$>./bin/game.exe
2 ++====================================++
3 || ||
4 || 、 ||
5 || ||
6 || ||
7 || ||
8 || ||
9 || ||
10 || ||
11 || OO ||
12 || ||
13 || ||
14 || ||
15 || ||
16 || ||
17 || ||
18 || ||
19 || ||
20 || ||
21 ++====================================++
1行上に移動して、それぞれ「w」、「s」、「a」、「d」をテストします。いずれも予想通りです。では、初期の長さが1でないとどうなりますか?
game.ccのinit方法を修正する:
1 int Game::init()
2 {
3 Coordinate coordinate = _map.get_map_center_pos();
4 _snake.init('O', EN_DIR_DOWN, 5, coordinate);
5
6 MapBase map;
7 map.char_icon = 'O';
8 map.int_type = EN_MAP_SNAKE;
9 _map.set_map_val(coordinate.int_x, coordinate.int_y, map);
10
11 _bool_is_need_exit = false;
12
13 reset_random_point();
14 output_map();
15
16 return 0;
17
18 }
一つの点から出てほしいので、最初から5の長さの蛇を見せないといけないので、シーンは処理していません。この時、snake.hとsnake.cは修正されていません。そのinit方法の中で、add_new_nodeはまだtodoの状態なので、このパラメータが変更されたのも白です。
そこで私はこの方法を加えて、前の一つが蛇の長さが1より大きい場合、coreのbugになるということを発見しました。
そこで、snakeを修正しました。
1 ///
2 /// @file snake.h
3 /// @author marrs([email protected])
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 add_new_node(char char_icon_new);
25 Snake_Base* del_tail_node();
26 Snake_Base* forward();
27 Snake_Base* get_snake_base();
28 SnakeHead* get_snake_head();
29 int get_snake_size();
30
31 private:
32 SnakeHead _snake;
33
34 };
35
36 }
37
38 #endif
1 /// /// @file snake.cc
2 /// @author marrs([email protected])
3 /// @date 2017-07-15 11:02:32
4 ///
5
6 #include <string.h>
7 #include
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 = 1;
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 add_new_node(char_icon);
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(char char_icon_new)
46 {
47 Snake_Base* pNode = new Snake_Base;
48 pNode->char_icon = char_icon_new;
49 pNode->pNext = _snake.pNext;
50 _snake.pNext = pNode;
51
52 ++_snake.int_size;
53
54 return 0;
55
56 }
57
58 int Snake::add_new_node(Coordinate coordinate_new, char char_icon_new)
59 {
60 Snake_Base* pNode = new Snake_Base;
61 memset(pNode, 0, sizeof(Snake_Base));
62 pNode->coordinate_cur = _snake.coordinate_cur;
63 pNode->char_icon = _snake.char_icon;
64
65 if (_snake.pNext == NULL)
66 {
67 _snake.pNext = pNode;
68 }else{
69 pNode->pNext = _snake.pNext;
70 _snake.pNext = pNode;
71 }
72
73 _snake.coordinate_cur = coordinate_new;
74 _snake.char_icon = char_icon_new;
75 ++_snake.int_size;
76
77 return 0;
78 }
79
80 Snake_Base* Snake::del_tail_node()
81 {
82 Snake_Base* pPre;
83 Snake_Base* pCur;
84 if(_snake.int_size == 1)
85 {
86 return NULL;
87 }
88 pCur = _snake.pNext;
89 if(!pCur->pNext)
90 {
91 _snake.pNext = NULL;
92 }
93 else{
94 while(pCur->pNext)
95 {
96 pPre = pCur;
97 pCur = pCur->pNext;
98 }
99 pPre->pNext = NULL;
100 }
101 --_snake.int_size;
102 return pCur;
103
104 }
105
106 Snake_Base* Snake::forward()
107 {
108 Snake_Base* pReturn = NULL;
109 if(_snake.int_size > 1)
110 {
111 add_new_node(_snake.coordinate_cur, _snake.char_icon);
112 pReturn = del_tail_node();
113 }
114 else
115 {
116 pReturn = new Snake_Base;
117 pReturn->coordinate_cur = _snake.coordinate_cur;
118 }
119
120 switch(_snake.int_direction)
121 {
122 case EN_DIR_UP:
123 _snake.coordinate_cur.int_x -= 1;
124 break;
125 case EN_DIR_DOWN:
126 _snake.coordinate_cur.int_x += 1;
127 break;
128 case EN_DIR_LEFT:
129 _snake.coordinate_cur.int_y -= 1;
130 break;
131 case EN_DIR_RIGHT:
132 _snake.coordinate_cur.int_y += 1;
133 break;
134 default:break;
135
136 }
137 return pReturn;
138
139 }
140
141 Snake_Base* Snake::get_snake_base()
142 {
143 return _snake.pNext;
144
145 }
146
147 SnakeHead* Snake::get_snake_head()
148 {
149 return &_snake;
150
151 }
152
153 int Snake::get_snake_size()
154 {
155 return _snake.int_size;
156 }
157
158 }
はい、 Snake::add_new_node(char charg charg Gauicon unew) 方法では、単にノードを挿しただけで、ビーコンなどは設置されていません。前進する時は、先にノードを増やして、最後のノードを削除する方式を採用しているからです。このように、最初の時だけは、ヘビの展示は一こまだけで、後は大丈夫です。(ここの表現はよく分かりません。)はい、テストしてみます。
プログラムを実行
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 ++====================================++
一つのノードだけあって、勝手に押してください。例えば、「wwaass」。 1 [ccx@ubuntu ~/Retro_Snaker]$>./bin/game.exe
2 ====================================++
3 || ||
4 || ||
5 || ||
6 || ||
7 || ||
8 || ||
9 || ||
10 || OOOOOO ||
11 || OO OO ||
12 || OO ||
13 || ||
14 || ||
15 || ||
16 || ||
17 || ||
18 || ||
19 || ||
20 || ||
21 ++====================================++
続けて、たとえば「ddddssaw」 1 [ccx@ubuntu ~/Retro_Snaker]$>./bin/game.exe
2 ====================================++
3 || ||
4 || ||
5 || ||
6 || ||
7 || ||
8 || ||
9 || ||
10 || ||
11 || ||
12 || OOOO ||
13 || OOOO ||
14 || OOOO ||
15 || ||
16 || ||
17 || ||
18 || ||
19 || ||
20 || ||
21 ++====================================++
現在は衝突検査をしていませんので、ずっと右か下に移動すると「壁」を食べて外に出ます。ずっと左か上に行くと、プログラムがかかります。左右または上下を繰り返すと、2つだけに展示されます。
今は前進と方向制御を分離します。いろいろな方法を考えました。例えば、epollを使って、タイマーを書いたり、マルチスレッドを使ったり、プロセスをしたりします。比較的簡単な方法は、入力をサブスレッドで待つことです。メインスレッドはデッドループで、タイミングよく前進すればいいです。
game.hの増加方法
static void* pthread_func(void* p_args);
game.ccの中の変化も小さいです。
1 int Game::init()
2 {
3 Coordinate coordinate = _map.get_map_center_pos();
4 _snake.init('O', EN_DIR_DOWN, 5, coordinate);
5
6 MapBase map;
7 map.char_icon = 'O';
8 map.int_type = EN_MAP_SNAKE;
9 _map.set_map_val(coordinate.int_x, coordinate.int_y, map);
10
11 _bool_is_need_exit = false;
12
13 reset_random_point();
14 output_map();
15
16 ::pthread_t pthid;
17 ::pthread_create(&pthid, NULL, Game::pthread_func, this);
18
19 return 0;
20
21 }
22
23 int Game::loop()
24 {
25 while(!_bool_is_need_exit)
26 {
27 forward();
28 refresh_map();
29 //sleep(1);
30 usleep(100000);
31 }
32 return 0;
33
34 }
35
36 void* Game::pthread_func(void* p_args)
37 {
38 Game* game_tmp = static_cast (p_args);
39 while(!game_tmp->_bool_is_need_exit)
40 {
41 game_tmp->change_direction();
42 }
43 }
テスト結果はここでは送れません。
未完次号
github:https://github.com/ccx19930930/Retro_スナカー