在cocos2d-x游戏中实现tips功能

前端之家收集整理的这篇文章主要介绍了在cocos2d-x游戏中实现tips功能前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

原文请猛戳:
http://galoisplusplus.coding.me/blog/2016/01/16/tips-in-cocos2d-x-game/

这次分享一个简单的小功能,用cocos2d-x实现tips效果,作为之前一篇博文的后续。tips的行为很简单:点击某个node(我们不妨称它为target_node)触发,当点击区域在target_node范围时出现tips,否则隐藏tips(有些情况需要指定有效点击范围不在某些node中,我们把这些node称为exclude_nodes);当target_node位于屏幕左半边时,tips出现在target_node右侧;否则tips就出现在target_node左侧,tipstarget_node有一个固定的水平间距(我们不妨定义为DEFAULT_TIPS_DIST);tipstarget_node底部对齐,但tips不能超过屏幕范围。

不废话,先上代码

  1. function setupTips(params)
  2. local targetNode = params.target_node
  3. local tips = params.tips
  4. local excludeNodes = params.exclude_nodes or {}
  5.  
  6. local DEFAULT_TIPS_DIST = 10
  7. local TIPS_ZORDER = 1000
  8.  
  9. if tolua.isnull(targetNode) or tolua.isnull(tips) then
  10. return
  11. end
  12.  
  13. tips:setVisible(false)
  14. targetNode:setTouchEnabled(false)
  15. display.getRunningScene():addChild(tips,TIPS_ZORDER)
  16.  
  17. targetNode:addNodeEventListener(cc.NODE_EVENT,function(event)
  18. if event.name == "exit" then
  19. local scene = display.getRunningScene()
  20. scene:performWithDelay(MyPackage.callbackWrapper({scene},function()
  21. if not tolua.isnull(tips) then
  22. tips:setVisible(false)
  23. end
  24. end),0)
  25.  
  26. local eventDispatcher = display.getRunningScene():getEventDispatcher()
  27. eventDispatcher:removeEventListenersForTarget(targetNode)
  28. end
  29. end)
  30. ------------------------------------------------------------
  31. local function setTipsPosition()
  32. local leftBottomPos = MyPackage.getPositionOfNode(targetNode,display.LEFT_BOTTOM)
  33. local targetNodePos = display.getRunningScene():convertToNodeSpace(targetNode:getParent():convertToWorldSpace(leftBottomPos))
  34. local targetNodeAnchorPoint = targetNode:getAnchorPoint()
  35. local tipsPos = targetNodePos
  36. local tipsAnchorPoint = cc.p(0,0)
  37. local director = cc.Director:getInstance()
  38. local glView = director:getOpenGLView()
  39. local frameSize = glView:getFrameSize()
  40. local viewSize = director:getVisibleSize()
  41.  
  42. if targetNodePos.x <= frameSize.width * 0.5 / glView:getScaleX() then
  43. -- show tips on the right of the targetNode if the targetNode is on the left screen
  44. tipsPos.x = tipsPos.x + targetNode:getContentSize().width + DEFAULT_TIPS_DIST
  45. else
  46. -- show tips on the left of the targetNode otherwises
  47. tipsPos.x = tipsPos.x - DEFAULT_TIPS_DIST
  48. tipsAnchorPoint.x = 1
  49. end
  50.  
  51. if targetNodePos.y + tips:getContentSize().height > viewSize.height then
  52. tipsPos.y = viewSize.height
  53. tipsAnchorPoint.y = 1
  54. end
  55. if targetNodePos.y < 0 then
  56. targetNodePos.y = 0
  57. end
  58.  
  59. tips:ignoreAnchorPointForPosition(false)
  60. tips:setAnchorPoint(tipsAnchorPoint)
  61. tips:setPosition(tipsPos)
  62. end
  63. ------------------------------------------------------------
  64. local function activeFunc()
  65. local scene = display.getRunningScene()
  66. -- NOTE: delay util the next frame in order to get the correct WorldSpace position
  67. scene:performWithDelay(MyPackage.callbackWrapper({scene,tips},function()
  68. setTipsPosition()
  69. tips:setVisible(true)
  70. end),0)
  71. end
  72.  
  73. local function inactiveFunc()
  74. if not tolua.isnull(tips) then
  75. tips:setVisible(false)
  76. end
  77. end
  78.  
  79. local function isTouchInNode(touch,node)
  80. if tolua.isnull(node) or tolua.isnull(touch) then
  81. return false
  82. end
  83.  
  84. local localLocation = node:convertToNodeSpace(touch:getLocation())
  85. local width = node:getContentSize().width
  86. local height = node:getContentSize().height
  87. local rect = cc.rect(0,width,height)
  88. return getCascadeVisibility(node) and node:isRunning() and cc.rectContainsPoint(rect,localLocation)
  89. end
  90.  
  91. local function isActive(touch)
  92. local isExcluded = false
  93. for _,excludeNode in ipairs(excludeNodes) do
  94. isExcluded = isExcluded or isTouchInNode(touch,excludeNode)
  95. end
  96. return isTouchInNode(touch,targetNode) and not isExcluded
  97. end
  98.  
  99. local function onTouchBegan(touch,event)
  100. if isActive(touch) then
  101. activeFunc()
  102. return true
  103. else
  104. return false
  105. end
  106. end
  107.  
  108. local function onTouchMoved(touch,event)
  109. local scene = display.getRunningScene()
  110. scene:performWithDelay(MyPackage.callbackWrapper({scene},function()
  111. if isActive(touch) then
  112. activeFunc()
  113. else
  114. inactiveFunc()
  115. end
  116. end),0)
  117. end
  118.  
  119. local function onTouchEnded(touch,function()
  120. inactiveFunc()
  121. end),0)
  122. end
  123.  
  124. local listener = cc.EventListenerTouchOneByOne:create()
  125. listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCH_BEGAN)
  126. listener:registerScriptHandler(onTouchMoved,cc.Handler.EVENT_TOUCH_MOVED)
  127. listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCH_ENDED)
  128. listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCH_CANCELLED)
  129. local eventDispatcher = display.getRunningScene():getEventDispatcher()
  130. eventDispatcher:removeEventListenersForTarget(targetNode)
  131. eventDispatcher:addEventListenerWithSceneGraPHPriority(listener,targetNode)
  132. end

关于MyPackage.getPositionOfNodeMyPackage.callbackWrapper等helper functions请参见之前某篇博文

上面的代码基本是很简单的,除了有几点需要额外说明一下:

1.几处调用performWithDelay的地方。这是因为我们用target_node的WorldSpace坐标来确定tips的位置,当target_node位于某个可滚动的node(如ScrollView)中时,需要延迟到下一帧才能拿到它正确的WorldSpace坐标,所以我们用了quickx定义的Node:performWithDelay来做延时。之所以用这个函数而不用scheduler,是因为它在Node的生命周期中,我们不需要担心如何去安全销毁scheduler所产生的handler。事实上我们只要看一下quickx定义在NodeEx.lua中的Node:performWithDelay就一目了然了:

  1. function Node:performWithDelay(callback,delay)
  2. local action = transition.sequence({
  3. cc.DelayTime:create(delay),cc.CallFunc:create(callback),})
  4. self:runAction(action)
  5. return action
  6. end

2.我们指定target_node在收到exit事件时隐藏tips,这是因为target_node可能在某些ClippingNode(如ScrollView)中,当它超出区域不再显示时,tips也不应该被显示

3.当同一个位置有多个具有tips行为的target_node时,需要判断当前的target_node是否有显示,这需要回溯看父节点的visibilitygetCascadeVisibility定义如下:

  1. function getCascadeVisibility(node)
  2. if tolua.isnull(node) then
  3. return true
  4. end
  5. local visibility = node:isVisible()
  6. if visibility then
  7. local parent = node:getParent()
  8. visibility = visibility and getCascadeVisibility(parent)
  9. end
  10. return visibility
  11. end

猜你在找的Cocos2d-x相关文章