首页 > 其他 > 详细

bbframework入门之路【五】触控绑定

时间:2015-02-27 22:54:15      阅读:387      评论:0      收藏:0      [点我收藏+]

【正文】

        前面我们介绍了如何在bbframework项目中创建我们自己的模块,也在场景里面添加了精灵节点,但是讲到编程就少不了要说到事件。因为我们是做手机游戏,而现在的手机又普遍都是大屏的智能触控手机,所以我们游戏涉及最多的当属触控操作了。今天我们便来简单介绍下bbframework的触控,帮助我们实现游戏的交互操作。

 

        接着上一次的内容,我们在Layer层上面放置了两个节点,代码如下:

 

----------------------
-- 结点渲染
----------------------
--[[--
视图渲染,处理视图结点加载、事件绑定等相关操作
]]
function M:onRender()
    M.super.onRender(self)

    local nodeObj1      = D.img("node.png"):p(480, 320):to(self)
    local nodeObj2      = D.img("node.png"):p(350, 300):scale(0.5):to(self)
end 

 

        我们打开模拟器,看到的效果如下:

 

技术分享

 

        两个图标nodeObj1和nodeObj2重叠在一起,其中较大的那个是nodeObj1。那我们现在想要说点击大的图片,大的图消失,点击小的图片,大的又出现,这个我们该如何实现呢?bbframework为我们提供了“:bindTouch()”函数来实现节点的触控绑定。然后重写节点的“:onTouchBegan(x, y, touches)”、onTouchMoved(x, y, touches)”和onTouchEnded(x, y, touches)”这三个函数来处理触控事件。onTouchBegan、onTouchMoved和onTouchEnded分别会在节点被点击下去、移动和松开时触发。但是,想要触发onTouchMoved和onTouchEnded还要在对应的onTouchBegan里面返回“true”才行,不返回或者返回“false”触控的onTouchMoved和onTouchEnded都不会被触发。这三个函数的前两个参数x和y表示的就是当前触控位置(触控点)的横纵坐标。最后一个参数touches是一个表,保存的是当前的触控信息,目前表中前两个成员保存的分别是触控的x和y,第三个成员是当前的触控点索引,因为电脑上用鼠标都是单点,所以那个值会等于“1”。

 

----------------------
-- 结点渲染
----------------------
--[[--
视图渲染,处理视图结点加载、事件绑定等相关操作
]]
function M:onRender()
    M.super.onRender(self)

    local nodeObj1      = D.img("node.png"):p(480, 320):to(self)
    local nodeObj2      = D.img("node.png"):p(350, 300):scale(0.5):to(self)

    nodeObj1:bindTouch()
    function nodeObj1:onTouchBegan(x, y, touches)
        print("ondeObj1 onTouchBegan!!!")
        return true 
    end
    function nodeObj1:onTouchMoved(x, y, touches)
        print("ondeObj1 onTouchMoved!!!")
    end
    function nodeObj1:onTouchEnded(x, y, touches)
        print("ondeObj1 onTouchEnded!!!")
    end
end 

 

        如上,我们给大的精灵绑定了触控,然后刷新模拟器,点击大个的精灵,发现控制台打印了相应函数里面的print()输出的内容,这就说明我们绑定触控成功了。同样的我们也给nodeObj2也绑定了触控。

 

----------------------
-- 结点渲染
----------------------
--[[--
视图渲染,处理视图结点加载、事件绑定等相关操作
]]
function M:onRender()
    M.super.onRender(self)

    local nodeObj1      = D.img("node.png"):p(480, 320):to(self)
    local nodeObj2      = D.img("node.png"):p(350, 300):scale(0.5):to(self)

    nodeObj1:bindTouch()
    function nodeObj1:onTouchBegan(x, y, touches)
        print("ondeObj1 onTouchBegan!!!")
        return true 
    end
    function nodeObj1:onTouchMoved(x, y, touches)
        print("ondeObj1 onTouchMoved!!!")
    end
    function nodeObj1:onTouchEnded(x, y, touches)
        print("ondeObj1 onTouchEnded!!!")
    end

    nodeObj2:bindTouch()
    function nodeObj2:onTouchBegan(x, y, touches)
        print("------------------nodeObj2 onTouchBegan!!!")
        return true 
    end
    function nodeObj2:onTouchMoved(x, y, touches)
        print("------------------nodeObj2 onTouchMoved!!!")
    end
    function nodeObj2:onTouchEnded(x, y, touches)
        print("------------------nodeObj2 onTouchEnded!!!")
    end
end 

 

        刷新模拟器分别点击nodeObj1和nodeObj2,可以看到如下控制台打印:

 

技术分享

 

        但是我们发现当我们点击在nodeObj1和nodeObj2的重叠部分时,模拟器也只会输出nodeObj2的触控打印,这说明我们只触发了nodeObj2的触控事件,而nodeObj1的触控事件被nodeObj2吞噬了,触控根本没有分发到nodeObj1上面。那么我们要如何实现两个精灵的触控事件都被触发呢?bbframework框架提供了一些定义好的标签给我们使用,我们只要在onTouchBegan函数里面返回“SIGN_TOUCH_BEGAN_NO_SWALLOWS”就可以实现触控穿透下去,而返回“SIGN_TOUCH_BEGAN_SWALLOWS”触控便被当前对象吞噬了,其他精灵便无法获得触控响应。于是我们修改nodeObj2的onTouchBegan代码如下:

 

    function nodeObj2:onTouchBegan(x, y, touches)
        print("------------------nodeObj2 onTouchBegan!!!")
        return SIGN_TOUCH_BEGAN_NO_SWALLOWS 
    end

 

        然后重新刷新模拟器,你就发现触控穿透了。

 

  技术分享

 

        修改nodeObj2的onTouchBegan代码如下,触控便又开始吞噬了。

 

    function nodeObj2:onTouchBegan(x, y, touches)
        print("------------------nodeObj2 onTouchBegan!!!")
        return SIGN_TOUCH_BEGAN_SWALLOWS 
    end

 

        节点的onTouchMoved函数只有在函数onTouchBegan里面return true或者SIGN_TOUCH_BEGAN_NO_SWALLOWS还有SIGN_TOUCH_BEGAN_SWALLOWS时并且发生移动才会触发。这时候我们会发现只要我们在onTouchBegan里面返回的不是“false”,那么不管onTouchMoved有没有被调用,onTouchEnded一定会被调用。这是因为当我们松开节点时,触控松开的事件肯定被触发了。但是我们有时会出现某个精灵在移动过程中被销毁,比如移动香蕉皮精灵到垃圾桶上就自动移除香蕉皮,这个时候触控还是被香蕉皮这个精灵所持有,当我们松开触控手指的时候,程序也会调用onTouchEnded函数,但是发现对象不存在了,要调用的onTouchEnded函数是一个空值。它调用不到了,控制台也输出了错误日志。那么这个时候我们更希望在移动香蕉皮到垃圾桶位置,然后删除完香蕉皮之后触控就此结束,不要再给我进onTouchEnded了,其实你也进不去了,因为没有哈。这个时候我们就用到了另外一个触控标签“SIGN_TOUCH_MOVED_STOP”,我们在onTouchMoved函数里面返回这个标签值,触控就不会进入onTouchEnded了。

 

    function nodeObj2:onTouchMoved(x, y, touches)
        print("------------------nodeObj2 onTouchMoved!!!")

        self:p(x, y)
        if x > 700 then 
            self:remove()
            return SIGN_TOUCH_MOVED_STOP 
        end
    end

 

        假设屏幕上横坐标大于700的位置都是垃圾桶的范围,我们的nodeObj2就是香蕉皮,于是我们修改nodeObj2的onTouchMoved函数如上,刷新模拟器后我们往右边拖动nodeObj2到横坐标大于700的位置,我们会发现nodeObj2消失了,然后控制台的打印也在onTouchMoved里面就结束了,就算我们松开触控也不会进入onTouchEnded。

 

技术分享

 

        看上面的代码,我们会发现我们是调用了节点的“:remove()”函数来移除一个节点对象的,就像上面博文开头说的,我们有时候只是想隐藏某个精灵,然后后面又要显示它该怎么办,bbframework让我们一样可以通过“show()”和“hide()”两个函数来实现显示和隐藏功能。

 

    function nodeObj1:onTouchBegan(x, y, touches)
        self:hide()
        return true 
    end
    function nodeObj1:onTouchMoved(x, y, touches)

    end
    function nodeObj1:onTouchEnded(x, y, touches)

    end

    nodeObj2:bindTouch()
    function nodeObj2:onTouchBegan(x, y, touches)
        nodeObj1:show()
        return SIGN_TOUCH_BEGAN_SWALLOWS 
    end
    function nodeObj2:onTouchMoved(x, y, touches)

    end
    function nodeObj2:onTouchEnded(x, y, touches)
        
    end

 

        如上,我们在nodeObj1的onTouchBegan里面隐藏掉自身(也就是nodeObj1),然后在nodeObj2的onTouchBegan里面显示nodeObj1,这样我们就实现看博文开头所举的那个例子。

 

        技术分享

 

        知道怎么绑定触控之后,我们来看下触控是如何分发的。首先,如上图所示,假设我们场景里面加载了一个MainLayer层,层上面又放置了一个叫“node”的节点和一个ButtonLayer层的实例对象。在node里面又有两个子节点分别是:node1和node2,node1又有一个叫做node11的子节点。然后ButtonLayer上面也放置了nodeA和nodeB两个节点。这样构成了如上所示的一棵树。

 

        当我们点击到node11的时候,bbframework会从根节点,也就是MainLayer的实例对象开始遍历这颗节点树。当MainLayer有绑定触控的时候,bbframework就会遍历其下的所有子节点。当它发现节点node有绑定触控的时候就会遍历node的子节点node1,以此类推。但是如果节点node没有绑定触控,那么就算node的所有子节点以及所有的子孙节点都绑定了触控,那也没有办法触发触控事件。因为触控根本没有分发到被点击的节点上。因为Layer的触控是单独处理的,没个Layer也只管理其下的节点的触控,所有当触控遍历到ButtonLayer实例对象时,触控就将ButtonLayer以及ButtonLayer下的所有后代节点的触控都交给ButtonLayer来管理了。当MainLayer所有的后代节点都有绑定触控的时候,由于我们点击的是node11这个节点,所有触控就会从node11开始触发。触控事件触发的节点顺序依次是:node11->mainLayer。如果node2和node11位置重叠,而且node1也和node11位置重叠,并且node11允许触控穿透的话,那么触控就会传递到node1和node2上面,其触控分发的顺序就是:node11->node1->node2->node->mainLayer。这样我们就发现不管被触控的节点是不是允许触控穿透传递,该节点所在的那个层的触控都会被触发,这是因为Layer的触控事件是独立分发的,和节点不同。

 

        同样值得注意的是,我们前面所说的“SIGN_TOUCH_BEGAN_SWALLOWS”和“SIGN_TOUCH_BEGAN_NO_SWALLOWS”还有“SIGN_TOUCH_MOVED_STOP”这三个标签也只对节点有用,对于Layer,我们一般只在层的onTouchBegan里面返回“true”或者“false”。那么层要如何实现穿透和不穿透呢?我们一般在Layer的构造函数的超类调用前面添加“params.swallowsTouches = false”来实现,这样,同一个场景里面的多个层就会实现触控穿透,否则现在的bbframework框架默认触控只会传递到层级最高的那个绑定了触控的层上面,层级比较低的层就算绑定了触控也无法接收到触控。

 

----------------------
-- 构造方法
----------------------
--[[--

构造方法,定义视图实例初始化逻辑

### Parameters:
-   table **params**    参数集合

### Return: 
-   object              对象实例

]]
function M:ctor(params)
    params.swallowsTouches     = false 
    -- [超类调用]
    M.super.ctor(self, params) 

end

 

        注意,我们现在的层都是通过“local M = classLayerTouch("层名称")”这个函数来创建的,如果是通过“classLayer("层名称")”或者UUI.lua文件里面的“loadLayer(params)”来创建的话我们需要通过调用层的“:bindTouch()”函数来手动给层绑定触控事件,否则层上面的节点精灵也将无法点击。

 

        我们创建自定义精灵节点一般会在模块的“node”文件夹下新建文件,大体上和Layer是一样的,只是创建的时候调用的不是classLayer()和classLayerTouch()而是调用“classSprite()”和“classSpriteTouch()”这两个函数。这两个函数一样也是接收一个字符串类型的参数作为精灵的类名,但是在创建层的时候,如“MainLayer.lua”时,我们的类名写的是“Main”,然后bbframework框架会自动添加“Layer”后缀,但是精灵与之不同,假设我们要创建一个名为“Dog”的类,我们一般将文件保存为“Dog.lua”,然后代码里面调用时也写全类名“local M = classSpriteTouch("Dog")”。

 

        和创建Layer类似的创建了我们的精灵类,然后我们想要在Layer里面创建这个类,那么我们只要调用require()函数将类引入,比如我的Dog.lua文件在“scripts/app/test/node”文件夹里面,那我只要在Layer里面写如下代码即可创建一个精灵:

 

----------------------
-- 结点渲染
----------------------
--[[--
视图渲染,处理视图结点加载、事件绑定等相关操作
]]
function M:onRender()
    M.super.onRender(self)

    local Dog     = require("app.test.node.Dog")
    local dog     = Dog.new({ imagePath = "node.png" }):pc():to(self)
end 

 

        我们先通过require()函数引入文件,类似于C#的using或者C++的include。然后通过得到的类对象来调用“.new()”函数,注意,这里的new()函数是通过“.”来调用的。它接受一个表来充当参数,最后这个参数会被传递到Dog类的构造函数那边的参数上。

 

--[[!--

相关操作方法及逻辑实现。


]]

----------------------
------------------------
local M = classSpriteTouch("Dog")


----------------------
-- 公共参数
----------------------
-- [常量]
-- ..

-- [操作变量]
-- ..








----------------------
-- 构造方法
----------------------
--[[--

构造方法,定义视图实例初始化逻辑

### Parameters:
-   table **params**    参数集合

### Return: 
-   object              对象实例

]]
function M:ctor(params)
    -- [超类调用]
    M.super.ctor(self, params) 

    -- 获取传递进来的贴图文件路径
    self.imageFile     = params.imagePath 
end








----------------------
-- 结点渲染
----------------------
--[[--
视图渲染,处理视图结点加载、事件绑定等相关操作
]]
function M:onRender()
    M.super.onRender(self)

    -- 显示贴图
    self:display(self.imageFile)
end 




----------------------
-- 结点析构
----------------------
--[[--

视图析构,处理视图结点卸载、事件解除绑定等相关操作

]]
function M:onDestructor()
    -- [超类调用]
    M.super.onDestructor(self)
end






----------------------
-- 触控
----------------------
function M:onTouchBegan(x, y, touches)
    return SIGN_TOUCH_BEGAN_SWALLOWS  
end

function M:onTouchMoved(x, y, touches)
    -- body
end

function M:onTouchEnded(x, y, touches)
    -- body 
end





return M

 

        如上所示,就是我们的Dog.lua文件的内容。我在构造函数里面通过“self.imageFile = params.imagePath”这句代码获得前面new()函数传递的“imagePath”这个参数的值。然后在渲染器(onRender)函数里面通过节点的“:display()”函数来显示贴图。display()函数接受一个字符串类型的参数,这个参数是要显示的图片资源文件的路径。同样的,由于我们的Dog类是精灵节点,所以它的触控支持我们的触控标签,所以我在Dog的onTouchBegan函数里面返回的是“SIGN_TOUCH_BEGAN_SWALLOWS”,用来吞噬触控。

 

        晚上也写了2个多小时了,今天就先到此为止了,如果对于触控还不是很了解的同志可以去SVN的Babybus-lua里面去找下框架1.3版本的触控视频教程来看,那是AC录制的,讲的应该会更准确些。

 

        然后下一次我们来说下bbframework的动作和动画该怎么实现,到时候我就简单的写两个例子,说明下动作的“:at()”和节点的“:runAction()”这两个函数,然后再说下怎么停止指定动作和停止所有动作,最后列举说明下“UAction.lua”里面常用的动作,动作就算过了哈。

 

【脚注】

        宝宝巴士-快乐童年!

bbframework入门之路【五】触控绑定

原文:http://www.cnblogs.com/babybus-ios/p/bbframework-005.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!