Categorygithub.com/Gonewithmyself/gobot
repositorypackage
0.0.2
Repository: https://github.com/gonewithmyself/gobot.git
Documentation: pkg.go.dev

# Packages

No description provided by the author
No description provided by the author
No description provided by the author

# README

设计思路

框架层总体包含前端、后端、聚合应用三部分

  • 前端front

    封装UI界面

  • 后端back

    提炼出客户端角度的玩家通用接口

    用户可继承,可重写

  • 聚合应用app

    作为连接前端后端的桥梁

    封装一些框架接口

前端

ui界面其实就是一个网页,内容就是index.html

开源库lorca负责拉起浏览器并访问index.html

并且提供了GO与JS相互调用的接口

  • GO调用JS

    假如js提供了函数add

    function add(x, y){
        return x + y
    }
    

    在GO代码中调用add

    ui.Eval(`add(2, 3)`).Int() // 
    

    调用操作已封装在calljs.go文件中

  • JS调用GO

    go实现的函数

    func Add(x, y int) int{
    	return x + y
    }
    // 调用 后相当于js环境有了Add这个变量
    ui.Bind("Add", Add)
    

    在JS代码中 使用

    // 调用Add返回的是个promise 是异步的
    Add(1, 2).then((res)=>{
        console.log(res) // res = 3
    })
    

    实际调用已封装在fromjs.go中

除了实现GO JS互相调用外,还需实现一个静态文件服务器

让浏览器可以获取js、css等静态文件

具体实现在fileserver.go

后端

主要是IGamer接口

type IGamer interface {
	GetUid() string // 玩家唯一标识,登录前就要确定
	Close()         // 主动调用 关闭玩家
	OnExit()        // 退出回调

	MsgChan() <-chan interface{} // 消息channel
	ExitChan() <-chan struct{}   // exit channel
	ProcessMsg(interface{})      // 网络消息处理函数

	GetTickMs() int64 // 玩家间隔多少毫秒跑一遍行为树
    Stop() 			 // 让玩家停止跑行为树,但是不退出 此时不发消息只收消息 提升消息指标的精度
	IsStopped() bool // 
}
聚合应用

主要就是IApp接口,用户直接继承即可

type IApp interface {
	Init(*Options) // 初始化应用
	Run(context.Context) // 程序主循环,已有默认实现, 可按需重写
	Close()    // 关闭应用
	OnExit(reason string) // 应用退出回调

	// 根据配置文件创建一个玩家
	CreateGamer(confJson string, seq int32) (back.IGamer, error)
	RunGamer(g back.IGamer, tree *btree.Tree) // 玩家主循环 ,已有默认实现, 可按需重写

	// 解析pb结构体
	ParsePbInfo(back.IPbInfo)

	StressStart(start, count int32, treeID, confJs string) // 压测开始
	PrintStressStatus()     // 打印压测状态
}

行为树

配置文件在conf/robot.b3

开源behavior3go已经实现节点And、Or等基础控制逻辑 https://github.com/magicsea/behavior3go

可以自行扩展其他控制逻辑,比如随机执行等

节点说明

节点状态:

控制节点会根据状态做出决策

  • Success

    成功

  • ERROR

    失败

  • Running

    表示节点会持续运行一定时间

默认控制节点说明:
  • Sequence

    相当于逻辑与操作

    下面的例子默认顺序执行A、B、C

    如果A返回失败,则不会继续执行B、C

    image-20220622181938442

  • Priority

    相当于逻辑或

    如果A返回成功,则不会执行B、C

    image-20220622182212111

  • MemSequence/MemPriority

    带Mem前缀的会记住返回running的节点,下次直接运行这个节点

    比如第一次遍历时C返回running

    则第二次遍历时会跳过运行A、B直接运行C

    image-20220622181938442

  • 随机节点 Rand/MemRand

    • Rand类型

      每次抽取均独立 即每次抽到A、B、C的概率相同

    • MemRand类型

      不放回抽取 第一次抽到了B 则第二次只能从A、C中选 假如是C 则第三次只能选择A

      抽完一轮则重置为初始状态

image-20230104174035144

自定义节点

编辑器中点击新建节点

image-20230105094811094

Name相当于面向对象语言中的类型名,Title相当于实例名称,不同实例可同名

节点类别有分支节点和叶子节点两种类型

分支节点
  • Composite 组合节点

    可以包含多个节点

    自定义时内嵌btree.Composite结构体

    通关Len方法获取子节点数量,GetChild方法拿到子节点

  • Decorator 装饰节点

    只包含一个节点

    自定义时内嵌btree.Decorator结构体

    通过GetChild方法拿到子节点

叶子节点

承载业务逻辑的实现

自定义节点时内嵌btree.Action

实现时按需重写Inode接口中的方法即可,一般只需重写OnTick

type INode interface {
	OnEnter(*Tick)       // 进入节点
	OnTick(*Tick) Status // 主要业务逻辑
	OnLeave(*Tick)       // 离开节点
	Execute(*Tick) Status // 节点控制逻辑 一般不用重写
}
一个例子

实现自定义节点的步骤其实就是

  • 先在编辑器中新建一个节点 假如Log节点
  • 在画布中编排好节点保存配置
  • 然后定义Log结构体,并内嵌对应的类型 比如btree.Action
  • 再重写OnTick接口 实现自己的业务逻辑
  • btree.Register注册结构体即可
type Log struct {
	btree.Action
}

func (node *Log) OnTick(tick *btree.Tick) btree.Status {
	// node.Properties.Get() 获取属性
	fmt.Println("runNode", node.Id, node.Name, node.Title)
	return btree.SUCCESS
}

//注册节点
btree.Register(&Log{})