lua 之 menu

这篇博客介绍了如何在 Lua 中创建和管理菜单,包括菜单项的创建、触控事件处理、菜单布局和动画效果。通过示例展示了使用 cc.MenuItem 和 cc.Menu 类创建不同类型的菜单项,如字体、图像和标签菜单项,并实现菜单项的点击事件和禁用状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

local    kTagMenu = 1
local    kTagMenu0 = 0
local    kTagMenu1 = 1

local MID_CALLBACK     = 1000
local MID_CALLBACK2    = 1001
local MID_DISABLED     = 1002
local MID_ENABLE       = 1003
local MID_CONFIG       = 1004
local MID_QUIT         = 1005
local MID_OPACITY      = 1006
local MID_ALIGN        = 1007
local MID_CALLBACK3    = 1008
local MID_BACKCALLBACK = 1009

--------------------------------------------------------------------
--
-- MenuLayerMainMenu
--
--------------------------------------------------------------------
local function MenuLayerMainMenu()
    local m_disabledItem = nil

    local ret = cc.Layer:create()

    -- Font Item
    local  spriteNormal = cc.Sprite:create(s_MenuItem, cc.rect(0,23*2,115,23))--创建一个精灵 第一个参数为图片 第二个参数为区域(x,y,width,height)
    local  spriteSelected = cc.Sprite:create(s_MenuItem, cc.rect(0,23*1,115,23))
    local  spriteDisabled = cc.Sprite:create(s_MenuItem, cc.rect(0,23*0,115,23))

    local  item1 = cc.MenuItemSprite:create(spriteNormal, spriteSelected, spriteDisabled)--创建精灵菜单项第一个正常时候,第二个点击时,第三个可以不设置

    local function menuCallback(sender)--回调函数,得到ret(layer)的父亲LayerMultiplex,每次只允许一个layer运行,切换过去
        cclog("menuCallback...")
        ret:getParent():switchTo(1)
    end

    item1:registerScriptTapHandler(menuCallback)--添加触控事件
    -- Image Item
    local function menuCallback2(sender)
        ret:getParent():switchTo(2)
    end

    local  item2 = cc.MenuItemImage:create(s_SendScore, s_PressSendScore)--创建图像菜单项
    item2:registerScriptTapHandler(menuCallback2)


    local schedulerEntry = nil
    local scheduler = cc.Director:getInstance():getScheduler()--得到当前实例的定时器
    local function allowTouches(dt)
        local  pDirector = cc.Director:getInstance()
        --pDirector:getTouchDispatcher():setPriority(cc.MENU_HANDLER_PRIORITY +1, ret)
        if nil ~=  schedulerEntry then 
            scheduler:unscheduleScriptEntry(schedulerEntry)
            schedulerEntry = nil
        end
        cclog("TOUCHES ALLOWED AGAIN")
    end


    local function menuCallbackDisabled(sender)
        -- hijack all touch events for 5 seconds
        local  pDirector = cc.Director:getInstance()
        --pDirector:getTouchDispatcher():setPriority(cc.MENU_HANDLER_PRIORITY -1, ret)
        schedulerEntry = scheduler:scheduleScriptFunc(allowTouches, 5, false)--每隔5秒执行
        cclog("TOUCHES DISABLED FOR 5 SECONDS")
    end

    -- Label Item (LabelAtlas)
    local  labelAtlas = cc.LabelAtlas:_create("0123456789", "fonts/labelatlas.png", 16, 24, string.byte('.'))--从map图中获取标签 4个参数 图中字符,图的地址,宽,高,从哪里开始
    local  item3 = cc.MenuItemLabel:create(labelAtlas)--创建标签菜单项 从map图中获取的标签
    item3:registerScriptTapHandler(menuCallbackDisabled)
    item3:setDisabledColor( cc.c3b(32,32,64) )--设置不同状态的颜色
    item3:setColor( cc.c3b(200,200,255) )

    local function menuCallbackEnable(sender)
        m_disabledItem:setEnabled(not m_disabledItem:isEnabled() )--反转操作
    end

    -- Font Item
    local item4 = cc.MenuItemFont:create("I toggle enable items")--创建字体菜单
    item4:registerScriptTapHandler(menuCallbackEnable)--设置点击事件

    item4:setFontSizeObj(20)--设置字体大小
    cc.MenuItemFont:setFontName("Marker Felt")--设置字体名字

    local function menuCallbackConfig(sender)
        ret:getParent():switchTo(3)
    end

    -- Label Item (cc.LabelBMFont)
    local  label = cc.Label:createWithBMFont("fonts/bitmapFontTest3.fnt", "configuration")--创建图片字体标签
    label:setAnchorPoint(cc.p(0.5, 0.5))--设置锚点为中间
    local  item5 = cc.MenuItemLabel:create(label)--创建标签菜单项
    item5:registerScriptTapHandler(menuCallbackConfig)

    -- Testing issue #500
    item5:setScale( 0.8 )--设置大小

    -- Events
    cc.MenuItemFont:setFontName("Marker Felt")
    local function menuCallbackBugsTest(pSender)
        ret:getParent():switchTo(4)
    end

    -- Bugs Item
    local item6 = cc.MenuItemFont:create("Bugs")--设置字体菜单
    item6:registerScriptTapHandler(menuCallbackBugsTest)

    local function onQuit(sender)
        cclog("onQuit item is clicked.")
    end

    -- Font Item
    local  item7 = cc.MenuItemFont:create("Quit")
    item7:registerScriptTapHandler(onQuit)

    local function menuMovingCallback(pSender)
        ret:getParent():switchTo(5)
    end

    local  item8 = cc.MenuItemFont:create("Remove menu item when moving")
    item8:registerScriptTapHandler(menuMovingCallback)

    local  color_action = cc.TintBy:create(0.5, 0, -255, -255)--设置颜色 上色时间 及颜色
    local  color_back = color_action:reverse()--类似消除颜色
    local  seq = cc.Sequence:create(color_action, color_back)--生成动作序列
    item7:runAction(cc.RepeatForever:create(seq))--一直重复

    local  menu = cc.Menu:create()--将各个菜单项添加到菜单menu中

    menu:addChild(item1)
    menu:addChild(item2)
    menu:addChild(item3)
    menu:addChild(item4)
    menu:addChild(item5)
    menu:addChild(item6)
    menu:addChild(item7)
    menu:addChild(item8)

    menu:alignItemsVertically()--纵向排列

    -- elastic effect
    local s = cc.Director:getInstance():getWinSize()--得到当前窗口的大小

    local i        = 0
    local child    = nil
    local pArray   = menu:getChildren()--得到孩子table
    local len      = table.getn(pArray)--table的长度
    local pObject  = nil
    for i = 0, len-1 do--遍历设置入场动画
        pObject = pArray[i + 1]
        if pObject == nil then
            break
        end
        child = pObject
        local dstPointX, dstPointY = child:getPosition()
        local offset = s.width/2 + 50
        if  i % 2 == 0 then
            offset = 0-offset
        end
        child:setPosition( cc.p( dstPointX + offset, dstPointY) )
        child:runAction( cc.EaseElasticOut:create(cc.MoveBy:create(2, cc.p(dstPointX - offset,0)), 0.35) )--缓冲动画,参数:动作效果,时间
    end

    m_disabledItem = item3
    item3:retain()

    m_disabledItem:setEnabled( false )

    ret:addChild(menu)
    menu:setPosition(cc.p(s.width/2, s.height/2))

--  local schedulerEntry = nil
    local function onNodeEvent(event)
        if event == "exit" then
            if (schedulerEntry ~= nil) then
                scheduler:unscheduleScriptEntry(schedulerEntry)
            end
            if m_disabledItem ~= nil then
--                m_disabledItem:release()
            end
        end
    end

    ret:registerScriptHandler(onNodeEvent)--注册当进入场景或者退出场景时要处理的事情

    return ret
end

--------------------------------------------------------------------
--
-- MenuLayer2
--
--------------------------------------------------------------------
local function MenuLayer2()
    local ret = cc.Layer:create()
    local m_centeredMenu = nil
    local m_alignedH = false

    local function alignMenusH()
        local i = 0
        for i=0, 1 do
            local menu = ret:getChildByTag(100+i)
            menu:setPosition( m_centeredMenu )
            if i==0 then
                -- TIP: if no padding, padding = 5
                menu:alignItemsHorizontally()--垂直排布 默认是5
                local x, y = menu:getPosition()
                menu:setPosition( cc.pAdd(cc.p(x, y), cc.p(0,30)) )
            else
                -- TIP: but padding is configurable
                menu:alignItemsHorizontallyWithPadding(40)--设置距离
                local x, y = menu:getPosition()
                menu:setPosition( cc.pSub(cc.p(x, y), cc.p(0,30)) )
            end
        end
    end

    local function alignMenusV()
        local i = 0
        for i=0, 1 do
            local menu = ret:getChildByTag(100+i)
            menu:setPosition( m_centeredMenu )
            if i==0 then
                -- TIP: if no padding, padding = 5
                menu:alignItemsVertically()
                local x, y = menu:getPosition()
                menu:setPosition( cc.pAdd(cc.p(x, y), cc.p(100,0)) )
            else
                -- TIP: but padding is configurable
                menu:alignItemsVerticallyWithPadding(40)
                local x, y = menu:getPosition()
                menu:setPosition( cc.pSub(cc.p(x, y), cc.p(100,0)) )
            end
        end
    end

    local function menuCallback(sender)
        ret:getParent():switchTo(0)
    end

    local function menuCallbackOpacity(tag, sender)
        local menu = sender:getParent()--得到当前的父类menu
        local opacity = menu:getOpacity()--不透明度
        if opacity == 128 then
            menu:setOpacity(255)
        else
            menu:setOpacity(128)
        end
    end

    local function menuCallbackAlign(sender)
        m_alignedH = not m_alignedH

        if m_alignedH then
            alignMenusH()
        else
            alignMenusV()
        end
    end

    local i = 0
    for i=0, 1 do
        local  item1 = cc.MenuItemImage:create(s_PlayNormal, s_PlaySelect)
        item1:registerScriptTapHandler(menuCallback)--回到最初菜单

        local  item2 = cc.MenuItemImage:create(s_HighNormal, s_HighSelect)
        item2:registerScriptTapHandler(menuCallbackOpacity)--设置菜单透明度

        local  item3 = cc.MenuItemImage:create(s_AboutNormal, s_AboutSelect)
        item3:registerScriptTapHandler(menuCallbackAlign)--改变布局

        item1:setScaleX( 1.5 )--设置x方向的放大缩小
        item2:setScaleX( 0.5 )
        item3:setScaleX( 0.5 )

        local  menu = cc.Menu:create()

        menu:addChild(item1)
        menu:addChild(item2)
        menu:addChild(item3)

        local s = cc.Director:getInstance():getWinSize()
        menu:setPosition(cc.p(s.width/2, s.height/2))

        menu:setTag( kTagMenu )

        ret:addChild(menu, 0, 100+i)--子类节点,z方向优先级,tag
        local x, y = menu:getPosition()
        m_centeredMenu = cc.p(x, y)
    end

    m_alignedH = true
    alignMenusH()

    return ret
end

--------------------------------------------------------------------
--
-- MenuLayer3
--
--------------------------------------------------------------------
local function MenuLayer3()
    local m_disabledItem = nil
    local ret = cc.Layer:create()
    local function menuCallback(sender)
        ret:getParent():switchTo(0)
    end

    local function menuCallback2(sender)
        cclog("Label clicked. Toogling AtlasSprite")
        m_disabledItem:setEnabled( not m_disabledItem:isEnabled() )
        m_disabledItem:stopAllActions()
    end

    local function menuCallback3(sender)
        cclog("MenuItemSprite clicked")
    end

    cc.MenuItemFont:setFontName("Marker Felt")
    cc.MenuItemFont:setFontSize(28)

    local  label = cc.Label:createWithBMFont("fonts/bitmapFontTest3.fnt", "Enable AtlasItem")--创建BITMAP的label
    label:setAnchorPoint(cc.p(0.5, 0.5))
    local  item1 = cc.MenuItemLabel:create(label)
    item1:registerScriptTapHandler(menuCallback2)

    local  item2 = cc.MenuItemFont:create("--- Go Back ---")
    item2:registerScriptTapHandler(menuCallback)

    local spriteNormal   = cc.Sprite:create(s_MenuItem,  cc.rect(0,23*2,115,23))
    local spriteSelected = cc.Sprite:create(s_MenuItem,  cc.rect(0,23*1,115,23))
    local spriteDisabled = cc.Sprite:create(s_MenuItem,  cc.rect(0,23*0,115,23))


    local  item3 = cc.MenuItemSprite:create(spriteNormal, spriteSelected, spriteDisabled)
    item3:registerScriptTapHandler(menuCallback3)
    m_disabledItem = item3
    item3:retain()
    m_disabledItem:setEnabled( false )

    local menu = cc.Menu:create()

    menu:addChild(item1)
    menu:addChild(item2)
    menu:addChild(item3)

    menu:setPosition( cc.p(0,0) )

    local s = cc.Director:getInstance():getWinSize()

    item1:setPosition( cc.p(s.width/2 - 150, s.height/2) )
    item2:setPosition( cc.p(s.width/2 - 200, s.height/2) )
    item3:setPosition( cc.p(s.width/2, s.height/2 - 100) )

    local  jump = cc.JumpBy:create(3, cc.p(400,0), 50, 4)--时间,目的坐标,跳的高度,跳的次数
    item2:runAction( cc.RepeatForever:create(cc.Sequence:create( jump, jump:reverse())))--重复做

    local  spin1 = cc.RotateBy:create(3, 360)--旋转,时间,角度
    local  spin2 = spin1:clone()--复制动作
    local  spin3 = spin1:clone()

    item1:runAction( cc.RepeatForever:create(spin1) )
    item2:runAction( cc.RepeatForever:create(spin2) )
    item3:runAction( cc.RepeatForever:create(spin3) )

    ret:addChild( menu )

    menu:setPosition(cc.p(0,0))

    local function onNodeEvent(event)
        if event == "exit" then
            if m_disabledItem ~= nil then
                --m_disabledItem:release()
            end
        end
    end

    ret:registerScriptHandler(onNodeEvent)

    return ret
end


--------------------------------------------------------------------
--
-- MenuLayer4
--
--------------------------------------------------------------------
local function MenuLayer4()
    local ret = cc.Layer:create()
    cc.MenuItemFont:setFontName("American Typewriter")
    cc.MenuItemFont:setFontSize(18)
    local title1 = cc.MenuItemFont:create("Sound")
    title1:setEnabled(false)--设置不能点击
    cc.MenuItemFont:setFontName( "Marker Felt" )
    cc.MenuItemFont:setFontSize(34)
    local  item1 = cc.MenuItemToggle:create(cc.MenuItemFont:create( "On" ))--toggle设置方法	

    local function menuCallback(tag, sender)
        cclog("selected item: tag: %d, index:%d", tag, sender:getSelectedIndex() )
    end

    local function backCallback(tag, sender)
        ret:getParent():switchTo(0)
    end

    item1:registerScriptTapHandler(menuCallback)
    item1:addSubItem(cc.MenuItemFont:create( "Off"))--增加toggle的内容

    cc.MenuItemFont:setFontName( "American Typewriter" )
    cc.MenuItemFont:setFontSize(18)
    local  title2 = cc.MenuItemFont:create( "Music" )
    title2:setEnabled(false)
    cc.MenuItemFont:setFontName( "Marker Felt" )
    cc.MenuItemFont:setFontSize(34)
    local item2 = cc.MenuItemToggle:create(cc.MenuItemFont:create( "On" ))
    item2:registerScriptTapHandler(menuCallback)
    item2:addSubItem(cc.MenuItemFont:create( "Off"))

    cc.MenuItemFont:setFontName( "American Typewriter" )
    cc.MenuItemFont:setFontSize(18)
    local  title3 = cc.MenuItemFont:create( "Quality" )
    title3:setEnabled( false )
    cc.MenuItemFont:setFontName( "Marker Felt" )
    cc.MenuItemFont:setFontSize(34)
    local item3 = cc.MenuItemToggle:create(cc.MenuItemFont:create( "High" ))
    item3:registerScriptTapHandler(menuCallback)
    item3:addSubItem(cc.MenuItemFont:create( "Low" ))

    cc.MenuItemFont:setFontName( "American Typewriter" )
    cc.MenuItemFont:setFontSize(18)
    local  title4 = cc.MenuItemFont:create( "Orientation" )
    title4:setEnabled(false)
    cc.MenuItemFont:setFontName( "Marker Felt" )
    cc.MenuItemFont:setFontSize(34)
    local item4 = cc.MenuItemToggle:create(cc.MenuItemFont:create( "Off"),
                                          cc.MenuItemFont:create( "33%" ),
                                          cc.MenuItemFont:create( "66%" ),
                                          cc.MenuItemFont:create( "100%"))
    item4:registerScriptTapHandler(menuCallback)

    -- you can change the one of the items by doing this
    item4:setSelectedIndex( 2 )

    cc.MenuItemFont:setFontName( "Marker Felt" )
    cc.MenuItemFont:setFontSize( 34 )

    local label = cc.Label:createWithBMFont("fonts/bitmapFontTest3.fnt", "go back")
    label:setAnchorPoint(cc.p(0.5, 0.5))
    local  back = cc.MenuItemLabel:create(label)
    back:registerScriptTapHandler(backCallback)

    local menu = cc.Menu:create()

    menu:addChild(title1)
    menu:addChild(title2)
    menu:addChild(item1 )
    menu:addChild(item2 )
    menu:addChild(title3)
    menu:addChild(title4)
    menu:addChild(item3 )
    menu:addChild(item4 )
    menu:addChild(back  )

    menu:alignItemsInColumns(2, 2, 2, 2, 1)--按行排列 每行个数

    ret:addChild(menu)

    local s = cc.Director:getInstance():getWinSize()
    menu:setPosition(cc.p(s.width/2, s.height/2))
    return ret
end

-- BugsTest
local function BugsTest()
    local ret = cc.Layer:create()
    local function issue1410MenuCallback(tag, pSender)
        local menu = pSender:getParent()
        menu:setEnabled(false)
        menu:setEnabled(true)
        cclog("NO CRASHES")
    end

    local function issue1410v2MenuCallback(tag, pSender)
        local menu = pSender:getParent()
        menu:setEnabled(true)
        menu:setEnabled(false)
        cclog("NO CRASHES. AND MENU SHOULD STOP WORKING")
    end

    local function backMenuCallback(tag, pSender)
        ret:getParent():switchTo(0)
    end


    local issue1410 = cc.MenuItemFont:create("Issue 1410")
    issue1410:registerScriptTapHandler(issue1410MenuCallback)
    local issue1410_2 = cc.MenuItemFont:create("Issue 1410 #2")
    issue1410_2:registerScriptTapHandler(issue1410v2MenuCallback)
    local back = cc.MenuItemFont:create("Back")
    back:registerScriptTapHandler(backMenuCallback)

    local menu = cc.Menu:create()
    menu:addChild(issue1410)
    menu:addChild(issue1410_2)
    menu:addChild(back)
    ret:addChild(menu)
    menu:alignItemsVertically()

    local s = cc.Director:getInstance():getWinSize()
    menu:setPosition(cc.p(s.width/2, s.height/2))
    return ret
end


local function RemoveMenuItemWhenMove()
    local ret = cc.Layer:create()
    local s = cc.Director:getInstance():getWinSize()

    local  label = cc.Label:createWithTTF("click item and move, should not crash", s_arialPath, 20)
    label:setAnchorPoint(cc.p(0.5, 0.5))
    label:setPosition(cc.p(s.width/2, s.height - 30))
    ret:addChild(label)

    local item = cc.MenuItemFont:create("item 1")
    item:retain()

    local back = cc.MenuItemFont:create("go back")
    local function goBack(tag, pSender)
        ret:getParent():switchTo(0)
    end

    back:registerScriptTapHandler(goBack)

    local menu = cc.Menu:create()
    menu:addChild(item)
    menu:addChild(back)

    ret:addChild(menu)
    menu:alignItemsVertically()

    menu:setPosition(cc.p(s.width/2, s.height/2))

    local function onTouchBegan(touch, event)
        return true
    end

    local function onTouchMoved(touch, event)
        if item ~= nil then
            item:removeFromParent(true)
            --item:release()
            --item = nil
        end
    end

    local listener = cc.EventListenerTouchOneByOne:create()--添加侦听事件
    listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCH_BEGAN )--注册
    listener:registerScriptHandler(onTouchMoved,cc.Handler.EVENT_TOUCH_MOVED )
    local eventDispatcher = ret:getEventDispatcher()
    eventDispatcher:addEventListenerWithFixedPriority(listener, -129)

    local function onNodeEvent(event)
        if event == "exit" then
           ret:getEventDispatcher():removeEventListener(listener)
        end
    end

    ret:registerScriptHandler(onNodeEvent)

    return ret
end

function MenuTestMain()
    cclog("MenuTestMain")
    local scene = cc.Scene:create()

    local  pLayer1 = MenuLayerMainMenu()
    local  pLayer2 = MenuLayer2()

    local  pLayer3 = MenuLayer3()
    local  pLayer4 = MenuLayer4()
    local  pLayer5 = BugsTest()
    local  pLayer6 = RemoveMenuItemWhenMove()

    local  layer = cc.LayerMultiplex:create(pLayer1,
                                            pLayer2,
                                            pLayer3,
                                            pLayer4,
                                            pLayer5,
                                            pLayer6 )--创建多个layer的集合 一次只有一个layer活着

    scene:addChild(layer, 0)
    scene:addChild(CreateBackMenuItem())
    return scene
end

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值