quick-cocos2d-x 学习系列之六 CoinFlip
quick-cocos2d-x 学习系列之六 CoinFlip 下面我们来看一个很完整的例子,CoinFlip,这个DEMO已经非常完整可以直接用来玩耍了。 代码路径:.. quicksamplescoinflip 这个游戏还是很益智的。 1.代码逻辑开始部分基本和其他的都一致,从main.lua文件进入,到达MyApp.lua文件中。(MyApp继承于cc.mvc.AppBase) 主要函数是run,enterMenuScene,enterMoreGamesScene,enterChooseLevelScene,playLevel (程序逻辑结构比之前略微复杂一点:有多个文件夹data,scenes,ui,views. 其中data用来存放关卡信息,ui是UI相关文件,scenes是4个场景文件,views是显示相关的函数和类) 1.1.1Run该函数会增加程序搜索路径 res文件,加载游戏的相关PNG文件,加载声音文件,然后调用程序self:enterMenuScene(). 2.1.1enterMenuScene该函数调用如下: self:enterScene("MenuScene",nil,"fade",0.6,display.COLOR_WHITE) 这个enterScene函数是继承自父类的。 直接进入到MenuScene场景中,该场景定义在文件 app/scenes/MenuScene.lua文件中。 3.1.1nterMoreGamesScene该函数调用如下: self:enterScene("MoreGamesScene",display.COLOR_WHITE) 其他同上 4.1.1enterChooseLevelScene该函数调用如下: self:enterScene("ChooseLevelScene",display.COLOR_WHITE) 其他同上 5.1.1playLevel该函数调用如下: self:enterScene("PlayLevelScene",{levelIndex},display.COLOR_WHITE) 其他同上 2.MenuScene导入其他函数如下: local AdBar = import("..views.AdBar") local BubbleButton = import("..views.BubbleButton") 游戏开始后的第一个场景,即菜单场景。 代码都在ctor函数中(构造函数) 增加背景图片,设置两个BUTTON。 一个开始,一个关于更多游戏。 点击开始后,进入选择LEVEL的场景 点击更多游戏后,进入MoreGamesScene场景 注:此处有个BUG,如果点击完开始后,立马点击更多游戏的按钮,程序会死掉,这个就交个小伙伴们自己去修正吧。 4.1BubbleButton定义了一个函数用于创建BUTTON,该BUTTON 带果冻样的特效,看上去很专业的,最后返回BUTTON,该文件核心也是实现这果冻效果(主要是简单动作把握时间进行合成)。 3.MoreGamesScene这个场景只有一个ctor构造函数,实现了背景图片添加, 一个测试BAR的添加,最后是一个返回按钮增加。 注:BAR在views/AdBar.lua文件夹中。 4.ChooseLevelScene这个LEVEL选择的场景当前在很多流行的游戏中管用的伎俩,应该说是手段,不过基本都是大同小异的。 该场景的主要函数还是其构造函数,ctor,此外还有两个函数分别是onTapLevelIcon,onEnter 还导入了两个其他功能块(这样实现功能解耦) local AdBar = import("..views.AdBar") local LevelsList = import("..views.LevelsList") 4.2Ctor首先是添加一个背景图片,增加一个TITLE,一个测试的BAR。 创建一个矩形,通过矩形创建LevelsList,为其添加监听onTapLevelIcon。 最后创建一个BACK按钮。 注:主要是LevelsList,在views/LevelsList.lua文件中。 4.2.1LevelsList先导入了3个其他文件如下: local LevelsListCell = import(".LevelsListCell") local Levels = import("..data.Levels") local PageControl = import("..ui.PageControl") 定义一个LevelsList类,继承于PageControl,PageControl继承与ScrollView. 该类是所有关卡的集合,按页分开。 定义了一个常量 LevelsList.INDICATOR_MARGIN = 46(指示关卡页的黑点间距) 每个关卡页存放4X4=16个关卡。如果高度大于1000,则存放5行。 此外主要是3个函数,ctor,scrollToCell,onTapLevelIcon. Ctor是构造函数 调用父类的构造函数LevelsList.super.ctor(self,rect,PageControl.DIRECTION_HORIZONTAL) 通过总关卡数量除以每页行数和列数计算得到总共页数。 设置每页的最后一个关卡,如果超过总关卡数则设置为实际最后关卡。 然后通过LevelsListCell 类将页填满,以此往复。 然后设置页下方的小点点,起到提示用户当前在哪个关卡页面上。 在表示第一页的小点上增加实心图片,然后循环增加空心图片如下: local x = (self:getClippingRect().width - LevelsList.INDICATOR_MARGIN * (numPages - 1)) / 2 local y = self:getClippingRect().y + 20 self.indicator_ = display.newSprite("#LevelListsCellSelected.png") self.indicator_:setPosition(x,y) self.indicator_.firstX_ = x for pageIndex = 1, numPages do local icon = display.newSprite("#LevelListsCellIndicator.png") icon:setPosition(x,y) self:addChild(icon) x = x + LevelsList.INDICATOR_MARGIN end scrollToCell 调用父节点的scrollToCell函数。 然后移动实心图片到实际的显示的页面上。 onTapLevelIcon函数就一条语句如下 self:dispatchEvent({name ="onTapLevelIcon",levelIndex = event.levelIndex}) 分发onTapLevelIcon时间,参数为levelIndex = event.levelIndex。 4.2.2PageControl导入了文件local ScrollView = import(".ScrollView") 类继承于ScrollView(该类定义与ScrollView.lua文件中) 主要实现函数onTouchEndedWithoutTap 局部变量offsetX,offset,index,count 根据direction变量,进行处理滑动关卡页面操作。 4.2.3ScrollView定义了ScrollView类,初始化需要一个RECT矩阵参数,如果没有则矩阵参数为(0,0) 通过该矩阵创建一个剪切区域。 通过如下命令增加组件: cc(node):addComponent("components.behavior.EventProtocol"):exportMethods() 初始化函数中,定义了一些变量, self.dragThreshold = 40 --拖动上限 self.bouncThreshold = 140 --滑动关卡页面的最大值,参看setContentOffset self.defaultAnimateTime = 0.4 –默认动画时间 self.defaultAnimateEasing = "backOut" –默认动画效果 self.direction = direction self.touchRect = rect self.offsetX = 0 self.offsetY = 0 self.cells = {} self.currentIndex = 0 添加NODE的事件监听, self:addNodeEventListener(cc.NODE_EVENT,function(event) if event.name == "enter" then self:onEnter() elseif event.name == "exit" then self:onExit() end end) 此外创建一个触摸层,对其增加触摸监听,调用onTouch函数。 self.view = display.newLayer() self:addChild(self.view) self.view:addNodeEventListener(cc.NODE_TOUCH_EVENT,function(event) return self:onTouch(event.name,event.x,event.y) end) onTouch函数中,进行多种情况 处理,按下,移动,弹起。 按下后调用:onTouchBegan 移动后调用:onTouchMoved 弹起后调用:onTouchEnded 其他则调用:onTouchEnded 函数getCurrentCell 获取当前所在的关卡。 Addcell函数增加一个包含关卡的页面到可视的view层中,该函数调用reorderAllCells函数。 LevelsList直接调用了Addcell函数。 reorderAllCells函数,处理CELLS的页面在view中的排序,会设置变量currentIndex变量的值,该变量指定当前触摸页面的数量,都按规则排放在views这个层上。 该类中比较复杂的应该是触摸函数的处理: l 有触摸函数: a)onTouch 该函数在触摸开始就调用,如果没有关卡就退出,也就没有后文了。如果是刚按下那么判断是否在可触摸范围当中,不在则返回FALSE退出触摸,如何在其中则调用onTouchBegan函数,其参数为按下的坐标。如果不是刚按下,则调用onTouchMoved即可处理鼠标移动。 如果触摸结束则调用函数onTouchEnded,如果是其他则调用函数onTouchCancelled b)onTouchBegan 设置拖动的起点,设置isTap为True(每次开始触摸都会设置为True,滑动后就变为FALSE了,防止滑动后还进入某个关卡) 通过函数getCurrentCell获取当前的cell. 调用CELL本身的onTouch 函数(这个函数就在LevelsListCell.lua 文件中了,实现按钮变化)。 c)onTouchMoved 获取当前的CELL,根据水平还是垂直,再判断超过临界值dragThreshold,是否isTrap,后进行调用setContentOffset 进行处理实时滑动,否则调用CELL的onTouch. d)onTouchEnded 如果设置了isTrap则调用函数onTouchEndedWithTap 如果没有设置,则调用函数onTouchEndedWithoutTap。 e)onTouchCancelled 该函数值只将self.drag变量设置为nil。 其他相关的函数 f)onTouchEndedWithTap 该改用调用cell本身的的onTouch和onTrap函数。 Cell本身的onTrap函数实现self:dispatchEvent({name= "onTapLevelIcon",levelIndex = button.levelIndex})事件分发,由LevelsList类中的onTapLevelIcon函数处理再一次分发,最后由ChooseLevelScene:onTapLevelIcon(event)函数处理,实现进入到具体关卡的作用。 这个函数就是不滑动关卡页面的处理。 g)onTouchEndedWithoutTap 在PageControl.lua文件中被重写。这个函数就是滑动关卡页面的处理。 根据判断进行滑动,调用scrollToCell函数,该函数会调用setContentOffset函数。 处理滑动页面情况。实际最后接手的函数依旧是setContentOffset。此时是带有动画效果的。 h)setContentOffset 处理实时滑动效果,根据水平、垂直,设置实时坐标值,不能超过上下限,最后设置位置,如果有动画则进行播放。 此处传入的参数是offset,该参数会被复制给self.offsetX进行保存。 该参数每次触摸开始的时候赋值给self.drag.currentOffsetX. 在传递给setContentOffset函数的时候发生变化,同时保存给self.offsetX进行保存。 4.2.4ScrollViewCell创建一个类ScrollViewCell,通过给定的大小创建一个Node. 为该node增加组件如下: cc(node):addComponent("components.behavior.EventProtocol"):exportMethods() 该类是一个触摸单元类。 4.2.5LevelsListCell该类继承于ScrollViewCell,是一个滑屏单元类。通过屏幕本身大小定义 rowHeight 屏幕高度-340 除以总行数 colWidth 屏幕宽度乘以0.9, 除以总列数得到。 pageIndex是关卡的当前页数。 页开始的X和,Y 根据显示屏幕计算的得到。 beginLevelIndex,endLevelIndex在构造函数中的参数。 根据一页能够容纳的BUTTON数量,卡的BUTTON,其中给BUTTON增加一个LABEL表示关卡等级。 该类中定义了函数onTap函数,根据点击位置返回BUTTON,最重要的是该函数进行了时间“onTrapLevelIcon”分发。(BUTTON是一个表结构,有一个图片和levelIndex变量) (该类主要的都是在本身自己类中完成的,其父类主要的工作是如下代码 local node = display.newNode() if contentSize then node:setContentSize(contentSize) end node:setNodeEventEnabled(true) cc(node):addComponent("components.behavior.EventProtocol"):exportMethods() return node ) 4.2.6Levels定义了关卡信息如: Levels表结构 levelsData 表结构 函数numLevels() get(levelIndex) 4.3onTapLevelIcon是levelsList 的onTapLevelIcon事件回调函数(该事件由LevelsListCell类中onTap函数分发,不过具体分发时间是由ScrollView类中的onTouchEndedWithTap函数调用),播放按钮声音,然后调用app:playLevel函数进入到选择的游戏场景中。 4.4onEnter该函数在构造函数执行完毕后执行,在此主要是使能按钮。 5PlayLevelScene先倒入其他的功能模块: local Levels = import("..data.Levels") local Board = import("..views.Board") local AdBar = import("..views.AdBar") Levels.lua文件中定义了各个关卡的数据,可以设置关卡几乘几,关卡初始化条件。 一个背景图片,一个TITLE,一个测试BAR,关卡级别的LABEL显示。游戏的BORAD,一个返回的BUTTON。 游戏中增加了self.board:addEventListener("LEVEL_COMPLETED",handler(self,self.onLevelCompleted))对事件监听,当胜利时会发出该事件消息,然后 PlayLevelScene:onLevelCompleted函数进行处理。 注:BOARD在 views.Board.lua文件中定义。 BOARD中有核心逻辑 5.1Board导入如下文件 local Levels = import("..data.Levels") local Coin = import("..views.Coin") 获取游戏关卡变量grid,rows,cols 计算得到offsetX,offset 摆放金币背景精灵。判断当前位置是否为空,不为空则创建一个金币。 将金币存放到coins数组中。使能触摸,创建触摸监听。 onTouch函数将金币进行反转。 这个度量常数是padding = NODE_PADDING /2 flipCoin函数可以同时将隔壁金币进行反转。 flipCoin函数会进行关卡检测是否完毕。 5.2Coin定义了一个Coin类,该类根据初始化正反面创建图片,还有一个isWhite变量。 还有一个重要函数Coin:flip,该函数中定义了一个动画,根据isWhite设置动画方向,即翻转的动画。 同时设置isWhite变量反转。 6个别函数说明self.levelsList:addEventListener("onTapLevelIcon",self.onTapLevelIcon)) 将 Lua 对象及其方法包装为一个匿名函数。 格式: 函数 = handler(对象,对象.方法) 在 quick-cocos2d-x 中,许多功能需要传入一个 Lua 函数做参数,然后在特定事件发生时就会调用传入的函数。例如触摸事件、帧事件等等。 Quick-Cocos2d-x中自定义事件官网查看地址: http://cn.cocos2d-x.org/article/index?type=quick_doc&url=/doc/cocos-docs-master/manual/framework/quick/V3/events/zh.md ·addEventListener ·removeEventListener ·removeAllEventListenersForEvent ·removeAllEventListeners cc(node):addComponent("components.behavior.EventProtocol"):exportMethods() 该句为node类添加了扩展的事件处理方法,现在我们可以使用EventProxy中的函数了,通过这些函数我们可以让cc(node)接收到自定义的消息然后进行处理。 分发事件“addCell” self:dispatchEvent({name = "addCell",count =#self.cells}) display.addSpriteFrames()display.addSpriteFrames(plistFilename,image,handler) 将指定的 Sprite Sheets 材质文件及其数据文件载入图像帧缓存。 格式: display.addSpriteFrames(数据文件名,材质文件名) cc.rect实际参数是 x,y,width,height 坐标X,Y,宽和高。实际使用如下: local rect = cc.rect(display.left,display.bottom+ 180,display.width,display.height - 280) display.newBatchNode()display.newBatchNode(image,capacity) 从指定的图像文件创建并返回一个批量渲染对象。 local imageName = "Sprites.png" display.addSpriteFrames("Sprites.plist",imageName) -- 载入图像到帧缓存
-- 下面的代码绘制 100 个图像只用了 1 次 OpenGL draw call local batch =display.newBatch(imageName) for i = 1,100 do local sprite = display.newSprite("#Sprite0001.png") batch:addChild(sprite) end
-- 下面的代码绘制 100 个图像则要使用 100 次 OpenGL draw call local group = display.newNode() for i = 1,100 do local sprite = display.newSprite("#Sprite0001.png") group:addChild(sprite) end Parameters stringimage图像文件名 integercapacity reorderChildreorderChild有两个参数如下图
Child 是准备添加的节点,zOrder 是cocos2d 里面的 z 值 这个函数意思就是根据新的 zOrder 重新排序 child 优先级 例如在一个 layer(场景)里面添加了一个图片,已经设置好了这个图片的绘制优先级,由于某种情况,这个优先级存在一定的问题,想修改一下这个图片的优先级。这个时候我就不用先使用layer(场景) 调用removeFromParentAndCleanup(boolcleanup);然后再addChild(Node * child,int zOrder);这么麻烦了 transition.playAnimationOnce()transition.playAnimationOnce(target,animation,removeWhenFinished,onComplete,delay) 在显示对象上播放一次动画,并返回 Action 动作对象。 7逻辑拓扑图
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |