版权声明:本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名elloop(包含链接)
前言
本文介绍了CCMenu类的实现原理,并在CCMenu的基础上稍加改造,实现了一个点击自动缩放的菜单类。
在上一篇文中里回顾了cocos中单点触摸的用法和触摸事件分发机制、优先级控制等内容,也给出了自己写的小demo,其实在cocos本身就有很好的触摸事件的使用范例,其中就包括CCMenu的实现,下面我们结合引擎源代码来分析一下它的实现原理。
CCMenu本质上就是一个Touchable,并且是单点触摸的。它身上挂满了各种“零件”(各种CCMenuItem的子类),你摸它的时候,假设你摸在A点,它就判断A点落在它的哪个“零件”上, 它就会叫那个“零件”做出反应, 完成那个“零件”应该完成的任务(调用你在创建CCMenuItem子类时绑定的handler).
CCMenu.h:
CCMenu.cpp
可以看到CCMenu的实现还是比较清晰、简单的,它本身作为一个CCMenuItem的容器,响应单点触摸事件,判断哪个item被点击,并调用其对应方法完成菜单消息响应,核心在于对触摸事件的处理,坐标点的判断。
点击缩放功能的菜单按钮
在实际的游戏开发中,最常用的CCMenuItem要属CCMenuItemImage了,在HelloWorld的Demo中可以看到,要创建一个关闭按钮通常是这样写:
其中用到了两张图片,第一张是按钮在正常状态下的图片,第二张是被点击时候的选中状态的图片。如果两种状态下按钮的图片是相近的那最好就只用一张,正常和选中都用同一个图片,然后在按钮被按下的时候让它有一个放大的效果,恢复正常之后再自动恢复原来的缩放。这样就节省了一张图片素材。
那么如果要实现一个点击缩放的菜单按钮该如何做呢?
我们知道CCMenuItemLabel在被选中的时候是有一个缩放效果的,它的selected和unselected方法是这样:
按照相同的处理方式,我可以copy一份CCMenuItemImage的实现,改个名字,然后按照CCMenuItemLabel的方式重写selected和unselected方法就可以实现和CCMenuItemLabel同样的缩放效果,但是这里会有一个问题,我实现了一个新的CCMenuItemImage达到了缩放的效果,那对于它的父类CCMenuItemSprite呢,其实跟CCMenuItemImage是一个东西,只是创建方式是传入Sprite,而不是纹理的名字,对于它也要缩放,那还要实现一遍CCMenuItemSprite的翻版,对于新定义的按钮,要缩放也要重写selected和unseleceted,加入的内容也都是相同的,即CCScaleTo的action动作。与其每个CCMenuItem的子类都重写一遍加入缩放代码,还不如在顶层只搞一次。顶层在哪里,我们从CCMenu的源码中已经看到,是CCMenu的触摸响应里调用的CCMenuItem的selected和unseleceted等方法,那么干脆在CCMenu里加上缩放行不行。
下面我自己copy了一份CCMenu的实现,改名为Menu,为避免名字冲突放在一个单独的命名空间里,暂且叫这个namespace为elloop
.
下面就是这个Menu类的实现代码:
自定义菜单类Menu.h, 仅列出改动的部分,其它部分跟CCMenu.h是一样的:
自定义缩放按钮实现文件:Menu.cpp, 也仅列出改变的部分
自定义菜单类的使用方法
代码中之所以加上一个CCMenuItemLabel类型的按钮是为了测试,本身就带有缩放功能的CCMenuItem会不会和带有缩放功能的Menu父容器产生冲突,是否会产生叠加放大的效果?
下面是运行截图:
从图中能看到,两个CCMenuItemImage是可以实现自动缩放效果的,CCMenuItemLabel的缩放动作也没有与Menu的缩放发生冲突(这是为什么?涉及到Action的更新,在后面总结到动作系统的时候再做出分析)。
此外,如果觉得Menu固定的把CCMenuItem放大到1.2不够灵活,可以把数字抽离成一个成员变量,并设置setter来灵活控制缩放比例.
测试的代码,跟上一篇文章的代码放在了一起,在TouchTestPage.cpp中。感兴趣的朋友可以到代码仓库瞅瞅。
源码
欢迎访问github博客,与本站同步更新