shell实例第15讲:俄罗斯方块游戏
生活随笔
收集整理的這篇文章主要介紹了
shell实例第15讲:俄罗斯方块游戏
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
?運行結果圖:
#!/bin/bash #作者:魏波 #時間:2017.02.04APP_NAME="${0##*[\\/]}" APP_VERSION="1.0"#顏色定義 iSumColor=7 #顏色總數 cRed=1 #紅色 cGreen=2 #綠色 cYellow=3 #黃色 cBlue=4 #藍色 cFuchsia=5 #紫紅色 cCyan=6 #青色(藍綠色) cWhite=7 #白色#位置與大小 marginLeft=3 #邊框左邊距 marginTop=2 #邊框上邊距 ((mapLeft=marginLeft+2)) #棋盤左邊距 ((mapTop=$marginTop+1)) #棋盤上邊距 mapWidth=10 #棋盤寬度 mapHeight=15 #棋盤高度#顏色設置 cBorder=$cGreen cScore=$cFuchsia cScoreValue=$cCyan#控制信號 #游戲使用兩個進程,一個用于接收輸入,一個用于游戲流程和顯示界面; #當前者接收到上下左右等按鍵時,通過向后者發送signal的方式通知后者。 sigRotate=25 #上鍵 sigLeft=26 #左鍵 sigRight=27 #右鍵 sigDown=28 #下鍵 sigAllDown=29 #空格鍵 sigExit=30#方塊定義,7大類19種樣式 #前8位為方塊坐標,后2位為方塊剛出現的時候的位置 box0_0=(0 0 0 1 1 0 1 1 0 4)box1_0=(0 1 1 1 2 1 3 1 0 3) box1_1=(1 0 1 1 1 2 1 3 -1 3)box2_0=(0 0 1 0 1 1 2 1 0 4) box2_1=(0 1 0 2 1 0 1 1 0 3)box3_0=(0 1 1 0 1 1 2 0 0 4) box3_1=(0 0 0 1 1 1 1 2 0 4)box4_0=(0 2 1 0 1 1 1 2 0 3) box4_1=(0 1 1 1 2 1 2 2 0 3) box4_2=(1 0 1 1 1 2 2 0 -1 3) box4_3=(0 0 0 1 1 1 2 1 0 4)box5_0=(0 0 1 0 1 1 1 2 0 3) box5_1=(0 1 0 2 1 1 2 1 0 3) box5_2=(1 0 1 1 1 2 2 2 -1 3) box5_3=(0 1 1 1 2 0 2 1 0 4)box6_0=(0 1 1 0 1 1 1 2 0 3) box6_1=(0 1 1 1 1 2 2 1 0 3) box6_2=(1 0 1 1 1 2 2 1 -1 3) box6_3=(0 1 1 0 1 1 2 1 0 4)iSumType=7 #方塊類型總數 boxStyle=(1 2 2 2 4 4 4) #各種方塊旋轉后可能的樣式數目iScoreEachLevel=50 #提升一個級別需要的分數 #運行時數據 sig=0 #接收到的signal iScore=0 #總分 iLevel=0 #速度級 boxNext=() #下一個方塊 iboxNextColor=0 #下一個方塊的顏色 iboxNextType=0 #下一個方塊的種類 iboxNextStyle=0 #下一個方塊的樣式 boxCur=() #當前方塊的位置定義 iBoxCurColor=0 #當前方塊的顏色 iBoxCurType=0 #當前方塊的種類 iBoxCurStyle=0 #當前方塊的樣式 boxCurX=-1 #當前方塊的x坐標位置 boxCurY=-1 #當前方塊的y坐標位置 map=() #棋盤圖表#初始化所有背景方塊為-1, 表示沒有方塊 for ((i = 0; i < mapHeight * mapWidth; i++)) domap[$i]=-1 done#接收輸入的進程的主函數 function RunAsKeyReceiver() {local pidDisplayer key aKey sig cESC sTTYpidDisplayer=$1aKey=(0 0 0)cESC=`echo -ne "\033"`cSpace=`echo -ne "\040"`#保存終端屬性。在read -s讀取終端鍵時,終端的屬性會被暫時改變。#如果在read -s時程序被不幸殺掉,可能會導致終端混亂,#需要在程序退出時恢復終端屬性。sTTY=`stty -g`#捕捉退出信號trap "MyExit;" INT QUITtrap "MyExitNoSub;" $sigExit#隱藏光標echo -ne "\033[?25l"while :do#讀取輸入。注-s不回顯,-n讀到一個字符立即返回read -s -n 1 keyaKey[0]=${aKey[1]}aKey[1]=${aKey[2]}aKey[2]=$keysig=0#判斷輸入了何種鍵if [[ $key == $cESC && ${aKey[1]} == $cESC ]]then#ESC鍵MyExitelif [[ ${aKey[0]} == $cESC && ${aKey[1]} == "[" ]]thenif [[ $key == "A" ]]; then sig=$sigRotate #<向上鍵>elif [[ $key == "B" ]]; then sig=$sigDown #<向下鍵>elif [[ $key == "D" ]]; then sig=$sigLeft #<向左鍵>elif [[ $key == "C" ]]; then sig=$sigRight #<向右鍵>fielif [[ $key == "W" || $key == "w" ]]; then sig=$sigRotate #W, welif [[ $key == "S" || $key == "s" ]]; then sig=$sigDown #S, selif [[ $key == "A" || $key == "a" ]]; then sig=$sigLeft #A, aelif [[ $key == "D" || $key == "d" ]]; then sig=$sigRight #D, delif [[ "[$key]" == "[]" ]]; then sig=$sigAllDown #空格鍵elif [[ $key == "Q" || $key == "q" ]] #Q, qthenMyExitfiif [[ $sig != 0 ]]then#向另一進程發送消息kill -$sig $pidDisplayerfidone }#退出前的恢復 MyExitNoSub() {local y#恢復終端屬性stty $sTTY((y = marginTop + mapHeight + 4))#顯示光標echo -e "\033[?25h\033[${y};0H"exit }MyExit() {#通知顯示進程需要退出kill -$sigExit $pidDisplayerMyExitNoSub }#處理顯示和游戲流程的主函數 RunAsDisplayer() {local sigThisInitDraw#掛載各種信號的處理函數trap "sig=$sigRotate;" $sigRotatetrap "sig=$sigLeft;" $sigLefttrap "sig=$sigRight;" $sigRighttrap "sig=$sigDown;" $sigDowntrap "sig=$sigAllDown;" $sigAllDowntrap "ShowExit;" $sigExitwhile :do#根據當前的速度級iLevel不同,設定相應的循環的次數for ((i = 0; i < 21 - iLevel; i++))dosleep 0.02sigThis=$sigsig=0#根據sig變量判斷是否接受到相應的信號if ((sigThis == sigRotate)); then BoxRotate; #旋轉elif ((sigThis == sigLeft)); then BoxLeft; #左移一列elif ((sigThis == sigRight)); then BoxRight; #右移一列elif ((sigThis == sigDown)); then BoxDown; #下落一行elif ((sigThis == sigAllDown)); then BoxAllDown; #下落到底fidone#kill -$sigDown $$BoxDown #下落一行done }#繪制當前方塊,傳第一個參數,0表示擦除當前方塊,1表示繪制當前方塊 DrawCurBox() {local i x y bErase sBoxbErase=$1if (( bErase == 0 ))thensBox="\040\040" #用兩個空格擦除elsesBox="[]"echo -ne "\033[1m\033[3${iBoxCurColor}m\033[4${iBoxCurColor}m"fifor ((i = 0; i < 8; i += 2))do((y = mapTop + 1 + ${boxCur[$i]} + boxCurY))((x = mapLeft + 1 + 2 * (boxCurX + ${boxCur[$i + 1]})))echo -ne "\033[${y};${x}H${sBox}"doneecho -ne "\033[0m" }#移動方塊 #BoxMove(y, x), 測試是否可以把移動中的方塊移到(y, x)的位置, 返回0則可以, 1不可以 BoxMove() {local i x y xPos yPosyPos=$1xPos=$2for ((i = 0; i < 8; i += 2))do#方塊相對于棋盤坐標((y = yPos + ${boxCur[$i]}))((x = xPos + ${boxCur[$i + 1]}))if (( y < 0 || y >= mapHeight || x < 0 || x >= mapWidth))then#撞到墻壁了return 1fiif (( ${map[y * mapWidth + x]} != -1 ))then#撞到其他已經存在的方塊了return 1fidonereturn 0; }#將方塊貼到棋盤上 Box2Map() {local i j x y line#將當前移動中的方塊貼到棋盤對應的區域for ((i = 0; i < 8; i += 2))do#計算方塊相對于棋盤的坐標((y = ${boxCur[$i]} + boxCurY))((x = ${boxCur[$i + 1]} + boxCurX))map[y*mapWidth+x]=$iBoxCurColor #將方塊顏色賦給地圖doneline=0for ((i = 0; i < mapHeight; i++))dofor ((j = 0; j < mapWidth; j++))do#如果棋盤上有空隙,跳出循環[[ ${map[i*mapWidth+j]} -eq -1 ]] && breakdone[ $j -lt $mapWidth ] && continue#說明當前行可消去,可消去行數加一(( line++ ))#第i行可被消除,將0行至第i-1行全部下移一行,從第i-1行開始移動for ((j = i*mapWidth-1; j >= 0; j--))do((x = j + mapWidth))map[$x]=${map[$j]}done#因為下移一行,第0行置空for ((i = 0; i < mapWidth; i++))domap[$i]=-1donedone[ $line -eq 0 ] && return#根據消去的行數line計算分數和速度級((x = marginLeft + mapWidth * 2 + 7))((y = marginTop + 11))((iScore += line * 2 - 1))#顯示新的分數echo -ne "\033[1m\033[3${cScoreValue}m\033[${y};${x}H${iScore} "if ((iScore % iScoreEachLevel < line * 2 - 1))thenif ((iLevel < 20))then((iLevel++))((y = marginTop + 14))#顯示新的速度級echo -ne "\033[3${cScoreValue}m\033[${y};${x}H${iLevel} "fifiecho -ne "\033[0m"#重新顯示背景方塊for ((i = 0; i < mapHeight; i++))do#棋盤相對于屏幕的坐標((y = i + mapTop + 1))((x = mapLeft + 1))echo -ne "\033[${y};${x}H"for ((j = 0; j < mapWidth; j++))do((tmp = i * mapWidth + j))if ((${map[$tmp]} == -1))thenecho -ne " "elseecho -ne "\033[1m\033[3${map[$tmp]}m\033[4${map[$tmp]}m[]\033[0m"fidonedone }#左移一格 BoxLeft() {local x((x = boxCurX - 1))if BoxMove $boxCurY $xthenDrawCurBox 0((boxCurX = x))DrawCurBox 1fi }#右移一格 BoxRight() {local x((x = boxCurX + 1))if BoxMove $boxCurY $xthenDrawCurBox 0((boxCurX = x))DrawCurBox 1fi }#向下移一格 BoxDown() {local y((y = boxCurY + 1)) #新的y坐標if BoxMove $y $boxCurX #測試是否可以下落一行thenDrawCurBox 0 #將舊的方塊抹去((boxCurY = y))DrawCurBox 1 #顯示新的下落后方塊else#走到這兒, 如果不能下落了Box2Map #將當前移動中的方塊貼到背景方塊中CreateBox #產生新的方塊fi }#下落到底 BoxAllDown() {local y iDown#計算能夠下落的行數iDown=0(( y = boxCurY + 1 ))while BoxMove $y $boxCurXdo(( y++ ))(( iDown++ ))doneDrawCurBox 0 #將舊的方塊抹去((boxCurY += iDown))DrawCurBox 1 #顯示新的下落后的方塊Box2Map #將當前移動中的方塊貼到背景方塊中CreateBox #產生新的方塊 }#翻轉 BoxRotate() {[ ${boxStyle[$iBoxCurType]} -eq 1 ] && return((rotateStyle = (iBoxCurStyle + 1) % ${boxStyle[$iBoxCurType]}))#將當前方塊保存到boxTmpboxTmp=( `eval 'echo ${boxCur[@]}'` )boxCur=( `eval 'echo ${box'$iBoxCurType'_'$rotateStyle'[@]}'` )if BoxMove $boxCurY $boxCurX #測試旋轉后是否有空間放的下then#抹去舊的方塊boxCur=( `eval 'echo ${boxTmp[@]}'` )DrawCurBox 0boxCur=( `eval 'echo ${box'$iBoxCurType'_'$rotateStyle'[@]}'` )DrawCurBox 1iBoxCurStyle=$rotateStyleelse#不能旋轉,還是繼續使用老的樣式boxCur=( `eval 'echo ${boxTmp[@]}'` )fi }#準備下一個方塊 PrepareNextBox() {local i x y#清除右邊預顯示的方塊if (( ${#boxNext[@]} != 0 )); thenfor ((i = 0; i < 8; i += 2))do((y = marginTop + 1 + ${boxNext[$i]}))((x = marginLeft + 2 * mapWidth + 7 + 2 * ${boxNext[$i + 1]}))echo -ne "\033[${y};${x}H\040\040"donefi#隨機生成預顯式方塊(( iBoxNextType = RANDOM % iSumType ))(( iBoxNextStyle = RANDOM % ${boxStyle[$iBoxNextType]} ))(( iBoxNextColor = RANDOM % $iSumColor + 1 ))boxNext=( `eval 'echo ${box'$iBoxNextType'_'$iBoxNextStyle'[@]}'` )#顯示右邊預顯示的方塊echo -ne "\033[1m\033[3${iBoxNextColor}m\033[4${iBoxNextColor}m"for ((i = 0; i < 8; i += 2))do((y = marginTop + 1 + ${boxNext[$i]}))((x = marginLeft + 2 * mapWidth + 7 + 2 * ${boxNext[$i + 1]}))echo -ne "\033[${y};${x}H[]"doneecho -ne "\033[0m"}#顯示新方塊 CreateBox() {if (( ${#boxCur[@]} == 0 )); then#當前方塊不存在(( iBoxCurType = RANDOM % iSumType ))(( iBoxCurStyle = RANDOM % ${boxStyle[$iBoxCurType]} ))(( iBoxCurColor = RANDOM % $iSumColor + 1 ))else#當前方塊已存在, 將下一個方塊賦給當前方塊iBoxCurType=$iBoxNextType;iBoxCurStyle=$iBoxNextStyle;iBoxCurColor=$iBoxNextColorfi#當前方塊數組boxCur=( `eval 'echo ${box'$iBoxCurType'_'$iBoxCurStyle'[@]}'` )#初始化方塊起始坐標boxCurY=boxCur[8];boxCurX=boxCur[9];DrawCurBox 1 #繪制當前方塊if ! BoxMove $boxCurY $boxCurXthenkill -$sigExit $PPIDShowExitfiPrepareNextBox}#繪制邊框 DrawBorder() {clearlocal i y x1 x2#顯示邊框echo -ne "\033[1m\033[3${cBorder}m\033[4${cBorder}m"((x1 = marginLeft + 1)) #左邊框x坐標((x2 = x1 + 2 + mapWidth * 2)) #右邊框x坐標for ((i = 0; i < mapHeight; i++))do((y = i + marginTop + 2))echo -ne "\033[${y};${x1}H||" #繪制左邊框echo -ne "\033[${y};${x2}H||" #繪制右邊框done((x1 = marginTop + mapHeight + 2))for ((i = 0; i < mapWidth + 2; i++))do((y = i * 2 + marginLeft + 1))echo -ne "\033[${mapTop};${y}H==" #繪制上邊框echo -ne "\033[${x1};${y}H==" #繪制下邊框doneecho -ne "\033[0m"#顯示"Score"和"Level"字樣echo -ne "\033[1m"((y = marginLeft + mapWidth * 2 + 7))((x1 = marginTop + 10))echo -ne "\033[3${cScore}m\033[${x1};${y}HScore"((x1 = marginTop + 11))echo -ne "\033[3${cScoreValue}m\033[${x1};${y}H${iScore}"((x1 = marginTop + 13))echo -ne "\033[3${cScore}m\033[${x1};${y}HLevel"((x1 = marginTop + 14))echo -ne "\033[3${cScoreValue}m\033[${x1};${y}H${iLevel}"echo -ne "\033[0m" }InitDraw() {clear #清屏DrawBorder #繪制邊框CreateBox #創建方塊 }#退出時顯示GameOVer! ShowExit() {local y((y = mapHeight + mapTop + 3))echo -e "\033[${y};1HGameOver!\033[0m"exit }#游戲主程序在這兒開始. if [[ "$1" == "--version" ]]; thenecho "$APP_NAME $APP_VERSION" elif [[ "$1" == "--show" ]]; then#當發現具有參數--show時,運行顯示函數RunAsDisplayer elsebash $0 --show& #以參數--show將本程序再運行一遍RunAsKeyReceiver $! #以上一行產生的進程的進程號作為參數 fikeytest.sh#!/bin/bashGetKey() {aKey=(0 0 0) #定義一個數組來保存3個按鍵cESC=`echo -ne "\033"`cSpace=`echo -ne "\040"`while :doread -s -n 1 key #讀取一個字符,將讀取到的字符保存在key中#echo $key#echo XXX aKey[0]=${aKey[1]} #第一個按鍵aKey[1]=${aKey[2]} #第二個按鍵aKey[2]=$key #第三個按鍵if [[ $key == $cESC && ${aKey[1]} == $cESC ]]thenMyExitelif [[ ${aKey[0]} == $cESC && ${aKey[1]} == "[" ]]thenif [[ $key == "A" ]]; then echo KEYUPelif [[ $key == "B" ]]; then echo KEYDOWNelif [[ $key == "D" ]]; then echo KEYLEFTelif [[ $key == "C" ]]; then echo KEYRIGHTfifidone }GetKeydraw.sh#!/bin/bash#位置與大小 marginLeft=8 #邊框左邊距 marginTop=6 #邊框上邊距 ((mapLeft=marginLeft+2)) #棋盤左邊距 ((mapTop=$marginTop+1)) #棋盤上邊距 mapWidth=10 #棋盤寬度 mapHeight=15 #棋盤高度#方塊定義,7大類19種樣式 #前8位為方塊坐標,后2位為方塊剛出現的時候的位置 box0_0=(0 0 0 1 1 0 1 1 0 4)box1_0=(0 1 1 1 2 1 3 1 0 3) box1_1=(1 0 1 1 1 2 1 3 -1 3)box2_0=(0 0 1 0 1 1 2 1 0 4) box2_1=(0 1 0 2 1 0 1 1 0 3)box3_0=(0 1 1 0 1 1 2 0 0 4) box3_1=(0 0 0 1 1 1 1 2 0 4)box4_0=(0 2 1 0 1 1 1 2 0 3) box4_1=(0 1 1 1 2 1 2 2 0 3) box4_2=(1 0 1 1 1 2 2 0 -1 3) box4_3=(0 0 0 1 1 1 2 1 0 4)box5_0=(0 0 1 0 1 1 1 2 0 3) box5_1=(0 1 0 2 1 1 2 1 0 3) box5_2=(1 0 1 1 1 2 2 2 -1 3) box5_3=(0 1 1 1 2 0 2 1 0 4)box6_0=(0 1 1 0 1 1 1 2 0 3) box6_1=(0 1 1 1 1 2 2 1 0 3) box6_2=(1 0 1 1 1 2 2 1 -1 3) box6_3=(0 1 1 0 1 1 2 1 0 4)#繪制邊框 DrawBorder() {clearlocal i y x1 x2#顯示邊框echo -ne "\033[1m\033[32m\033[42m"((x1 = marginLeft + 1)) #左邊框x坐標((x2 = x1 + 2 + mapWidth * 2)) #右邊框x坐標for ((i = 0; i < mapHeight; i++))do((y = i + marginTop + 2))echo -ne "\033[${y};${x1}H||" #繪制左邊框echo -ne "\033[${y};${x2}H||" #繪制右邊框done((x1 = marginTop + mapHeight + 2))for ((i = 0; i < mapWidth + 2; i++))do((y = i * 2 + marginLeft + 1))echo -ne "\033[${mapTop};${y}H==" #繪制上邊框echo -ne "\033[${x1};${y}H==" #繪制下邊框doneecho -ne "\033[0m" }DrawBox() {local i x y xPos yPosyPos=${box0_0[8]}xPos=${box0_0[9]}echo -ne "\033[1m\033[35m\033[45m"for ((i = 0; i < 8; i += 2))do(( y = mapTop + 1 + ${box0_0[$i]} + yPos ))(( x = mapLeft + 1 + 2 * (${box0_0[$i + 1]} + xPos) ))echo -ne "\033[${y};${x}H[]"doneecho -ne "\033[0m" }InitDraw() {clear #清屏DrawBorder #繪制邊框DrawBoxwhile :dosleep 1done }InitDraw?
總結
以上是生活随笔為你收集整理的shell实例第15讲:俄罗斯方块游戏的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: shell实例第14讲:字符串截取的8种
- 下一篇: shell实例第16讲:猜拳游戏