贪吃蛇-Shell实现

2016/08/03 Linux

1 简介

这几天在看Shell脚本编程,正所谓“寓教于乐”,为了激发自己的学习效率呢,就考虑通过游戏方式来边学边玩!所以这条贪吃蛇就诞生啦!

选择做贪吃蛇最重要的原因就2个字:“简单”!苗条的身体,固定的转向!想想就觉得超好做!超有成就感! 果然,大约花了1天的时间吧,利用5毛钱界面,编出了这简单版本!这里来分享一下! 有效代码250行左右~

代码已经上传到Github上了我是代码!快点我!一言不合先上图:

我是贪吃蛇

2 问题分析

好了,光说不干假本事!下面就来一起分析问题与解决方法!

2.1 键盘读取与多进程

代码中使用“上、下、左、右”(‘上’编码:27 91 65)键进行蛇行走方向的控制, 为了实时读取键盘输入,并且控制不回显,那就要死循环检测键盘状态啦!

function readinput()
{
    local input;
    while(true);do
    {
        read -st 1 -n 1 input;
        if [[ $input == $'\033' ]];then
            read -st 1 -n 1 input;
            if [[ $input == '[' ]];then
                read -st 1 -n 1 input;
                case $input in
                "A") `kill -35 $PIDSnack`;;
                "B") `kill -36 $PIDSnack`;;
                "D") `kill -38 $PIDSnack`;;
                "C") `kill -37 $PIDSnack`;;
                esac;
            fi;
        fi;
    };done;
}

为了同时正常刷新地图又避免耽误读键盘,我们就需要引入多进程,将蛇的控制与显示放到单独的进程中!互不影响,但又互相通信!

2.2 进程间通信与信号传递

键盘进程读取到了数据,需要立刻传递给控制进程,那在Shell中如何进行进程间通信呢?我们就使用了“信号”机制!

2.1节中 kill -35 $PIDSnack 就是向控制进程发送35信号!控制进程需要捕捉与处理!

function initSnackTrap()
{
    trap "readisign A" 35
    trap "readisign B" 36
    trap "readisign D" 37
    trap "readisign C" 38
    trap "exit 2" 2
}

使用trap捕捉信号,并根据信号调用相应处理函数!到这,这就完成了一次完美的进程间通讯!怎么样?是不是很简单?

现在控制进程已经得到下一步要走的方向了,一旦时间到达时,就可以移动蛇身啦!

2.3 蛇身控制

蛇头要根据读入数据进行上下左右转向(不能反向转向),蛇尾巴和蛇身要根据前一元素进行替换!


function movetoNext()
{
    snackEat
    print "clear" ${xsnackBody[((${l_snack}-1))]} ${ysnackBody[((${l_snack}-1))]}
    for((i=$l_snack;i>0;i--))
    {
        ysnackBody[$i]=${ysnackBody[((${i}-1))]};
        xsnackBody[$i]=${xsnackBody[((${i}-1))]};
    }
    case ${way[0]} in
    "上")   let ysnackBody[0]-- ;;
    "下")   let ysnackBody[0]++ ;;
    "左")   let xsnackBody[0]-- ;;
    "右")   let xsnackBody[0]++ ;;
    esac;
    gameOverTest;
    printSnack;
}

除了蛇身体的变化之外,每次变化还需要食物检测碰撞检测就是:

  • snackEat
  • gameOverTest

这2个函数!满满的“爱与恨”!就是他们让小蛇长大,也让小蛇结束!

2.4 地图显示

游戏么!交互性一定要好!虽然没时间,我们也可以做一些5毛钱特效!

地图交互要分类型!下面就利用case语句实现了7种不同的显示!

function print()
{
    case "$1" in
        "map")  echo -e "\e[${3};${2}H\e[44m \e[0m";;
        "wall") echo -e "\e[${3};${2}H\e[42;30m#\e[0m";;
        "head") echo -e "\e[${3};${2}H\e[42;30m*\e[0m";;
        "body") echo -e "\e[${3};${2}H\e[42m+\e[0m";;
        "tail") echo -e "\e[${3};${2}H\e[42;30m-\e[0m";;
        "food") echo -e "\e[${3};${2}H\e[30m@\e[0m";;
        "clear") echo -e "\e[${3};${2}H \e[0m";;
    esac;
}

2.5 终端交互

除了上面的显示,还需要一些其他终端交互:

  • 自适应窗口大小 tput lines tput cols
  • 光标隐藏与恢复 tput civis tput cnorm
  • 清屏 echo -ne "\e[2J"
  • 欢迎界面 "she"

3 实现

代码200多行,我这里就不粘贴了,感兴趣的同学可以去下载!免费的吆!

4 总结

虽然代码不多,但是真的能学到很多知识!

花1天时间弄出来,是对以前那么多天Shell命令学习的肯定!很赚呀!^_^

Search

    Post Directory