简易新手引导

前面介绍了ClippingNode的简单使用,补充说明setAlphaThreshold方法设定alpha阈值,只有模板(stencil)中像素的alpha值大于alpha阈值时,内容才会被绘制。默认为1,当为1时,模板全部绘制。若不是1,表示只绘制模板中alpha像素大于阈值的内容。
所以当setAlphaThreshold(1.0f)时,stencil全部绘制(红框内的全部),setInverted(false)显示被模板裁剪下来的底板内容是一个右图大小的草地图片简易新手引导_第1张图片,setInverted(true)显示剩余部分简易新手引导_第2张图片

结合之前用到的屏蔽触摸的层,做一个简易的新手引导。
首先在MainScene中添加了2个Button

function MainScene:createUI()
    local _size = cc.Director:getInstance():getWinSize()
    local function btnClicked(sender,_type)
        print('--btn click--')
    end
    local btn = ccui.Button:create('res/DS07.png','res/DS08.png','res/DS09.png')
    self:addChild(btn)
    btn:setPosition(_size.width/3,_size.height/3)
    btn:addTouchEventListener(btnClicked)

    local function btnClicked2(sender,_type)
        print('--btn2 click--')
    end
    local btn2 = ccui.Button:create('res/DS10.png','res/DS11.png','res/DS12.png')
    self:addChild(btn2)
    btn2:setPosition(_size.width/3,_size.height/4.5)
    btn2:addTouchEventListener(btnClicked2)
end

运行->简易新手引导_第3张图片

在新手引导时,需要玩家去点击Auto按钮,其他可以互动的控件全部不能响应,而且需要在视觉上将Auto按钮所在地方点亮,其他地方蒙蔽,那么可以结合之前的ClippingNode和屏蔽触摸层来实现。
新建一个Lua文件,代码:

local GuideShade = class('GuideShade',function () return cc.Node:create() end)

function GuideShade:ctor(x,y)
    self.x = x
    self.y = y
    self:createUI()
    self:openTouch()
end

function GuideShade:createUI()
    local stencil = cc.Sprite:create('res/mask.png')
    self.r = stencil:getContentSize().width / 2 
    local clipping = cc.ClippingNode:create(stencil)
    clipping:setInverted(true)
    clipping:setAlphaThreshold(0.3)
    self:addChild(clipping,-1)
    clipping:setPosition(self.x,self.y) 

    local pb = require("app/views/Pingbilayer").new()
    clipping:addChild(pb)
    pb:setPosition(-self.x,-self.y)
end

function GuideShade:checkPointInCircle(c_x,c_y)
    local d_x = math.abs(c_x - self.x)
    local d_y = math.abs(c_y - self.y)
    local distance = math.pow(d_x,2) + math.pow(d_y,2)
    if math.sqrt(distance) < self.r then
        return true
    end
    return false
end

function GuideShade:openTouch()
    local listener = cc.EventListenerTouchOneByOne:create()

    local contain = false
    local function onTouchBegan( touch,event )
        local pos = touch:getLocation()
        if self:checkPointInCircle(pos.x,pos.y) then
            contain = true
        else
            contain = false
        end
        return true  
    end

    local function onTouchMoved( touch,event )
    end

    local function onTouchEnded( touch,event )
        local pos = touch:getLocation()
        if contain and self:checkPointInCircle(pos.x,pos.y) then
            print('--in circle--')
        end
    end

    listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCH_BEGAN)
    listener:registerScriptHandler(onTouchMoved,cc.Handler.EVENT_TOUCH_MOVED)
    listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCH_ENDED)

    self:getEventDispatcher():addEventListenerWithSceneGraphPriority(listener,self)

    local function onNodeEvent(event)
        if event == 'exit' then
            self:getEventDispatcher():removeEventListener(listener)
        end 
    end
    self:registerScriptHandler(onNodeEvent)
end

return GuideShade

在createUI方法中用到的模板:这里写图片描述,所以点亮的地方是一个圆形,参数x,y为这个圆在世界坐标系中的位置。剪裁节点添加了屏蔽触摸的层,那么在GuideShade这个Node之下的控件将无法监听到触摸事件。

将GuideShade添加到MainScene中

function MainScene:onEnter() local _size = cc.Director:getInstance():getWinSize() local sp=cc.Sprite:create('res/HelloWorld.png') self:addChild(sp) sp:setPosition(_size.width/2,_size.height/2) self:createUI() self:openTouch() self:guide(_size) end function MainScene:guide(_size) local guideLayer = require('app/views/GuideShade').new(_size.width/3,_size.height/3) self:addChild(guideLayer) end

简易新手引导_第4张图片
由于屏蔽了触摸,2个按钮都不能点击,function GuideShade:checkPointInCircle(c_x,c_y)判断了点击点是否在圆内,只有当触摸开始的点在圆内以及结束点也在圆内时,输出了–in circle–。

现在视觉上除了Auto按钮上方的圆点亮之外,其他地方都蒙灰了,且点击圆之外的地方,都没有反应(屏蔽层有反应),但是点击圆内的位置也没有反应,所以需要在引导时将要引导的数据传递过来,在点击圆内时响应原本Auto按钮的事件。
下面是MainScene中添加了模拟数据后的完整代码:

local MainScene = class("MainScene", cc.load("mvc").ViewBase)

local _data = {['1'] = {normal = nil,pressed = nil,disabled = nil,event = nil,name = nil},
               ['2'] = {normal = nil,pressed = nil,disabled = nil,event = nil,name = nil}}

function MainScene:ctor()
    self:enableNodeEvents()
end

function MainScene:onEnter()
    local _size = cc.Director:getInstance():getWinSize()
    local sp=cc.Sprite:create('res/HelloWorld.png')
    self:addChild(sp)
    sp:setPosition(_size.width/2,_size.height/2)
    self:createUI()
    self:openTouch()
    self:guide(_size)
end

function MainScene:createUI()
    local _size = cc.Director:getInstance():getWinSize()
    local function btnClicked(sender,_type)
        print('--btn click--')
    end
    local btn = ccui.Button:create('res/DS07.png','res/DS08.png','res/DS09.png')
    self:addChild(btn)
    btn:setPosition(_size.width/3,_size.height/3)
    btn:addTouchEventListener(btnClicked)

    local function btnClicked2(sender,_type)
        print('--btn2 click--')
    end
    local btn2 = ccui.Button:create('res/DS10.png','res/DS11.png','res/DS12.png')
    self:addChild(btn2)
    btn2:setPosition(_size.width/3,_size.height/4.5)
    btn2:addTouchEventListener(btnClicked2)

    _data['1'].normal = 'res/DS07.png'
    _data['1'].pressed = 'res/DS08.png'
    _data['1'].disabled = 'res/DS09.png'
    _data['1'].event = btnClicked

    _data['2'].normal = 'res/DS10.png'
    _data['2'].pressed = 'res/DS11.png'
    _data['2'].disabled = 'res/DS12.png'
    _data['2'].event = btnClicked2
end

function MainScene:openTouch()
    local listener = cc.EventListenerTouchOneByOne:create()

    local function onTouchBegan( touch,event )
        print("--touchBegan--")
        return true  
    end

    local function onTouchMoved( touch,event )
        print("--touchMoved--")
    end

    local function onTouchEnded( touch,event )
        print("--touchEnded--")
    end

    listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCH_BEGAN)
    listener:registerScriptHandler(onTouchMoved,cc.Handler.EVENT_TOUCH_MOVED)
    listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCH_ENDED)

    self:getEventDispatcher():addEventListenerWithSceneGraphPriority(listener,self)

    local function onNodeEvent(event)
        if event == 'exit' then
            self:getEventDispatcher():removeEventListener(listener)
        end     
    end
    self:registerScriptHandler(onNodeEvent)
end

function MainScene:guide(_size)
    local guideLayer = require('app/views/GuideShade').new(_size.width/3,_size.height/3,_data)
    self:addChild(guideLayer)
end

return MainScene

_data中保存了2个按钮的数据,那么在创建GuideShade时传入这个数据,在开始结束都点在圆内时响应按钮的事件。

    local function onTouchEnded( touch,event )
        local pos = touch:getLocation()
        if contain and self:checkPointInCircle(pos.x,pos.y) then
            print('--in circle--')
            local func = self._data['1'].event
            if func then
                func()
            end
        end
    end

点圆可以看到
输出了–btn click–,原来点击Auto会输出2个–btn click–是因为,在回调函数中没有对事件进行判断,在点击到按钮的began和ended时都调用了回调函数,所以输出有2个,如果点到按钮之后moved会输出更多。而且回调函数有2个参数。在点击圆之后只是调用了这个回调函数,只输出了一次,并且没有2个参数,无法获得按钮以及事件,sender参数是可以通过_data记录并在调用回调函数时使用,在_data中添加一个sender,

local _data = {['1'] = {normal = nil,pressed = nil,disabled = nil,event = nil,name = nil,sender = nil},
               ['2'] = {normal = nil,pressed = nil,disabled = nil,event = nil,name = nil,sender = nil}}

_data['1'].sender = btn

print('--in circle--')
local func = self._data['1'].event
local sender = self._data['1'].sender
if func then
    func(sender)
end

这里用的是一个圆形的模板,那么就有一个体验不好的地方,如果点击的点在圆内,但是在按钮外边,仍然能响应事件,这里需要做优化。另外,原本点击按钮时,有按钮的点击效果,现在没有这个按下去的效果,因为根本不是真正的点中了按钮,不过在_data中记录有这个按钮的资源,可以再创建一个按钮摆放在那个位置。
如果_data中记录有按钮本身,那么可以有个更好的办法,在GuideShade中,

function GuideShade:createUI()
    local stencil = cc.Sprite:create('res/mask.png')
    self.r = stencil:getContentSize().width / 2 
    local clipping = cc.ClippingNode:create(stencil)
    clipping:setInverted(true)
    clipping:setAlphaThreshold(0.3)
    self:addChild(clipping,-1)
    clipping:setPosition(self.x,self.y) 

    local pb = require("app/views/Pingbilayer").new()
    clipping:addChild(pb)
    pb:setPosition(-self.x,-self.y)

    local sender = self._data['1'].sender
    local btn = sender:clone()
    self:addChild(btn)
    btn:setPosition(self.x,self.y)
end

createUI方法中直接clone了按钮并摆放在原本按钮上方,这个clone出的按钮和原来的按钮用同一个回调函数,并且2个参数都能获取
简易新手引导_第5张图片
简易新手引导_第6张图片
这样不仅有按钮的点击效果,有按下去的感觉,而且在回调函数中能获取按钮和事件2个参数。不过这样也有一个缺点,就是看起来整个按钮都在圆形的上方,视觉效果不好。在实际开发中,还需要根据需求选择合适的方案。

你可能感兴趣的:(简易新手引导)