Zinx下MMO游戏具体实现-03世界聊天、上线的位置信息同步、移动位置信息广播、玩家下线

Zinx下MMO游戏具体实现-03世界聊天、上线的位置信息同步、移动位置信息广播、玩家下线

1.世界聊天
1.1.在msg.proto中添加一个message Talk
//聊天数据(client 发送给 server)
message Talk{
	string Content=1;
}

运行build.go生成go文件

1.2.在创建player的时候,给conn配置一个链接属性,作用是从conn中得到pid从而得到player对象
//当前客户端建立链接之后触发Hook函数
func OnConnectionAdd(conn ziface.IConnection) {
	......
	//给conn添加一个属性 pid属性
	conn.SetProperty("pid", p.Pid)
	......
}
1.3.给player添加广播消息的方法
func (p *Player) SendTalkMsgToAll(content string) {
	/*
	message BroadCast{
	int32 Pid=1;
	int32 Tp=2;
	oneof Data {
		string Content=3;
		Position P=4;
		int32 ActionData=5;
	}
}
	 */
	//定义一个广播的proto消息数据类型
	proto_msg := &pb.BroadCast{
		Pid:p.Pid,
		Tp:1,
		Data: &pb.BroadCast_Content{
			Content:content,
		},
	}


	//获取全部的在线玩家有哪些
	players := WorldMgrObj.GetAllPlayers()

	//向全部的玩家进行广播 proto_msg 数据
	for  _, player := range players {
		player.SendMsg(200, proto_msg)
	}
}
1.4.在main中添加一个路由,放在apis文件夹中,改变Handle方法

在Handle中将客户端发来的message进行解析并广播

func main() {
	......
	//针对MsgID2 建立路由业务
	s.AddRouter(2, &apis.WorldChat{})
	......
}
type WorldChat struct {
	net.BaseRouter
}

func (wc *WorldChat) Handle(request ziface.IRequest) {
	//1 解析客户端传递进来的protobuf数据
	proto_msg := &pb.Talk{}
	if err := proto.Unmarshal(request.GetMsg().GetMsgData(), proto_msg);err != nil {
		fmt.Println("Talk message unmarshal error ", err)
		return
	}

	//通过获取链接属性,得到当前的玩家ID
	pid, err := request.GetConnection().GetProperty("pid")
	if err != nil {
		fmt.Println("get Pid error ", err)
		return
	}

	//通过pid 来得到对应的player对象
	player := core.WorldMgrObj.GetPlayerByPid(pid.(int32))

	// 当前的聊天数据广播给全部的在线玩家
	//当前玩家的windows客户端发送过来的消息
	player.SendTalkMsgToAll(proto_msg.GetContent())

}
2.上线位置信息同步
2.1.添加一个message SyncPlayers用于同步周围人的位置消息
//告知当前玩家 周边都有哪些玩家的位置信息
message SyncPlayers{
	repeated Player ps=1;
}
//其中一个玩家的信息
message Player{
	int32 Pid=1;
	Position P=2;
}
2.2.在player中添加同步位置消息的方法
//将自己的消息同步给周边的玩家
func (p *Player) SyncSurrounding() {
	//获取当前玩家的周边九宫格的玩家有哪些?
	players := p.GetSurroundingPlayers()

	//构建一个广播消息200, 循环全部players 分别给player对应的客户端发送200消息(让其他玩家看见当前玩家)
	proto_msg := &pb.BroadCast{
		Pid:p.Pid,
		Tp:2,
		Data: &pb.BroadCast_P{
			P:&pb.Position{
				X:p.X,
				Y:p.Y,
				Z:p.Z,
				V:p.V,
			},
		},
	}

	//将当前玩家id和位置消息发送给周边玩家(发送多次)
	for _, player := range players {
		player.SendMsg(200, proto_msg)
	}

	//将其他玩家告诉当前玩家  (让当前玩家能够看见周边玩家的坐标)
	//构建一个202消息  players的信息 告知当前玩家 p.send(202, ... )
	//得到全部周边玩家的player集合message Player
	players_proto_msg := make([]*pb.Player, 0, len(players))
	for _, player := range players {
		//制作一个message Player 消息
		p := &pb.Player{
			Pid:player.Pid,
			P:&pb.Position{
				X:player.X,
				Y:player.Y,
				Z:player.Z,
				V:player.V,
			},
		}

		players_proto_msg = append(players_proto_msg, p)
	}
	//创建一个 Message SyncPlayers
	syncPlayers_proto_msg := &pb.SyncPlayers{
		Ps: players_proto_msg[:],
	}
	//将当前的周边的全部的玩家信息 发送给当前的客户端
	p.SendMsg(202,syncPlayers_proto_msg)
}
2.3.在建立连接之后(建立链接后的Hook函数)调用同步位置消息的方法
//当前客户端建立链接之后触发Hook函数
func OnConnectionAdd(conn ziface.IConnection) {
	......
	//同步周边玩家,告知他们当前玩家已经上线,广播当前的玩家的位置信息
	p.SyncSurrounding()
	......
}
3.移动位置信息的广播
3.1.注册一个针对MsgID为3的路由
func main() {
	s := net.NewServer("MMO Game Server")
	......
	s.AddRouter(3, &apis.Move{})
	......
}
3.2.解析客户端传过来的message
//业务更新坐标 路由业务
type Move struct {
	net.BaseRouter
}

func(m *Move) Handle(request ziface.IRequest) {
	//解析客户端发送过来的proto协议 msgID:3
	proto_msg := &pb.Position{}
	proto.Unmarshal(request.GetMsg().GetMsgData(), proto_msg)

	//通过链接属性 得到当前玩家的ID
	pid , _ := request.GetConnection().GetProperty("pid")

	fmt.Println("player id = ",pid.(int32), " move --> ", proto_msg.X, ", ", proto_msg.Z, ", ", proto_msg.V)


	//通过pid 得到当前的玩家对象
	player := core.WorldMgrObj.GetPlayerByPid(pid.(int32))

	//玩家对象方法(将当前的新坐标位置 发送给全部的周边玩家)
	player.UpdatePosition(proto_msg.X, proto_msg.Y, proto_msg.Z,proto_msg.V)
}
3.3.将最新坐标更新到当前玩家(实现player的UpdatePosition方法),并进行广播
//更新广播当前玩家的最新位置
func (p *Player) UpdatePosition(x, y, z, v float32) {
	//需要将最新的坐标 更新给当前玩家
	p.X = x
	p.Y = y
	p.Z = z
	p.V = v

	//组建广播proto协议 MSGID:200, Tp-4
	proto_msg := &pb.BroadCast{
		Pid:p.Pid,
		Tp:4, //更新坐标
		Data:&pb.BroadCast_P{
			P:&pb.Position{
				X:p.X,
				Y:p.Y,
				Z:p.Z,
				V:p.V,
			},
		},
	}
	//获取当前玩家周边的AOI九宫格之内的玩家 player
	players := p.GetSurroundingPlayers()
	//依次调用Player对象 Send方法将200消息发过去
	for _, player := range players {
		player.SendMsg(200, proto_msg) //每个玩家都会给格子的 client客户端发送200消息
	}
}
4.玩家下线
4.1.注册一个Hook函数,在链接断开之前执行,进行玩家下线通知
func OnConnectionLost(conn ziface.IConnection) {
	//客户端已经关闭

	//得到当前下线的是哪个玩家
	pid, _ := conn.GetProperty("pid")

	player := core.WorldMgrObj.GetPlayerByPid(pid.(int32))

	//玩家的下线业务(发送消息)
	player.OffLine()
}
func main() {
	s := net.NewServer("MMO Game Server")
	......
	s.AddOnConnStop(OnConnectionLost)
	......
}
4.2.在player中添加一个处理玩家下线的方法
func (p *Player ) OffLine() {
	//	得到当前玩家的周边的玩家有哪些  players
	players := p.GetSurroundingPlayers()

	//制作一个消息MSgID:201
	proto_msg := &pb.SyncPid{
		Pid:p.Pid,
	}
	//	给周边的玩家广播一个消息 MsgID:201
	for _, player := range players {
		player.SendMsg(201, proto_msg)//客户端就会将当前的玩家从视野中删除
	}
	//	将该下线的玩家 从世界管理器移除
	WorldMgrObj.RemovePlayerByPid(p.Pid)
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值