Zinx下MMO游戏具体实现-02玩家模块和世界模块

Zinx下MMO游戏具体实现-02玩家模块和世界模块

1.构建项目目录

core:存放算法、核心功能

conf:zinx框架配置文件

pb:存放用来与前端交互的proto文件

apis:存放用户自定义的路由业务,一个msgID对应一个业务

main.go:zinx-server开发的编程流程

2.实现一个Player玩家模块
2.1.在core中创建Player结构体并实现初始化函数
type Player struct {
	Pid int32 //玩家ID
	Conn ziface.IConnection //当前玩家的链接(与对应客户端通信)
	X float32 //平面的x轴坐标
	Y float32 //高度
	Z float32 //平面的y轴坐标
	V float32 //玩家脸朝向的方向
}

// playerID 生成器
var PidGen int32 = 1//用于生产玩家ID计数器
var IdLock sync.Mutex //保护PidGen生成器的互斥锁

//初始化玩家的方法
func NewPlayer(conn ziface.IConnection) *Player{
	//分配一个玩家ID
	IdLock.Lock()
	id := PidGen
	PidGen++
	IdLock.Unlock()

	//创建一个玩家对象
	p := &Player{
		Pid:id,
		Conn:conn,
		X: float32(160 + rand.Intn(10)),//随机生成玩家上线所在的x轴坐标
		Y:0,
		Z: float32(140 + rand.Intn(10)), //随机在140坐标点附近 y轴坐标上线
		V:0,//角度为0
	}

	return p
}
2.2.实现玩家可以和对端客户端发送消息的方法
func (p *Player) SendMsg(msgID uint32, proto_struct proto.Message) error {
	//要将proto结构体 转换成 二进制的数据
	binary_proto_data, err := proto.Marshal(proto_struct)
	if err != nil {
		fmt.Println("marshal proto struct error ", err)
		return err
	}


	//再调用zinx原生的connecton.Send(msgID, 二进制数据)
	if err := p.Conn.Send(msgID, binary_proto_data); err != nil {
		fmt.Println("Player send error!" , err)
		return err
	}

	return nil
}
2.3.实现上线业务

需要实现服务器给客户端发送玩家初始ID和服务器给客户端发送一个玩家的初始化位置信息,这时需要用到proto创建message用来发送数据

//返回给玩家上线的ID信息
message SyncPid{
		int32 Pid=1;
}

//返回给上线玩家初始的坐标
message BroadCast{
	int32 Pid=1;
	int32 Tp=2; //Tp: 1 世界聊天, 2 坐标, 3 动作, 4 移动之后坐标信息更新
	oneof Data {
		string Content=3;
		Position P=4;
		int32 ActionData=5;
	}
}

//位置信息
message Position{
	float X=1;
	float Y=2;
	float Z=3;
	float V=4;
}

将msg.proto生成对应的go文件,实现通信

//服务器给客户端发送玩家初始ID
func (p *Player) ReturnPid() {
	//定义个msg:ID 1  proto数据结构
	proto_msg := &pb.SyncPid{
		Pid:p.Pid,
	}

	//将这个消息 发送给客户端
	p.SendMsg(1, proto_msg)
}

//服务器给客户端发送一个玩家的初始化位置信息
func (p *Player) ReturnPlayerPosition() {
	//组建MsgID:200消息
	proto_msg := &pb.BroadCast{
		Pid:p.Pid,
		Tp:2, //2 -坐标信息
		Data: &pb.BroadCast_P{
			P:&pb.Position{
				X:p.X,
				Y:p.Y,
				Z:p.Z,
				V:p.V,
			},
		},
	}

	//将这个消息 发送给客户端
	p.SendMsg(200, proto_msg)
}

在main中具体实现上述功能

//当前客户端建立链接之后触发Hook函数
func OnConnectionAdd(conn ziface.IConnection) {
	fmt.Println("conn Add..")

	//创建一个玩家 将链接和玩家模块绑定
	p := core.NewPlayer(conn)

	//给客户端发送一个msgID:1
	p.ReturnPid()

	//给客户端发送一个msgID:200
	p.ReturnPlayerPosition()
}
func main() {
	s := net.NewServer("MMO Game Server")

	//注册一些 链接创建/销毁的 Hook钩子函数
	s.AddOnConnStart(OnConnectionAdd)

	//注册一些路由业务
	s.Serve()
}
3.实现一个WorldManager世界模块
3.1.在core中创建WorldManager结构体并实现初始化函数
//当前世界地图的边界参数
const (
	AOI_MIN_X int = 85
	AOI_MAX_X int = 410
	AOI_CNTS_X int = 10
	AOI_MIN_Y int = 75
	AOI_MAX_Y int = 400
	AOI_CNTS_Y int = 20
)

/*
当前的场景的世界管理模块
 */
 type WorldManager struct {
	 //当前全部在线的Player集合
	 Players map[int32] *Player
	 //保护Player集合的锁
	 pLock sync.RWMutex
	 //AOIManager当前的地图的管理器
	 AoiMgr *AOIManager
 }

 //对外提供一个全局世界管理模块指针
 var WorldMgrObj *WorldManager

 func init() {
 	//创建一个全局的世界管理对象
 	WorldMgrObj = NewWorldManager()
 }

//初始化方法
func NewWorldManager() *WorldManager {
	wm := &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),
	}

	return wm
}
3.2实现和玩家有关的方法
//添加一个玩家
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) {
	//从世界管理删除
	wm.pLock.Lock()

	//先通过pid 从世界管理器得到player对象
	player := wm.Players[pid]

	//从世界地图中删除
	wm.AoiMgr.RemoteFromGridbyPos(int(pid), player.X, player.Z)


	delete(wm.Players, pid)
	wm.pLock.Unlock()
}


//通过一个玩家ID得到一个Player对象
func (wm *WorldManager) GetPlayerByPid(pid int32) *Player {
	wm.pLock.RLock()
	p := wm.Players[pid]
	wm.pLock.RUnlock()

	return p
}

//获取全部的在线玩家集合
func (wm *WorldManager) GetAllPlayers() []*Player {
	wm.pLock.RLock()
	defer wm.pLock.RUnlock()

	players := make([]*Player, 0)

	//将世界管理器的player对象加入到返回的切片中
	for _, player := range wm.Players {
		players = append(players, player)
	}

	return players
}

在main中的OnConnectionAdd中把Player添加到WorldMgrObj中

func OnConnectionAdd(conn ziface.IConnection) {
	fmt.Println("conn Add..")

	//创建一个玩家 将链接和玩家模块绑定
	p := core.NewPlayer(conn)

	//给客户端发送一个msgID:1
	p.ReturnPid()

	//给客户端发送一个msgID:200
	p.ReturnPlayerPosition()

	//上线成功了
	//将玩家对象添加到世界管理器中
	core.WorldMgrObj.AddPlayer(p)

	fmt.Println("----> player ID = ", p.Pid, "Online...", ", Player num = ", len(core.WorldMgrObj.Players))
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值