quick cocos2d-x重写消灭星星

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

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

 1 function MainScene:ctor()
 2     self.bg = display.newSprite("bg_menuscene.jpg", display.cx,display.cy)
 3     self:addChild(self.bg)
 4     local item ={}
 5     item[1]= ui.newImageMenuItem({image = "menu_start.png", imageSelected = "menu_start.png",
 6         listener = function()  
 7         game.enterGameScene() end , x = display.cx, y = display.cy})
 8     local menu = ui.newMenu(item)
 9     self:addChild(menu)
10 end

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

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

 1 local STAR_RES_LIST = {"blue.png","green.png",
 2 "orange.png","red.png","purple.png"}
 3 
 4 function MatrixStar:initMatrix()  
 5     --[[self.STAR[i][j]是一个表,其中i表示星星矩阵的行,j表示列,它包含四个元素
 6         self.STAR[i][j][1]表示星星精灵
 7         self.STAR[i][j][2]表示该精灵的颜色 
 8         self.STAR[i][j][3]表示该精灵是否被选中
 9         self.STAR[i][j][4]表示该精灵的x轴坐标
10         self.STAR[i][j][5]表示该精灵的y轴坐标           
11         ]]
12     math.randomseed(os.time())    
13     for row = 1, ROW do
14         local y = (row-1) * STAR_HEIGHT + STAR_HEIGHT/2
15         self.STAR[row] = {}
16         for col = 1, COL do
17             self.STAR[row][col] = {}
18             local x = (col-1) * STAR_WIDTH + STAR_WIDTH/2
19             local i=math.random(1,5)
20             local star = display.newSprite(STAR_RES_LIST[i])
21             self.STAR[row][col][1] = star
22             self.STAR[row][col][2] = i
23             self.STAR[row][col][3] = false
24             star:setPosition(x,y)
25             self.STAR[row][col][4] = x
26             self.STAR[row][col][5] = y
27             self:addChild(star)
28         end
29     end
30 end
这里利用随机函数,在for循环中生成了不同颜色的星星精灵表 STAR_RES_LIST记录了六种颜色的星星精灵,使用表self.STAR[i][j]
记录了每一个星星的颜色、位置、是否被选中,这些信息用于后面对星星的消除算法,在C++中我们可以使用一个结构体来定义这些变量,而
Lua中使用的是table. 分数的菜单使用了3个Label对象来实现的,分别记录了最高分数,目标分数以及当前分数,并且通过设置TAG来方便
以后对该Label对象实现分数更新。
 1 HSCORETAG = 100
 2 LEVELTAG = 101
 3 CSCORETAG = 102
 4 
 5 function MatrixStar:setLabel(Hscore,Level,Goal,Cscore)
 6     local HscoreUI = ui.newTTFLabel({
 7         text = string.format("HighestScore: %s", tostring(Hscore)),
 8         x, y = display.left, display.top, 
 9     })
10     HscoreUI:setScale(SCALE)
11     HscoreUI:setPosition(display.right, display.cy)
12     HscoreUI:setPosition(display.cx, display.top - SCALE * HscoreUI:getContentSize().height)
13     self:addChild(HscoreUI)
14     HscoreUI:setTag(HSCORETAG)
15 
16     local LevelUI = ui.newTTFLabel({
17         text = string.format("Level: %s".." ".."Goal: %s", tostring(Level),tostring(Goal)),
18         x, y = display.left, display.top, 
19     })
20     LevelUI:setScale(SCALE)
21     LevelUI:setPosition(display.cx, display.top - SCALE * (HscoreUI:getContentSize().height + 
22             LevelUI:getContentSize().height))
23     self:addChild(LevelUI)
24     LevelUI:setTag(LEVELTAG)
25 
26     local CscoreUI = ui.newTTFLabel({
27         text = string.format("CurrentScore: %s", tostring(Cscore)),
28         x, y = display.left, display.top, 
29     })
30     CscoreUI:setScale(SCALE)
31     CscoreUI:setPosition(display.cx, display.top - SCALE * (HscoreUI:getContentSize().height + 
32             LevelUI:getContentSize().height + CscoreUI:getContentSize().height))
33     self:addChild(CscoreUI)
34     CscoreUI:setTag(CSCORETAG)
35 end

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

 1     local travel = {}  --当作一个队列使用,用于选出周围与触摸星星颜色相同的星星
 2     if self.STAR[i][j][1] == nil then
 3         return
 4     end 
 5 
 6     table.insert(travel, {self.STAR[i][j][1], i, j})
 7     while #travel ~= 0 do
 8         if i + 1 <= ROW and self.STAR[i][j][3] ~= true and 
 9             self.STAR[i][j][2] == self.STAR[i + 1][j][2] then
10             table.insert(travel, {self.STAR[i+1][j][1],i+1,j})
11         end
12 
13         if i-1 >= 1 and self.STAR[i][j][3] ~= true and
14             self.STAR[i][j][2] ==self.STAR[i-1][j][2] then
15             table.insert(travel, {self.STAR[i-1][j][1],i-1,j})
16         end
17 
18         if j+1 <= COL and self.STAR[i][j][3] ~= true and
19             self.STAR[i][j][2] ==self.STAR[i][j+1][2] then
20             table.insert(travel, {self.STAR[i][j+1][1],i,j+1}) 
21         end
22 
23         if j-1 >= 1 and self.STAR[i][j][3] ~= true and
24             self.STAR[i][j][2] ==self.STAR[i][j-1][2] then
25             table.insert(travel, {self.STAR[i][j-1][1],i,j-1})
26         end
27         
28         if self.STAR[i][j][3] ~= true then
29            self.STAR[i][j][3] = true
30            table.insert(self.SELECT_STAR,{self.STAR[i][j][1],i,j})
31         end
32 
33         table.remove(travel,1)  --table没有类似双向队列的功能直接删除第一个元素
34         if #travel ~= 0 then 
35             i, j = travel[1][2], travel[1][3] --取出表的第一个元素
36         end  
37     end

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

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

 1 function MatrixStar:UpdateMatrix()
 2     for i = 1, ROW do
 3         for j = 1,COL do
 4             if self.STAR[i][j][1] == nil then 
 5                 local up = i
 6                 local dis = 0
 7                 while self.STAR[up][j][1] == nil do
 8                     dis = dis + 1
 9                     up = up + 1
10                     if(up>ROW) then
11                         break
12                     end
13                 end
14 
15                 for begin_i = i + dis, ROW do
16                     if self.STAR[begin_i][j][1]~=nil then 
17                         self.STAR[begin_i-dis][j][1]=self.STAR[begin_i][j][1]
18                         self.STAR[begin_i-dis][j][2]=self.STAR[begin_i][j][2]
19                         self.STAR[begin_i-dis][j][3]=self.STAR[begin_i][j][3]
20                         local x = (j-1)*STAR_WIDTH + STAR_WIDTH/2  
21                         local y = (begin_i-dis-1)*STAR_HEIGHT + STAR_HEIGHT/2 
22                         self.STAR[begin_i-dis][j][4] = x
23                         self.STAR[begin_i-dis][j][5] = y
24                         self.STAR[begin_i][j][1] = nil
25                         self.STAR[begin_i][j][2] = nil
26                         self.STAR[begin_i][j][3] = nil
27                         self.STAR[begin_i][j][4] = nil
28                         self.STAR[begin_i][j][5] = nil
29                     end
30                 end
31             end
32         end
33     end
34 
35     for j = 1, COL do
36         if self.STAR[1][j][1] == nil then
37             local des = 0 
38             local right = j
39             while self.STAR[1][right][1] == nil do
40                 des = des + 1
41                 right = right + 1
42                 if right>COL then
43                     break
44                 end
45             end
46             for begin_i = ROW, 1,-1 do
47                 for begin_j = j + des, COL do 
48                     if self.STAR[begin_i][begin_j][1] ~= nil then
49                         self.STAR[begin_i][begin_j-des][1]=self.STAR[begin_i][begin_j][1]
50                         self.STAR[begin_i][begin_j-des][2]=self.STAR[begin_i][begin_j][2]
51                         self.STAR[begin_i][begin_j-des][3]=self.STAR[begin_i][begin_j][3]
52                         local x = (begin_j-des-1)*STAR_WIDTH + STAR_WIDTH/2  
53                         local y = (begin_i-1)*STAR_HEIGHT + STAR_HEIGHT/2 
54                         self.STAR[begin_i][begin_j-des][4] = x
55                         self.STAR[begin_i][begin_j-des][5] = y
56                         self.STAR[begin_i][begin_j][1] = nil
57                         self.STAR[begin_i][begin_j][2] = nil
58                         self.STAR[begin_i][begin_j][3] = nil
59                         self.STAR[begin_i][begin_j][4] = nil
60                         self.STAR[begin_i][begin_j][5] = nil
61                     end
62                 end
63             end
64         end
65     end
66 end

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

 1 function MatrixStar:updatePos(posX,posY,i,j)
 2     if posY ~= self.STAR[i][j][5] then
 3         self.STAR[i][j][1]:setPositionY(self.STAR[i][j][5] - MOVESPEED)
 4         if self.STAR[i][j][1]:getPositionY() < self.STAR[i][j][5]  then
 5              self.STAR[i][j][1]:setPositionY(self.STAR[i][j][5])
 6              local x, y = self.STAR[i][j][1]:getPosition()
 7         end
 8     end
 9 
10     if posX ~= self.STAR[i][j][4] then
11         self.STAR[i][j][1]:setPositionX(self.STAR[i][j][4] - MOVESPEED)
12         if self.STAR[i][j][1]:getPositionX() < self.STAR[i][j][4]  then
13              self.STAR[i][j][1]:setPositionX(self.STAR[i][j][4])
14         end
15     end
16 end

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

 
原文地址:https://www.cnblogs.com/zhulong890816/p/4688966.html