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