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(255, 0, 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:"..