贪吃蛇作为一款经典的手机游戏,曾经风靡全世界,这里简单说一说玩法。
用游戏把子上下左右控制蛇的方向,寻找吃的东西,每吃一口就能得到一定的积分,而且蛇的身子会越吃越长,身子越长玩的难度就越大,不能碰墙,不能咬到自己的身体,更不能咬自己的尾巴,等到了一定的分数,就能过关,然后继续玩下一关。
这里我将使用qml来实现一个简单的贪吃蛇游戏
这个游戏现阶段没有通关,蛇的身子不会越吃越长。
我们简单分析一下贪吃蛇这个游戏的主要的实体有哪些吧~
一个是游戏视窗,一个是蛇,一个是糖果。
蛇不能越出游戏视窗,不然视为游戏结束,糖果出现的地方只能在游戏视窗内。
好,先看看蛇这个实体怎么用qml来构造吧(现阶段的蛇其实只是个矩形,不能变长也不能弯曲)。
====================================
Snake.qml
import QtQuick 2.4
Rectangle {
id:snake;
width: 20;
height: 20;
color:"red";
x: 0.5 * areaX;
y: 0.5 * areaY;
property real areaX:500;
property real areaY:500;
readonly property int step: 10;
readonly property int timeStep: 50;
signal out;
property int moveDirection:3; // 0,1,2,3,4 ; left ,right, up, down, death
focus:true;
Keys.onPressed: {
if(event.key == Qt.Key_Left) {
snake.moveDirection = 0;
snake.start();
}
if(event.key == Qt.Key_Right) {
snake.moveDirection = 1;
snake.start();
}
if(event.key == Qt.Key_Up) {
snake.moveDirection = 2;
snake.start();
}
if(event.key == Qt.Key_Down) {
snake.moveDirection = 3;
snake.start();
}
event.accepted = true;
}
NumberAnimation on x { duration: snake.timeStep; }
NumberAnimation on y { duration: snake.timeStep; }
function start(){
if(!time.running) {
time.running = true;
snake.x = 0.5 * areaX;
snake.y = 0.5 * areaY;
snake.color = "red";
}
}
function stop() { time.running = false; }
function move(){
switch(moveDirection)
{
case 0: /*left */
snake.x -= snake.step;
break;
case 1: /*right*/
snake.x += snake.step;
break;
case 2: /*up*/
snake.y -= snake.step;
break;
case 3: /*down*/
snake.y += snake.step;
break;
case 4: /*death*/
snake.y = 0;
snake.x = 0;
break;
default: /*death*/
snake.y = 0;
snake.x = 0;
break;
}
checkOut();
}
function checkOut(){
if(snake.x < 0 || snake.y < 0 || (snake.x+snake.width) > areaX || (snake.y+snake.height) > areaY ) {
out();
return true;
} else {
return false;
}
}
Timer{
id:time;
interval:snake.timeStep;
repeat:true;
onTriggered : move();
}
onOut: {
snake.stop();
snake.moveDirection = 4;
snake.color = "black";
}
}
Snake通过定时调用move()来进行移动,move()函数内判断moveDirection的数值来确定Snake的移动方向,每移动一次,使用checkOut()函数判断Snake是否移动出了游戏视窗(也就是撞墙)。当Snake撞墙后,发射out信号,使用out的信号处理函数来让snake颜色变黑,并且停止计时器。
我们再来看看Candy这个实体
======================
Candy.qml
import QtQuick 2.0
Rectangle {
id:candy;
width: 20;
height: 20;
signal ate; // 被吃时发信号
x:Math.random() * 500;
y : Math.random() * 500;
color:Qt.rgba(Math.random(),Math.random(),Math.random(),1);
function newCandy(){
candy.x = Math.random() * 500;
candy.y = Math.random() * 500;
candy.color = Qt.rgba(Math.random(),Math.random(),Math.random(),1);
candy.opacity = 1;
}
NumberAnimation on x { duration: 50; }
NumberAnimation on y { duration: 50; }
onAte:candy.opacity = 0;
}
当Candy被吃时(也就是和Snake发生碰撞)发出ate这个信号,然后将自己变成透明的。还有一个函数时newCandy(),他的作用是让Candy这个实体,以随机的颜色和位置出现在游戏视窗里,达到Candy被Snake吃之后,又产生新的糖果。
现在看看游戏主视窗吧=============================
main.qml
import QtQuick 2.4
Rectangle {
id:gameView;
width: 500;
height: 500;
property int score:0;
Text{
anchors.centerIn: parent;
text:"score: "+ gameView.score;
}
Snake{
id:snake;
areaX : 500;
areaY : 500;
onOut:{
gameView.score = 0;
}
}
Candy { id:candy; }
Timer{
id:time;
interval:10;
repeat:true;
running:true;
onTriggered: {
if(collide(snake,candy)) {
candy.ate(); // signal;
++gameView.score;
candy.newCandy();
}
}
}
// to check two rectangles collided 碰撞
function collide(item1,item2) {
if( ((item1.y+item1.height) >= item2.y)
&& (item1.y <=( item2.y+item2.height)) ) {
if( ((item1.x+item1.width) >= item2.x)
&& (item1.x <=( item2.x+item2.width)) ) {
return true;
}
return false;
}
return false;
}
}
游戏主视窗里有个比较重要的碰撞检测函数(矩形碰撞检测,定时被调用),当snake和candy发生了碰撞,也就是snake吃了candy时就会让candy发送ate信号,同时计分加一,candy调用newCandy函数。
看看效果