公会系统:guild_chat_panel.lua
```lua
-- game/ui/guild_chat_panel.lua
-- 公会聊天面板UI,实现完整的聊天界面
local utils = require("core.utils")
local class = require("core.class")
local mvc = require("core.mvc")
local event = require("core.event")
local chatManager = require("modules.chat_manager")
local guildManager = require("modules.guild_manager")
local GuildChatPanelView = mvc.View:extend("GuildChatPanelView")
function GuildChatPanelView:onBind()
-- 获取UI组件
self.chatContainer = self:getComponent("ChatContainer", "Transform")
self.chatTemplate = self:getComponent("ChatTemplate", "GameObject")
self.chatInput = self:getComponent("ChatInput", "InputField")
self.sendButton = self:getComponent("SendButton", "Button")
-- 频道切换按钮
self.worldButton = self:getComponent("WorldButton", "Button")
self.guildButton = self:getComponent("GuildButton", "Button")
self.privateButton = self:getComponent("PrivateButton", "Button")
-- 成员列表
self.memberList = self:getComponent("MemberList", "Transform")
self.memberTemplate = self:getComponent("MemberTemplate", "GameObject")
-- 私聊面板
self.privatePanel = self:getComponent("PrivatePanel", "GameObject")
self.privateChatContainer = self:getComponent("PrivateChatContainer", "Transform")
-- 表情按钮
self.emojiButton = self:getComponent("EmojiButton", "Button")
self.emojiPanel = self:getComponent("EmojiPanel", "GameObject")
-- 隐藏模板
self.chatTemplate:SetActive(false)
self.memberTemplate:SetActive(false)
self.emojiPanel:SetActive(false)
-- 创建聊天消息缓存池
self.messagePool = {}
self.maxPoolSize = 20
-- 绑定按钮事件
self:BindButtonEvents()
-- 注册UI事件
self:RegisterUIEvents()
-- 初始化表情面板
self:InitEmojiPanel()
end
function GuildChatPanelView:BindButtonEvents()
-- 发送按钮
self.sendButton.onClick:AddListener(function()
event.emit("GUILD_CHAT_SEND_CLICKED")
end)
-- 频道切换
self.worldButton.onClick:AddListener(function()
event.emit("GUILD_CHAT_SWITCH_CHANNEL", chatManager.ChannelType.WORLD)
end)
self.guildButton.onClick:AddListener(function()
event.emit("GUILD_CHAT_SWITCH_CHANNEL", chatManager.ChannelType.GUILD)
end)
self.privateButton.onClick:AddListener(function()
event.emit("GUILD_CHAT_OPEN_PRIVATE_LIST")
end)
-- 表情按钮
self.emojiButton.onClick:AddListener(function()
self.emojiPanel:SetActive(not self.emojiPanel.activeSelf)
end)
end
function GuildChatPanelView:RegisterUIEvents()
-- 监听频道切换
event.on("CHAT_CHANNEL_CHANGED", function(channelType)
self:UpdateChannelUI(channelType)
end)
-- 监听新消息
event.on("CHAT_MESSAGE_ADDED", function(chatMessage)
self:OnNewMessage(chatMessage)
end)
-- 监听历史消息加载
event.on("CHAT_HISTORY_LOADED", function(channelType, messages)
if channelType == chatManager:GetCurrentChannel() then
self:RefreshMessageList(messages)
end
end)
-- 监听成员列表加载
event.on("GUILD_MEMBERS_LOADED", function(members)
self:RefreshMemberList(members)
end)
-- 监听私聊会话添加
event.on("CHAT_PRIVATE_SESSION_ADDED", function(session)
self:OnPrivateSessionAdded(session)
end)
end
function GuildChatPanelView:InitEmojiPanel()
local emojis = {"笑", "哭", "色", "嘘", "酷", "怒", "怕", "棒", "拉"}
for i, emoji in ipairs(emojis) do
local emojiButton = CS.UnityEngine.Object.Instantiate(self.emojiButton.transform, self.emojiPanel.transform)
emojiButton.gameObject:SetActive(true)
local text = emojiButton:GetComponentInChildren(typeof(CS.UnityEngine.UI.Text))
if text then
text.text = emoji
end
local btn = emojiButton:GetComponent(typeof(CS.UnityEngine.UI.Button))
btn.onClick:AddListener(function()
self.chatInput.text = self.chatInput.text .. emoji
end)
end
self.emojiButton.transform:SetAsLastSibling()
end
-- 更新频道UI
function GuildChatPanelView:UpdateChannelUI(channelType)
local buttons = {
[chatManager.ChannelType.WORLD] = self.worldButton,
[chatManager.ChannelType.GUILD] = self.guildButton,
[chatManager.ChannelType.PRIVATE] = self.privateButton
}
-- 更新按钮状态
for type, button in pairs(buttons) do
local colors = button.colors
if type == channelType then
colors.normalColor = CS.UnityEngine.Color(0.3, 0.5, 1, 1)
colors.highlightedColor = CS.UnityEngine.Color(0.4, 0.6, 1, 1)
else
colors.normalColor = CS.UnityEngine.Color(0.8, 0.8, 0.8, 1)
colors.highlightedColor = CS.UnityEngine.Color(0.9, 0.9, 0.9, 1)
end
button.colors = colors
end
-- 刷新消息列表
self:RefreshMessageList(chatManager:GetMessages(channelType))
end
-- 刷新消息列表
function GuildChatPanelView:RefreshMessageList(messages)
-- 清空现有消息
for i = 1, self.chatContainer.childCount do
local child = self.chatContainer:GetChild(i - 1)
self:RecycleMessageItem(child.gameObject)
end
-- 添加新消息
for i, chatMessage in ipairs(messages) do
self:AddMessageItem(chatMessage)
end
-- 滚动到底部
CS.CoroutineUtility.StartCoroutine(function()
CS.UnityEngine.Yield(CS.UnityEngine.WaitForEndOfFrame())
local scrollRect = self.chatContainer:GetComponent(typeof(CS.UnityEngine.UI.ScrollRect))
if scrollRect then
scrollRect.verticalNormalizedPosition = 0
end
end)
end
-- 添加消息项
function GuildChatPanelView:AddMessageItem(chatMessage)
local messageItem = self:GetMessageItem()
messageItem.transform:SetParent(self.chatContainer, false)
-- 获取组件
local nameLabel = messageItem.transform:Find("NameLabel"):GetComponent(typeof(CS.UnityEngine.UI.Text))
local timeLabel = messageItem.transform:Find("TimeLabel"):GetComponent(typeof(CS.UnityEngine.UI.Text))
local contentLabel = messageItem.transform:Find("ContentLabel"):GetComponent(typeof(CS.UnityEngine.UI.Text))
local channelLabel = messageItem.transform:Find("ChannelLabel"):GetComponent(typeof(CS.UnityEngine.UI.Text))
local levelLabel = messageItem.transform:Find("LevelLabel"):GetComponent(typeof(CS.UnityEngine.UI.Text))
-- 填充数据
if nameLabel then
nameLabel.text = chatMessage.sender_name
end
if timeLabel then
timeLabel.text = chatManager:FormatTime(chatMessage.timestamp)
end
if contentLabel then
contentLabel.text = chatMessage.content
end
if channelLabel then
channelLabel.text = chatManager:GetMessageTypeName(chatMessage)
end
if levelLabel then
levelLabel.text = "Lv." .. chatMessage.level
end
-- 设置VIP等级颜色
local vipColor = self:GetVIPColor(chatMessage.vip_level)
if nameLabel then
nameLabel.color = vipColor
end
-- 保存消息数据
local luaBehaviour = messageItem:GetComponent(typeof(CS.LuaBehaviour))
if not luaBehaviour then
luaBehaviour = messageItem:AddComponent(typeof(CS.LuaBehaviour))
end
luaBehaviour:SetLuaData("chatMessage", chatMessage)
-- 绑定点击事件(用于@功能)
local button = messageItem:GetComponent(typeof(CS.UnityEngine.UI.Button))
if button then
button.onClick:AddListener(function()
self:OnMessageClicked(chatMessage)
end)
end
end
-- 消息点击事件
function GuildChatPanelView:OnMessageClicked(chatMessage)
-- 在输入框中@玩家
self.chatInput.text = self.chatInput.text .. "@" .. chatMessage.sender_name .. " "
self.chatInput:ActivateInputField()
end
-- 获取消息项(从池中或创建新项)
function GuildChatPanelView:GetMessageItem()
if #self.messagePool > 0 then
local item = table.remove(self.messagePool)
item:SetActive(true)
return item
end
return CS.UnityEngine.Object.Instantiate(self.chatTemplate, self.chatContainer)
end
-- 回收消息项到池中
function GuildChatPanelView:RecycleMessageItem(item)
if #self.messagePool < self.maxPoolSize then
item:SetActive(false)
table.insert(self.messagePool, item)
else
CS.UnityEngine.Object.Destroy(item)
end
end
-- 获取VIP颜色
function GuildChatPanelView:GetVIPColor(vipLevel)
if vipLevel >= 10 then
return CS.UnityEngine.Color(1, 0.5, 0, 1) -- 金色
elseif vipLevel >= 5 then
return CS.UnityEngine.Color(0.8, 0.4, 1, 1) -- 紫色
elseif vipLevel >= 3 then
return CS.UnityEngine.Color(0, 0.8, 1, 1) -- 蓝色
else
return CS.UnityEngine.Color(1, 1, 1, 1) -- 白色
end
end
-- 刷新成员列表
function GuildChatPanelView:RefreshMemberList(members)
-- 清空现有成员
for i = 1, self.memberList.childCount do
CS.UnityEngine.Object.Destroy(self.memberList:GetChild(i - 1).gameObject)
end
-- 添加成员
for i, member in ipairs(members) do
self:AddMemberItem(member)
end
end
-- 添加成员项
function GuildChatPanelView:AddMemberItem(member)
local memberItem = CS.UnityEngine.Object.Instantiate(self.memberTemplate, self.memberList)
memberItem:SetActive(true)
-- 获取组件
local nameLabel = memberItem.transform:Find("NameLabel"):GetComponent(typeof(CS.UnityEngine.UI.Text))
local levelLabel = memberItem.transform:Find("LevelLabel"):GetComponent(typeof(CS.UnityEngine.UI.Text))
local positionLabel = memberItem.transform:Find("PositionLabel"):GetComponent(typeof(CS.UnityEngine.UI.Text))
local onlineIndicator = memberItem.transform:Find("OnlineIndicator"):GetComponent(typeof(CS.UnityEngine.UI.Image))
-- 填充数据
if nameLabel then
nameLabel.text = member.player_name
end
if levelLabel then
levelLabel.text = "Lv." .. member.level
end
if positionLabel then
positionLabel.text = guildManager.GetPositionName(member.position)
end
if onlineIndicator then
onlineIndicator.color = member.is_online and CS.UnityEngine.Color.green or CS.UnityEngine.Color.gray
end
-- 绑定点击事件(私聊)
local button = memberItem:GetComponent(typeof(CS.UnityEngine.UI.Button))
if button then
button.onClick:AddListener(function()
self:OnMemberClicked(member)
end)
end
end
-- 成员点击事件
function GuildChatPanelView:OnMemberClicked(member)
-- 打开私聊
event.emit("GUILD_CHAT_OPEN_PRIVATE", member.player_id, member.player_name)
end
-- 私聊会话添加
function GuildChatPanelView:OnPrivateSessionAdded(session)
-- 更新私聊列表UI
utils.print("新的私聊会话: " .. session.user_name)
end
-- 新消息处理
function GuildChatPanelView:OnNewMessage(chatMessage)
-- 如果是当前频道的消息,添加到列表
if chatMessage.type == chatManager:GetCurrentChannel() then
self:AddMessageItem(chatMessage)
-- 滚动到底部
CS.CoroutineUtility.StartCoroutine(function()
CS.UnityEngine.Yield(CS.UnityEngine.WaitForEndOfFrame())
local scrollRect = self.chatContainer:GetComponent(typeof(CS.UnityEngine.UI.ScrollRect))
if scrollRect then
scrollRect.verticalNormalizedPosition = 0
end
end)
end
end
-- 清理
function GuildChatPanelView:destroy()
-- 清理对象池
for _, item in ipairs(self.messagePool) do
CS.UnityEngine.Object.Destroy(item)
end
self.messagePool = {}
end
local GuildChatPanelController = mvc.Controller:extend("GuildChatPanelController")
function GuildChatPanelController:onBind()
-- 初始化聊天管理器
self.chatManager = chatManager.getModule("ChatManager")
self.guildManager = guildManager.getModule("GuildManager")
-- 注册事件
self:RegisterControllerEvents()
-- 初始化UI
self:InitializeUI()
-- 加载初始数据
self:LoadInitialData()
end
function GuildChatPanelController:RegisterControllerEvents()
-- 发送消息
event.on("GUILD_CHAT_SEND_CLICKED", function()
self:OnSendClicked()
end)
-- 切换频道
event.on("GUILD_CHAT_SWITCH_CHANNEL", function(channelType)
self:OnSwitchChannel(channelType)
end)
-- 发送成功
event.on("CHAT_SEND_SUCCESS", function(chatMessage)
self:OnSendSuccess(chatMessage)
end)
-- 发送失败
event.on("CHAT_SEND_FAILED", function(errorMsg)
self:OnSendFailed(errorMsg)
end)
-- 打开私聊
event.on("GUILD_CHAT_OPEN_PRIVATE", function(userId, userName)
self:OnOpenPrivate(userId, userName)
end)
end
function GuildChatPanelController:InitializeUI()
-- 设置初始频道
self.view:UpdateChannelUI(self.chatManager:GetCurrentChannel())
-- 加载成员列表
if self.guildManager and self.guildManager:IsInGuild() then
local members = self.guildManager:GetMembers()
if #members > 0 then
self.view:RefreshMemberList(members)
else
self.guildManager:RequestGuildMembers(function(success, members)
if success then
self.view:RefreshMemberList(members)
end
end)
end
end
end
function GuildChatPanelController:LoadInitialData()
-- 加载当前频道的历史消息
local currentChannel = self.chatManager:GetCurrentChannel()
local messages = self.chatManager:GetMessages(currentChannel)
if #messages > 0 then
self.view:RefreshMessageList(messages)
else
self.chatManager:RequestChatHistory(currentChannel)
end
end
function GuildChatPanelController:OnSendClicked()
local content = self.view.chatInput.text
if not content or #content == 0 then
return
end
-- 提取@的用户ID
local atUserIds = self:ExtractAtUserIds(content)
-- 发送消息
local success, errorMsg = self.chatManager:SendMessage(
self.chatManager:GetCurrentChannel(),
content,
nil,
atUserIds
)
if success then
-- 清空输入框
self.view.chatInput.text = ""
else
utils.print("发送失败: " .. errorMsg)
end
end
function GuildChatPanelController:OnSwitchChannel(channelType)
self.chatManager:SwitchChannel(channelType)
end
function GuildChatPanelController:OnSendSuccess(chatMessage)
utils.print("消息发送成功")
end
function GuildChatPanelController:OnSendFailed(errorMsg)
utils.print("消息发送失败: " .. errorMsg)
-- 显示错误提示
self:ShowToast(errorMsg)
end
function GuildChatPanelController:OnOpenPrivate(userId, userName)
utils.print("打开私聊: " .. userName)
-- 切换到私聊频道
self.chatManager:SwitchChannel(chatManager.ChannelType.PRIVATE)
end
-- 提取@的用户ID
function GuildChatPanelController:ExtractAtUserIds(content)
local atUserIds = {}
-- 解析@用户名,转换为用户ID
local pattern = "@([^%s]+)"
for username in string.gmatch(content, pattern) do
local member = self.guildManager:GetMemberByName(username)
if member then
table.insert(atUserIds, member.player_id)
end
end
return atUserIds
end
-- 显示Toast提示
function GuildChatPanelController:ShowToast(message)
CS.UIManager.Instance:ShowToast(message, 2)
end
return {
View = GuildChatPanelView,
Controller = GuildChatPanelController
}
```