打算從零開始開發貪喫蛇遊戲,寫個帖子,記錄一下製作過程
先準備一個空項目,當然是熟悉的qt on android框架
剛開始什麼都沒有,先做一個虛擬搖桿
審美不行,只能P成這樣,經過測試,顯示的角度如圖,爲啥會是這樣結果,暫時不明,不過不影響使用
關於搖桿控制貪喫蛇轉向問題,我的設想是以蛇頭爲自身座標系,當向上時候,實際以蛇頭的方向向前
自身座標系已經把我繞暈了,改用全局座標系,虛擬搖桿和qml界面,四象限對應關係
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(一個身位),身體部分設置爲前一個位置,實現移動
- 爲了去掉一格格閃現效果(卡頓效果),設定移動動畫,實現假流暢效果
遊戲截圖,
新的設計影響到貪喫蛇從屏幕循環,所以去掉屏幕循環,爲了防止蛇跑出屏幕,追加乒乓球效果,就是碰到屏幕反彈
我很笨拙的把四象限挨個判斷了一遍,效果還是不錯的
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
}
}
}
增加一個加速按鈕,可以手動加速爬行
有了兩個按鈕,出現了新的問題,因爲用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了,支持恢復,重新開始,排行榜,退出
排行榜界面
下次加個開始界面
修復
首先修復一個bug,快速輕點加速鍵,會暫停貪喫蛇,所以爲加速鍵追加了一個長壓判斷
//長壓判斷
Timer{
id: timerLongPress
interval: 300
onTriggered: {
//加速鍵被長壓
fire.scale = 0.9
isFired = true
longPressed = false
}
}
開始畫面
提示
追加操作提示按鈕
保存數據
使用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"
}
完成
程序下載:下載地址
源代碼下載:下載地址