cocos2d-lua消除遊戲實戰(二)水果生成演算法和消除演算法
阿新 • • 發佈:2019-01-06
效果是這樣的:
程式碼如下:
FruitItem = import("app.scenes.FruitItem") local PlayScene = class("PlayScene", function() return display.newScene("PlayScene") end) function PlayScene:ctor() -- init value self.highSorce = 0 -- 最高分數 self.stage = 1 -- 當前關卡 self.target = 123 -- 通關分數 self.curSorce = 0 -- 當前分數 self.xCount = 8 -- 水平方向水果數 self.yCount = 8 -- 垂直方向水果數 self.fruitGap = 0 -- 水果間距 self.scoreStart = 5 -- 水果基分 self.scoreStep = 10 -- 加成分數 self.activeScore = 0 -- 當前高亮的水果得分 self:initUI() -- 初始化隨機數 math.newrandomseed() -- 計算水果矩陣左下角的x、y座標:以矩陣中點對齊螢幕中點來計算,然後再做Y軸修正。 self.matrixLBX = (display.width - FruitItem.getWidth() * self.xCount - (self.yCount - 1) * self.fruitGap) / 2 self.matrixLBY = (display.height - FruitItem.getWidth() * self.yCount - (self.xCount - 1) * self.fruitGap) / 2 - 30 -- 等待轉場特效結束後再載入矩陣 self:addNodeEventListener(cc.NODE_EVENT, function(event) if event.name == "enterTransitionFinish" then self:initMartix() end end) end function PlayScene:initUI() -- 背景圖片 display.newSprite("playBG.png") :pos(display.cx, display.cy) :addTo(self) -- high sorce display.newSprite("#high_score.png") :align(display.LEFT_CENTER, display.left + 15, display.top - 30) :addTo(self) display.newSprite("#highscore_part.png") :align(display.LEFT_CENTER, display.cx + 10, display.top - 26) :addTo(self) self.highSorceLabel = display.newTTFLabel({text = tostring(self.highSorce), font = "font/earth38"}) :align(display.CENTER, display.cx + 105, display.top - 24) :addTo(self) -- 聲音 display.newSprite("#sound.png") :align(display.CENTER, display.right - 60, display.top - 30) :addTo(self) -- stage display.newSprite("#stage.png") :align(display.LEFT_CENTER, display.left + 15, display.top - 80) :addTo(self) display.newSprite("#stage_part.png") :align(display.LEFT_CENTER, display.left + 170, display.top - 80) :addTo(self) self.highStageLabel = display.newTTFLabel({text = tostring(self.stage), font = "font/earth32"}) :align(display.CENTER, display.left + 214, display.top - 78) :addTo(self) -- target display.newSprite("#tarcet.png") :align(display.LEFT_CENTER, display.cx - 50, display.top - 80) :addTo(self) display.newSprite("#tarcet_part.png") :align(display.LEFT_CENTER, display.cx + 130, display.top - 78) :addTo(self) self.highTargetLabel = display.newTTFLabel({text = tostring(self.target), font = "font/earth32"}) :align(display.CENTER, display.cx + 195, display.top - 76) :addTo(self) -- current sorce display.newSprite("#score_now.png") :align(display.CENTER, display.cx, display.top - 150) :addTo(self) self.curSorceLabel = display.newTTFLabel({Utext = tostring(self.curSorce), font = "font/earth48"}) :align(display.CENTER, display.cx, display.top - 150) :addTo(self) -- 選中水果分數 self.activeScoreLabel = display.newTTFLabel({text = "", size = 30}) :pos(display.width / 2, 120) :addTo(self) self.activeScoreLabel:setColor(display.COLOR_WHITE) end function PlayScene:initMartix() -- 建立空矩陣 self.matrix = {} -- 高亮水果 self.actives = {} for y = 1, self.yCount do for x = 1, self.xCount do if 1 == y and 2 == x then -- 確保有可消除的水果 self:createAndDropFruit(x, y, self.matrix[1].fruitIndex) else self:createAndDropFruit(x, y) end end end end function PlayScene:createAndDropFruit(x, y, fruitIndex) local newFruit = FruitItem.new(x, y, fruitIndex) local endPosition = self:positionOfFruit(x, y) local startPosition = cc.p(endPosition.x, endPosition.y + display.height / 2) newFruit:setPosition(startPosition) local speed = startPosition.y / (2 * display.height) newFruit:runAction(cc.MoveTo:create(speed, endPosition)) self.matrix[(y - 1) * self.xCount + x] = newFruit self:addChild(newFruit) -- 繫結觸控事件,此處3.7框架與3.6不太一樣了 需要先繫結,後啟用節點 newFruit:addNodeEventListener(cc.NODE_TOUCH_EVENT, function(event) print( event.name) if event.name == "ended" then if newFruit.isActive then print("remove") self:removeActivedFruits() self:dropFruits() else self:inactive() self:activeNeighbor(newFruit) self:showActivesScore() end end if event.name == "began" then if newFruit.isActive then print("remove") self:removeActivedFruits() self:dropFruits() else self:inactive() self:activeNeighbor(newFruit) self:showActivesScore() end return true end end) newFruit:setTouchEnabled(true) end function PlayScene:removeActivedFruits() local fruitScore = self.scoreStart for _, fruit in pairs(self.actives) do if (fruit) then -- 從矩陣中移除 self.matrix[(fruit.y - 1) * self.xCount + fruit.x] = nil -- 分數特效 self:scorePopupEffect(fruitScore, fruit:getPosition()) fruitScore = fruitScore + self.scoreStep fruit:removeFromParent() end end -- 清空高亮陣列 self.actives = {} -- 更新當前得分 self.curSorce = self.curSorce + self.activeScore self.curSorceLabel:setString(tostring(self.curSorce)) -- 清空高亮水果分數統計 self.activeScoreLabel:setString("") self.activeScore = 0 end function PlayScene:scorePopupEffect(score, px, py) print(scorePopupEffect) local labelScore = display.newTTFLabel({ text = tostring(score), font = "font/earth32"}) local move = cc.MoveBy:create(0.8, cc.p(0, 80)) local fadeOut = cc.FadeOut:create(0.8) local action = cc.Sequence:create( cc.Spawn:create(move,fadeOut), -- 動畫結束移除 Label cc.CallFunc:create(function() labelScore:removeFromParent() end) ) labelScore:pos(px, py) :addTo(self) :runAction(action) end function PlayScene:dropFruits() local emptyInfo = {} -- 1. 掉落已存在的水果 -- 一列一列的處理 for x = 1, self.xCount do local removedFruits = 0 local newY = 0 -- 從下往上處理 for y = 1, self.yCount do local temp = self.matrix[(y - 1) * self.xCount + x] if temp == nil then -- 水果已被移除 removedFruits = removedFruits + 1 else -- 如果水果下有空缺,向下移動空缺個位置 if removedFruits > 0 then newY = y - removedFruits self.matrix[(newY - 1) * self.xCount + x] = temp temp.y = newY self.matrix[(y - 1) * self.xCount + x] = nil local endPosition = self:positionOfFruit(x, newY) local speed = (temp:getPositionY() - endPosition.y) / display.height temp:stopAllActions() --停止之前的動畫 temp:runAction(cc.MoveTo:create(speed, endPosition)) end end end -- 紀錄本列最終空缺數 emptyInfo[x] = removedFruits end -- 2. 掉落新水果補齊空缺 for x = 1, self.xCount do for y = self.yCount - emptyInfo[x] + 1, self.yCount do self:createAndDropFruit(x, y) end end end function PlayScene:positionOfFruit(x, y) local px = self.matrixLBX + (FruitItem.getWidth() + self.fruitGap) * (x - 1) + FruitItem.getWidth() / 2 local py = self.matrixLBY + (FruitItem.getWidth() + self.fruitGap) * (y - 1) + FruitItem.getWidth() / 2 return cc.p(px, py) end function PlayScene:activeNeighbor(fruit) -- 高亮fruit if false == fruit.isActive then fruit:setActive(true) table.insert(self.actives, fruit) end -- 檢查fruit左邊的水果 if (fruit.x - 1) >= 1 then local leftNeighbor = self.matrix[(fruit.y - 1) * self.xCount + fruit.x - 1] if (leftNeighbor.isActive == false) and (leftNeighbor.fruitIndex == fruit.fruitIndex) then leftNeighbor:setActive(true) table.insert(self.actives, leftNeighbor) self:activeNeighbor(leftNeighbor) end end -- 檢查fruit右邊的水果 if (fruit.x + 1) <= self.xCount then local rightNeighbor = self.matrix[(fruit.y - 1) * self.xCount + fruit.x + 1] if (rightNeighbor.isActive == false) and (rightNeighbor.fruitIndex == fruit.fruitIndex) then rightNeighbor:setActive(true) table.insert(self.actives, rightNeighbor) self:activeNeighbor(rightNeighbor) end end -- 檢查fruit上邊的水果 if (fruit.y + 1) <= self.yCount then local upNeighbor = self.matrix[fruit.y * self.xCount + fruit.x] if (upNeighbor.isActive == false) and (upNeighbor.fruitIndex == fruit.fruitIndex) then upNeighbor:setActive(true) table.insert(self.actives, upNeighbor) self:activeNeighbor(upNeighbor) end end -- 檢查fruit下邊的水果 if (fruit.y - 1) >= 1 then local downNeighbor = self.matrix[(fruit.y - 2) * self.xCount + fruit.x] if (downNeighbor.isActive == false) and (downNeighbor.fruitIndex == fruit.fruitIndex) then downNeighbor:setActive(true) table.insert(self.actives, downNeighbor) self:activeNeighbor(downNeighbor) end end end function PlayScene:inactive() for _, fruit in pairs(self.actives) do if (fruit) then fruit:setActive(false) end end self.actives = {} end function PlayScene:showActivesScore() -- 只有一個高亮,取消高亮並返回 if 1 == #self.actives then self:inactive() self.activeScoreLabel:setString("") self.activeScore = 0 return end -- 水果分數依次為5、15、25、35... ,求它們的和 self.activeScore = (self.scoreStart * 2 + self.scoreStep * (#self.actives - 1)) * #self.actives / 2 self.activeScoreLabel:setString(string.format("%d 連消,得分 %d", #self.actives, self.activeScore)) end function PlayScene:onEnter() end function PlayScene:onExit() end return PlayScene