Quick-Cocos2d-x-3.2中示例Coinfilp解析(三)

一、进入游戏场景PlayLevelScene
接着上篇http://www.cocoachina.com/bbs/read.php?tid=234098的内容,回到MenuScene后,点击StartButton 进入 游戏关卡选择场景ChooseLevelScene


但是我没还打算讲解这个场景的内容,而且跳过它,先从游戏场景PlayLevelScene 开始讲解。原因有二:
1、 游戏关卡选择场景ChooseLevelScene使用的控件并不是单纯的Quick框架定义的控件,而且自己封装的(比起上篇的自定义按钮BubbleButton难度不是一个级别),我打算另外单独讲解;
2、另外一个原因就是提前进入 进行游戏的场景PlayLevelScene了解该游戏的核心不是更让人提起精神吗?所以我想先讲PlayLevelScene

那么我们就随便选择一个等级的关卡进入游戏场景吧,(我点击6,因为我学号是6班6号:14:)
 <img title = '新标签页(1).png' src='http://cdn.cocimg.com/bbs/attachment/Fid_56/56_371891_ad62619377bc019.png' >

我们以视觉分析该场景的组成元素:
 有好多的银币;
 每个硬币下面有一块半透明的方块;
 背景图
 一个后退键
 一信息条
 还有一个“Level:6”的等级文本
好,带着这些“视觉认知”,我们打开PlayLevelScene.lua,看看其中的ctor()函数是怎样定义界面的吧

local Levels = import("..data.Levels")
local Board = import("..views.Board")
local AdBar = import("..views.AdBar")

local PlayLevelScene = class("PlayLevelScene", function()
    return display.newScene("PlayLevelScene")
end)

function PlayLevelScene:ctor(levelIndex)
    -- 1、背景
    local bg = display.newSprite("#PlayLevelSceneBg.png")
    -- make background sprite always align top
    bg:setPosition(display.cx, display.top - bg:getContentSize().height / 2)
    self:addChild(bg)

    -- 2、标题
    local title = display.newSprite("#Title.png", display.left + 150, display.top - 50)
    title:setScale(0.5)
    self:addChild(title)

    -- 3、信息条
    local adBar = AdBar.new()
    self:addChild(adBar)

    -- 4、等级文本
    local label = cc.ui.UILabel.new({
        UILabelType = 1,
        text  = string.format("Level: %s", tostring(levelIndex)),
        font  = "UIFont.fnt",
        x     = display.left + 10,
        y     = display.bottom + 120,
        align = cc.ui.TEXT_ALIGN_LEFT,
    })
    self:addChild(label)

    -- 5、硬币板
    self.board = Board.new(Levels.get(levelIndex))
    self.board:addEventListener("LEVEL_COMPLETED", handler(self, self.onLevelCompleted))
    self:addChild(self.board)


    -- 6、后退按钮
    cc.ui.UIPushButton.new({normal = "#BackButton.png", pressed = "#BackButtonSelected.png"})
        :align(display.CENTER, display.right - 100, display.bottom + 120)
        :onButtonClicked(function()
            app:enterChooseLevelScene()
        end)
        :addTo(self)
End


```

    哈,看样子猜中很多啊,出差错的地方就是那个“硬币板”,所以我认为所以的硬币与半透明方块都在内嵌在这个“硬币板”中。先不管它了,我们从头分析起:1、背景;2、标题;3、信息条;这三个没什么好讲得,前面都已经理解基本能独立看懂与使用,重点我们先讲讲4、等级文本;学学文本控件的用法


了解UILabel的用法
    根据cc.ui.UILabel.new,我打开quick-cocos2d-x-3.2rc0\quick\framework\cc\ui 找到了UILabel.lua,打开它,我们就可以来查看源码了!我们找到创建UILabel.类的这段代码
----
quick UILabel控件
]]

local UILabel
UILabel = class("UILabel", function(options)
    if not options then
        return
    end

    if 1 == options.UILabelType then
        return UILabel.newBMFontLabel_(options)
    elseif not options.UILabelType or 2 == options.UILabelType then
        return UILabel.newTTFLabel_(options)
    else
        printInfo("UILabel unkonw UILabelType")
    end
end)


```

       因为UILabelType = 1 ,根据上面代码,我们知道了接下来执行的应该是UILabel.newBMFontLabel_(options),接着我们在UILabel.lua 找到了
----

用位图字体创建文本显示对象,并返回 LabelBMFont 对象。

BMFont 通常用于显示英文内容,因为英文字母加数字和常用符号也不多,生成的 BMFont 文件较小。如果是中文,应该用 TTFLabel。

可用参数:

-    text: 要显示的文本
-    font: 字体文件名
-    align: 文字的水平对齐方式(可选)
-    x, y: 坐标(可选)

~~~ lua

local label = UILabel:newBMFontLabel({
    text = "Hello",
    font = "UIFont.fnt",
})

~~~

@param table params 参数表格对象

@return LabelBMFont LabelBMFont对象

]]
function UILabel.newBMFontLabel_(params)
    return display.newBMFontLabel(params)
end


```

    噢耶:2:找到了这段代码加注释后就完全明白UILabel的用法了,根本就不需我解释了啊!所以,希望大家以后看到类似不懂的情况,也要懂得这样找框架源码,里面的注释极其强大,对我们菜鸟的学习很有帮助的。
      对于6、后退按钮;大家也可以用这种方法,学会UIPushButton的用法,我也就省省口水不用讲了(说多错多啊)。



二、游戏进行场景的重要组件:Level.lua、Coin.lua
    重新看会“硬币板”的那段代码,我知道知道接下要去打开src\app\views\Board.lua,在Board.lua这个脚本上出现了两个代码:
local Levels = import("..data.Levels")
local Coin   = import("..views.Coin")


```

明显的,我们先应该了解Levels.lua和Coin.lua后再来看Board.lua会更清晰易懂


1、Level.lua
      好,那我们从Level.lua入手:
local Levels = {}

Levels.NODE_IS_WHITE  = 1        -- 金色面                                 正                                        
Levels.NODE_IS_BLACK  = 0        -- 白色面 。。。写BLACK是干嘛,色盲?    反
Levels.NODE_IS_EMPTY  = "X"      -- 空,就是没有硬币

local levelsData = {}

levelsData = {
    rows = 4,               -- 行数
    cols = 4,                -- 列类
    grid = {                  -- 网格,也就是硬币状态的布局
        {1, 1, 1, 1},
        {1, 1, 0, 1},
        {1, 0, 0, 0},
        {1, 1, 0, 1}
    }
}
--中间省略了99个关卡布局数据

function Levels.numLevels()
    -- 长度操作符#用于返回一个数组或者线性表的最后的一个索引值
    return #levelsData
end

function Levels.get(levelIndex)
    --assert (v , message])
    --参数:
    --v:当表达式v为nil或false将触发错误,
    --message:发生错误时返回的信息,默认为"assertion failed!"
    -- 确保levelIndex >= 1 and levelIndex <= #levelsData,如果不是,将输出错误信息 :levelsData.get() - invalid levelIndex %s, 
    assert(levelIndex >= 1 and levelIndex <= #levelsData, string.format("levelsData.get() - invalid levelIndex %s", tostring(levelIndex)))
    return clone(levelsData)
end

return Levels


```

    Level.lua脚本相对简单,就是游戏关卡的硬币布局相关的数据,总共有100个levelsData,量真大!理解请看代码注释,应该不难懂。但想更大家统一下思路,反面后面思路混乱。
就是对硬币状态的规定:正面—金色面—1—Levels.NODE_IS_WHITE
                                        :反面—银色面—0—Levels.NODE_IS_BLACK
                                        :空—X—Levels.NODE_IS_EMPTY



2、Coin.lua
      打开Coin.lua,先看前面一份的代码:
local Levels = import("..data.Levels")

local Coin = class("Coin", function(nodeType)
    -- 先设定为1,正面
    local index = 1
    -- 判断 
    if nodeType == Levels.NODE_IS_BLACK then
        index = 8  -- 8是反面
    end
    
    -- 依靠index选择创建的coin是用哪张图片资源
    local sprite = display.newSprite(string.format("#Coin%04d.png", index))
    -- 为该精灵添加一个属性,是否为正面
    sprite.isWhite = index == 1
    return sprite
end) 


```

    思路是这样的:以传入参数决定决定 index的值,再已index的值创建精灵,最后继续依靠index的值决定sprite.isWhite 此属性。
    从此可看出index的值很重要,起决定性作为,但它为什么是1或8 呢?
    好,现在是解密时间!这回打开res\AllSprites.plist,找到这几个:
         
大家可以看到Coin0001到Coin0008是硬币由正面(金)到反面(银)的8张图片,所以上面代码才会以index = 1代表正面,index = 8代表反面。


    接着我们把Coin.lua剩下需要解析的代码看完: 
-- 创建并执行硬币翻转特效的函数
function Coin:flip(onComplete)

    -- 1、创建并执行翻转动画
    -- 创建8张精灵帧,1到8 是 正面到反面的翻转               
    -- 注意:第四个参数,当其为false,按正常引索创建,为true是,按递减引索的方式创建
    local frames = display.newFrames("Coin%04d.png", 1, 8, not self.isWhite)
    -- 以上面创建的8张精灵帧集 创建动画,第二个参数是每一桢动画之间的间隔时间
    local animation = display.newAnimation(frames, 0.3 / 8)
    self:playAnimationOnce(animation, false, onComplete)  -- 播放动画


    -- 2、翻转后的一系列的缩放动作
    self:runAction(transition.sequence({
        -- 两个参数:第一个参数是时间(s),第二个参数是缩放倍数
        cc.ScaleTo:create(0.15, 1.5),
        cc.ScaleTo:create(0.1, 1.0),
        cc.CallFunc:create(function()
            local actions = {}
            local scale = 1.1
            local time = 0.04
            for i = 1, 5 do
                -- 三个参数,第一个是时间,第二个是X方向的缩放倍数,第三个是Y方向的缩放倍数
                actions#actions + 1] = cc.ScaleTo:create(time, scale, 1.0)
                actions#actions + 1] = cc.ScaleTo:create(time, 1.0, scale)
                scale = scale * 0.95
                time = time * 0.8
            end
            actions#actions + 1] = cc.ScaleTo:create(0, 1.0, 1.0)
            self:runAction(transition.sequence(actions))
        end)
    }))


    -- 3、翻转结束后,修改“是否为正面”这个属性
    self.isWhite = not self.isWhite
end


```


1、创建并执行翻转动画:先分清一点,动画与动作是不一样的哦!这样的动画是所刚才看过的Coin0001到Coin0008所创建的帧动画。首先,先创建动画要播放的精灵帧集合local frames = display.newFrames("Coin%04d.png", 1, 8, not self.isWhite)
为了学习我们去找源码吧!里面肯定解析清楚用法了,还记得怎么找吗?
----
以特定模式创建一个包含多个图像帧对象的数组。

~~~ lua

-- 创建一个数组,包含 Walk0001.png 到 Walk0008.png 的 8 个图像帧对象
local frames = display.newFrames("Walk%04d.png", 1, 8)

-- 创建一个数组,包含 Walk0008.png 到 Walk0001.png 的 8 个图像帧对象
local frames = display.newFrames("Walk%04d.png", 1, 8, true)

~~~

@param string pattern 模式字符串
@param integer begin 起始索引
@param integer length 长度
@param boolean isReversed 是否是递减索引

@return table 图像帧数组

]]
function display.newFrames(pattern, begin, length, isReversed)


```

简单明了,只要注意一点,就是第四个参数,我们是以sprite.isWhite该属性为基础,很代码更为灵活与智能:是正面的话就正序创建精灵帧集合(正面到反面),是反面的话则相反。精灵帧集合创建完成后,再以其为基础创建动画,再播放动画就OK了!不懂的地方记得查框架源码!!


2、翻转后的一系列的缩放动作:一系列的动作组合。


3、翻转结束后,修改“是否为正面”这个属性:切记这一步很重要,该属性是判断硬币当前的状态的一个接口,对于该游戏的核心玩法和动画的创建都起的决定的作用。



    OK,本篇先讲到这里,在了解完Board.lua的组件,下篇我们在开好好谈论下Board.lua吧,谢谢。

继续支持楼主!:2:

谢谢,真爱啊 :7:

:7:好教程,多谢!

支持楼主帖子:7:

从(一)一口气看到(三),很有收获,谢谢楼主。

楼主写得太好了

谢谢:756:

谢谢 :756:

其实这个例子很旧了,不知道是1.0版本哪个贡献出来的,

其中很多方法,我用2.3版本的时候已经整合,或者弃用了

更不用说现在quick 3.0了

现在研究是你不懂,还是想误导别人,什么意思?

当时我也稍微看过这个,对理解lua 或者 quick cocos2dx比较有帮助,但是对于如何用quick引擎没什么作用的