自制贪吃蛇——方向控制,初始长度增加

  上篇地址 :http://www.cnblogs.com/chinxi/p/7185309.html

  有了一条会移动的“蛇”,就可以开始写改变它方向的方法了。

  由于这是运行在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 [[email protected] ~/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 [[email protected] ~/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 ++====================================++

  向上移了一行,分别测试"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.cc没有修改,它的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 <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 = 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 char_icon_new)  方法中,只是简单地头插了节点,并没有设置从标什么的,是因为在前进的时候,是采用先增加节点,再删除最后一个节点的方式。这样,只有在一开始的时候,蛇会展示成只有一节,后面不会有问题。(此处可能表达不是很清楚)

  好了,来测试一下。

  运行程序

 1 [[email protected] ~/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 [[email protected] ~/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 [[email protected] ~/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 ++====================================++

  由于目前没有做碰撞检测,所以会出现一些有趣的现象,比如一直向右或者下移动,会把“墙”吃了,并且跑到场景外面去,如果一直左或者上,则程序会core。如果反复左右或者上下,则会展示成只有两节。

  未完待续....

  github:https://github.com/ccx19930930/Retro_Snaker

时间: 2024-08-24 15:33:14

自制贪吃蛇——方向控制,初始长度增加的相关文章

自制贪吃蛇游戏中的几个“大坑”

贪吃蛇游戏已经告一段落了,在完成这个游戏的过程中,我遭遇了许多"坎坷"和"挫折",下面就几个让我印象深刻的"挫折"做一个具体的讲解,以此来为这个贪吃蛇项目画上一个完整句号.(包括打包这个游戏时遇到的问题及解决方式.) BUG1  在运行贪吃蛇游戏时,如果同时按下两个方向键会出现贪吃蛇"莫名其妙"死亡的情况.针对此情况我先是判断贪吃蛇的死亡原因: #贪吃蛇死亡判定 def isdead(self): #条件1--贪吃蛇撞墙 if

A.探路者——贪吃蛇游戏(测评人:黄泽宇)

一.基于NABCD评论作品,及改进建议 每个小组评论其他小组Alpha发布的作品:1.根据(不限于)NABCD评论作品的选题:2.评论作品对选题的实现效果:3.就现有技术和工作量,不改变选题的主要方向,为该作品在beta版本可增减的功能提出改进意见. 1.根据(不限于)NABCD评论作品的选题. 根据探路者的Alpha发布选题背景及意义进行考量: 贪吃蛇游戏团队的选题背景及意义 NABCD标准考量 贪吃蛇作为一个经典的游戏,设计简单,实用和娱乐性高.对于贪吃蛇传统的玩法,大家众所周知,即:玩家通

《结对-贪吃蛇-结对项目总结》

 这个 学期也快要i结束了 ,从这次结对编程中我学到了很多.也真正重视到了团队的重要性.一个人和一个团队同时做一件事情上.团队占有的很大的优势. 我也从结对的伙伴身上学到了很多.但是结对也有着他的问题.但问题出现分歧时没有办法很快的解决会导致程序更快的完成. 代码 码云地址:https://gitee.com/a540816440/TanChiShe/tree/master 贪吃蛇是一款很风靡的游戏,我想如果大家使用过或者了解过诺基亚手机的话一定会对这款游戏十分的了解.  游戏的基本操作: 1.

Java控制台下的贪吃蛇游戏

实现贪吃蛇游戏的思路:   class Node(i,j)  //表示坐标 class Worm(List<Node> nodes)        //   行数:10行//用LinkedList存储蛇的坐标点.当前进是用addFirst(Node node)方法添加一个一个坐标点(可以通过getFirst()得到上一个坐标-1得出):然后再删除尾节点.如果碰到食物则不删除尾节点. // 列数:32列 step()//往前走一步 step(int dir)//根据方向往前走一步 class W

游戏开发(一)——控制台 贪吃蛇

贪吃蛇游戏设计中主要需要注意的几点: 1:坐标的定义:定义为左上角为(0,0),向右为x正方向,向下为y正方向 2:蛇的设计, 蛇身:m_body,这里用的是链表(是之前写好的双链表),一个节点就是蛇身的一节 每节蛇身的属性包括x,y坐标:column_x,row_y,x表示在地图上的第几列,y表示在地图上的第几行 蛇有一个属性叫朝向,也就是当前在往上.下.左.右的哪个方向移动:m_forward 蛇的动作有:Turn,转向.转向有个判断,就是不能向相反的方向转,比如本来向上运动,按向下键,是无

基于C#开发的简易贪吃蛇

最近一直忙着11月份软考的复习,一直没有练习C#.觉得对于一个新手,长时间不练肯定不行,所以觉得敲敲代码练练手.刚好电脑磁盘里有以前Down的C#开源游戏,于是挑中了贪吃蛇,来练练手. 贪吃蛇游戏界面如下: 为了实现贪吃蛇,一共写了四个类,分别是: 1)Bean:食物类,就是玩家要吃的那个食物,里面实现了两个方法:食物的显示与食物的消失(因为食物被吃了以后应该消失) 2)Block:蛇块类,就是组成蛇的单元,玩家吃到食物,蛇的蛇块增加一节. 3)Snake:蛇类,游戏中的主角,玩家通过上下左右四

贪吃蛇小游戏编写心得

https://github.com/Devilzero/6 package 贪吃蛇; import java.awt.*; import java.awt.event.*; public class GreedSnake //主类 { /** * @param args */ public static void main(String[] args) { new MyWindow(); } } class MyPanel extends Panel implements KeyListene

JavaScript与html5写的贪吃蛇完整代码

JavaScript与html5写的贪吃蛇完整代码 查看运行效果可访问http://www.codesocang.com/texiao/youxitexiao/2014/0402/7045.html# <!doctype html><html lang="en"><head><meta charset="utf-8"><title>js网页版的贪吃蛇游戏</title><style typ

js+jQuery实现贪吃蛇小游戏

这是我第一次这么认真的去写一个程序.今天老师布置的编程任务是实现一个贪吃蛇的小游戏,一开始感觉很茫然的,因为以前都没有这么系统的去做过一个编程任务.后来理清思路去做,感觉问题也并不是那么的难. 首先,第一步肯定是要编写出我们的的静态页面. 第二步,让我们的贪吃蛇先从一个开始动起来. 第三步,让我们通过键盘去控制他的运动方向. 第四步,让我们去判断我们的贪吃蛇有没有撞墙,有没有吃到自己,因为这已经犯规了. 第五步,给我们的贪吃蛇随机生成一个‘食物’. 第六步,实现每当我们的贪吃蛇吃了一个食物,他都