您的位置:首页 > 移动开发 > Cocos引擎

quick cocos2d-x重写消灭星星

2015-08-09 12:14 447 查看
之前学习过c++在cocos2d-x游戏引擎上实现的消灭星星游戏,为了熟悉quickcocos2d-x以及Lua语言,我使用2.1.4版本的quickcocos2d-x重写了消灭星星,不过只是实现了其基本的消除,移动,计分以及过关等功能,一些文字漂移、粒子特效等功能有待以后完善。

该游戏的界面非常简单,只有两个场景的切换,首先是一个开始场景,该场景下有一个背景图片以及一个按钮,点击该按钮可以进入到游戏场景界面。开始场景的主要实现代码如下:

functionMainScene:ctor()
self.bg=display.newSprite("bg_menuscene.jpg",display.cx,display.cy)
self:addChild(self.bg)
localitem={}
item[1]=ui.newImageMenuItem({image="menu_start.png",imageSelected="menu_start.png",
listener=function()
game.enterGameScene()end,x=display.cx,y=display.cy})
localmenu=ui.newMenu(item)
self:addChild(menu)
end


其中菜单按钮用table来实现,在Lua语言中没有其他的数据结构,只有table,利用table可以实现各种数据结构,下面讲解星星的消除算法的时候会详细介绍,这里的按钮事件是game.enterGameScene(),这是在game文件中实现的一个函数,用于进入游戏场景,在game文件中game被申明为一个全局的table变量,可以在其他的文件中使用。

在游戏场景上面添加了一个层,该层用来实现星星矩阵的初始化显示,分数菜单的显示以及触摸事件。我们先看星星矩阵的初始化:

localSTAR_RES_LIST={"blue.png","green.png",
"orange.png","red.png","purple.png"}

functionMatrixStar:initMatrix()
--[[self.STAR[i][j]是一个表,其中i表示星星矩阵的行,j表示列,它包含四个元素
self.STAR[i][j][1]表示星星精灵
self.STAR[i][j][2]表示该精灵的颜色
self.STAR[i][j][3]表示该精灵是否被选中
self.STAR[i][j][4]表示该精灵的x轴坐标
self.STAR[i][j][5]表示该精灵的y轴坐标
]]
math.randomseed(os.time())
forrow=1,ROWdo
localy=(row-1)*STAR_HEIGHT+STAR_HEIGHT/2
self.STAR[row]={}
forcol=1,COLdo
self.STAR[row][col]={}
localx=(col-1)*STAR_WIDTH+STAR_WIDTH/2
locali=math.random(1,5)
localstar=display.newSprite(STAR_RES_LIST[i])
self.STAR[row][col][1]=star
self.STAR[row][col][2]=i
self.STAR[row][col][3]=false
star:setPosition(x,y)
self.STAR[row][col][4]=x
self.STAR[row][col][5]=y
self:addChild(star)
end
end
end


这里利用随机函数,在for循环中生成了不同颜色的星星精灵表STAR_RES_LIST记录了六种颜色的星星精灵,使用表self.STAR[i][j]
记录了每一个星星的颜色、位置、是否被选中,这些信息用于后面对星星的消除算法,在C++中我们可以使用一个结构体来定义这些变量,而
Lua中使用的是table.分数的菜单使用了3个Label对象来实现的,分别记录了最高分数,目标分数以及当前分数,并且通过设置TAG来方便
以后对该Label对象实现分数更新。


HSCORETAG=100
LEVELTAG=101
CSCORETAG=102

functionMatrixStar:setLabel(Hscore,Level,Goal,Cscore)
localHscoreUI=ui.newTTFLabel({
text=string.format("HighestScore:%s",tostring(Hscore)),
x,y=display.left,display.top,
})
HscoreUI:setScale(SCALE)
HscoreUI:setPosition(display.right,display.cy)
HscoreUI:setPosition(display.cx,display.top-SCALE*HscoreUI:getContentSize().height)
self:addChild(HscoreUI)
HscoreUI:setTag(HSCORETAG)

localLevelUI=ui.newTTFLabel({
text=string.format("Level:%s".."".."Goal:%s",tostring(Level),tostring(Goal)),
x,y=display.left,display.top,
})
LevelUI:setScale(SCALE)
LevelUI:setPosition(display.cx,display.top-SCALE*(HscoreUI:getContentSize().height+
LevelUI:getContentSize().height))
self:addChild(LevelUI)
LevelUI:setTag(LEVELTAG)

localCscoreUI=ui.newTTFLabel({
text=string.format("CurrentScore:%s",tostring(Cscore)),
x,y=display.left,display.top,
})
CscoreUI:setScale(SCALE)
CscoreUI:setPosition(display.cx,display.top-SCALE*(HscoreUI:getContentSize().height+
LevelUI:getContentSize().height+CscoreUI:getContentSize().height))
self:addChild(CscoreUI)
CscoreUI:setTag(CSCORETAG)
end


接下来是实现触摸事件,在触摸事件中要将点中的星星和他周围与他颜色相同的星星消除,这里先用一个table记录选中的相同颜色星星个数,每次点击都要先将其设置为空。并且使用一个table来帮助选出周围与触摸星星颜色相同的星星,当触摸到一个星星后,将该星星插入到该表中,然后遍历它四周的星星是否与该星星相同,相同则插入表中。然后将表中的第一个元素从表中移除,接着对表中的元素进行上述操作,值到表为空为止。这个过程实际上就是利用队列来实现一个广度优先算法。具体代码如下:

localtravel={}--当作一个队列使用,用于选出周围与触摸星星颜色相同的星星
ifself.STAR[i][j][1]==nilthen
return
end

table.insert(travel,{self.STAR[i][j][1],i,j})
while#travel~=0do
ifi+1<=ROWandself.STAR[i][j][3]~=trueand
self.STAR[i][j][2]==self.STAR[i+1][j][2]then
table.insert(travel,{self.STAR[i+1][j][1],i+1,j})
end

ifi-1>=1andself.STAR[i][j][3]~=trueand
self.STAR[i][j][2]==self.STAR[i-1][j][2]then
table.insert(travel,{self.STAR[i-1][j][1],i-1,j})
end

ifj+1<=COLandself.STAR[i][j][3]~=trueand
self.STAR[i][j][2]==self.STAR[i][j+1][2]then
table.insert(travel,{self.STAR[i][j+1][1],i,j+1})
end

ifj-1>=1andself.STAR[i][j][3]~=trueand
self.STAR[i][j][2]==self.STAR[i][j-1][2]then
table.insert(travel,{self.STAR[i][j-1][1],i,j-1})
end

ifself.STAR[i][j][3]~=truethen
self.STAR[i][j][3]=true
table.insert(self.SELECT_STAR,{self.STAR[i][j][1],i,j})
end

table.remove(travel,1)--table没有类似双向队列的功能直接删除第一个元素
if#travel~=0then
i,j=travel[1][2],travel[1][3]--取出表的第一个元素
end
end


在C++的deque容器可以在O(1)的时间复杂度中将队头元素移除,而这里的table.remove的时间复杂度为O(n),不知道是否有更好的

方法实现。当我们得到选中的星星后便可以更新分数,将选中的星星删除同时更新剩余星星的位置。位置的更新主要涉及垂直方向与水平方向。先看垂直方向,当我们删除部分星星时,这些星星上面的星星自然要掉下来,我们用掉下来的星星信息覆盖已删除星星的信息,并且将掉下来的星星信息设为nil。再看水平方向,当有一列的星星全部删除时,我们要求该列右边的星星能自动向左移动,实现过程与垂直方向类似,源代码如下:

functionMatrixStar:UpdateMatrix()
fori=1,ROWdo
forj=1,COLdo
ifself.STAR[i][j][1]==nilthen
localup=i
localdis=0
whileself.STAR[up][j][1]==nildo
dis=dis+1
up=up+1
if(up>ROW)then
break
end
end

forbegin_i=i+dis,ROWdo
ifself.STAR[begin_i][j][1]~=nilthen
self.STAR[begin_i-dis][j][1]=self.STAR[begin_i][j][1]
self.STAR[begin_i-dis][j][2]=self.STAR[begin_i][j][2]
self.STAR[begin_i-dis][j][3]=self.STAR[begin_i][j][3]
localx=(j-1)*STAR_WIDTH+STAR_WIDTH/2
localy=(begin_i-dis-1)*STAR_HEIGHT+STAR_HEIGHT/2
self.STAR[begin_i-dis][j][4]=x
self.STAR[begin_i-dis][j][5]=y
self.STAR[begin_i][j][1]=nil
self.STAR[begin_i][j][2]=nil
self.STAR[begin_i][j][3]=nil
self.STAR[begin_i][j][4]=nil
self.STAR[begin_i][j][5]=nil
end
end
end
end
end

forj=1,COLdo
ifself.STAR[1][j][1]==nilthen
localdes=0
localright=j
whileself.STAR[1][right][1]==nildo
des=des+1
right=right+1
ifright>COLthen
break
end
end
forbegin_i=ROW,1,-1do
forbegin_j=j+des,COLdo
ifself.STAR[begin_i][begin_j][1]~=nilthen
self.STAR[begin_i][begin_j-des][1]=self.STAR[begin_i][begin_j][1]
self.STAR[begin_i][begin_j-des][2]=self.STAR[begin_i][begin_j][2]
self.STAR[begin_i][begin_j-des][3]=self.STAR[begin_i][begin_j][3]
localx=(begin_j-des-1)*STAR_WIDTH+STAR_WIDTH/2
localy=(begin_i-1)*STAR_HEIGHT+STAR_HEIGHT/2
self.STAR[begin_i][begin_j-des][4]=x
self.STAR[begin_i][begin_j-des][5]=y
self.STAR[begin_i][begin_j][1]=nil
self.STAR[begin_i][begin_j][2]=nil
self.STAR[begin_i][begin_j][3]=nil
self.STAR[begin_i][begin_j][4]=nil
self.STAR[begin_i][begin_j][5]=nil
end
end
end
end
end
end


星星的位置信息通过上述代码得到更新,我们通过设置Update事件,在每帧中更新星星的位置,为了有一个移动的效果,我们不是直接使用setPostion到目的位置,而是使用一个速度参数使其移动到目的位置。

functionMatrixStar:updatePos(posX,posY,i,j)
ifposY~=self.STAR[i][j][5]then
self.STAR[i][j][1]:setPositionY(self.STAR[i][j][5]-MOVESPEED)
ifself.STAR[i][j][1]:getPositionY()<self.STAR[i][j][5]then
self.STAR[i][j][1]:setPositionY(self.STAR[i][j][5])
localx,y=self.STAR[i][j][1]:getPosition()
end
end

ifposX~=self.STAR[i][j][4]then
self.STAR[i][j][1]:setPositionX(self.STAR[i][j][4]-MOVESPEED)
ifself.STAR[i][j][1]:getPositionX()<self.STAR[i][j][4]then
self.STAR[i][j][1]:setPositionX(self.STAR[i][j][4])
end
end
end


整个游戏的基本代码就这些,代码写的比较乱,有待改进,但还是能跑起来,源代码地址:https://github.com/zhulong890816/xinxin


                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: