cocos-lua 手游之游戏新手引导
1.新手引导在游戏中还是比较重要的 往往新手引导的实现都是在游戏开发的后期
2.新手引导有这么几个要点
1.不影响原有的代码
2.断线后引导继续(也可跳过引导具体看策划的需求)
3.和服务器的交互
3.其实新手引导不仅仅可以作为开始游戏的引导 也可作为任务的对话
ok,因为新手引导的方法很多 我现在就来说下我的新手引导的逻辑
1.把每一步的引导以枚举的形式保存(也可用配置文件)
2.GuideMgr只记录当前的步骤和当前引导的信息
3.添加引导 删除引导 用通知者模式通知界面
4.不影响原有的代码
具体的代码可能比较乱 所以我就只贴部分的代码
先来看下部分枚举
NewHandDef.STAGE = {
STAGE_BUILD_FARM = 1,
SRAGE_BUILD_IRON = 2,
SRAGE_BUILD_SOLDIER = 3,
}
NewHandDef.BUILD_FARM_SUB_STAGE = {
SUBSTAGE_1 = 1,
SUBSTAGE_2 = 2,
SUBSTAGE_3 = 3,
SUBSTAGE_4 = 4,
}
枚举分为Stage SubStage 分别表示第几阶段 第几小步
再看下mgr的代码
NewHandMgr = class("NewHandMgr")
--[[
1.判断是否需要引导
2.记录下引导到当前的步骤 和引导的信息
--]]
local _instance = nil
local _guideIndex = nil -- 指引的顺序索引
local _guideInfo = nil -- 当前引导信息
local _isGuiding = nil-- 是否开启指引
local _isGuideLayer = nil --是否有引导层
function NewHandMgr:ctor()
_guideInfo = {}
_isGuiding = false
_isGuideLayer = false
end
function NewHandMgr:getInstance()
if _instance == nil then
_instance = NewHandMgr.new()
end
return _instance
end
-----外部调用这个函数 可以通知到adGuide 知道 _guideInfo 的信息
--进行判断
function NewHandMgr:setGuideInfo(data)
if not data then
print("---------没有设置引导信息------------")
return
end
if not data.STAGE then
print("---------没有设置引导信息的阶段------------")
return
end
if not data.SUBSTAGE then
print("---------没有设置引导信息的步骤------------")
return
end
_guideInfo = data
end
function NewHandMgr:addGuide()
if _isGuiding and _guideInfo then
DataCenter:getInstance():sendMsg(DataEvent.GUIDE.ADD, _guideInfo)
_isGuideLayer = true
printInfo("开始指引的是第%s阶段%s小步",_guideInfo.STAGE,_guideInfo.SUBSTAGE)
end
end
function NewHandMgr:removeGuide()
if _isGuideLayer then
DataCenter:getInstance():sendMsg(DataEvent.GUIDE.END,_guideInfo)
printInfo("指引的第%s阶段%s小步,完成",_guideInfo.STAGE,_guideInfo.SUBSTAGE)
_guideInfo = nil
self:nextGuide()
end
_isGuideLayer = false
end
function NewHandMgr:nextGuide()
if _isGuiding == false and _isGuideLayer then
return
end
if _guideInfo.STAGE == NewHandDef.STAGE.STAGE_BUILD_FARM then
if _guideIndex < = #NewHandDef.BUILD_FARM_SUB_STAGE then<span style="font-family: Arial, Helvetica, sans-serif;"> </span>
<span ></span><pre name="code" class="cpp"> _guideIndex = _guideIndex + 1
_guideInfo = {STAGE = NewHandDef.STAGE.STAGE_BUILD_FARM , SUBSTAGE = _guideIndex}
self:addGuide()
return
end
elseif _guideInfo.STAGE == NewHandDef.STAGE.SRAGE_BUILD_IRON then
if _guideIndex < = #NewHandDef.BUILD_IRON_SUB_STAGE then
_guideInfo = {STAGE = NewHandDef.STAGE.STAGE_BUILD_FARM , SUBSTAGE = _guideIndex}
self:addGuide()
return
end
elseif _guideInfo.STAGE == NewHandDef.STAGE.SRAGE_BUILD_SOLDIER then
if _guideIndex < = #NewHandDef.BUILD_SOLDIER_SUB_STAGE then
_guideInfo = {STAGE = NewHandDef.STAGE.SRAGE_BUILD_SOLDIER , SUBSTAGE = _guideIndex}
self:addGuide()
return
end
end
print("----------引导全部完成-------------")
_isGuiding = false
_guideIndex = nil
_guideInfo = nil
end
-- 是否进行新手引导
function NewHandMgr:isGuiding()
return _isGuiding
end
-- 获取当前引导信息
function NewHandMgr:getInfo()
return _guideInfo
end
在外部进行每一个触发条件的时候 引用setGuideInfo 假如现在城市到达了3级 提示需要建造农场 那进入农场层的时候 设置guideInfo
由于外部都需要调用GuideLayer (引导层) 所以我们拿出来写
<pre name="code" class="cpp">require("app.Test.NewHandMgr")
local GuideLayer=class("GuideLayer", function()
return cc.Layer:create()
end)
function GuideLayer:ctor(widget_data)
local widget = widget_data.widget
local pos = widget_data.pos
--压黑
local layerColor = cc.LayerColor:create(cc.c4f(0, 0, 0, 200), display.width, display.height)
--高亮
local clipNode = cc.ClippingNode:create()
clipNode:setInverted(true)
clipNode:addChild(layerColor)
local stencilNode = cc.Node:create()
local highLightNode = widget:clone()
pos.x = pos.x+widget:getAnchorPoint().x*widget:getBoundingBox().width
pos.y = pos.y+widget:getAnchorPoint().y*widget:getBoundingBox().height
highLightNode:setPosition(cc.p(pos.x,pos.y))
local tip_sprite = display.newSprite("equip_21.png")
tip_sprite:setAnchorPoint(cc.p(0,0))
tip_sprite:setPosition(highLightNode:getPosition())
local action = cc.Blink:create(1,2)
tip_sprite:runAction(cc.RepeatForever:create(action))
tip_sprite:addTo(self)
stencilNode:addChild(highLightNode)
stencilNode:setAnchorPoint(cc.p(0.5,0.5))
clipNode:setStencil(stencilNode)
clipNode:setAlphaThreshold(0)
self:addChild(clipNode)
self:setTouchEnabled(true)
local eventDispatcher = self:getEventDispatcher()
local function onTouchBegan(touch, event)
local locationInNode = highLightNode:getParent():convertToNodeSpace(touch:getLocation())
-- dump(touch:getLocation())
printInfo("点击的X=%s 点击的Y=%s",locationInNode.x,locationInNode.y )
local rect = highLightNode:getBoundingBox()
-- dump(rect)
if self:isVisible() == false then
return false
elseif cc.rectContainsPoint(rect, locationInNode) then
print("----在高亮区域里---")
NewHandMgr:getInstance():removeGuide()
return false
else
return true
end
end
local function onTouchMoved(touch, event)
end
local function onTouchEnded(touch, event)
print("-----------触摸结束----------")
end
local listener = cc.EventListenerTouchOneByOne:create()
self._listener = listener
listener:setSwallowTouches(true)
listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCH_BEGAN )
listener:registerScriptHandler(onTouchMoved,cc.Handler.EVENT_TOUCH_MOVED )
listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCH_ENDED )
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, self)
end
return GuideLayer
其实guideLayer的方法有很多种 我这只是利用剪切高亮实现的一种 下面我贴一个链接
利用的是其他方法 剪切区域 把非剪切区域变暗
或许你还会不理解convertToWorldSpace 和convertToNodeSpace再贴一个链接
现在我贴一部分在UI上使用这些类的代码
<pre name="code" class="cpp">require("app.View.UIManager")
require("app.Test.DataCenter")
require("app.Def.NewHandDef")
require("app.Test.NewHandMgr")
require("app.Def.DataEvent")
MainLayer = class("MainLayer", function()
return display.newLayer()
end)
MainLayer.FILE_NAME = "csb/new_hand_guide.csb"
function MainLayer:onCreate()
DataCenter:getInstance():addRegister(self)
self:init()
end
function MainLayer:onRelease()
DataCenter:getInstance():removeRegister(self)
end
function MainLayer:init()
local guide_info = {STAGE = 1 , SUBSTAGE = 1}
dump(guide_info)
NewHandMgr:getInstance():setGuideInfo(guide_info)
self._btn_1 = cc.uiloader:seekNodeByName(self,"test_btn_1")
self._btn_2 = cc.uiloader:seekNodeByName(self,"test_btn_2")
self._btn_3 = cc.uiloader:seekNodeByName(self,"test_btn_3")
self._btn_1:addClickEventListener(handler(self, self.oneCallback))
self._btn_2:addClickEventListener(handler(self, self.twoCallback))
self._btn_3:addClickEventListener(handler(self, self.threeCallback))
self.label = display.newTTFLabel({
text ="111111",
size = 64,
color = cc.c3b(255, 0, 0)
})
self.label:setPosition(display.cx,display.cy)
self.label:addTo(self)
NewHandMgr:getInstance():addGuide()
end
function MainLayer:oneCallback()
local text = "i am _btn_1 clicked"
self.label:setString(text)
end
function MainLayer:twoCallback()
self.label:setString("i am _btn_2 clicked")
end
function MainLayer:threeCallback()
self.label:setString("i am _btn_3 clicked")
end
function MainLayer:onDataChange(eventTag, param)
if eventTag == DataEvent.GUIDE.ADD then
self:NewHandEvnet(param)
elseif eventTag == DataEvent.GUIDE.END then
self:removeNewHandEvent(param)
end
end
function MainLayer:NewHandEvnet(param)
if not param.STAGE == NewHandDef.STAGE.STAGE_BUILD_FARM then
return
end
if param.SUBSTAGE == NewHandDef.BUILD_FARM_SUB_STAGE.SUBSTAGE_1 then
local widget_data = {widget = self._btn_1 , pos = self._btn_1:convertToWorldSpace(cc.p(0,0)) }
dump(widget_data)
UIManager:getInstance():addGuideLayer(widget_data)
elseif param.SUBSTAGE == NewHandDef.BUILD_FARM_SUB_STAGE.SUBSTAGE_2 then
local widget_data = {widget = self._btn_2 , pos = self._btn_2:convertToWorldSpace(cc.p(0,0)) }
UIManager:getInstance():addGuideLayer(widget_data)
elseif param.SUBSTAGE == NewHandDef.BUILD_FARM_SUB_STAGE.SUBSTAGE_3 then
local widget_data = {widget = self._btn_3 , pos = self._btn_3:convertToWorldSpace(cc.p(0,0)) }
UIManager:getInstance():addGuideLayer(widget_data)
end
end
function MainLayer:removeNewHandEvent(param)
if not param.STAGE == NewHandDef.STAGE.STAGE_BUILD_FARM then
return
end
UIManager:getInstance():removeGuideLayer()
end