15-zinx-Golang-MMO-世界聊天系统

前言

  • 要实现玩家的世界聊天,需要⼀个管理当前世界所有玩家的⼀个管理器,管理器应该拥有全部的当前在线玩家信息和当前世
    界的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 {
	//AOIManager 当前世界地图AOI的管理模块
	AoiMgr *AOIManager
	//当前全部在线的Players集合
	Players map[int32]*Player
	//保护Players集合的锁
	pLock sync.RWMutex
}

//提供一个对外的世界管理模块的句柄(全局)
var WorldMgrObj *WorldManager

//初始化方法
func init() {
	WorldMgrObj = &WorldManager{
		//创建世界AOI地图规划
		AoiMgr: NewAOIManager(AOI_MIN_X, AOI_MAX_X, AOI_CNTS_X, AOI_MIN_Y, AOI_MAX_Y, AOI_CNTS_Y),
		//初始化Player集合
		Players: make(map[int32]*Player),
	}
}

//添加一个玩家
func (wm *WorldManager) AddPlayer(player *Player) {
	wm.pLock.Lock()
	wm.Players[player.Pid] = player
	wm.pLock.Unlock()

	//将player添加到 AOIManager中
	wm.AoiMgr.AddToGridByPos(int(player.Pid), player.X, player.Z)
}

//删除一个玩家
func (wm *WorldManager) RemovePlayerByPid(pid int32) {
	//得到当前的玩家
	player := wm.Players[pid]
	//将玩家从AOIManager中删除
	wm.AoiMgr.RemoveFromGridbyPos(int(pid), player.X, player.Z)

	//将玩家从世界管理中删除
	wm.pLock.Lock()
	delete(wm.Players, pid)
	wm.pLock.Unlock()
}

//通过玩家ID查询Player对象
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 - 玩家上线添加到世界管理模块

  • mmo_game_zinx/main.go
//当前客户端建立连接之后的hook函数
func OnConnectionAdd(conn ziface.IConneciton) {
	//创建一个Player对象
	player := core.NewPlayer(conn)

	//给客户端发送MsgID:1的消息: 同步当前Player的ID给客户端
	player.SyncPid()

	//给客户端发送MsgID:200的消息: 同步当前Player的初始位置给客户端
	player.BroadCastStartPosition()

	//将当前新上线的玩家添加到WorldManager中
	core.WorldMgrObj.AddPlayer(player)

	fmt.Println("=====> Player pid = ", player.Pid, " is arrived <=====")
}

2 - 聊天业务API与实现

  • 实现思路
    在这里插入图片描述
  • src/mmo_game_zinx/main.go:玩家上线后绑定一个玩家ID的pid属性
//当前客户端建立连接之后的hook函数
func OnConnecionAdd(conn ziface.IConneciton) {
	//创建一个Player对象
	player := core.NewPlayer(conn)

	//给客户端发送MsgID:1的消息: 同步当前Player的ID给客户端
	player.SyncPid()

	//给客户端发送MsgID:200的消息: 同步当前Player的初始位置给客户端
	player.BroadCastStartPosition()

	//将当前新上线的玩家添加到WorldManager中
	core.WorldMgrObj.AddPlayer(player)

	//将该连接绑定一个Pid 玩家ID的属性
	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) {
	//1 解析客户端传递进来的proto协议
	proto_msg := &pb.Talk{}
	err := proto.Unmarshal(request.GetData(), proto_msg)
	if err != nil {
		fmt.Println("Talk Unmarshal error ", err)
		return
	}

	//2 当前的聊天数据是属于哪个玩家发送的
	pid, err := request.GetConnection().GetProperty("pid")

	//3 根据pid得到对应的player对象
	player := core.WorldMgrObj.GetPlayerByPid(pid.(int32))

	//4 将这个消息广播给其他全部在线的玩家
	player.Talk(proto_msg.Content)
}

  • src/mmo_game_zinx/core/player.go:添加广播方法Talk
//玩家广播世界聊天消息
func (p *Player) Talk(content string) {
	//1 组建MsgID:200 proto数据
	proto_msg := &pb.BroadCast{
		Pid: p.Pid,
		Tp:  1, //tp-1 代表聊天广播
		Data: &pb.BroadCast_Content{
			Content: content,
		},
	}
	//2 得到当前世界所有的在线玩家
	players := WorldMgrObj.GetAllPlayers()

	//3 向所有的玩家(包括自己) 发送MsgID:200消息
	for _, player := range players {
		//player分别给对应的客户端发送消息
		player.SendMsg(200, proto_msg)
	}
}
  • src/mmo_game_zinx/main.go:世界聊天路由业务注册
func main() {
	//创建zinx server句柄
	s := znet.NewServer("MMO Game Zinx")

	//连接创建和销毁的HOOK钩子函数
	s.SetOnConnStart(OnConnecionAdd)

	//注册一些路由业务
	s.AddRouter(2, &apis.WorldChatApi{})

	//启动服务
	s.Serve()
}

四、世界聊天测试

  • 测试结论
    • 可以看到palyer1发送的消息player2可以看到
    • player2发送的消息player1也可以看到
      在这里插入图片描述

五、目录结构与完整源码

在这里插入图片描述
点击下载完整源码:mmo_game_zinxV2.0
点击下载对应客户端:mmo_game_u3d_client

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无休止符

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值