新建行为树
This commit is contained in:
1 parent
4bb083f736
commit
5653ff7ff6
8 files changed
+73
-11
No files matched your search
@@ -2,12 +2,6 @@
|
||||
这是一个直观、可视化的行为树编辑器,行为树的保存格式为json,可以让策划自行去实现AI,技能,buff等复杂的游戏逻辑,从而减少不必要的沟通成本和提升开发效率。
|
||||

|
||||
|
||||
## 技术栈
|
||||
+ react + ts
|
||||
+ g6
|
||||
+ antd
|
||||
+ electron
|
||||
|
||||
## 使用方法
|
||||
+ 打开编辑器
|
||||
+ 工作区->节点定义->选择文件(json)
|
||||
@@ -37,13 +31,28 @@ interface BehaviorNodeTypeModel {
|
||||
doc?: string; //文档说明(markdown格式)
|
||||
}
|
||||
```
|
||||
节点定义也是json格式,参照[sample/node-config.json](sample/node-config.json),编辑器不提供节点定义的编辑,强烈建议节点定义文件由代码生成。
|
||||
|
||||
## 编译与构建
|
||||
```shell
|
||||
npm install # 安装依赖
|
||||
npm start # 运行测试
|
||||
npm run build # 编译exe可执行文件
|
||||
```
|
||||
|
||||
## 技术栈
|
||||
+ react + ts
|
||||
+ g6
|
||||
+ antd
|
||||
+ electron
|
||||
|
||||
## TODO
|
||||
+ 复制粘贴功能(跨工作区)
|
||||
+ 历史记录(撤销/恢复)
|
||||
+ 资源面板支持树型结构
|
||||
+ 快捷键功能
|
||||
+ 右键菜单
|
||||
+ 联调功能
|
||||
|
||||
## About
|
||||
目前编辑器还处于非常简陋的阶段,本项目将长期维护,望前端大佬们多提点~
|
||||
目前编辑器还处于非常简陋的阶段,有问题可以联系作者(QQ1013299930),本项目将长期维护,望前端大佬们多提点~
|
||||
@@ -2,6 +2,7 @@ export default {
|
||||
OPEN_FILE: "OPEN_FILE",
|
||||
OPEN_DIR: "OPEN_DIR",
|
||||
OPEN_WORKSPACE: "OPEN_WORKSPACE",
|
||||
CREATE_TREE: 'CREATE_TREE',
|
||||
CREATE_NODE: 'CREATE_NODE',
|
||||
SAVE: 'SAVE',
|
||||
SAVE_ALL: 'SAVE_ALL',
|
||||
|
||||
+18
-1
@@ -1,7 +1,8 @@
|
||||
import { TreeGraphData } from "@antv/g6/lib/types"
|
||||
import { BehaviorNodeModel, GraphNodeModel } from "./BehaviorTreeModel";
|
||||
import { BehaviorNodeModel, BehaviorTreeModel, GraphNodeModel } from "./BehaviorTreeModel";
|
||||
import Settings from "../main-process/Settings";
|
||||
import { remote } from "electron";
|
||||
import * as path from 'path';
|
||||
|
||||
export const cloneNodeData = (nodeData: GraphNodeModel) => {
|
||||
const newData: GraphNodeModel = {
|
||||
@@ -112,3 +113,19 @@ export const findFromAllChildren = (node: TreeGraphData, id: string): TreeGraphD
|
||||
export const getRemoteSettings = () => {
|
||||
return remote.getGlobal("settings") as Settings;
|
||||
}
|
||||
|
||||
export const fileName2treeName = (filename: string) => {
|
||||
return path.basename(filename).slice(0, -5);
|
||||
}
|
||||
|
||||
export const createNewTree = (filename: string) => {
|
||||
const tree: BehaviorTreeModel = {
|
||||
name: fileName2treeName(filename),
|
||||
root: {
|
||||
id: 1,
|
||||
name: 'Sequence',
|
||||
desc: '新建行为树'
|
||||
}
|
||||
}
|
||||
return tree;
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
import { Menu, app, dialog, BrowserWindow, MenuItem, WebContents, MenuItemConstructorOptions } from 'electron';
|
||||
import * as fs from 'fs';
|
||||
import * as Utils from '../common/Utils';
|
||||
import MainEventType from '../common/MainEventType';
|
||||
import { MainProcess } from './MainProcess';
|
||||
import Settings from './Settings';
|
||||
@@ -40,6 +42,24 @@ export default class AppMenu {
|
||||
return new MenuItem({
|
||||
label: "行为树",
|
||||
submenu: [
|
||||
{
|
||||
label: "新建",
|
||||
click: () => {
|
||||
(async () => {
|
||||
const res = await dialog.showSaveDialog({
|
||||
properties: ['showOverwriteConfirmation'],
|
||||
filters: [
|
||||
{ name: "Json", extensions: ['json'] }
|
||||
]
|
||||
});
|
||||
if (!res.canceled) {
|
||||
const path = res.filePath;
|
||||
fs.writeFileSync(path, JSON.stringify(Utils.createNewTree(path), null, 2));
|
||||
this.webContents.send(MainEventType.CREATE_TREE, path);
|
||||
}
|
||||
})();
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "打开文件",
|
||||
accelerator: "Ctrl+O",
|
||||
|
||||
@@ -22,7 +22,6 @@ const sampleNodeClassify: BehaviorNodeClassify[] = [
|
||||
]
|
||||
|
||||
|
||||
|
||||
export default class Settings {
|
||||
private settings: SettingsModel;
|
||||
curWorkspace?: Workspace;
|
||||
@@ -61,7 +60,7 @@ export default class Settings {
|
||||
this.settings = JSON.parse(str);
|
||||
} else {
|
||||
this.settings = {
|
||||
recentWorkspaces: [],
|
||||
recentWorkspaces: ['sample/workspace.json'],
|
||||
recentFiles: [],
|
||||
nodeClassify: sampleNodeClassify,
|
||||
};
|
||||
|
||||
@@ -2,6 +2,8 @@ import React, { Component } from "react";
|
||||
import { Menu, Input } from "antd";
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { ipcRenderer } from "electron";
|
||||
import MainEventType from "../common/MainEventType";
|
||||
|
||||
const { Search } = Input;
|
||||
|
||||
@@ -33,6 +35,12 @@ export default class Properties extends Component<PropertiesProps> {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
ipcRenderer.on(MainEventType.CREATE_TREE, (event: any, path: string) => {
|
||||
console.log("on Create tree", path);
|
||||
this.props.onOpenTree(path);
|
||||
this.forceUpdate();
|
||||
});
|
||||
|
||||
var workspace = this.props.workspace;
|
||||
if (workspace == '') {
|
||||
return;
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "test",
|
||||
"root": {
|
||||
"id": 1,
|
||||
"name": "Sequence",
|
||||
"desc": "新建行为树"
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"nodeConfPath": "sample\\node-config.json",
|
||||
"workdir": "sample\\workdir"
|
||||
"workdir": "E:\\code\\behavior3editor\\sample\\workdir"
|
||||
}
|
||||
Reference in new issue
Block a user