GO EASY 框架 之 游戏AOI 08

目录

Overview

应用

初始化aoi

场景操作aoi

视野消息处理器

用户对象实现aoi.AgentEntity

源码接口

import

Entity 进入aoi的基类接口

带链接的Entity,AgentEntity

其它Entity

邻居Neighbour接口

AOI接口

AoiCaller接口


Overview

游戏业务AOI业务部分,视野热区,多人同步大体是相同的;在这里easy中精简出aoi的逻辑部分。位置easy/vendors/aoi。easy的AOI是可以限制视野人数,但依据邻居关系限定就近原则缺少自定义化。若是没有限制人数,则也不需要什么就近原则自定义化了。

核心算法:十字链表和跳表综合实现的aoi;内存占用小,不需要提前创建内存块;高性能;

应用

初始化aoi


func newaoi() aoi.AOI {
	return aoi.New(option.OptionWith(&aoi.Option{
		NeighbourCount: conf.TomlConf.Line.AoiPlayerCount,
		Radius:         float32(conf.TomlConf.Line.Radius),
		Axis:           []int{0, 1, 2},
	}).Default(option.DEFAULT_IGNORE_ZERO))
}

场景操作aoi

enter/leave/move


func (this *Scene) Enter(entity aoi.Entity) {
	// 默认将人物放到空中
	// 由客户端 的 send transform 纠正坐标
	if usr, ok := entity.(*UserEntity); ok {
		usr.MoveHandle([]float32{0, 180, 0}, []float32{})
	}
	//
	this.aoi.Enter(entity)
	logq.DebugF("LINE.ENTER-SCENE scene:%v", this.SceneID)
}

func (this *Scene) Leave(entity aoi.Entity) {
	oper := this.Oper(entity, aoi.OPER_NOAGENT_LEAVE, nil)
	if _, ok := entity.(aoi.AgentEntity); ok {
		oper.Op = aoi.OPER_AGENT_LEAVE
	}
	logq.DebugF("LINE.LEAVE-SCENE scene:%v", this.SceneID)
	this.aoi.Leave(entity)
}

func (this *Scene) Move(entity aoi.Entity) {
	//return // PPROF.DELETE
	oper := this.Oper(entity, aoi.OPER_NOAGENT_MOVE, nil)
	if _, ok := entity.(aoi.AgentEntity); ok {
		oper.Op = aoi.OPER_AGENT_MOVE
	}
	//this.aoi.Handle(oper)
	this.aoi.Move(entity)
}

视野消息处理器

实现接口aoi.AoiMessage;

需要将MessageUser绑定到User类上;


type MessageUser struct {
	master       *UserEntity
	mu           sync.Locker
	move_entitys []aoi.Entity
	aoi.Message
}

func (self *MessageUser) Appear(arr []aoi.Entity) {
	if len(arr) == 0 {
		return
	}

	ms := &goproto.AppearRoleAoi_S2C{Players: []*goproto.AppearRoleAoi_S2C_Player{}}
	ms.MsgCode = code.SUCCESS
	for i := 0; i < len(arr); i++ {
		switch u := arr[i].(type) {
		case *UserEntity:
			p := &goproto.AppearRoleAoi_S2C_Player{
				PID:      u.GetPlayerID(),
				Position: u.Position(),
				Rotate:   u.Rotation(),
				SceneID:  u.SceneID,
				Sex:      u.GetSex(),
				ClothID:  u.GetClothID(),
				NickName: u.GetNickName(),
			}
			ms.Players = append(ms.Players, p)
		}
	}
	ants.AntsPool().Submit(func() {
		self.master.WriteMessage(ms)
	})
	logq.Debugf("APPEAR-------------master.ID:%v ------- neight.len:%v", self.master.ID(), len(ms.Players))
}

func (self *MessageUser) Disappear(arr []aoi.Entity) {
	if len(arr) == 0 {
		return
	}

	ms := &goproto.DisappearRoleAoi_S2C{Players: []*goproto.DisappearRoleAoi_S2C_Player{}}
	ms.MsgCode = code.SUCCESS
	for i := 0; i < len(arr); i++ {
		switch u := arr[i].(type) {
		case *UserEntity:
			p := &goproto.DisappearRoleAoi_S2C_Player{
				PID:      u.GetPlayerID(),
				SceneID:  u.SceneID,
				ClothID:  u.GetClothID(),
				NickName: u.GetNickName(),
			}
			ms.Players = append(ms.Players, p)
		}
	}
	ants.AntsPool().Submit(func() {
		self.master.WriteMessage(ms)
	})
}

func (self *MessageUser) Move(arr []aoi.Entity) {
	self.mu.Lock()
	defer self.mu.Unlock()
	self.move_entitys = append(self.move_entitys, arr...)
}

func (self *MessageUser) MoveTick() {

	ms := &goproto.FrameTransform_S2C{Players: []*goproto.FrameTransform_S2C_Player{}}
	ms.MsgCode = code.SUCCESS
	for i := 0; i < len(self.move_entitys); i++ {
		if self.move_entitys[i] == nil {
			continue
		}
		switch u := self.move_entitys[i].(type) {
		case *UserEntity:
			if u.GetActive() == ENTITY_IDEL {
				break
			}
			p := &goproto.FrameTransform_S2C_Player{
				PID:      u.GetPlayerID(),
				Position: u.Position(),
				Rotate:   u.Rotation(),
				ActID:    u.GetActID(),
			}
			ms.Players = append(ms.Players, p)
		}
	}

	self.mu.Lock()
	self.move_entitys = []aoi.Entity{}
	self.mu.Unlock()

	ants.AntsPool().Submit(func() {
		self.master.WriteMessage(ms)
	})
}

用户对象实现aoi.AgentEntity


func (this *UserEntity) Agent() agent.Agent {
	return this.User.GetAgent()
}

func (this *UserEntity) Neighbour() aoi.Neighbour {
	return this.neighbour
}

func (this *UserEntity) AoiMessage() aoi.AoiMessage {
	return this.aoiMessage
}

func (this *UserEntity) PositionPre(args ...float32) []float32 {
	if len(args) > 0 {
		this.move_tran.Position = args
	}
	return this.move_tran.Position
}

aoi.Behaivour;aoi执行对应的操作时,调用Entity的行为事件;

// Behaivour
func (this *UserEntity) Select(aoiobj any) {
	this.aoi, _ = aoiobj.(aoi.AOI)
}
func (this *UserEntity) Enter() {
	this.SetActive(ENTITY_IDEL)
	this.ValideAoi(VALID_AOI_OK)
}

func (this *UserEntity) Leave() {
	this.SetActive(ENTITY_IDEL)
	this.ValideAoi(VALID_AOI_NO)
}

func (this *UserEntity) Move() {
	this.moveLock.Lock()
	defer this.moveLock.Unlock()
	// move aoi 之后 旧的旧没有用了,可以做参数
	this.Position(this.PositionPre()...)
	this.Rotation(this.move_tran.Rotation...)
}

ID和坐标相关实现AgentEntity

func (this *UserEntity) ID() int {
	return int(this.GetPlayerID())
}

func (this *UserEntity) Position(args ...float32) []float32 {
	n := len(args)
	if n == 0 {
		return this.transform.Position
	}
	// 新值换旧值
	n--
	for i, m := 0, len(this.transform.Position); i < m; i++ {
		this.transform_old.Position[i] = this.transform.Position[i]
		if i <= n {
			this.transform.Position[i] = args[i]
		}
	}
	return this.transform.Position
}

func (this *UserEntity) PositionOld() []float32 {
	return this.transform_old.Position
}

func (this *UserEntity) Rotation(args ...float32) []float32 {
	n := len(args)
	if n == 0 {
		return this.transform.Rotation
	} // 新值换旧值
	n--
	for i, m := 0, len(this.transform.Rotation); i < m; i++ {
		this.transform_old.Rotation[i] = this.transform_old.Rotation[i]
		if i <= n {
			this.transform.Rotation[i] = args[i]
		}
	}
	return this.transform.Rotation
}

func (this *UserEntity) RotationOld() []float32 {
	return this.transform_old.Rotation
}

源码接口

import


import (
	"github.com/slclub/easy/nets/agent"
)

Entity 进入aoi的基类接口


// The game player object should implements the Entity interface.
// It is a basic operating unit in aoi.
// Entity interface is mainly compatible with three parts.
// 		Object displacement;
// 		Callback of aoi event handle;
// 		Aoi messages handle;

type Entity interface {
	ID() int
	Position(args ...float32) []float32    //位置
	PositionPre(args ...float32) []float32 //位置
	PositionOld() []float32
	AoiCaller
	AoiMessage() AoiMessage
}

带链接的Entity,AgentEntity


// Entity object with link.
// Your game player should implement AgentEntity interface.
// Neighbour() method return the neighbour object. So, your AgentEntiy object should include a field for neighbour object.
// and use aoi.NewNeighbour(aoi.Option()) to initialized it.

type AgentEntity interface {
	Entity
	Neighbour() Neighbour
	Agent() agent.Agent
}

其它Entity


type Monster interface {
	Entity
	Monster()
}

type Npc interface {
	Entity
	Npc()
}

邻居Neighbour接口

// The number of people displayed on the same screen in mobile games is limited.
// So, we need neighbour moudule to controll the players of interessting area.

type Neighbour interface {
	neighbourInternel
	RangeIncrease(fn func(entity Entity) bool)
	RangeMove(fn func(entity Entity) bool)
	RangeLeave(fn func(entity Entity) bool)
	RangeBeenObservedSet(fn func(entity Entity) bool)
}
// This module was born solely for the convenience of interal code invoked.
type neighbourInternel interface {
	join(v any) int
	beenJoin(v any) int
	leave(v any) int
	beenLeave(v any) int
	// v:nil将 move和increase 集合的entity 移动到 leave集合中
	// v:clean 将increase 合并到move集合,清空 leave 和 increase 集合
	reset(v any)
	clear()
	increaseEntitys() []Entity
	moveEntitys() []Entity
	leaveEntitys() []Entity
	cutIncrease()
}

AOI接口

// It is the mainly interface of AOI
// Your scene object should prepare a field for AOI interface.
// It implement the AOIHandle interface.
// The AoiHandle interface is related to your scene logic.

type AOI interface {
	Count(string) int
	Range(func(entity Entity) bool)
	Clear()
	Option() *Option
	AOIHandler
}

type AOIHandler interface {
	Enter(entity Entity)
	Leave(entity Entity)
	Move(entity Entity)
	BroadcastInterstingAll(entity Entity, fn func(mine, other Entity))
	BroadcastAgentAll(fn func(mine, other Entity))
}

AoiCaller接口

// Entity Callback
// Your entity object should implement the AoiCaller interface.
// Please, do not use it as message handler.
// It just your entity should do  when aoi was event happened.
// it is suitable for the changing logic of your entity object when aoi event is happening.

type AoiCaller interface {
	Enter()
	Move()
	Leave()
}

消息接收器接口

// 消息接收器
// Aoi message handle interface.
// It should be Hang on your entity.
// It is reasonable for different type of entity generate the different messages.

type AoiMessage interface {
	Appear([]Entity)
	Move([]Entity)
	Disappear([]Entity)
}

你可能感兴趣的:(Go游戏服务器框架EASY,go,golang,go网络框架,go网络路由,easy,easy框架)