前言
要实现玩家的世界聊天,需要⼀个管理当前世界所有玩家的⼀个管理器,管理器应该拥有全部的当前在线玩家信息和当前世 界的AOI划分规则。⽅便玩家与玩家之间进⾏聊天,同步位置等功能
一、世界聊天实现
1 - 实现思路
2 - 聊天协议定义
mmo_game_zinx/pb/msg.proto :增加世界聊天消息,执⾏build.sh⽣成新的 msg.proto.go ⽂件
message Talk{
string Content= 1 ;
}
二、世界管理模块
1 - 实现思路
需求分析 :因为世界聊天消息需要广播给其他玩家,我们就需要获取到所有的玩家,这里使用世界模块来进行管理
2 - 添加世界管理对象
mmo_game_zinx/core/world_manager.go
package core
import "sync"
type WorldManager struct {
AoiMgr * AOIManager
Players map [ int32 ] * Player
pLock sync. RWMutex
}
var WorldMgrObj * WorldManager
func init ( ) {
WorldMgrObj = & WorldManager{
AoiMgr: NewAOIManager ( AOI_MIN_X, AOI_MAX_X, AOI_CNTS_X, AOI_MIN_Y, AOI_MAX_Y, AOI_CNTS_Y) ,
Players: make ( map [ int32 ] * Player) ,
}
}
func ( wm * WorldManager) AddPlayer ( player * Player) {
wm. pLock. Lock ( )
wm. Players[ player. Pid] = player
wm. pLock. Unlock ( )
wm. AoiMgr. AddToGridByPos ( int ( player. Pid) , player. X, player. Z)
}
func ( wm * WorldManager) RemovePlayerByPid ( pid int32 ) {
player := wm. Players[ pid]
wm. AoiMgr. RemoveFromGridbyPos ( int ( pid) , player. X, player. Z)
wm. pLock. Lock ( )
delete ( wm. Players, pid)
wm. pLock. Unlock ( )
}
func ( wm * WorldManager) GetPlayerByPid ( pid int32 ) * Player {
wm. pLock. RLock ( )
defer wm. pLock. RUnlock ( )
return wm. Players[ pid]
}
func ( wm * WorldManager) GetAllPlayers ( ) [ ] * Player {
wm. pLock. RLock ( )
defer wm. pLock. RUnlock ( )
players := make ( [ ] * Player, 0 )
for _ , p := range wm. Players {
players = append ( players, p)
}
return players
}
三、业务集成世界管理模块
1 - 玩家上线添加到世界管理模块
func OnConnectionAdd ( conn ziface. IConneciton) {
player := core. NewPlayer ( conn)
player. SyncPid ( )
player. BroadCastStartPosition ( )
core. WorldMgrObj. AddPlayer ( player)
fmt. Println ( "=====> Player pid = " , player. Pid, " is arrived <=====" )
}
2 - 聊天业务API与实现
实现思路 src/mmo_game_zinx/main.go :玩家上线后绑定一个玩家ID的pid属性
func OnConnecionAdd ( conn ziface. IConneciton) {
player := core. NewPlayer ( conn)
player. SyncPid ( )
player. BroadCastStartPosition ( )
core. WorldMgrObj. AddPlayer ( player)
conn. SetProperty ( "pid" , player. Pid)
fmt. Println ( "=====> Player pid = " , player. Pid, " is arrived <=====" )
}
src/mmo_game_zinx/apis/world_chat.go
package apis
import (
"fmt"
"google.golang.org/protobuf/proto"
"mmo_game_zinx/core"
pb "mmo_game_zinx/pb"
"zinx/ziface"
"zinx/znet"
)
type WorldChatApi struct {
znet. BaseRouter
}
func ( wc * WorldChatApi) Handle ( request ziface. IRequest) {
proto_msg := & pb. Talk{ }
err := proto. Unmarshal ( request. GetData ( ) , proto_msg)
if err != nil {
fmt. Println ( "Talk Unmarshal error " , err)
return
}
pid, err := request. GetConnection ( ) . GetProperty ( "pid" )
player := core. WorldMgrObj. GetPlayerByPid ( pid. ( int32 ) )
player. Talk ( proto_msg. Content)
}
src/mmo_game_zinx/core/player.go :添加广播方法Talk
func ( p * Player) Talk ( content string ) {
proto_msg := & pb. BroadCast{
Pid: p. Pid,
Tp: 1 ,
Data: & pb. BroadCast_Content{
Content: content,
} ,
}
players := WorldMgrObj. GetAllPlayers ( )
for _ , player := range players {
player. SendMsg ( 200 , proto_msg)
}
}
src/mmo_game_zinx/main.go :世界聊天路由业务注册
func main ( ) {
s := znet. NewServer ( "MMO Game Zinx" )
s. SetOnConnStart ( OnConnecionAdd)
s. AddRouter ( 2 , & apis. WorldChatApi{ } )
s. Serve ( )
}
四、世界聊天测试
测试结论
可以看到palyer1发送的消息player2可以看到 player2发送的消息player1也可以看到
五、目录结构与完整源码
点击下载完整源码:mmo_game_zinxV2.0 点击下载对应客户端:mmo_game_u3d_client