14-zinx-Golang-MMO项目构建与用户上线

前言

  • 前面我们已经介绍完AOI算法与Protobuf协议,接下来正式进入MMO游戏后端的开发

一、构建项目

在这里插入图片描述

  • 目录结构:创建⼀个项⽬ mmo_game ,在项⽬内分别创建⼏个⽂件夹 api , conf , core , game_client , pb等
    • apis:主要是注册⼀些mmo业务的⼀些Router处理业务
    • conf:存放mmo_game的一些配置文件,比如“zinx.json”
    • core:存放一些核心算法或者游戏控制等模块
    • game_client:存放游戏客户端
    • pb:存放一些protobuf的协议文件和go文件
      在这里插入图片描述
  • main.go
package main

import "zinx/znet"

func main() {
	//创建zinx server句柄
	s := znet.NewServer("MMO Game Zinx")

	//连接创建和销毁的HOOK钩子函数

	//注册一些路由业务

	//启动服务
	s.Serve()
}
  • ** conf ⽂件添加 zinx.conf**
在这里插入代码片{
  "Name":"MMO Game Zinx",
  "Host": "0.0.0.0",
  "TcpPort":8999,
  "MaxConn":3000,
  "WorkerPoolSize":10
}
  • 在 pb 下创建msg.proto
syntax="proto3"; //Proto协议
package pb; //当前包名
option csharp_namespace="Pb"; //给C#提供的选项
option go_package = "./";
  • 在 pb下创建build.sh编译指令脚本
#!/bin/bash
protoc --go_out=. *.proto

二、用户上线流程

在这里插入图片描述

1 - 实现思路

在这里插入图片描述

2 - 定义proto协议

  • msg.proto:上线的业务会涉及到MsgID:1 和 MsgID:200 两个消息
syntax = "proto3"; //Proto协议
package pb; //当前包名
option csharp_namespace = "Pb"; //给C#提供的选项
option go_package = "./";

//同步玩家ID
message SyncPid{
  int32 Pid = 1;    //服务器新生成玩家ID
}

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

//广播消息
message BroadCast{
  int32 Pid = 1;
  int32 Tp = 2;  //1-世界聊天,2-玩家位置 3-动作 4-移动之后的坐标信息更新
  oneof Data {
    string Content = 3;   //玩家的聊天信息
    Position P = 4;       //广播玩家的位置
    int32 ActionData = 5; //玩家具体的动作
  }
}

3 - 玩家Player模块

  • src/mmo_game_zinx/core/player.go
    • Plyaer类中有当前玩家的ID,和当前玩家与客户端绑定的conn,还有就是地图的坐标信, NewPlayer()提供初始化玩家⽅法
    • 以给 Player 提供⼀个 SendMsg() ⽅法,供客户端发送消息;SendMsg() 是将发送的数据,通过proto序列化,然后再调⽤ Zinx 框架的SendMsg⽅法发送给对⽅客户端
package core

import (
	"fmt"
	"google.golang.org/protobuf/proto"
	"math/rand"
	"sync"
	"zinx/ziface"
)

//玩家对象
type Player struct {
	Pid  int32              //玩家ID
	Conn ziface.IConneciton //当前玩家的连接(用于和客户端的连接)
	X    float32            //平面的x坐标
	Y    float32            //高度
	Z    float32            //平面y坐标(注意不是Y)
	V    float32            //旋转的0-360角度
}

/*
 Player ID 生成器
*/
var PidGen int32 = 1  //用来生产玩家ID的计数器
var IdLock sync.Mutex //保护PidGen的Mutex

//创建一个玩家的方法
func NewPlayer(conn ziface.IConneciton) *Player {
	//生成一个玩家ID
	IdLock.Lock()
	id := PidGen
	PidGen++
	IdLock.Unlock()
	//创建一个玩家对象
	p := &Player{
		Pid:  id,
		Conn: conn,
		X:    float32(160 + rand.Intn(10)), //随机在160坐标点 基于X轴若干偏移
		Y:    0,
		Z:    float32(140 + rand.Intn(20)), //随机在140坐标点,基于Y轴若干偏移
		V:    0,                            //角度为0
	}
	return p
}

/*
   提供一个发送给客户端消息的方法
   主要是将pb的protobuf数据序列化之后,再调用zinx的SendMsg方法
*/
func (p *Player) SendMsg(msgId uint32, data proto.Message) {
	//将proto Message结构体序列化 转换成二进制
	msg, err := proto.Marshal(data)
	if err != nil {
		fmt.Println("marshal msg err: ", err)
		return
	}

	//将二进制文件 通过zinx框架的sendmsg将数据发送给客户端
	if p.Conn == nil {
		fmt.Println("connection in player is nil")
		return
	}

	if err := p.Conn.SendMsg(msgId, msg); err != nil {
		fmt.Println("Player SendMsg error!")
		return
	}
	return
}

4 - 实现上线业务

  • src/mmo_game_zinx/main.go
    • 在Server的main⼊⼝,给链接绑定⼀个创建之后的hook⽅法,因为上线的时候是服务器⾃动回复客户端玩家ID和坐标,那么需要我们在连接创建完毕之后,⾃动触发,正好我们可以利⽤ Zinx 框架的 SetOnConnStart ⽅法
package main

import (
	"fmt"
	"mmo_game_zinx/core"
	"zinx/ziface"
	"zinx/znet"
)

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

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

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

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

func main() {
	//创建zinx server句柄
	s := znet.NewServer("MMO Game Zinx")

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

	//注册一些路由业务

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

  • src/mmo_game_zinx/core/player.go
    • 之前的流程分析,那么在客户端建⽴连接过来之后,Server要⾃动的回复给客户端⼀个玩家ID,同时也要讲当前玩家的坐标发送给客户端。所以我们这⾥⾯给Player定制了两个⽅法Player.SyncPid() 和 Player.BroadCastStartPosition()
//告知客户端玩家Pid,同步已经生成的玩家ID给客户端
func (p *Player) SyncPid() {
	//组建MsgID:0 的proto数据
	proto_msg := &pb.SyncPid{
		Pid: p.Pid,
	}
	//将消息发送给客户端
	p.SendMsg(1, proto_msg)
}

//广播玩家自己的出生地点
func (p *Player) BroadCastStartPosition() {
	//组建MsgID:200 的proto数据
	proto_msg := &pb.BroadCast{
		Pid: p.Pid,
		Tp:  2, //Tp2 代表广播的位置坐标
		Data: &pb.BroadCast_P{
			P: &pb.Position{
				X: p.X,
				Y: p.Y,
				Z: p.Z,
				V: p.V,
			},
		},
	}
	//将消息发送给客户端
	p.SendMsg(200, proto_msg)
}

在这里插入图片描述

三、目录结构与完整源码

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

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

无休止符

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

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

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

打赏作者

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

抵扣说明:

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

余额充值