深入探索AOI算法实现(十字链表篇)

游戏的AOI算法应该算作游戏的基础核心了,许多逻辑都是因为AOI进出事件驱动的,许多网络同步数据也是因为AOI进出事件产生的。因此,良好的AOI算法和基于AOI算法的优化,是提高游戏性能的关键。
我在实践中所熟知的游戏AOI算法大致有两种,在此做一些总结,顺便梳理一下,打算设计出一套统一的接口封装不同的算法实现(网络上还有些其他算法,因为不熟悉不作记录了)。我所记录的这两种算法也算经典了,一个叫做网格法,一个叫做双链表法。具体细节可参考如下:https://zhuanlan.zhihu.com/p/201588990

根据 文章描述,自己动手初步实现了十字链表篇算法,该版本支持不同半径AOI。

grid_link.go代码如下:

package grid

import "fmt"

// 十字链表法, 实现AOI
// 节点增加左右哨兵功能, 同时增加地标功能

type nodeType int

var NormalNode nodeType = 0    // 正常玩家节点
var LeftSentinel nodeType = 1  // 左哨兵节点
var RightSentinel nodeType = 2 // 右哨兵节点
var LandMark nodeType = 3      // 地标节点

type Direction int

var XDirect Direction = 0
var YDirect Direction = 1

var MaxArea int = 10 // 最大视距

type Pos [2]int

// 双链表结构
type Node struct {
	EntityId int
	PreNode  *Node
	NextNode *Node
	Pos      Pos
	NodeType nodeType
}

type SceneAOIManagerByLink struct {
	SceneId       int
	Length        int
	Width         int
	XNodeList     *Node
	YNodeList     *Node
	XLandMarkList []*Node //地标节点,用于二分查找
	YLandMarkList []*Node
}

func initNode(EntityId, X, Y int, NodeType nodeType) *Node {
	node := &Node{
		EntityId: EntityId,
		Pos:      Pos{X, Y},
		NodeType: NodeType,
	}

	return node
}

func minInt(x, y int) int {
	if x <= y {
		return x
	}
	return y
}

func maxInt(x, y int) int {
	if x >= y {
		return x
	}
	return y
}

func disInt(node1, node2 *Node) int {
	return (node1.Pos[0]-node2.Pos[0])*(node1.Pos[0]-node2.Pos[0]) + (node1.Pos[1]-node2.Pos[1])*(node1.Pos[1]-node2.Pos[1])
}

func (scene *SceneAOIManagerByLink) initLandMarkList(direct Direction) {
	var FirstNode *Node
	var LandMarkList []*Node = make([]*Node, 0)

	if direct == XDirect {
		FirstNode = scene.XNodeList
	} else {
		FirstNode = scene.YNodeList
	}

	LandMarkList = append(LandMarkList, FirstNode)
	x := FirstNode.Pos[0]
	y := FirstNode.Pos[1]

	for {
		x = x + MaxArea*int(direct^YDirect)
		y = y + MaxArea*int(direct^XDirect)

		if x > scene.Length+MaxArea || y > scene.Width+MaxArea {
			break
		}

		node := initNode(0, x, y, LandMark)
		FirstNode.NextNode = node
		node.PreNode = FirstNode
		FirstNode = node

		LandMarkList = append(LandMarkList, node)
	}

	if direct == XDirect {
		scene.XLandMarkList = LandMarkList
	} else {
		scene.YLandMarkList = LandMarkList
	}
}

func (scene *SceneAOIManagerByLink) Travel() {
	fmt.Printf("Pos info:\nX: ")
	node := scene.XNodeList
	for node != nil {
		fmt.Printf("(%d, %d) ", node.Pos[0], node.Pos[1])
		node = node.NextNode
	}
	fmt.Printf("\nY: ")
	node = scene.YNodeList
	for node != nil {
		fmt.Printf("(%d, %d) ", node.Pos[0], node.Pos[1])
		node = node.NextNode
	}
	fmt.Println()
}

func (scene *SceneAOIManagerByLi
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值