Browse Source

添加基于Zinx服务应用案例mmo_game, 新增AOI兴趣点模块

master
aceld 6 years ago
parent
commit
e34f7c9227
  1. 3
      zinx_app_demo/mmo_game/README.md
  2. 171
      zinx_app_demo/mmo_game/core/aoi.go
  3. 27
      zinx_app_demo/mmo_game/core/aoi_test.go
  4. 65
      zinx_app_demo/mmo_game/core/grid.go

3
zinx_app_demo/mmo_game/README.md

@ -0,0 +1,3 @@
#基于Zinx的MMO多人在线游戏服务端代码示例

171
zinx_app_demo/mmo_game/core/aoi.go

@ -0,0 +1,171 @@
package core
import "fmt"
/*
AOI管理模块
*/
type AOIManager struct {
MinX int //区域左边界坐标
MaxX int //区域右边界坐标
CntsX int //x方向格子的数量
MinY int //区域上边界坐标
MaxY int //区域下边界坐标
CntsY int //y方向的格子数量
grids map[int]*Grid //当前区域中都有哪些格子,key=格子ID, value=格子对象
}
/*
初始化一个AOI区域
*/
func NewAOIManager(minX, maxX, cntsX, minY, maxY, cntsY int) *AOIManager {
aoiMgr := &AOIManager{
MinX: minX,
MaxX: maxX,
CntsX: cntsX,
MinY: minY,
MaxY: maxY,
CntsY: cntsY,
grids: make(map[int]*Grid),
}
//给AOI初始化区域中所有的格子
for y := 0; y < cntsY; y++ {
for x := 0; x < cntsX; x++ {
//计算格子ID
//格子编号:id = idy *nx + idx (利用格子坐标得到格子编号)
gid := y*cntsX + x
//初始化一个格子放在AOI中的map里,key是当前格子的ID
aoiMgr.grids[gid] = NewGrid(gid,
aoiMgr.MinX+ x*aoiMgr.gridWidth(),
aoiMgr.MinX+(x+1)*aoiMgr.gridWidth(),
aoiMgr.MinY+ y*aoiMgr.gridLength(),
aoiMgr.MinY+(y+1)*aoiMgr.gridLength())
}
}
return aoiMgr
}
//得到每个格子在x轴方向的宽度
func (m *AOIManager) gridWidth() int {
return (m.MaxX - m.MinX) / m.CntsX
}
//得到每个格子在x轴方向的长度
func (m *AOIManager) gridLength() int {
return (m.MaxY - m.MinY) / m.CntsY
}
//打印信息方法
func (m *AOIManager) String() string {
s := fmt.Sprintf("AOIManagr:\nminX:%d, maxX:%d, cntsX:%d, minY:%d, maxY:%d, cntsY:%d\n Grids in AOI Manager:\n",
m.MinX, m.MaxX, m.CntsX, m.MinY, m.MaxY, m.CntsY)
for _,grid := range m.grids {
s += fmt.Sprintln(grid)
}
return s
}
//根据格子的gID得到当前周边的九宫格信息
func (m *AOIManager) GetSurroundGridsByGid(gID int) (grids []*Grid) {
//判断gID是否存在
if _, ok := m.grids[gID]; !ok {
return
}
//将当前gid添加到九宫格中
grids = append(grids, m.grids[gID])
//根据gid得到当前格子所在的X轴编号
idx := gID % m.CntsX
//判断当前idx左边是否还有格子
if idx > 0 {
grids = append(grids, m.grids[gID-1])
}
//判断当前的idx右边是否还有格子
if idx < m.CntsX - 1 {
grids = append(grids, m.grids[gID+1])
}
//将x轴当前的格子都取出,进行遍历,再分别得到每个格子的上下是否有格子
//得到当前x轴的格子id集合
gidsX := make([]int, 0, len(grids))
for _, v := range grids {
gidsX = append(gidsX, v.GID)
}
//遍历x轴格子
for _, v := range gidsX {
//计算该格子处于第几列
idy := v / m.CntsX
//判断当前的idy上边是否还有格子
if idy > 0 {
grids = append(grids, m.grids[v-m.CntsX])
}
//判断当前的idy下边是否还有格子
if idy < m.CntsY - 1 {
grids = append(grids, m.grids[v+m.CntsX])
}
}
return
}
//通过横纵坐标获取对应的格子ID
func (m *AOIManager) GetGidByPos(x, y float32) int {
gx := (int(x) - m.MinX) / m.gridWidth()
gy := (int(x) - m.MinY) / m.gridLength()
return gy * m.CntsX + gx
}
//通过横纵坐标得到周边九宫格内的全部PlayerIDs
func (m *AOIManager) GetPidsByPos(x, y float32) (playerIDs []int) {
//根据横纵坐标得到当前坐标属于哪个格子ID
gID := m.GetGidByPos(x, y)
//根据格子ID得到周边九宫格的信息
grids := m.GetSurroundGridsByGid(gID)
for _, v := range grids {
playerIDs = append(playerIDs, v.GetPlyerIDs()...)
fmt.Printf("===> grid ID : %d, pids : %v ====", v.GID, v.GetPlyerIDs())
}
return
}
//通过GID获取当前格子的全部playerID
func (m *AOIManager) GetPidsByGid(gID int) (playerIDs []int) {
playerIDs = m.grids[gID].GetPlyerIDs()
return
}
//移除一个格子中的PlayerID
func (m *AOIManager) RemovePidFromGrid(pID, gID int) {
m.grids[gID].Remove(pID)
}
//添加一个PlayerID到一个格子中
func (m *AOIManager) AddPidToGrid(pID, gID int) {
m.grids[gID].Add(pID)
}
//通过横纵坐标添加一个Player到一个格子中
func (m *AOIManager) AddToGridByPos(pID int, x, y float32) {
gID := m.GetGidByPos(x, y)
grid := m.grids[gID]
grid.Add(pID)
}
//通过横纵坐标把一个Player从对应的格子中删除
func (m *AOIManager) RemoveFromGridByPos(pID int, x, y float32) {
gID := m.GetGidByPos(x, y)
grid := m.grids[gID]
grid.Remove(pID)
}

27
zinx_app_demo/mmo_game/core/aoi_test.go

@ -0,0 +1,27 @@
package core
import (
"fmt"
"testing"
)
func TestNewAOIManager(t *testing.T) {
aoiMgr := NewAOIManager(100,300, 4, 200,450, 5)
fmt.Println(aoiMgr)
}
func TestAOIManagerSuroundGridsByGid(t *testing.T) {
aoiMgr := NewAOIManager(0,250, 5, 0,250, 5)
for k, _ := range aoiMgr.grids {
//得到当前格子周边的九宫格
grids := aoiMgr.GetSurroundGridsByGid(k)
//得到九宫格所有的IDs
fmt.Println("gid : ", k, " grids len = ", len(grids))
gIDs := make([]int, 0, len(grids))
for _, grid := range grids {
gIDs = append(gIDs, grid.GID)
}
fmt.Printf("grid ID: %d, surrounding grid IDs are %v\n", k, gIDs)
}
}

65
zinx_app_demo/mmo_game/core/grid.go

@ -0,0 +1,65 @@
package core
import (
"fmt"
"sync"
)
/*
一个地图中的格子类
*/
type Grid struct {
GID int //格子ID
MinX int //格子左边界坐标
MaxX int //格子右边界坐标
MinY int //格子上边界坐标
MaxY int //格子下边界坐标
playerIDs map[int]bool //当前格子内的玩家或者物体成员ID
pIDLock sync.RWMutex //playerIDs的保护map的锁
}
//初始化一个格子
func NewGrid(gID, minX, maxX, minY, maxY int) *Grid {
return &Grid{
GID: gID,
MinX: minX,
MaxX: maxX,
MinY: minY,
MaxY: maxY,
playerIDs: make(map[int]bool),
}
}
//向当前格子中添加一个玩家
func (g *Grid) Add(playerID int) {
g.pIDLock.Lock()
defer g.pIDLock.Unlock()
g.playerIDs[playerID] = true
}
//从格子中删除一个玩家
func (g *Grid) Remove(playerID int) {
g.pIDLock.Lock()
defer g.pIDLock.Unlock()
delete(g.playerIDs, playerID)
}
//得到当前格子中所有的玩家
func (g *Grid) GetPlyerIDs() (playerIDs []int) {
g.pIDLock.RLock()
defer g.pIDLock.RUnlock()
for k, _ := range g.playerIDs {
playerIDs = append(playerIDs, k)
}
return
}
//打印信息方法
func (g *Grid) String() string {
return fmt.Sprintf("Grid id: %d, minX:%d, maxX:%d, minY:%d, maxY:%d, playerIDs:%v",
g.GID, g.MinX, g.MaxX, g.MinY, g.MaxY, g.playerIDs)
}
Loading…
Cancel
Save