從零開始的貪喫蛇遊戲

打算從零開始開發貪喫蛇遊戲,寫個帖子,記錄一下製作過程

先準備一個空項目,當然是熟悉的qt on android框架

0_1524188175385_QQ圖片20180420093243.jpg

剛開始什麼都沒有,先做一個虛擬搖桿

0_1524191936095_QQ截圖20180420103825.png

審美不行,只能P成這樣,經過測試,顯示的角度如圖,爲啥會是這樣結果,暫時不明,不過不影響使用

關於搖桿控制貪喫蛇轉向問題,我的設想是以蛇頭爲自身座標系,當向上時候,實際以蛇頭的方向向前

0_1524202991870_QQ截圖20180420134300.png

自身座標系已經把我繞暈了,改用全局座標系,虛擬搖桿和qml界面,四象限對應關係

0_1524205926415_QQ截圖20180420143148.png

if(angle<0)
        {
            rotationHead.angle = Math.abs(angle) + 90
        }
        else if(angle>=90 && angle <= 180)
        {
            rotationHead.angle = 180-angle+270
        }
        else
        {
            //0-90
            rotationHead.angle = 90-angle
        }

通過timer控制蛇移動

Timer{
        id: timerGame
        interval: 30
        repeat: true
        running: bStartGame
        onTriggered: {
            snake.move(step)
        }
    }

move函數裏面一點點移動貪喫蛇,先移動蛇頭,根據旋轉角度和step計算新的座標,後面的身體和尾巴使用前一個點的座標

貪喫蛇跑出屏幕很不好,我又不想這樣算死亡,需要計算屏幕寬度,重置座標,希望蛇跑出屏幕,從另一頭再出來

修改

從虛擬遙感到蛇頭移動,其實不用座標系轉換,計算角度時候我使用的是Math.atan2,這裏的參數 是(y, x),我原來用的(x, y),修正後,不用轉換座標系,蛇頭就是正常的:loudly_crying_face:

var radian = Math.atan2(snakerCY - centerY, snakerCX - centerX )

傳統貪喫蛇都是一格格移動,後一個移動到前一個位置,我想實現很流暢的移動,改用下面這個方案

  • Timer設定30ms更新,每次更新蛇頭移動10px,身體部分靠角度計算實現移動

現實是殘酷的,結果是身體各種亂飛,然後我放棄了這種方案,改爲傳統一格格移動

  • Timer設定500ms更新,每次更新蛇頭移動100px(一個身位),身體部分設置爲前一個位置,實現移動
  • 爲了去掉一格格閃現效果(卡頓效果),設定移動動畫,實現假流暢效果

遊戲截圖,

0_1524574165718_Screenshot_20180424-203539.jpg

新的設計影響到貪喫蛇從屏幕循環,所以去掉屏幕循環,爲了防止蛇跑出屏幕,追加乒乓球效果,就是碰到屏幕反彈

0_1524633827546_QQ截圖20180425132334.png

我很笨拙的把四象限挨個判斷了一遍,效果還是不錯的

function checkScreen(x, y){
        var w = Screen.width
        var h = Screen.height

        var point = Qt.point(x,y)


        if(x<=0 && (rotationHead.angle>=90 && rotationHead.angle<=180)){
            rotationHead.angle = 180-rotationHead.angle
        }
        else if(x<=0 && (rotationHead.angle>=-180 && rotationHead.angle<=-90)){
            rotationHead.angle = -180-rotationHead.angle
        }
        else if(x>=w && (rotationHead.angle>=-90 && rotationHead.angle<=0)){
            rotationHead.angle = -180-rotationHead.angle
        }
        else if(x>=w && (rotationHead.angle>=0 && rotationHead.angle<=90)){
            rotationHead.angle = 180-rotationHead.angle
        }

        if(y<=0 && (rotationHead.angle>=-180 && rotationHead.angle<=-90) ){
            rotationHead.angle = -rotationHead.angle
        }
        else if(y<=0 && (rotationHead.angle>=-90 && rotationHead.angle<=0) ){
            rotationHead.angle = -rotationHead.angle
        }
        else if(y>=h && (rotationHead.angle>=0 && rotationHead.angle<=90) ){
            rotationHead.angle = -rotationHead.angle
        }
        else if(y>=h && (rotationHead.angle>=90 && rotationHead.angle<=180) ){
            rotationHead.angle = -rotationHead.angle
        }


        return point
    }

隨着分數的提升,加快蛇的爬行速度

onScoreChanged: {

        //每10分提升一個level的速度(-10)
        //level最大20,對應分數200
        var level = Math.floor(score/10)

        if(level==0){
        }
        else{
            if(speed - 10*level <= 100){
                speed = 100
            }
            else{
                speed = 300-10*level
            }
        }
    }

增加一個加速按鈕,可以手動加速爬行

0_1524640903680_Screenshot_20180425-152046.jpg

有了兩個按鈕,出現了新的問題,因爲用MouseArea實現的,這兩個按鈕不能同時按下去

多點觸控

爲了能同時旋轉+加速,採用多點觸控,MultiPointTouchArea組件是qml提供的現成的多點觸控組件

touchPoints: [
            TouchPoint{
                id: point1
            },
            TouchPoint{
                id: point2
            }
        ]

添加了兩個觸控點,需要考慮兩個點分別佔用搖桿和加速鍵的情況

    property int touchYaoGan: 0     //0=沒有,1=觸控點1佔用,2=觸控點2佔用
    property int touchSpeed: 0    //0=沒有,1=觸控點1佔用,2=觸控點2佔用

把兩個操作的邏輯在MultiPointTouchArea上又實現了一遍,完成後的體驗真酸爽

消減

如果一直不死,遊戲缺乏難度,因此追加了,如果碰到邊界,會消減一段身體,當然頭是不能消得。
這樣就變成了,永遠不死,但是分數不會無限增加,想加個分數排行榜

菜單

在遊戲界面按下手機返回鍵,顯示菜單,菜單界面我很努力的去P了,支持恢復,重新開始,排行榜,退出

0_1524654206568_Screenshot_20180425-190156.jpg

排行榜界面

0_1524654313544_Screenshot_20180425-190213.jpg

下次加個開始界面

修復

首先修復一個bug,快速輕點加速鍵,會暫停貪喫蛇,所以爲加速鍵追加了一個長壓判斷

//長壓判斷
    Timer{
        id: timerLongPress
        interval: 300
        onTriggered: {
            //加速鍵被長壓
            fire.scale = 0.9
            isFired = true
            longPressed = false
        }
    }

開始畫面

0_1524719315192_startBg.png

提示

追加操作提示按鈕

0_1524721293282_QQ圖片20180426134044.jpg

保存數據

使用QSettings 將最大分數進行本地化保存

void MyCommon::saveScore(double score)
{
    QSettings settings(QDir::currentPath()+"/data.ini", QSettings::IniFormat);
    settings.setValue("config/score", score);
}

double MyCommon::getScore()
{
    QSettings settings(QDir::currentPath()+"/data.ini", QSettings::IniFormat);
    double score = 0.0;
    score = settings.value("config/score").toDouble();

    return score;
}

音效

這個喫東西的音效,特別脆

SoundEffect {
        id: playSound
        source: "qrc:/music/music/eat1.wav"
    }

完成

程序下載:下載地址

源代碼下載:下載地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章