Tank Shell游戏编写之三:接收键盘按键输入,让坦克动起来【2】

先我们定义一个打印坦克的函数, 我们根据坦克的头坐标和方向即可确定坦克的整体位置:

# args: {point1, point2, [UP|DOWN|LEFT|RIGHT]}   #只接收三个参数即可
# eg: 10 20 UP
# file: Tank2_2.sh
f_print_tank(){ v_hp1
=$1 v_hp2=$2 v_direc=$3 #没做任何的参数正确性判断,默认正确使用 if [[ $v_direc == 'UP' ]] then echo -e "\033[$((v_hp1+0));$((v_hp2+0))H\033[42m \033[0m" echo -e "\033[$((v_hp1+1));$((v_hp2-1))H\033[42m \033[0m" echo -e "\033[$((v_hp1+1));$((v_hp2+1))H\033[42m \033[0m" echo -e "\033[$((v_hp1+2));$((v_hp2-1))H\033[42m \033[0m" echo -e "\033[$((v_hp1+2));$((v_hp2+1))H\033[42m \033[0m" fi if [[ $v_direc == 'DOWN' ]] then echo -e "\033[$((v_hp1+0));$((v_hp2+0))H\033[42m \033[0m" echo -e "\033[$((v_hp1-1));$((v_hp2-1))H\033[42m \033[0m" echo -e "\033[$((v_hp1-1));$((v_hp2+1))H\033[42m \033[0m" echo -e "\033[$((v_hp1-2));$((v_hp2-1))H\033[42m \033[0m" echo -e "\033[$((v_hp1-2));$((v_hp2+1))H\033[42m \033[0m" fi if [[ $v_direc == 'LEFT' ]] then echo -e "\033[$((v_hp1+0));$((v_hp2+0))H\033[42m \033[0m" echo -e "\033[$((v_hp1-1));$((v_hp2+1))H\033[42m \033[0m" echo -e "\033[$((v_hp1-1));$((v_hp2+2))H\033[42m \033[0m" echo -e "\033[$((v_hp1+1));$((v_hp2+1))H\033[42m \033[0m" echo -e "\033[$((v_hp1+1));$((v_hp2+2))H\033[42m \033[0m" fi if [[ $v_direc == 'RIGHT' ]] then echo -e "\033[$((v_hp1+0));$((v_hp2+0))H\033[42m \033[0m" echo -e "\033[$((v_hp1-1));$((v_hp2-1))H\033[42m \033[0m" echo -e "\033[$((v_hp1-1));$((v_hp2-2))H\033[42m \033[0m" echo -e "\033[$((v_hp1+1));$((v_hp2-1))H\033[42m \033[0m" echo -e "\033[$((v_hp1+1));$((v_hp2-2))H\033[42m \033[0m" fi }

 效果图:

在实现移动坦克的函数之前,应该考虑到, 一旦移动了坦克,之前的坐标会留有痕迹,所以我们还需要实现一个擦除坦克旧痕迹的函数,实现方式也很简单,跟打印函数类似,只不过是不带颜色的输出一个空格即可,其实可以完全整合到f_print_tank中,但为了功能单一化原则,还是单独定义f_clean_tank

f_clean_tank(){
    v_hp1=$1
    v_hp2=$2
    v_direc=$3
    if [[ $v_direc == 'UP' ]]
    then
        echo -e "\033[$((v_hp1+0));$((v_hp2+0))H "
        echo -e "\033[$((v_hp1+1));$((v_hp2-1))H "
        echo -e "\033[$((v_hp1+1));$((v_hp2+1))H "
        echo -e "\033[$((v_hp1+2));$((v_hp2-1))H "
        echo -e "\033[$((v_hp1+2));$((v_hp2+1))H "
    fi
    if [[ $v_direc == 'DOWN' ]]
    then
        echo -e "\033[$((v_hp1+0));$((v_hp2+0))H "
        echo -e "\033[$((v_hp1-1));$((v_hp2-1))H "
        echo -e "\033[$((v_hp1-1));$((v_hp2+1))H "
        echo -e "\033[$((v_hp1-2));$((v_hp2-1))H "
        echo -e "\033[$((v_hp1-2));$((v_hp2+1))H "
        fi
    if [[ $v_direc == 'LEFT' ]]
    then
        echo -e "\033[$((v_hp1+0));$((v_hp2+0))H "
        echo -e "\033[$((v_hp1-1));$((v_hp2+1))H "
        echo -e "\033[$((v_hp1-1));$((v_hp2+2))H "
        echo -e "\033[$((v_hp1+1));$((v_hp2+1))H "
        echo -e "\033[$((v_hp1+1));$((v_hp2+2))H "
    fi        
    if [[ $v_direc == 'RIGHT' ]]
    then
        echo -e "\033[$((v_hp1+0));$((v_hp2+0))H "
        echo -e "\033[$((v_hp1-1));$((v_hp2-1))H "
        echo -e "\033[$((v_hp1-1));$((v_hp2-2))H "
        echo -e "\033[$((v_hp1+1));$((v_hp2-1))H "
        echo -e "\033[$((v_hp1+1));$((v_hp2-2))H "
    fi
}

以下是测试代码:

f_print_tank 20 30 'UP'
sleep 1
f_print_tank 20 40 'DOWN'
sleep 1
f_print_tank 20 50 'LEFT'
sleep 1
f_print_tank 20 60 'RIGHT'
sleep 1
f_clean_tank 20 30 'UP' 
sleep 1
f_clean_tank 20 40 'DOWN'
sleep 1
f_clean_tank 20 50 'LEFT'
sleep 1
f_clean_tank 20 60 'RIGHT'

现在可以考虑移动坦克了, 其实所谓的移动,只不过是将旧的痕迹擦除,然后在新的位置上重新输出而已。

给出一个向上移动坦克的函数,以代码为例做下简单讲述:

f_turn_up(){ 
    v_hp1=${v_tank_head_points[0]}     # v_tank_head_points 是保存初始坦克位置坐标的一个数组,v_tank_direction 是初始坦克的朝向,两个都是全局变量
    v_hp2=${v_tank_head_points[1]}     # 这样方便我们通过不同的函数来控制这两个随时要改变的变量
    v_direc=$v_tank_direction      # 为了方便操作,我们需要使用三个变量先将他们的值保存下来
    
    f_clean_tank $v_hp1 $v_hp2 $v_direc    # 在打印新坦克时,我们先清除旧的痕迹
                                 # 下面的代码块用来计算新的头坐标             
    [[ $v_direc == 'UP'    ]] && v_hp1=$((v_hp1 - 1))  # 既然该函数负责上移,如果旧方向是UP,则y坐标只需要减1即可          
    [[ $v_direc == 'DOWN'  ]] && v_hp1=$((v_hp1 - 2))  # 这里为什么不是加1而是加2呢? 主要是调整坦克方向时,不至于移动坦克的位置, 可以加1后调试看显示加过
    [[ $v_direc == 'LEFT'  ]] && v_hp1=$((v_hp1 - 1)) && v_hp2=$((v_hp2 + 1)) #同上
    [[ $v_direc == 'RIGHT' ]] && v_hp1=$((v_hp1 - 1)) && v_hp2=$((v_hp2 - 1)) #同上
    
    f_print_tank $v_hp1 $v_hp2 'UP'  # 打印新的坦克
    
    v_tank_head_points=($v_hp1 $v_hp2)  # 重新赋值全局变量,因为所有函数都会用到他们
    v_tank_direction='UP'
}

移动坦克就是不断的擦除旧的痕迹然后重新打印新的坐标位置, 难点就是新坐标的计算,只能靠想象然后不断尝试,让坦克每次改变方向时尽可能显得自然一些。

其他三个操作函数代码如下:

f_turn_down(){
        v_hp1=${v_tank_head_points[0]}
        v_hp2=${v_tank_head_points[1]}
        v_direc=$v_tank_direction

        f_clean_tank $v_hp1 $v_hp2 $v_direc

        [[ $v_direc == 'UP'    ]] && v_hp1=$((v_hp1 + 2))
        [[ $v_direc == 'DOWN'  ]] && v_hp1=$((v_hp1 + 1))
       [[ $v_direc == 'LEFT'  ]] && v_hp1=$((v_hp1 + 1)) && v_hp2=$((v_hp2 + 1))
        [[ $v_direc == 'RIGHT' ]] && v_hp1=$((v_hp1 + 1)) && v_hp2=$((v_hp2 - 1))
        
        f_print_tank $v_hp1 $v_hp2 'DOWN'

        v_tank_head_points=($v_hp1 $v_hp2)
        v_tank_direction='DOWN'
}

f_turn_left(){
        v_hp1=${v_tank_head_points[0]}
        v_hp2=${v_tank_head_points[1]}
        v_direc=$v_tank_direction

        f_clean_tank $v_hp1 $v_hp2 $v_direc

        [[ $v_direc == 'UP'    ]] && v_hp1=$((v_hp1 + 1)) && v_hp2=$((v_hp2 - 1))
        [[ $v_direc == 'DOWN'  ]] && v_hp1=$((v_hp1 - 1)) && v_hp2=$((v_hp2 - 1))
        [[ $v_direc == 'LEFT'  ]] && v_hp2=$((v_hp2 - 1))
        [[ $v_direc == 'RIGHT' ]] && v_hp2=$((v_hp2 - 2))
        
        f_print_tank $v_hp1 $v_hp2 'LEFT'

        v_tank_head_points=($v_hp1 $v_hp2)
        v_tank_direction='LEFT'
}
f_turn_right(){
        v_hp1=${v_tank_head_points[0]}
        v_hp2=${v_tank_head_points[1]}
        v_direc=$v_tank_direction

        f_clean_tank $v_hp1 $v_hp2 $v_direc

        [[ $v_direc == 'UP'    ]] && v_hp1=$((v_hp1 + 1)) && v_hp2=$((v_hp2 + 1))
        [[ $v_direc == 'DOWN'  ]] && v_hp1=$((v_hp1 - 1)) && v_hp2=$((v_hp2 + 1))
        [[ $v_direc == 'LEFT'  ]] && v_hp2=$((v_hp2 + 2))
        [[ $v_direc == 'RIGHT' ]] && v_hp2=$((v_hp2 + 1))

        f_print_tank $v_hp1 $v_hp2 'RIGHT'

        v_tank_head_points=($v_hp1 $v_hp2)
        v_tank_direction='RIGHT'
}

重复代码太多,但还是为了通俗易懂, 这几个函数后续需要增加很多功能, 例如:移动边界的判断、和敌方的碰撞等等

现在我们控制坦克移动,以下是主程序代码,涉及的函数均已介绍:

tput civis # 隐藏光标  

v_tank_head_points=(10 20) #初始打印一个坦克模型 v_tank_direction='UP' f_print_tank ${v_tank_head_points[0]} ${v_tank_head_points[1]} $v_tank_direction v_special_char=`echo -e "\033"` while :                #接收按键,并移动坦克                  do read -s -n 1 v_pressed_key v_pressed_key=`echo $v_pressed_key | tr 'a-z' 'A-Z'` if [[ $v_pressed_key == 'C' ]] then break fi if [[ $v_pressed_key == $v_special_char ]]; then read -s -n 2 v_pressed_key [[ ${v_pressed_key:1:1} == 'A' ]] && f_turn_up [[ ${v_pressed_key:1:1} == 'B' ]] && f_turn_down [[ ${v_pressed_key:1:1} == 'D' ]] && f_turn_left [[ ${v_pressed_key:1:1} == 'C' ]] && f_turn_right fi [[ $v_pressed_key = 'W' ]] && f_turn_up [[ $v_pressed_key = 'S' ]] && f_turn_down [[ $v_pressed_key = 'A' ]] && f_turn_left [[ $v_pressed_key = 'D' ]] && f_turn_right done
tput cnorm  # 显示光标

 效果:

移动到屏幕边界时会出现问题,因为坐标位置已经超出了屏幕的范围

下一节介绍如何限定坦克的移动范围。

猜你喜欢

转载自www.cnblogs.com/gipagod/p/9117179.html
今日推荐