@frilix
Иногда "творю"

Анимация в bash?

Добрый день! Как можно улучшить скрипт который рисует летучую мышь, которая двигается в разных направлениях. Проблема в том, что постоянно мерцает курсор, перед сменой кадка он в начале терминала, а после отрисовки рисунка он соотвественно в конце. Можно как-то сделать это плавнее? Скорее всего дело в clear. Есть предположения?

И второй вопрос: сейчас у меня количество строк, помещающихся в одни экран терминала не вычисляется. Функция `tput rows` выдает неверное значение.

P.S задание дали в универе

#!/bin/bash

let y=0
let x=0
let max_x=$(tput cols)
let max_y=24
let wall=0

draw_top() {
    local line1='   ######   ## | ##   #####    '
    local line2='.##############################'
    local line3='   ########################    '
    local line4='      ###################      '
    local line5='            #######            '
    local line6='             ####              '
    local line7='              #                '

    # Сдвиг сверху
    for ((i = 0; i < $1; i++)) ; do
        echo " "
    done

    # Сдвиг слева
    for index in {1..7}; do
        for ((j = 0; j < $2; j++)) ; do
             echo -n " "
        done
        var="line$index"
        echo "${!var}"
    done
}

draw_bottom() { 
    local line1='                #              '
    local line2='              #####            '
    local line3='        ##################     '
    local line4='    ########################   '
    local line5='###############################'
    local line6='  ########   ## | ##   ####### '
    local line7='     ###                 ###   '

    # Сдвиг сверху
    for ((i = 0; i < $1; i++)) ; do
        echo " "
    done

    # Сдвиг слева
    for index in {1..7}; do
        for ((j = 0; j < $2; j++)) ; do
             echo -n " "
        done
        var="line$index"
        echo "${!var}"
    done
}

draw_right() {
    local line1='          #   '
    local line2='          ##  '
    local line3='         #### '
    local line4='       #######'
    local line5='     ######## '
    local line6='     #######  '
    local line7='     ######   '
    local line8='  ##########  '
    local line9='###########-  '
    local line10='  ##########  '
    local line11='     ######   '
    local line12='      ####### '
    local line13='      ########'
    local line14='        ##### '
    local line15='         ###  '
    local line16='          #   '

    # Сдвиг сверху
    for ((i = 0; i < $1; i++)) ; do
        echo " "
    done

    # Сдвиг слева
    for index in {1..16}; do
        for ((j = 0; j < $2; j++)) ; do
             echo -n " "
        done
        var="line$index"
        echo "${!var}"
    done
}

draw_left() {
    local line1='    #       '
    local line2='   ##       '
    local line3='  ####      '
    local line4=' ########   '
    local line5='########    '
    local line6=' #######    '
    local line7='  #######   '
    local line8='##########  '
    local line9=' -##########'
    local line10='##########  '
    local line11='  ########  '
    local line12=' ########   '
    local line13='##########  '
    local line14='  #######   '
    local line15='    ####    '
    local line16='     ##     '

    # Сдвиг сверху
    for ((i = 0; i < $1; i++)) ; do
        echo " "
    done

    # Сдвиг слева
    for index in {1..16}; do
        for ((j = 0; j < $2; j++)) ; do
             echo -n " "
        done
        var="line$index"
        echo "${!var}"
    done
}

move_right() {
    if ((x < max_x - 15))
    then
        ((x++))
    else
        wall=1
    fi

    clear
    draw_right $y $x
}

move_bottom() {
    if ((y < max_y - 8))
    then
        ((y++))
    else
        wall=1
    fi
    
    clear
    draw_bottom $y $x
}

move_left() {
    if (( x > 0 ))
    then
        ((x--))
    else
        wall=1
    fi

    clear
    draw_left $y $x
}

move_top() {
    if (( y > 0 ))
    then
        ((y--))
    else
        wall=1
    fi

    clear
    draw_top $y $x
}

random_choice() {
    RANGE=$1
    number=$RANDOM
    let "number %= $RANGE"
    echo "$number"
}

move() {
    if [ "$1" == 0 ]
    then
        move_right
    fi

    if [ "$1" == 1 ]
    then
        move_left
    fi

    if [ "$1" == 2 ]
    then
        move_top
    fi

    if [ "$1" == 3 ]
    then
        move_bottom
    fi
}

calculate_coords() {
    let vertical=$1

    # Вертикально -> Горизонтально
    if (( vertical > 0))
    then
        x=$((x-8))
        y=$((y+5))

        if (( x < 0 ))
        then
            x=0
        fi

        if (( x + 31 > max_x))
        then
            x=$((max_x-31))
        fi

        if (( y + 8 > max_y))
        then
            y=$((max_y-8))
        fi

    # Горизонтально -> Вертикально
    else
        x=$((x+8))
        y=$((y-5))

        if (( y < 0 ))
        then
            y=0
        fi

        if ((x + 13 > max_x))
        then
            x=$((max_x - 13))
        fi

        if ((y + 17 > max_y))
        then
            y=$((max_y - 17))
        fi
    fi
}

start() {
    current=0
    direction=0
    prevent_direction=0

    while true; do
        # Calculate dicrection
        if ((current == 20 || wall == 1))
        then
            wall=0
            current=0
            prevent_direction=$direction
            direction=$(random_choice 4)

            if (( direction < 2 && prevent_direction > 1 ))
            then
                calculate_coords 0
            fi

            if (( direction > 1 && prevent_direction < 2 ))
            then
                calculate_coords 1
            fi
        fi

        # Move
        move $direction
        current=$((current+1))
        sleep .2
    done
}

start
  • Вопрос задан
  • 1453 просмотра
Решения вопроса 1
saboteur_kiev
@saboteur_kiev Куратор тега bash
software engineer
вместо clear попробуйте использовать "tput cup $y 0", а clear сделать только при смене направления.
Также можно сократить вычисления, высчитывая двиг слева только при движении влево и вправо.
И использовать индексы, вместо преобразования имени переменной.
И как-то у вас все не-аккуратненько. Мышка кривая, вы бы ее подрисовали ровнее, как-то так:

spoiler
#!/bin/bash

let y=0
let x=0
let max_x=120 #$(tput cols)
let max_y=24
let wall=0
let space=""

draw_top() {
    local line[0]='   ###               ###'
    local line[1]='  #####   ## | ##   #####'
    local line[2]='########################### '
    local line[3]='  #######################  '
    local line[4]='     #################   '
    local line[5]='          #######     '
    local line[6]='           ##### '
    local line[7]='             #  '
    local line[8]='              '

    for index in {0..8}; do
        echo "$space${line[$index]}"
    done
}

draw_bottom() { 
    local line[0]='              '
    local line[1]='             #  '
    local line[2]='           ##### '
    local line[3]='          #######     '
    local line[4]='     #################   '
    local line[5]='  #######################  '
    local line[6]='###########################'
    local line[7]='  #####   ## | ##   #####'
    local line[8]='   ###               ###'

    for index in {0..8}; do
        echo "$space${line[$index]}"
    done
}

draw_right() {
    local  line[0]='          #   '
    local  line[1]='          ##  '
    local  line[2]='         #### '
    local  line[3]='       #######'
    local  line[4]='     ######## '
    local  line[5]='     #######  '
    local  line[6]='     ######   '
    local  line[7]='  ##########  '
    local  line[8]='###########-  '
    local  line[9]='  ##########  '
    local line[10]='     ######   '
    local line[11]='     #######  '
    local line[12]='       #######'
    local line[13]='         #### '
    local line[14]='          ##  '
    local line[15]='          #   '

    # Вычисляем сдвиг слева
    space=""
    for ((j = 0; j < $2; j++)) ; do
      space="$space "
    done
    for index in {0..15}; do
        echo "$space${line[$index]}"
    done
}

draw_left() {
    local  line[0]='   # '
    local  line[1]='  ## '
    local  line[2]=' #### '
    local  line[3]='####### '
    local  line[4]=' ######## '
    local  line[5]='  ####### '
    local  line[6]='   ###### '
    local  line[7]='  ########## '
    local  line[8]=' -########### '
    local  line[9]='  ########## '
    local line[10]='   ###### '
    local line[11]='  ####### '
    local line[12]='####### '
    local line[13]=' #### '
    local line[14]='  ## '
    local line[15]='   # '

    # Вычисляем сдвиг слева
    space=""
    for ((j = 0; j < $2; j++)) ; do
      space="$space "
    done
    for index in {0..15}; do
        echo "$space${line[$index]}"
    done
}

move_right() {
    if ((x < max_x - 15))
    then
        ((x++))
    else
        wall=1
    fi

    tput cup $y 0
    draw_right $y $x
}

move_bottom() {
    if ((y < max_y - 8))
    then
        ((y++))
    else
        wall=1
    fi
    
    tput cup $y 0
    draw_bottom $y $x
}

move_left() {
    if (( x > 0 ))
    then
        ((x--))
    else
        wall=1
    fi

    tput cup $y 0
    draw_left $y $x
}

move_top() {
    if (( y > 0 ))
    then
        ((y--))
    else
        wall=1
    fi

    tput cup $y 0
    draw_top $y $x
}

random_choice() {
    RANGE=$1
    number=$RANDOM
    let "number %= $RANGE"
    echo "$number"
}

move() {
    if [ "$1" == 0 ]
    then
        move_right
    fi

    if [ "$1" == 1 ]
    then
        move_left
    fi

    if [ "$1" == 2 ]
    then
        move_top
    fi

    if [ "$1" == 3 ]
    then
        move_bottom
    fi
}

calculate_coords() {
    let vertical=$1

    # Вертикально -> Горизонтально
    if (( vertical > 0))
    then
        x=$((x-8))
        y=$((y+5))

        if (( x < 0 ))
        then
            x=0
        fi

        if (( x + 31 > max_x))
        then
            x=$((max_x-31))
        fi

        if (( y + 8 > max_y))
        then
            y=$((max_y-8))
        fi

    # Горизонтально -> Вертикально
    else
        x=$((x+8))
        y=$((y-5))

        if (( y < 0 ))
        then
            y=0
        fi

        if ((x + 13 > max_x))
        then
            x=$((max_x - 13))
        fi

        if ((y + 17 > max_y))
        then
            y=$((max_y - 17))
        fi
    fi
}

start() {
    current=0
    direction=0
    prevent_direction=0
    clear

    while true; do
        # Calculate dicrection
        if ((current == 20 || wall == 1))
        then
            wall=0
            current=0
            prevent_direction=$direction
            direction=$(random_choice 4)

            if (( direction < 2 && prevent_direction > 1 ))
            then
                calculate_coords 0
            fi

            if (( direction > 1 && prevent_direction < 2 ))
            then
                calculate_coords 1
            fi
            clear
        fi

        # Move
        move $direction
        current=$((current+1))
        /bin/sleep .05
    done
}

start
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы