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

【正文】

前面我们介绍了如何在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”里面常用的动作,动作就算过了哈。

【脚注】

宝宝巴士-快乐童年!

时间: 2024-10-10 05:55:51

bbframework入门之路【五】触控绑定的相关文章

bbframework入门之路【四】

[正文] 前面我们基本上已经将bbframework开发的必备工作都已经做好了,今天我们就来往我们那乌漆麻黑的场景里面添加点东西,让游戏慢慢的像个游戏.首先我们来看下一个空的Layer(层)所应该有的东西: --[[!-- 场景层类,定义层相关操作方法及逻辑实现. - 定义场景层功能方法. ]] ---------------------- -- 类 ---------------------- local M = classLayerTouch("Main") -----------

bbframework入门之路【二】

[附加信息] 上一篇我们已经介绍了如何搭建bbframework的开发环境,其中我们还讲到了Sublime Text这款编辑器,关于Sublime的用法,我们可以参照http://www.cnblogs.com/wuguanglei/p/4286550.html这篇博文,详细的我们就不再这里阐述了. [正文] 今天我们一起来看下关于公司常用资源的存放目录和我们项目目录的组成结构,了解这些目录结构,是我们进行高效快速开发的必要条件,虽然不起眼,但也不能忽视. 首先,我们先来看下SVN上面的目录结构

bbframework入门之路【六】常用的动作和动画

[正文] 今天我们来介绍下游戏开发中必不可少的东西,那就是动作和动画.bbframework除了支持Cocos2D-X里面提供的动作之外,我们自己也根据实际项目需求往框架里面新增了不少的动作,所以这部分的内容比较多,我们简单的列举几个常用的动作和一些常用的和动作相关的函数,剩下的大家可以自行参考框架的“UAction.lua”文件,UAction里面包含了bbframework提供的所有动作,包括每个动作的案例代码和详细的注释. 话不多说,我们直接进入主题.我们bbframework的动作是通过

bbframework入门之路【三】

[正文] 上一篇我们已经了解了一部分项目开发相关的目录结构,今天我们依然继续为大家介绍我们这套框架的一些访问更为频繁的目录结构.也就是“main/bbframework/res”和“main/bbframework/script/app”底下的目录结构. 话不多说,我们先来看下“main/bbframework/res”(简称:“res”),也就是资源文件夹. 上图就是res文件夹的子目录,其中“ccb”里面是用于CocosBuilder开发方式使用的资源路径,简称为“ccb”.因为现在还没有使

bbframework入门之路【一】

[前言] 众所周知,目前手游市场上大部分的游戏都是通过Cocos2D-X这个引擎来开发的.Cocos2D-X简称“-x”是从Cocos2D-iphone衍生而来的,-x是使用C++编程语言搭建的框架,但是会C++的人都知道C++那繁琐的语法总是让程序员(猿)带着那么点淡淡的忧伤.近几年编程开始走向脚本化,于是乎,Cocos2D也出现了不同的版本.有用Lua搭建的Cocos2D-Lua,或者叫做quick-x:也有用Javascript搭建的Cocos2D-Js.然后随着平台的多样化,也出现了以C

bbframework入门之路【八】粒子系统和音效

[正文] 一款游戏除了动作和动画之外,在视觉上最容易提升画面效果的当属粒子系统了.关于粒子系统的详细介绍我们在这里就不在阐述,因为那不是重点,有兴趣的可以自己百度了解粒子系统. bbframework框架提供了“P.newParticle()”函数来播放粒子文件.cocos2D引擎支持的是“.plist”格式的粒子文件,plist文件可以通过专门的粒子编辑器来导出.newParticle()函数有三个参数,第一个是粒子plist文件的位置,我们同样是放在X4或者X2里面.第二个和第三个参数分别是

触控五周年品牌升级 全新VI形象公布

感恩五年成长之路,触控科技今日正式对外公布全新品牌形象,除启用全新的logo外,还全面升级了企业视觉识别系统(VI).而品牌的升级,也标志着触控科技公司发展战略的全面升级,在深耕游戏发行.自主研发.移动广告和基于引擎的开发者平台四大领域的基础上,触控科技正在构建移动数字娱乐领域的生态系统. 触控科技logo 新logo以银灰色光感为主,充满科技感,替换掉了原来只有“触控科技”中英文名的品牌形象,像一个椭圆缺了一个角,寓意触控对完美追求永远觉得差一点,需要不断的勇于创新追求极致.而以箭头标志幻化而

HTML5移动开发之路(52)——jquerymobile中的触控交互

本文为 兄弟连IT教育 机构官方 HTML5培训 教程,主要介绍:HTML5移动开发之路(52)--jquerymobile中的触控交互 当使用移动设备进行触控操作时,最常用的就是轻击.按住屏幕或者手势操作,jQuery Mobile可以通过绑定的触控事件来响应使用者的特定触控行为. 一.轻击与按住 直接上代码(一切皆在代码中,细细品吧!) [html] view plain copy print? <!DOCTYPE html> <html> <head> <t

小强的HTML5移动开发之路(52)——jquerymobile中的触控交互

当使用移动设备进行触控操作时,最常用的就是轻击.按住屏幕或者手势操作,jQuery Mobile可以通过绑定的触控事件来响应使用者的特定触控行为. 一.轻击与按住 直接上代码(一切皆在代码中,细细品吧!) <!DOCTYPE html> <html> <head> <title>练习</title> <meta charset="utf-8"> <meta name="viewport"