aceld
6 years ago
4 changed files with 266 additions and 0 deletions
-
3zinx_app_demo/mmo_game/README.md
-
171zinx_app_demo/mmo_game/core/aoi.go
-
27zinx_app_demo/mmo_game/core/aoi_test.go
-
65zinx_app_demo/mmo_game/core/grid.go
@ -0,0 +1,3 @@ |
|||||
|
#基于Zinx的MMO多人在线游戏服务端代码示例 |
||||
|
|
||||
|
|
@ -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) |
||||
|
} |
@ -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) |
||||
|
} |
||||
|
} |
@ -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) |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue