1. 程式人生 > >Cocos2d x 手遊聊天系統Demo實現 Lua實現

Cocos2d x 手遊聊天系統Demo實現 Lua實現

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

               

Cocos2d-x 手遊聊天系統Demo實現

 轉載請註明:IT_xiao小巫

   本篇部落格給大家分享的是一個手遊聊天系統,筆者也是第一次使用Cocos2d-x來實現這樣一個模組,其中有很多不清楚不明白的地方都是通過自己不斷摸索實現的,前面筆者對聊天系統做的簡單的需求分析,只是對聊天的一些元素進行的說明還不太夠專業。本篇部落格會給大家介紹如何實現一個手遊聊天Demo,會從程式碼層面上給大家做相關的說明,如有不對或者錯漏的地方請各位明確指出並糾正。


首先來給大家看一下動態效果圖:

 


本篇部落格內容大綱:

1. 載入Cocostudio製作的UI

2. Button的觸控事件監聽

3. ListView新增列表項並設定列表點選事件

4. 富文字實現(可顯示顏色文字和圖片、動畫)

5. 文字輸入框實現(解決pc鍵盤無法刪除字元的bug)

6. 動態往ListView新增列表項



一、載入Cocostudio製作的UI

  筆者所分享的這個Demo是通過Cocostudio的UI編輯器製作的,童鞋們也可自己製作更加好看的UI,不過一般都會有美工幫我們做好讓我使用的。如下圖所示:

 


  UI製作完之後,匯出專案,然後把資源複製到我們專案的res目錄下,筆者這裡是把ChatUI_1複製到了res下,然後我們使用Lua程式碼實現載入json檔案到我們的程式中去:

 ChatScene.widget = ccs.GUIReader:getInstance():widgetFromJsonFile( "ChatUI_1/ChatUI_1.json" )

我們在編輯器添加了多個物件:

WorldPanel、PartyPanel、ChatPanel分別對應世界、公會、私聊三個板塊,板塊下面對應其相應的子節點:WordList、PartyList、ChatList。

我們需要在程式中找到它們:

--[[============================findViews()找到UI控制元件============================]]--function ChatScene.findViews()    ChatScene.widget = ccs.GUIReader:getInstance():widgetFromJsonFile( "ChatUI_1/ChatUI_1.json" )    ChatScene.widget:setPosition( cc.p( 40, 40 ) )    loadListViewItemFromJson()    -- 獲得UI介面上的3個按鈕    worldButton = ChatScene.widget:getChildByTag(6)    partyButton = ChatScene.widget:getChildByTag(7)    chatButton = ChatScene.widget:getChildByTag(8)    -- 獲得三個每個按鈕對應的三個面板    wordPanel = ChatScene.widget:getChildByTag(5)    partyPanel = ChatScene.widget:getChildByTag(9)    chatPanel = ChatScene.widget:getChildByTag(10)    -- 獲得每個面板的ListView    worldList = wordPanel:getChildByTag(13)    partyList = partyPanel:getChildByTag(14)    chatList = chatPanel:getChildByTag(15)    -- 獲得輸入框    inputBox = ChatScene.widget:getChildByTag(11)    sendButton = ChatScene.widget:getChildByTag(12)    dialog = ChatScene.widget:getChildByTag(20)    chat = dialog:getChildByTag(21)    lahei = dialog:getChildByTag(22)    closeButton = dialog:getChildByTag(27)end

  每個UI物件有相應的Tag屬性,我們可以通過找到其父節點,然後呼叫getChildByTag傳進tag的值找到控制元件。只有找到這些控制元件,我們才能去使用它。


二、Button的觸控事件監聽

  筆者這個demo,通過監聽“世界”、“公會”、“私聊”三個按鈕來分別切換不同的板塊,按鈕的觸控監聽事件很簡單:

 -- 設定按鈕監聽事件    worldButton:addTouchEventListener(touchEvent)    partyButton:addTouchEventListener(touchEvent)    chatButton:addTouchEventListener(touchEvent)

--[[touchEvent觸控事件回撥方法]]--local function touchEvent( sender, eventType )    if sender:getTag() == TAG_WORLD_BUTTON then        wordPanel:setVisible(true)        partyPanel:setVisible(false)        chatPanel:setVisible(false)        dialog:setVisible(false)        ChatScene.setCurrentTag( TAG_WORLD )    elseif sender:getTag() == TAG_PARTY_BUTTON then        partyPanel:setVisible(true)        wordPanel:setVisible(false)        chatPanel:setVisible(false)        dialog:setVisible(false)        ChatScene.setCurrentTag( TAG_PARTY )    elseif sender:getTag() == TAG_CHAT_BUTTON then        partyPanel:setVisible(false)        wordPanel:setVisible(false)        chatPanel:setVisible(true)        dialog:setVisible(false)        ChatScene.setCurrentTag( TAG_CHAT )end

以上面這種方式就可以實現切換三個板塊了。


三、ListView新增列表項並設定列表點選事件

 我們可以看到效果圖裡面每個板塊下面有對應的列表,它是使用Cocos2d-x UI中的ListView所呈現的。

 筆者感覺使用ListView比較麻煩,這裡筆者給出相應的使用方法供大家參考:

--首先我們為ListView提供三組資料

 -- 初始化三組資料    local array = {}    for i = 1, 20 do        array[i] = string.format("請叫我巫大大%d", i - 1)    end    local array1 = {}    for i = 1, 20 do        array1[i] = string.format("公會開放啦%d", i - 1 )    end    local array2 = {}    for i = 1, 20 do        array2[i] = string.format("私聊列表項%d", i - 1 )    end

--設定預設模型

    -- 建立模型    local default_button = ccui.Button:create("cocosui/backtotoppressed.png", "cocosui/backtotopnormal.png")    default_button:setName("Title Button")    -- 建立預設item    local default_itme = ccui.Layout:create()    default_itme:setTouchEnabled(true)    default_itme:setContentSize(default_button:getContentSize())    default_button:setPosition(cc.p( default_itme:getContentSize().width / 2.0, default_itme:getContentSize().height / 2.0 ))    default_itme:addChild(default_button)    -- 設定模型    worldList:setItemModel(default_itme)

--新增自定義項

-- 獲得陣列的大小    local count = table.getn(array)    print("count:"..count)    -- 新增自定義item    for i = 1, count do        -- 建立一個Button        local custom_button = ccui.Button:create("cocosui/button.png", "cocosui/buttonHighlighted.png")        -- 設定Button名字        custom_button:setName("Title Button")        --  設定按鈕使用九宮(scale9)渲染器進行渲染        custom_button:setScale9Enabled(true)        -- 設定內容尺寸        custom_button:setContentSize(default_button:getContentSize())        -- 建立一個佈局        local custom_item = ccui.Layout:create()        -- 設定內容大小        custom_item:setContentSize(custom_button:getContentSize())        -- 設定位置        custom_button:setPosition(cc.p(custom_item:getContentSize().width / 2.0, custom_item:getContentSize().height / 2.0))        -- 往佈局中新增一個按鈕        custom_item:addChild(custom_button)        -- 往ListView中新增一個佈局        worldList:addChild(custom_item)    end

--每一項資料

 -- 設定item data    items_count = table.getn(worldList:getItems())    for i = 1, items_count do        -- 返回一個索引和引數相同的項.        local item = worldList:getItem( i - 1 )        local button = item:getChildByName("Title Button")        local index = worldList:getIndex(item)        button:setTitleText(array[index + 1])    end

--設定ListView的點選事件和滾動事件

    -- 設定ListView的監聽事件    worldList:addScrollViewEventListener(scrollViewEvent)    worldList:addEventListener(listViewEvent)

-- ListView點選事件回撥local function listViewEvent(sender, eventType)    -- 事件型別為點選結束    if eventType == ccui.ListViewEventType.ONSELECTEDITEM_END then        print("select child index = ",sender:getCurSelectedIndex())        if dialog:isVisible() == true then            dialog:setVisible(false)        else            ChatScene.showDialog()        end    endend-- 滾動事件方法回撥local function scrollViewEvent(sender, eventType)    -- 滾動到底部    if eventType == ccui.ScrollviewEventType.scrollToBottom then        print("SCROLL_TO_BOTTOM")        -- 滾動到頂部    elseif eventType == ccui.ScrollviewEventType.scrollToTop then        print("SCROLL_TO_TOP")    endend

四、 富文字實現(可顯示顏色文字和圖片、動畫)

   何為富文字?筆者的理解是有著豐富文字的展示方式,比如可以展示顏色文字、圖片、動畫、還有超連結的這種就叫富文字。以前舊的版本Cocos2d-x可能並未提供這方面的支援,至於是哪個版本支援的筆者也沒有去深究,筆者這裡使用版本是Cocos2d-x 3.2,它就提供了類似富文字的類,滿足基本的需求。

 


程式碼實現:

--[[==================RichText富文字=================]]--function ChatScene.RichText()    local richText = ccui.RichText:create()    richText:ignoreContentAdaptWithSize(false)    richText:setContentSize(cc.size(100, 100))    local re1 = ccui.RichElementText:create( 1, cc.c3b(255, 255, 255), 255, "This color is white. ", "Helvetica", 10 )    local re2 = ccui.RichElementText:create( 2, cc.c3b(255, 255,   0), 255, "And this is yellow. ", "Helvetica", 10 )    local re3 = ccui.RichElementText:create( 3, cc.c3b(0,   0, 255), 255, "This one is blue. ", "Helvetica", 10 )    local re4 = ccui.RichElementText:create( 4, cc.c3b(0, 255,   0), 255, "And green. ", "Helvetica", 10 )    local re5 = ccui.RichElementText:create( 5, cc.c3b(2550,   0), 255, "Last one is red ", "Helvetica", 10 )    local reimg = ccui.RichElementImage:create( 6, cc.c3b(255, 255, 255), 255, "cocosui/sliderballnormal.png" )    -- 新增ArmatureFileInfo, 由ArmatureDataManager管理    ccs.ArmatureDataManager:getInstance():addArmatureFileInfo( "cocosui/100/100.ExportJson" )    local arr = ccs.Armature:create( "100" )    arr:getAnimation():play( "Animation1" )    local recustom = ccui.RichElementCustomNode:create( 1, cc.c3b(255, 255, 255), 255, arr )    local re6 = ccui.RichElementText:create( 7, cc.c3b(255, 127,   0), 255, "Have fun!! ", "Helvetica", 10 )    richText:pushBackElement(re1)    richText:insertElement(re2, 1)    richText:pushBackElement(re3)    richText:pushBackElement(re4)    richText:pushBackElement(re5)    richText:insertElement(reimg, 2)    richText:pushBackElement(recustom)    richText:pushBackElement(re6)    richText:setLocalZOrder(10)    return richTextend

五、文字輸入框實現(解決pc鍵盤無法刪除字元的bug)

  CocostudioUI編輯器提供TextField(輸入框),筆者在這裡也對它進行了實現,聊天系統一般需要玩家輸入資訊,所以這裡提供了一個輸入框。但筆者在使用這個UI的時候,發現在win32平臺不能對輸入的文字進行刪除,但在移動裝置可以使用輸入法對它進行編輯,所以筆者在這裡做了相關的處理把這個bug修正了。

 --- 鍵盤事件監聽回撥方法    local function onkeyPressed(keycode, event)        print("keypress")        if keycode == cc.KeyCode.KEY_BACKSPACE then           local str = inputBox:getStringValue()            str = string.sub( str, 0, string.len( str ) - 1 )            inputBox:setText( str )                end    end        -- 鍵盤監聽事件    local keyListener = cc.EventListenerKeyboard:create()    keyListener:registerScriptHandler(onkeyPressed,cc.Handler.EVENT_KEYBOARD_PRESSED)    local eventDispatcher = ChatScene.uiLayer:getEventDispatcher()    eventDispatcher:addEventListenerWithSceneGraphPriority(keyListener, ChatScene.uiLayer)

通過以上方式,我們就可以使用簡拼的BackSpace對字元進行刪除了。大家請叫我活雷鋒。


六、動態往ListView新增列表項

  筆者想到聊天系統的列表是不斷重新整理的,所以可能需要實現動態新增列表項,其實這個實現很簡單的,只需要在程式碼中監聽相應的事件,然後往ListView新增一項就可以了。

這裡我監聽了傳送按鈕的點選事件,然後獲取到輸入框的文字,在把文字新增到列表項中去。

if sender:getTag() == TAG_SEND_BUTTON then        print("sendText...")        -- 獲得輸入框的文字        local value = inputBox:getStringValue()        local textView = ccui.Text:create(value,"Arial",20)        print("value:"..value)        if eventType == ccui.TouchEventType.began then--            local custom_text = ChatScene.RichText()            local custom_item = ccui.Layout:create()            custom_item:setContentSize( textView:getContentSize() )            textView:setPosition( cc.p( custom_item:getContentSize().width / 2.0, custom_item:getContentSize().height / 2.0 ) )            custom_item:addChild( textView )            -- 如果當前Tag為世界            if ChatScene.getCurrentTag() == TAG_WORLD then                -- 插入自定義項                worldList:insertCustomItem( custom_item, 0 )                --                worldList:addChild(custom_item)            elseif ChatScene.getCurrentTag() == TAG_PARTY then                --                partyList:addChild(custom_item)                partyList:insertCustomItem( custom_item, 0 )            elseif ChatScene.getCurrentTag() == TAG_CHAT then                --                chatList:addChild(custom_item)                chatList:insertCustomItem( custom_item, 0 )            end        end


以上基本是筆者這個聊天系統的重要內容,下面把完整的實現程式碼給大家:

--[[===============ChatSence聊天系統模組===============]]---- 類local ChatScene = {}ChatScene.uiLayer = nilChatScene.widget = nil-- 視窗大小local winSize = nil-- 獲得UI介面上的3個按鈕local worldButton = nillocal partyButton = nillocal chatButton = nil-- 獲得三個每個按鈕對應的三個面板local wordPanel = nillocal partyPanel = nillocal chatPanel = nil-- 獲得每個面板的ListViewlocal worldList = nillocal partyList = nillocal chatList = nil-- 列表項local listview_item = nillocal head_icon = nillocal level = nillocal name = nillocal text = nil-- 列表項個數local items_count = nil-- 獲得輸入框local inputBox = nillocal sendButton = nil-- 彈出對話方塊local dialog = nillocal chat = nillocal lahei = nillocal closeButton = nil-- 三個標記local flag = nillocal TAG_WORLD = 1 -- 標識世界local TAG_PARTY = 2 -- 標識公會local TAG_CHAT = 3 -- 標識私聊-- 一些按鈕的Taglocal TAG_WORLD_BUTTON = 1local TAG_PARTY_BUTTON = 2local TAG_CHAT_BUTTON = 3local TAG_SEND_BUTTON = 4local TAG_CHAT_BUTTON2 = 5local TAG_LAHEI_BUTTON = 6local TAG_CLOSE_BUTTON = 7-- 場景建立ChatScene.create = function()    local scene = cc.Scene:create()    scene:addChild( ChatScene.createChatLayer() )    return sceneend--[[touchEvent觸控事件回撥方法]]--local function touchEvent( sender, eventType )    if sender:getTag() == TAG_WORLD_BUTTON then        wordPanel:setVisible(true)        partyPanel:setVisible(false)        chatPanel:setVisible(false)        dialog:setVisible(false)        ChatScene.setCurrentTag( TAG_WORLD )    elseif sender:getTag() == TAG_PARTY_BUTTON then        partyPanel:setVisible(true)        wordPanel:setVisible(false)        chatPanel:setVisible(false)        dialog:setVisible(false)        ChatScene.setCurrentTag( TAG_PARTY )    elseif sender:getTag() == TAG_CHAT_BUTTON then        partyPanel:setVisible(false)        wordPanel:setVisible(false)        chatPanel:setVisible(true)        dialog:setVisible(false)        ChatScene.setCurrentTag( TAG_CHAT )    elseif sender:getTag() == TAG_SEND_BUTTON then        print("sendText...")        -- 獲得輸入框的文字        local value = inputBox:getStringValue()        local textView = ccui.Text:create(value,"Arial",20)        print("value:"..value)        if eventType == ccui.TouchEventType.began then--            local custom_text = ChatScene.RichText()            local custom_item = ccui.Layout:create()            custom_item:setContentSize( textView:getContentSize() )            textView:setPosition( cc.p( custom_item:getContentSize().width / 2.0, custom_item:getContentSize().height / 2.0 ) )            custom_item:addChild( textView )            -- 如果當前Tag為世界            if ChatScene.getCurrentTag() == TAG_WORLD then                -- 插入自定義項                worldList:insertCustomItem( custom_item, 0 )                --                worldList:addChild(custom_item)            elseif ChatScene.getCurrentTag() == TAG_PARTY then                --                partyList:addChild(custom_item)                partyList:insertCustomItem( custom_item, 0 )            elseif ChatScene.getCurrentTag() == TAG_CHAT then                --                chatList:addChild(custom_item)                chatList:insertCustomItem( custom_item, 0 )            end        end    elseif sender:getTag() == TAG_CHAT_BUTTON2 then        partyPanel:setVisible(false)        wordPanel:setVisible(false)        chatPanel:setVisible(true)        dialog:setVisible(false)    elseif sender:getTag() == TAG_LAHEI_BUTTON then        print("我就把你拉黑,逗比")    elseif sender:getTag() == TAG_CLOSE_BUTTON then        dialog:setVisible(false)    elseif sender:getTag() == 8 then        if eventType == ccui.TouchEventType.ended then            ChatScene.widget:setVisible( not ChatScene.widget:isVisible() )        end    endendlocal function onExit(strEventName)    ChatScene.uiLayer:release()    ChatScene.uiLayer = nilend--[[=================addOpenButton新增一個開啟的按鈕=================]]--function ChatScene.addOpenButton()    local openButton = ccui.Button:create() -- 建立一個按鈕    openButton:setTouchEnabled(true)-- 設定可觸控    openButton:loadTextures( "cocosui/animationbuttonnormal.png", "cocosui/animationbuttonpressed.png", "" )--載入紋理    openButton:setAnchorPoint( cc.p( 0, 0 ) )    openButton:setPosition( cc.p( winSize.width -100, winSize.height - 50 ) )    ChatScene.uiLayer:addChild(openButton, 1)    openButton:setTag(8)    openButton:addTouchEventListener(touchEvent)end--[[==============textFieldEvent輸入框監聽事件回撥方法==============]]--local function textFieldEvent(sender, eventType)    if eventType == ccui.TextFiledEventType.attach_with_ime then        print("attach_with_ime")    elseif eventType == ccui.TextFiledEventType.detach_with_ime then        print("detach_with_ime")    elseif eventType == ccui.TextFiledEventType.insert_text then        print("insert_text")    elseif eventType == ccui.TextFiledEventType.delete_backward then        print("delete_backward")    endend-- ListView點選事件回撥local function listViewEvent(sender, eventType)    -- 事件型別為點選結束    if eventType == ccui.ListViewEventType.ONSELECTEDITEM_END then        print("select child index = ",sender:getCurSelectedIndex())        if dialog:isVisible() == true then            dialog:setVisible(false)        else            ChatScene.showDialog()        end    endend-- 滾動事件方法回撥local function scrollViewEvent(sender, eventType)    -- 滾動到底部    if eventType == ccui.ScrollviewEventType.scrollToBottom then        print("SCROLL_TO_BOTTOM")        -- 滾動到頂部    elseif eventType == ccui.ScrollviewEventType.scrollToTop then        print("SCROLL_TO_TOP")    endend--[[====================createChatLayer建立聊天層====================]]--function ChatScene.createChatLayer()    ChatScene.uiLayer = cc.Layer:create()-- 建立ui層    print("getReferenceCount1:"..ChatScene.uiLayer:getReferenceCount())    winSize = cc.Director:getInstance():getWinSize()-- 獲得螢幕大小    ChatScene.setCurrentTag(TAG_WORLD)    ChatScene.addOpenButton()    ChatScene.findViews()    ChatScene.setTouchEnabled()    ChatScene.setTags()    ChatScene.addTouchEventListener()    -- 初始化三組資料    local array = {}    for i = 1, 20 do        array[i] = string.format("請叫我巫大大%d", i - 1)    end    local array1 = {}    for i = 1, 20 do        array1[i] = string.format("公會開放啦%d", i - 1 )    end    local array2 = {}    for i = 1, 20 do        array2[i] = string.format("私聊列表項%d", i - 1 )    end    -- 建立模型    local default_button = ccui.Button:create("cocosui/backtotoppressed.png", "cocosui/backtotopnormal.png")    default_button:setName("Title Button")    -- 建立預設item    local default_itme = ccui.Layout:create()    default_itme:setTouchEnabled(true)    default_itme:setContentSize(default_button:getContentSize())    default_button:setPosition(cc.p( default_itme:getContentSize().width / 2.0, default_itme:getContentSize().height / 2.0 ))    default_itme:addChild(default_button)    -- 設定模型    worldList:setItemModel(default_itme)                -- 這裡是5項    --    for i = 1, math.floor( count / 4 ) do    --        print("i:"..