bash 做了个贪吃蛇

sh/bash/dash/ksh/zsh等Shell脚本
tune
帖子: 135
注册时间: 2009-04-28 21:47

Re: bash 做了个贪吃蛇

#31

帖子 tune » 2009-08-14 11:29

默认game_height=25,结果由于我的终端窗口比较小,导致有一部分隐藏 :em06
图片
调整为20,就比较正常了
图片
cocoready
帖子: 15
注册时间: 2009-08-13 12:11

Re: bash 做了个贪吃蛇

#32

帖子 cocoready » 2009-08-18 11:41

在下是个菜鸟,正在学习研究这个代码中。
想问一下 下面这个代码是什么意思?怎么理解?

echo -ne "\033[$y1;${x1}H\033[44;32m==\033[0m"
头像
O_O_BOT
帖子: 2461
注册时间: 2009-05-20 19:32

Re: bash 做了个贪吃蛇

#33

帖子 O_O_BOT » 2009-08-18 11:49

man echo -> -n -e 就知道什么意思了 n不转行 e解析\xxx字符

代码: 全选

  \33[0m   关闭所有属性  
  \33[1m   设置高亮度  
  \33[4m   下划线  
  \33[5m   闪烁  
  \33[7m   反显  
  \33[8m   消隐  
  \33[30m   --   \33[37m   设置前景色  
  \33[40m   --   \33[47m   设置背景色  
  \33[nA   光标上移n行  
  \33[nB   光标下移n行  
  \33[nC   光标右移n行  
  \33[nD   光标左移n行  
  \33[y;xH设置光标位置  
  \33[2J   清屏  
  \33[K   清除从光标到行尾的内容  
  \33[s   保存光标位置  
  \33[u   恢复光标位置  
  \33[?25l   隐藏光标  
  \33[?25h   显示光标
irc 聊天室
ubuntu-cn 的irc 频道为
irc.ubuntu.com 8001 #ubuntu-cn
UTF8编码 可用 irssi xchat pidgin weechat 登录

http://webchat.freenode.net/?channels=ubuntu-cn
[url]irc://irc.freenode.net/ubuntu-cn[/url]
billbear
帖子: 3681
注册时间: 2008-05-03 23:42

Re: bash 做了个贪吃蛇

#34

帖子 billbear » 2009-08-18 12:44

OS X 里可以正常运行了。为啥改成 30 就好了涅。
头像
O_O_BOT
帖子: 2461
注册时间: 2009-05-20 19:32

Re: bash 做了个贪吃蛇

#35

帖子 O_O_BOT » 2009-08-18 13:26

和linux 的sign 有点不同吧
irc 聊天室
ubuntu-cn 的irc 频道为
irc.ubuntu.com 8001 #ubuntu-cn
UTF8编码 可用 irssi xchat pidgin weechat 登录

http://webchat.freenode.net/?channels=ubuntu-cn
[url]irc://irc.freenode.net/ubuntu-cn[/url]
cocoready
帖子: 15
注册时间: 2009-08-13 12:11

Re: bash 做了个贪吃蛇

#36

帖子 cocoready » 2009-08-18 22:43

ESC=$(echo -ne "\033")

LZ 是代表什么意思?
头像
O_O_BOT
帖子: 2461
注册时间: 2009-05-20 19:32

Re: bash 做了个贪吃蛇

#37

帖子 O_O_BOT » 2009-08-19 10:22

cocoready 写了:ESC=$(echo -ne "\033")

LZ 是代表什么意思?
ESC=$'\033' 同义
irc 聊天室
ubuntu-cn 的irc 频道为
irc.ubuntu.com 8001 #ubuntu-cn
UTF8编码 可用 irssi xchat pidgin weechat 登录

http://webchat.freenode.net/?channels=ubuntu-cn
[url]irc://irc.freenode.net/ubuntu-cn[/url]
cocoready
帖子: 15
注册时间: 2009-08-13 12:11

Re: bash 做了个贪吃蛇

#38

帖子 cocoready » 2009-08-19 13:40

O_O_BOT 不好意思,给你添麻烦了。有以下几个问题,麻烦指教

(1)key_rountine函数是不是用来读取键盘信号的?
(2)当我调用key_rountine函数的时候,运行到如下代码
read -s -n 1 key 后,我点击方向键 右
程序开始继续执行。以下是一些变量的值
keys[0]=0
keys[1]=0
keys[2]=$'\E'

从输出屏幕上看到 后面的read -s -n 1 key 命令并没有与人进行交互而是直接运行。这是为什么呢?


一上
头像
O_O_BOT
帖子: 2461
注册时间: 2009-05-20 19:32

Re: bash 做了个贪吃蛇

#39

帖子 O_O_BOT » 2009-08-19 15:26

key_routine 是读取键盘的。

read -s -n 1 key 是读 一个 键到 key 变量

你按向上 其实 已经发了3个键值 \033 [ A
这也是为什么 要用key 1-3 来存键的原因。。
irc 聊天室
ubuntu-cn 的irc 频道为
irc.ubuntu.com 8001 #ubuntu-cn
UTF8编码 可用 irssi xchat pidgin weechat 登录

http://webchat.freenode.net/?channels=ubuntu-cn
[url]irc://irc.freenode.net/ubuntu-cn[/url]
头像
O_O_BOT
帖子: 2461
注册时间: 2009-05-20 19:32

Re: bash 做了个贪吃蛇

#40

帖子 O_O_BOT » 2009-08-19 18:44

其实如果read 的timeout 延时是ms级别的 就不用开2个进程用sign通讯了
下面的snake2 用了一个 C 小程序 来读取按键 程序结构就简单很多

代码: 全选

#!/bin/bash
#O_O learn3
#fvw vimtexhappy@gmail.com
#setting
game_with=15
game_height=25
game_top=2
game_left=10
game_no_wall=1

#tmp
game_start=0

#key
key_up=$'\033'"[A"
key_down=$'\033'"[B"
key_right=$'\033'"[C"
key_left=$'\033'"[D"

#direction
dirt_up=0
dirt_down=1
dirt_left=2
dirt_right=3

#map data
var_init(){
    usr_level=0
    usr_score=0

    snake_color=4
    snake_head=0
    snake_end=0
    snake_len=1
    snake_cur_x=0
    snake_cur_y=0
    snake_move_dirt=0

    dot_color=3
    dot_cur_x=0
    dot_cur_y=0
}

show_frame() {
    #make game frame
    local i x1 x2 y1 y2
    ((x1 = game_left))
    ((y1 = game_top))
    ((y2 = game_top+game_height+1))
    for ((i=0; i<game_with+2; i++));do
        echo -ne "\033[$y1;${x1}H\033[44;32m==\033[0m"
        echo -ne "\033[$y2;${x1}H\033[44;32m==\033[0m"
        ((x1 += 2))
    done

    ((x1 = game_left))
    ((x2 = game_left+game_with*2+2))
    ((y1 = game_top+1))
    for ((i=0; i<game_height; i++));do
        echo -ne "\033[$y1;${x1}H\033[44;32m||\033[0m"
        echo -ne "\033[$y1;${x2}H\033[44;32m||\033[0m"
        ((y1++))
    done
}

show_txt() {
    local x y 
    local score level
    score=${1:-$usr_score}
    level=${2:-$usr_level}
    ((x = game_left + game_with*2 + 4 + 6))
    ((y = game_top + game_height/3))
    echo -ne "\033[${y};${x}H\033[40;36mScore\033[0m"
    ((y++))
    echo -ne "\033[${y};${x}H\033[40;37m${score}\033[0m"
    ((y+=2))
    echo -ne "\033[${y};${x}H\033[40;36mLevel\033[0m"
    ((y++))
    echo -ne "\033[${y};${x}H\033[40;37m${level}\033[0m"
}

show_end_text(){
    local x y
    len=${#1}
    ((x = game_left + game_with-len/2))
    ((y = game_top + game_height/2 - 1))
    echo -ne "\033[${y};${x}H$1"
    game_start=0
}

show_dot() {
    local show index x y color
    show=$1
    x=${2:-$snake_cur_x}
    y=${3:-$snake_cur_y}
    color=${4:-$snake_color}
    ((x= game_left + 2 + x* 2 ))
    ((y= game_top + 1 + y))
    echo -ne "\033[${y};${x}H"
    if (($show == 1)); then
        echo -ne "\033[1;7;4${color};3${color}m[]\033[0m"
    else
        echo -ne "  "
    fi
}

make_map() {
    local i x y
    ((x = game_left + 2))
    ((y = game_top + 1))
    for ((i=0; i<game_height; i++));do
        echo -ne "\033[$((y+i));${x}H"
        for ((j=0; j<game_with; j++));do
            echo -ne "  "
        done
    done
    snake_color=4
    snake_head=0
    snake_end=0
    snake_len=1
    ((snake_cur_x=RANDOM%(game_with/2)+game_with/4))
    ((snake_cur_y=RANDOM%(game_height/2)+game_height/4))
    snakes=($snake_cur_x $snake_cur_y)
    ((snake_move_dirt=RANDOM % 4))
    show_dot 1
}

dot_new(){
    local dot_x dot_y
    local max_try i
    max_try=200
    while ((max_try--));do
        ((dot_x=RANDOM%game_with))
        ((dot_y=RANDOM%game_height))
        for ((i=snake_end; i<=snake_head; i+=2));do
            ((snakes[i]==dot_x && snakes[i+1]==dot_y)) && break
        done
        ((i>snake_head)) && break 
    done
    if ((max_try>=0));then
        dot_cur_x=$dot_x
        dot_cur_y=$dot_y
        show_dot 1 $dot_x $dot_y $dot_color
    else
        show_end_text "Very good!"
    fi
}

snake_go() {
    local go_x go_y
    go_x=$snake_cur_x
    go_y=$snake_cur_y
    try_move=$1
    case $try_move in
        $dirt_up) ((go_y--));;
        $dirt_down) ((go_y++));;
        $dirt_left) ((go_x--));;
        $dirt_right) ((go_x++));;
    esac
    if ((snake_len != 1)) && ((snakes[snake_head-2]==go_x && snakes[snake_head-1]== go_y));then
        #don't move
        return
    fi
    #hold move dirt
    snake_move_dirt=$try_move
    if ((game_no_wall == 1));then
        ((go_x<0)) && ((go_x+=game_with))
        ((go_x>=game_with)) && ((go_x-=game_with))
        ((go_y<0)) && ((go_y+=game_height))
        ((go_y>=game_height)) && ((go_y-=game_height))
    else
        if ((go_x<0 || go_x>=game_with || go_y<0 || go_y>=game_height));then
            show_end_text "Game over!"
            return
        fi
    fi

    #local i index
    ##snake_end over max->0 is ok too.
    #((index=snake_end))
    #for ((i=0; i<snake_len; i++));do
        #((snakes[index]==go_x && snakes[index+1]==go_y)) && break
        #((index+=2))
    #done
    #if ((i<snake_len));then
        #show_end_text "Game over!"
        #return
    #fi
    #array index very long 2^6x
    local i
    for ((i=snake_end; i<=snake_head; i+=2));do
        ((snakes[i]==go_x && snakes[i+1]==go_y)) && break
    done
    if ((i<=snake_head));then
        show_end_text "Game over!"
        return
    fi
    ((snake_head+=2))
    snakes[snake_head]=$go_x
    snakes[snake_head+1]=$go_y
    snake_cur_x=$go_x
    snake_cur_y=$go_y
    show_dot 1
    if ((go_x == dot_cur_x && go_y == dot_cur_y));then
        ((snake_len++))
        ((usr_score++))
        ((usr_level=usr_score/10))
        ((usr_level>20)) && ((usr_level=20))
        show_txt
        dot_new
    else
        show_dot 0 ${snakes[$snake_end]} $((snakes[snake_end+1]))
        unset snakes[snake_end]
        unset snakes[$((snake_end+1))]
        ((snake_end+=2))
    fi
}

init_game(){
    clear
    var_init
    show_frame
    show_txt 
    make_map
    dot_new
}

start_game(){
    tty=$(stty -g)
[color=#BF4040]    stty -echo cbreak[/color]
    echo -ne "\033[?25l"
    trap "exit_game;" INT TERM
}

exit_game(){
    stty $tty
    echo -ne "\033[?25h"
    clear
    exit 0
}

game_routine(){
    local timeout, key
    start_game
    init_game
    read -s -n 1
    game_start=1
    while :;do
    while ((game_start));do
            timeout=$(echo 0.02 \* \(20 - $usr_level\) | bc)
            key=$(cread $timeout)
            case $key in
                $key_down ) snake_go $dirt_down;;
                $key_left ) snake_go $dirt_left;;
                $key_right) snake_go $dirt_right;;
                $key_up   ) snake_go $dirt_up;;
                "q") exit_game;;
                *) snake_go $snake_move_dirt;;
            esac
        done
        read -s -n 1
        game_start=1
        init_game
    done
    exit_game
}

game_routine
key=$(cread $timeout) 的C 小程序 cread 如下

代码: 全选

#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>
#include <sys/select.h>

int main(int argc, char *argv[]) 
{
    int timeout_us = atof(argv[1]) * 1000 * 1000;
    struct timeval tv;  
    struct termios oldt,newt;
    fd_set fds;  
    int c1, c2, c3;

    tv.tv_sec = 0;  
    tv.tv_usec = timeout_us;  
    FD_ZERO(&fds);  
    FD_SET(STDIN_FILENO, &fds); //STDIN_FILENO is 0  

    tcgetattr( STDIN_FILENO, &oldt );
    newt = oldt;
    newt.c_lflag &= ~( ICANON | ECHO );
    tcsetattr( STDIN_FILENO, TCSANOW, &newt );

    select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);  
    if (FD_ISSET(STDIN_FILENO, &fds)) {
        c1 = getchar();
        if (c1 == 033) {
            c2 = getchar();
            c3 = getchar();
            printf("%c%c%c", c1, c2, c3);;
        } else {
            printf("%c", c1);
        }
    }
    tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
    return 0;
}
irc 聊天室
ubuntu-cn 的irc 频道为
irc.ubuntu.com 8001 #ubuntu-cn
UTF8编码 可用 irssi xchat pidgin weechat 登录

http://webchat.freenode.net/?channels=ubuntu-cn
[url]irc://irc.freenode.net/ubuntu-cn[/url]
GodPig
帖子: 240
注册时间: 2007-04-27 23:07

Re: bash 做了个贪吃蛇

#42

帖子 GodPig » 2009-09-03 0:59

厉害!
头像
潇洒走一回
帖子: 735
注册时间: 2009-05-20 21:43

Re: bash 做了个贪吃蛇

#43

帖子 潇洒走一回 » 2009-09-06 15:01

这条蛇撞不死
xcloveubuntu
帖子: 1
注册时间: 2009-08-05 22:07

Re: bash 做了个贪吃蛇

#44

帖子 xcloveubuntu » 2009-09-06 15:24

好 虽然我是菜鸟 :em11
头像
O_O_BOT
帖子: 2461
注册时间: 2009-05-20 19:32

Re: bash 做了个贪吃蛇

#45

帖子 O_O_BOT » 2009-09-06 21:04

潇洒走一回 写了:这条蛇撞不死
game_no_wall=0
irc 聊天室
ubuntu-cn 的irc 频道为
irc.ubuntu.com 8001 #ubuntu-cn
UTF8编码 可用 irssi xchat pidgin weechat 登录

http://webchat.freenode.net/?channels=ubuntu-cn
[url]irc://irc.freenode.net/ubuntu-cn[/url]
回复