This commit is contained in:
honmono 2022-03-22 15:35:41 +08:00
parent 91e741a895
commit c7d30bc03b
16 changed files with 531 additions and 125 deletions

View File

@ -263,9 +263,9 @@
"_opacity": 255,
"_color": {
"__type__": "cc.Color",
"r": 27,
"g": 38,
"b": 46,
"r": 135,
"g": 135,
"b": 135,
"a": 255
},
"_contentSize": {

View File

@ -1,4 +1,5 @@
import { ComAttackable } from "../ECS/components/ComAttackable";
import { ComBeAttacked } from "../ECS/components/ComBeAttacked";
import { ComCocosNode } from "../ECS/components/ComCocosNode";
import { ComMonitor } from "../ECS/components/ComMonitor";
import { ComMovable } from "../ECS/components/ComMovable";
@ -43,7 +44,8 @@ export namespace BT {
/** 节点类型 */
export enum NodeType {
// 组合节点
Sequence, // 顺序节点
LockedSequence, // 锁状态顺序节点
Sequence, //
Selector, // 选择节点
RandomSelector, // 随机选择节点
Parallel, // 并行节点
@ -64,8 +66,12 @@ export namespace BT {
Monitor, // 监视
Attack,
EnoughAttr, // 死亡
GoDeath, // 检查是否
EnoughAttr, // 足够的属性
WillBeAttacked, // 即将收到攻击
Avoid, // 闪避
RunAway, // 逃跑
InAttacking
}
export class NodeBase {
@ -87,7 +93,6 @@ export namespace BT {
}
}
/** 依次执行子节点, 遇到执行失败的则退出并返回失败, 全部执行成功则返回成功 */
export class SequenceNode extends CombineNode {
public currIdx = 0;
public ignoreFailure = false;
@ -98,6 +103,17 @@ export namespace BT {
}
}
/** 依次执行子节点, 遇到执行失败的则退出并返回失败, 全部执行成功则返回成功 */
export class LockedSequenceNode extends CombineNode {
public currIdx = 0;
public ignoreFailure = false;
constructor(children: NodeBase[], ignoreFailture = false) {
super(NodeType.LockedSequence, children);
this.ignoreFailure = ignoreFailture;
}
}
/** 依次执行子节点, 遇到执行成功的则退出并返回成功, 全部执行失败则返回失败 */
export class SelectorNode extends CombineNode {
public currIdx:number = -1;
@ -226,7 +242,7 @@ export namespace BT {
}
export class AttackNode extends NodeBase {
constructor(waitSeconds: number) {
constructor() {
super(NodeType.Attack);
}
}
@ -243,12 +259,29 @@ export namespace BT {
}
}
export class GoDeathNode extends NodeBase {
public waitSeconds: number;
public countDown: number;
constructor(waitSeconds: number) {
super(NodeType.GoDeath);
this.waitSeconds = waitSeconds;
export class WillBeAttackedNode extends NodeBase {
constructor() {
super(NodeType.WillBeAttacked);
}
}
export class AvoidNode extends NodeBase {
public speed: number;
constructor(speed: number) {
super(NodeType.Avoid);
this.speed = speed;
}
}
export class RunAwayNode extends NodeBase {
constructor() {
super(NodeType.RunAway);
}
}
export class InAttackingNode extends NodeBase {
constructor() {
super(NodeType.InAttacking);
}
}
@ -267,6 +300,43 @@ export namespace BT {
node.state = NodeState.Executing;
},
onUpdate(node: SequenceNode, context: ExecuteContext) : void {
if(node.currIdx < 0 || node.currIdx >= node.children.length) {
// 越界了, 不应该发生, 直接认为是失败了
node.state = NodeState.Fail;
return;
}
// 检查前置条件是否满足
for(let i=0; i<node.currIdx; i++) {
context.executor.updateBTNode(node.children[i], context);
if(node.children[i].state !== NodeState.Success) return;
}
context.executor.updateBTNode(node.children[node.currIdx], context);
let state = node.children[node.currIdx].state;
if(state == NodeState.Executing) return;
if(state === NodeState.Fail && !node.ignoreFailure) {
node.state = NodeState.Fail;
return;
}
if(state === NodeState.Success && node.currIdx == node.children.length-1) {
node.state = NodeState.Success;
return ;
}
context.executor.onEnterBTNode(node.children[++node.currIdx], context);
}
};
/** LockedSequence node */
NodeHandlers[NodeType.LockedSequence] = {
onEnter(node: LockedSequenceNode, context: ExecuteContext) : void {
node.currIdx = 0;
context.executor.onEnterBTNode(node.children[node.currIdx], context);
node.state = NodeState.Executing;
},
onUpdate(node: LockedSequenceNode, context: ExecuteContext) : void {
if(node.state !== NodeState.Executing) return ;
if(node.currIdx < 0 || node.currIdx >= node.children.length) {
// 越界了, 不应该发生, 直接认为是失败了
@ -495,6 +565,7 @@ export namespace BT {
comMovable.points.push(cc.v2(comTrans.x, comTrans.y), node.targetPos);
comMovable.speed = node.speed;
comMovable.speedDirty = true;
comMovable.keepDir = false;
node.state = NodeState.Executing;
comMovable.running = false;
},
@ -519,6 +590,7 @@ export namespace BT {
comMovable.points.push(cc.v2(comTrans.x, comTrans.y), cc.v2(targetX, targetY));
comMovable.speed = node.speed;
comMovable.speedDirty = true;
comMovable.keepDir = false;
node.state = NodeState.Executing;
comMovable.running = false;
},
@ -539,12 +611,13 @@ export namespace BT {
let comMonitor = context.world.getComponent(context.entity, ComMonitor);
if(comMonitor.others.length <= 0) return ;
let target = context.world.getComponent(comMonitor.others[0], ComTransform);
let xOffdet = Math.sign(comTrans.x - target.x) * 10;
let xOffdet = Math.sign(comTrans.x - target.x) * 80;
comMovable.pointIdx = 0;
comMovable.points.length = 0;
comMovable.points.push(cc.v2(comTrans.x, comTrans.y), cc.v2(target.x + xOffdet, target.y));
comMovable.speed = node.speed;
comMovable.speedDirty = true;
comMovable.keepDir = false;
node.state = NodeState.Executing;
comMovable.running = false;
@ -555,6 +628,9 @@ export namespace BT {
let comMonitor = context.world.getComponent(context.entity, ComMonitor);
let comMovable = context.world.getComponent(context.entity, ComMovable);
if(comMovable.points.length == 0 || comMovable.pointIdx < 0 || comMovable.pointIdx >= comMovable.points.length) {
let target = context.world.getComponent(comMonitor.others[0], ComTransform);
comTrans.dir.x = Math.abs(comTrans.dir.x) * -Math.sign(comTrans.x - target.x)
node.state = BT.NodeState.Success;
return ;
}
@ -563,7 +639,7 @@ export namespace BT {
return ;
}
let target = context.world.getComponent(comMonitor.others[0], ComTransform);
let xOffdet = Math.sign(comTrans.x - target.x) * 10;
let xOffdet = Math.sign(comTrans.x - target.x) * 80;
comMovable.points[1].x = target.x + xOffdet;
comMovable.points[1].y = target.y;
}
@ -592,13 +668,18 @@ export namespace BT {
comCocosNode.events.push(new (EventAttack));
let comAttackable = context.world.getComponent(context.entity, ComAttackable);
comAttackable.duration = 1.2;
comAttackable.countDown = comAttackable.duration;
comAttackable.dirty = true;
comAttackable.hurtArea = cc.v2(20, 10);
comAttackable.debugInfo = null;
comAttackable.willHurtFrame = 0.8;
comAttackable.willHurtFrameCompleted = false;
comAttackable.hurtFrame = 0.5;
comAttackable.mustAttackFrame = 0.6;
comAttackable.attack = 10;
comAttackable.hurtFrameCompleted = false;
},
onUpdate(node: AttackNode, context: ExecuteContext) : void {
if(node.state !== NodeState.Executing) return ;
@ -624,21 +705,72 @@ export namespace BT {
}
};
/** GoDeath node */
NodeHandlers[NodeType.GoDeath] = {
onEnter(node: GoDeathNode, context: ExecuteContext) : void {
node.countDown = node.waitSeconds;
/** WillBeAttacked node */
NodeHandlers[NodeType.WillBeAttacked] = {
onEnter(node: WillBeAttackedNode, context: ExecuteContext) : void {
let comBeAttacked = context.world.getComponent(context.entity, ComBeAttacked);
if(!comBeAttacked) return ;
node.state = NodeState.Executing;
},
onUpdate(node: GoDeathNode, context: ExecuteContext) : void {
if(node.countDown <= 0) {
node.state = NodeState.Success;
onUpdate(node: WillBeAttackedNode, context: ExecuteContext) : void {
let comBeAttacked = context.world.getComponent(context.entity, ComBeAttacked);
let comMonitor = context.world.getComponent(context.entity, ComMonitor);
let monitor = comMonitor.others && comMonitor.others.indexOf(comBeAttacked.attacker) !== -1;
if(!comBeAttacked) return ;
node.state = (monitor && comBeAttacked.attacker !== -1 && Math.random() > 0.8) ? NodeState.Success : NodeState.Fail;
}
};
/** Avoid node */
NodeHandlers[NodeType.Avoid] = {
onEnter(node: AvoidNode, context: ExecuteContext) : void {
let comTrans = context.world.getComponent(context.entity, ComTransform);
let comMovable = context.world.getComponent(context.entity, ComMovable);
comMovable.pointIdx = 0;
comMovable.points.length = 0;
let selfPoint = cc.v2(comTrans.x, comTrans.y);
comMovable.points.push(selfPoint, selfPoint.sub(cc.v2(50 * Math.sign(comTrans.dir.x), 0)));
comMovable.speed = node.speed;
comMovable.speedDirty = true;
comMovable.running = false;
comMovable.keepDir = true;
node.state = NodeState.Executing;
},
onUpdate(node: AvoidNode, context: ExecuteContext) : void {
if(node.state !== NodeState.Executing) return ;
let comMovable = context.world.getComponent(context.entity, ComMovable);
if(!comMovable) {
node.state = BT.NodeState.Fail;
return ;
}
if(comMovable.points.length == 0 || comMovable.pointIdx < 0 || comMovable.pointIdx >= comMovable.points.length) {
node.state = BT.NodeState.Success;
}
}
};
/** NotInAttack node */
NodeHandlers[NodeType.InAttacking] = {
onEnter(node: InAttackingNode, context: ExecuteContext) : void {
let comAttackable = context.world.getComponent(context.entity, ComAttackable);
if(!comAttackable) return ;
node.state = NodeState.Executing;
},
onUpdate(node: InAttackingNode, context: ExecuteContext) : void {
let comAttackable = context.world.getComponent(context.entity, ComAttackable);
if(!comAttackable) return ;
node.state = (comAttackable.countDown > 0 && comAttackable.countDown < comAttackable.duration-0.2) ? NodeState.Success : NodeState.Fail;
}
};
}

View File

@ -30,24 +30,36 @@ export class ECSController<T extends ECSWorld> {
let comBehavior = this.world.addComponent(entity, ComBehaviorTree);
let view = cc.view.getVisibleSize();
let patrol = new BT.SequenceNode([
new BT.WaitNode(2),
new BT.WalkToRandomPosNode(100, cc.size(view.width - 200, view.height - 200)),
]);
let follow = new BT.SequenceNode([
new BT.WalkToTargetNode(250),
new BT.AttackNode(1.2)
]);
let mainBehavior = new BT.SelectorNode([
new BT.ParallelNode([
new BT.InverterNode(new BT.MonitorNode()),
patrol
], true),
follow
]);
let root = new BT.RepeaterNode(mainBehavior, 9999);
let root = new BT.RepeaterNode(
new BT.SelectorNode([
new BT.ParallelNode([
new BT.InverterNode(new BT.SequenceNode([
new BT.WillBeAttackedNode(),
new BT.InverterNode(new BT.InAttackingNode())
])),
new BT.SelectorNode([
new BT.ParallelNode([
new BT.InverterNode(new BT.MonitorNode()),
new BT.LockedSequenceNode([
new BT.WaitNode(1.5),
new BT.WalkToRandomPosNode(100, cc.size(view.width - 200, view.height - 200)),
])
], true),
new BT.LockedSequenceNode([
new BT.WalkToTargetNode(250),
new BT.AttackNode(),
new BT.WaitNode(0.8)
])
])
], true),
new BT.LockedSequenceNode([
new BT.AvoidNode(500),
new BT.WaitNode(1),
])
])
, 9999);
comBehavior.root = root;
@ -56,9 +68,10 @@ export class ECSController<T extends ECSWorld> {
comMovable.running = false;
let comMonitor = this.world.addComponent(entity, ComMonitor);
comMonitor.lookLen = 350;
comMonitor.lookSize = 300;
comMonitor.aroundLen = 100;
comMonitor.lookLen = 200;
comMonitor.lookWidth = 160;
comMonitor.outLen = 100;
comMonitor.aroundLen = 0;
let comRoleConfig = this.world.addComponent(entity, ComRoleConfig);
comRoleConfig.maxHP = 100;
@ -69,9 +82,13 @@ export class ECSController<T extends ECSWorld> {
let comAttackable = this.world.addComponent(entity, ComAttackable);
comAttackable.dirty = false;
comAttackable.duration = 1.2;
comAttackable.countDown = 0;
comAttackable.hurtArea = cc.v2(90, 30);
comAttackable.attack = 10;
let comBeAttack = this.world.addComponent(entity, ComBeAttacked);
let comBeAttacked = this.world.addComponent(entity, ComBeAttacked);
comBeAttacked.attacker = -1;
return entity;

View File

@ -1,6 +1,5 @@
import CocosHelper from "../Common/CocosHelper";
import FrameAnimation from "../Common/FrameAnimation";
import { EventBase, EventDeath, EventHPChange, EventType } from "../Struct/NodeEvent";
import { EventBase, EventDeath, EventGraphicsDraw, EventHPChange, EventType } from "../Struct/NodeEvent";
import { EventProcess } from "./EventProcess";
const {ccclass, property} = cc._decorator;
@ -10,8 +9,9 @@ export default class RoleEventProcess extends EventProcess {
@property(cc.Animation) anim: cc.Animation = null;
private graphics: cc.Graphics = null;
start () {
this.graphics = this.getComponent(cc.Graphics);
}
onAttach(): void {
@ -36,7 +36,12 @@ export default class RoleEventProcess extends EventProcess {
this.anim.play('run');
break;
case EventType.Attack:
this.anim.play('punch');
if(Math.random() > 0.5) {
this.anim.play('punch');
}else {
this.anim.play('attack');
}
_reset('stand');
break;
case EventType.Hurt:
@ -53,6 +58,10 @@ export default class RoleEventProcess extends EventProcess {
this._changeHP(event as EventHPChange);
break;
case EventType.GraphicsDraw:
this._graphicsDraw(event as EventGraphicsDraw);
break;
}
}
@ -64,6 +73,26 @@ export default class RoleEventProcess extends EventProcess {
CocosHelper.tweenFloat(from, to, 0.2, (v) => {
progressBar.progress = v;
});
}
private _graphicsDraw(event: EventGraphicsDraw) {
if(event.points.length <= 0) {
this.graphics.clear();
return ;
}
for(const p of event.points) {
p.subSelf(this.node.getPosition());
}
this.graphics.strokeColor = event.color;
this.graphics.moveTo(event.points[0].x, event.points[0].y);
for(let i=1; i<event.points.length; i++) {
this.graphics.lineTo(event.points[i].x, event.points[i].y);
}
this.graphics.lineTo(event.points[0].x, event.points[0].y);
this.graphics.stroke();
}
@ -71,7 +100,7 @@ export default class RoleEventProcess extends EventProcess {
this.node.x = x;
this.node.y = y;
this.node.getChildByName('sp').scaleX = dir.x >= 0 ? 3 : -3;
this.node.getChildByName('HP').x = dir.x >= 0 ? -30 : 30;
//this.node.getChildByName('HP').x = dir.x >= 0 ? -30 : 30;
}
// update (dt) {}

View File

@ -5,11 +5,19 @@ import { ECSComponent } from "../lib/ECSComponent";
export class ComAttackable {
public duration: number; // 攻击持续时间
public countDown: number; // 攻击剩余时间
public hurtFrame: number; // 攻击帧
public mustAttackFrame: number;
public hurted: boolean;
public dirty: boolean; //
public attack: number; // 攻击力
public willHurtFrame: number; // 即将攻击
public willHurtFrameCompleted: boolean; // 即将攻击完成
public hurtFrame: number; // 攻击
public hurtFrameCompleted: boolean; // 攻击完成
public attack: number; // 攻击力
public hurtArea: cc.Vec2; // 攻击区域
public debugInfo: any;
public willHurts: number[] = [];
}

View File

@ -1,7 +1,7 @@
import { ComType } from "../lib/Const";
import { ComType, EntityIndex } from "../lib/Const";
import { ECSComponent } from "../lib/ECSComponent";
@ECSComponent(ComType.ComBeAttacked)
export class ComBeAttacked {
public attacker: EntityIndex = -1;
}

View File

@ -4,7 +4,9 @@ import { ECSComponent } from "../lib/ECSComponent";
@ECSComponent(ComType.ComMonitor)
export class ComMonitor {
public lookLen = 0;
public lookSize = 0;
public lookWidth = 0;
public outLen = 0;
public aroundLen = 0;
public others: EntityIndex[] = [];
public debugInfo: any;
}

View File

@ -8,5 +8,7 @@ export class ComMovable {
public points: cc.Vec2[] = [];
public pointIdx = 0;
public keepDir = false;
public speedDirty = false;
}

View File

@ -1,5 +1,6 @@
import { ComAttackable } from "../components/ComAttackable";
import { ComBeAttacked } from "../components/ComBeAttacked";
import { ComMonitor } from "../components/ComMonitor";
import { ComRoleConfig } from "../components/ComRoleConfig";
import { ComTransform } from "../components/ComTransform";
import { ECSSystem } from "../lib/ECSSystem";
@ -31,20 +32,61 @@ export class SysAttack extends ECSSystem {
let comTransSelf = world.getComponent(entity, ComTransform);
let comAttackable = world.getComponent(entity, ComAttackable);
let comRoleConfigSelf = world.getComponent(entity, ComRoleConfig);
if(comAttackable.countDown <= 0) return ;
comAttackable.countDown -= dt;
if(!comAttackable.dirty) return ;
if(comAttackable.mustAttackFrame)
if(comAttackable.dirty && comAttackable.countDown <= comAttackable.hurtFrame) {
comAttackable.countDown -= dt;
if(comAttackable.countDown <= 0) {
comAttackable.dirty = false;
for(const entityOther of comAttackable.willHurts) {
let comBeAttacked = world.getComponent(entityOther, ComBeAttacked);
if(comBeAttacked && comBeAttacked.attacker == entity) comBeAttacked.attacker = -1;
}
comAttackable.willHurts.length = 0;
}
let limitX = comTransSelf.x + Math.sign(comTransSelf.dir.x) * comAttackable.hurtArea.x;
let minX = Math.min(comTransSelf.x, limitX);
let maxX = Math.max(comTransSelf.x, limitX);
let minY = comTransSelf.y - comAttackable.hurtArea.y;
let maxY = comTransSelf.y + comAttackable.hurtArea.y;
let _checkBeAttack = (entityOther: number) => {
if(entity == entityOther) return false;
let comRoleConfigOther = world.getComponent(entityOther, ComRoleConfig);
if(!comRoleConfigOther || comRoleConfigOther.team == comRoleConfigSelf.team) return false;
let comTransOther = world.getComponent(entityOther, ComTransform);
if(comTransOther.x < minX || comTransOther.x > maxX || Math.abs(comTransOther.y - comTransSelf.y) >= comAttackable.hurtArea.y) {
return false;
}
return true
}
comAttackable.debugInfo = {
points: [cc.v2(minX, minY), cc.v2(maxX, minY), cc.v2(maxX, maxY), cc.v2(minX, maxY)],
color: cc.Color.RED,
};
// 即将攻击未完成, 并且处于即将攻击时间段
if(!comAttackable.willHurtFrameCompleted && comAttackable.countDown <= comAttackable.willHurtFrame) {
comAttackable.willHurtFrameCompleted = true;
world.getFilter(FILTER_BEATTACKED).walk((entityOther: number) => {
if(!_checkBeAttack(entityOther)) return ;
let comBeAttackedOther = world.getComponent(entityOther, ComBeAttacked);
comBeAttackedOther.attacker = entity;
comAttackable.willHurts.push(entityOther)
return false;
})
}
if(!comAttackable.hurtFrameCompleted && comAttackable.countDown <= comAttackable.hurtFrame) {
comAttackable.hurtFrameCompleted = true;
world.getFilter(FILTER_BEATTACKED).walk((entityOther: number) => {
let comBeAttacked = world.getComponent(entityOther, ComBeAttacked);
if(comBeAttacked && comBeAttacked.attacker == entity) comBeAttacked.attacker = -1;
if(!_checkBeAttack(entityOther)) return ;
let comRoleConfigOther = world.getComponent(entityOther, ComRoleConfig);
let comTransOther = world.getComponent(entityOther, ComTransform);
if(!comRoleConfigOther || comRoleConfigOther.team == comRoleConfigSelf.team) return ;
let xDiff = comTransOther.x - comTransSelf.x;
if(xDiff * Math.sign(xDiff) >= comAttackable.hurtArea.x || Math.abs(comTransOther.y - comTransSelf.y) >= comAttackable.hurtArea.y) {
return ;
}
// 扣血
if(!comRoleConfigOther || comRoleConfigOther.nowHP <= 0) return ;
@ -55,11 +97,13 @@ export class SysAttack extends ECSSystem {
// 打断对方的攻击动作
let comAttackableOther = world.getComponent(entityOther, ComAttackable);
if(!comAttackableOther || comAttackableOther.countDown <= 0) return ;
if(comAttackableOther.countDown >= comAttackableOther.mustAttackFrame) {
comAttackableOther.dirty = false;
}
comAttackableOther.hurtFrameCompleted = true;
comAttackableOther.countDown = 0.25;
comAttackable.countDown = 0.25;
let comMonitorOther = world.getComponent(entityOther, ComMonitor);
if(comMonitorOther.others.indexOf(entity) == -1) {
comMonitorOther.others[0] = entity;
}
return false;
});

View File

@ -41,27 +41,31 @@ export class SysMonitor extends ECSSystem {
let comTrans = world.getComponent(entity, ComTransform);
let comRoleConfig = world.getComponent(entity, ComRoleConfig);
let a = cc.v2(comTrans.x, comTrans.y);
let centerPoint = a.add(comTrans.dir.mul(comMonitor.lookLen));
let b = centerPoint.add(cc.v2(comTrans.dir.y, -comTrans.dir.x).mul(comMonitor.lookWidth));
let c = centerPoint.add(cc.v2(-comTrans.dir.y, comTrans.dir.x).mul(comMonitor.lookWidth));
let d = centerPoint.add(comTrans.dir.mul(comMonitor.outLen));
comMonitor.debugInfo = {
points: [a, b, d, c],
color: cc.Color.BLUE,
};
// 判断当前monitor是否
filter.entities.forEach((value: boolean, otherEntity: number) => {
let comTransOther = world.getComponent(otherEntity, ComTransform);
let comRoleConfigOther = world.getComponent(otherEntity, ComRoleConfig);
if(entity == otherEntity || !comRoleConfigOther || comRoleConfigOther.team == comRoleConfig.team) return ;
let a = cc.v2(comTrans.x, comTrans.y);
let centerPoint = a.add(comTrans.dir.mul(comMonitor.lookLen));
let b = centerPoint.add(cc.v2(comTrans.dir.y, -comTrans.dir.x).mul(comMonitor.lookSize));
let c = centerPoint.add(cc.v2(-comTrans.dir.y, comTrans.dir.x).mul(comMonitor.lookSize));
let _check = (com: ComTransform) => {
return (a.sub(cc.v2(com.x, com.y)).len() < comMonitor.aroundLen || isInTriangle(cc.v2(com.x, com.y), a, b, c))
}
for(let i=comMonitor.others.length-1; i>=0; i--) {
const com = world.getComponent(comMonitor.others[i], ComTransform);
if(!com || !_check(com)) {
comMonitor.others.splice(i, 1);
}
return (a.sub(cc.v2(com.x, com.y)).len() < comMonitor.aroundLen || isInTriangle(cc.v2(com.x, com.y), a, b, c) || isInTriangle(cc.v2(com.x, com.y), b, c, d))
}
// for(let i=comMonitor.others.length-1; i>=0; i--) {
// const com = world.getComponent(comMonitor.others[i], ComTransform);
// if(!com || !_check(com)) {
// comMonitor.others.splice(i, 1);
// }
// }
if(comMonitor.others.indexOf(otherEntity) == -1 && _check(comTransOther)) {
comMonitor.others.push(otherEntity);

View File

@ -51,10 +51,12 @@ export class SysMovable extends ECSSystem {
comMovable.pointIdx ++;
continue;
}
comTrans.dir.x = offsetX / offsetLen;
comTrans.dir.y = offsetY / offsetLen;
comTrans.x += moveLen * comTrans.dir.x;
comTrans.y += moveLen * comTrans.dir.y;
if(!comMovable.keepDir) {
comTrans.dir.x = offsetX / offsetLen || comTrans.dir.x;
comTrans.dir.y = offsetY / offsetLen;
}
comTrans.x += moveLen * offsetX / offsetLen;
comTrans.y += moveLen * offsetY / offsetLen;
moveLen = -1;
}

View File

@ -1,4 +1,5 @@
import { EventDeath, EventHPChange, EventHurt, EventRun, EventStand } from "../../Struct/NodeEvent";
import { EventDeath, EventGraphicsDraw, EventHPChange, EventHurt, EventRun, EventStand } from "../../Struct/NodeEvent";
import { ComAttackable } from "../components/ComAttackable";
import { ComBehaviorTree } from "../components/ComBehaviorTree";
import { ComCocosNode } from "../components/ComCocosNode";
import { ComMonitor } from "../components/ComMonitor";
@ -33,6 +34,20 @@ export class SysRoleState extends ECSSystem {
if(!comCocosNode.loaded) return ;
let comRoleConfig = world.getComponent(entity, ComRoleConfig);
let comMovable = world.getComponent(entity, ComMovable);
let comMonitor = world.getComponent(entity, ComMonitor);
let comAttackable = world.getComponent(entity, ComAttackable);
comCocosNode.events.push(new EventGraphicsDraw([]));
if(comMonitor && comMonitor.debugInfo) {
comCocosNode.events.push(new EventGraphicsDraw(comMonitor.debugInfo.points, comMonitor.debugInfo.color));
}
if(comAttackable && comAttackable.debugInfo) {
comCocosNode.events.push(new EventGraphicsDraw(comAttackable.debugInfo.points, comAttackable.debugInfo.color));
}
if(comMovable && comMovable.speedDirty) {
comMovable.speedDirty = false;

View File

@ -4,7 +4,8 @@ export enum EventType {
Attack,
Hurt,
HPChange,
Death
Death,
GraphicsDraw,
}
export class EventBase {
@ -57,3 +58,13 @@ export class EventHPChange extends EventBase {
this.nowHP = nowHP;
}
}
export class EventGraphicsDraw extends EventBase {
public points: cc.Vec2[];
public color: cc.Color;
constructor(points: cc.Vec2[], color?: cc.Color) {
super(EventType.GraphicsDraw)
this.points = points;
this.color = color;
}
}

View File

@ -28,10 +28,13 @@
"_components": [
{
"__id__": 13
},
{
"__id__": 14
}
],
"_prefab": {
"__id__": 14
"__id__": 15
},
"_opacity": 255,
"_color": {
@ -115,8 +118,8 @@
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
"x": 0.25,
"y": 0
},
"_trs": {
"__type__": "TypedArray",
@ -273,8 +276,8 @@
"__type__": "TypedArray",
"ctor": "Float64Array",
"array": [
-30,
43.706,
15,
129.706,
0,
0,
0,
@ -478,6 +481,39 @@
},
"_id": ""
},
{
"__type__": "cc.Graphics",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 1
},
"_enabled": true,
"_materials": [
{
"__uuid__": "a153945d-2511-4c14-be7b-05d242f47d57"
}
],
"_lineWidth": 2,
"_strokeColor": {
"__type__": "cc.Color",
"r": 255,
"g": 0,
"b": 0,
"a": 255
},
"_lineJoin": 2,
"_lineCap": 0,
"_fillColor": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_miterLimit": 10,
"_id": ""
},
{
"__type__": "cc.PrefabInfo",
"root": {

View File

@ -28,10 +28,13 @@
"_components": [
{
"__id__": 13
},
{
"__id__": 14
}
],
"_prefab": {
"__id__": 14
"__id__": 15
},
"_opacity": 255,
"_color": {
@ -115,8 +118,8 @@
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
"x": 0.25,
"y": 0
},
"_trs": {
"__type__": "TypedArray",
@ -273,8 +276,8 @@
"__type__": "TypedArray",
"ctor": "Float64Array",
"array": [
-30,
43.706,
10,
119.706,
0,
0,
0,
@ -478,6 +481,39 @@
},
"_id": ""
},
{
"__type__": "cc.Graphics",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 1
},
"_enabled": true,
"_materials": [
{
"__uuid__": "a153945d-2511-4c14-be7b-05d242f47d57"
}
],
"_lineWidth": 2,
"_strokeColor": {
"__type__": "cc.Color",
"r": 255,
"g": 0,
"b": 0,
"a": 255
},
"_lineJoin": 2,
"_lineCap": 0,
"_fillColor": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_miterLimit": 10,
"_id": ""
},
{
"__type__": "cc.PrefabInfo",
"root": {

View File

@ -1,34 +1,34 @@
<mxfile host="65bd71144e">
<diagram id="endGVnAz2XQP9egm64uB" name="第 1 页">
<mxGraphModel dx="937" dy="767" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="0" shadow="0">
<mxGraphModel dx="937" dy="767" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="583" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="4" style="edgeStyle=none;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="2" target="3" edge="1">
<mxCell id="4" style="edgeStyle=none;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="2" target="48" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="2" value="&lt;div style=&quot;color: rgb(51 , 51 , 51) ; background-color: rgb(245 , 245 , 245) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;span style=&quot;color: #7a3e9d ; font-weight: bold&quot;&gt;RepeaterNode&lt;/span&gt;&lt;/div&gt;" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="504" y="20" width="120" height="60" as="geometry"/>
<mxGeometry x="530" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="5" style="edgeStyle=none;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="3" target="6" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="450" y="220" as="targetPoint"/>
<mxPoint x="670" y="320" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="24" style="edgeStyle=none;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="3" target="8" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="3" value="&lt;div style=&quot;color: rgb(51 , 51 , 51) ; background-color: rgb(245 , 245 , 245) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;span style=&quot;color: #7a3e9d ; font-weight: bold&quot;&gt;SelectorNode&lt;/span&gt;&lt;/div&gt;" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="504" y="120" width="120" height="60" as="geometry"/>
<mxGeometry x="580" y="310" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="14" style="edgeStyle=none;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="6" target="10" edge="1">
<mxCell id="40" style="edgeStyle=none;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="6" target="10" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="15" style="edgeStyle=none;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="6" target="11" edge="1">
<mxCell id="41" style="edgeStyle=none;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="6" target="11" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="6" value="&lt;div style=&quot;color: rgb(51 , 51 , 51) ; background-color: rgb(245 , 245 , 245) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;span style=&quot;color: #7a3e9d ; font-weight: bold&quot;&gt;ParallelNode&lt;/span&gt;&lt;/div&gt;" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="300" y="220" width="120" height="60" as="geometry"/>
<mxGeometry x="580" y="420" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="22" style="edgeStyle=none;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="8" target="20" edge="1">
<mxGeometry relative="1" as="geometry"/>
@ -36,14 +36,17 @@
<mxCell id="23" style="edgeStyle=none;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="8" target="21" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="8" value="&lt;div style=&quot;color: rgb(51 , 51 , 51) ; background-color: rgb(245 , 245 , 245) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;span style=&quot;color: #7a3e9d ; font-weight: bold&quot;&gt;SequenceNode&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="800" y="220" width="120" height="60" as="geometry"/>
<mxCell id="66" style="edgeStyle=none;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="8" target="65">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="8" value="&lt;div style=&quot;color: rgb(51 , 51 , 51) ; background-color: rgb(245 , 245 , 245) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;span style=&quot;color: #7a3e9d ; font-weight: bold&quot;&gt;LockedSequenceNode&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="870" y="510" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="13" style="edgeStyle=none;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="10" target="12" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="10" value="&lt;div style=&quot;color: rgb(51 , 51 , 51) ; background-color: rgb(245 , 245 , 245) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;span style=&quot;color: #7a3e9d ; font-weight: bold&quot;&gt;InverterNode&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="180" y="320" width="120" height="60" as="geometry"/>
<mxGeometry x="470" y="510" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="17" style="edgeStyle=none;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="11" target="16" edge="1">
<mxGeometry relative="1" as="geometry"/>
@ -51,23 +54,88 @@
<mxCell id="19" style="edgeStyle=none;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="11" target="18" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="11" value="&lt;div style=&quot;color: rgb(51 , 51 , 51) ; background-color: rgb(245 , 245 , 245) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;span style=&quot;color: #7a3e9d ; font-weight: bold&quot;&gt;SequenceNode&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="420" y="320" width="120" height="60" as="geometry"/>
<mxCell id="11" value="&lt;div style=&quot;color: rgb(51 , 51 , 51) ; background-color: rgb(245 , 245 , 245) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;span style=&quot;color: #7a3e9d ; font-weight: bold&quot;&gt;LockedSequenceNode&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="700" y="510" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="12" value="&lt;div style=&quot;color: rgb(51 , 51 , 51) ; background-color: rgb(245 , 245 , 245) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;span style=&quot;color: #7a3e9d ; font-weight: bold&quot;&gt;MonitorNode&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="180" y="420" width="120" height="60" as="geometry"/>
<mxGeometry x="470" y="610" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="16" value="&lt;div style=&quot;color: rgb(51 , 51 , 51) ; background-color: rgb(245 , 245 , 245) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;span style=&quot;color: #7a3e9d ; font-weight: bold&quot;&gt;WaitNode&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="340" y="420" width="120" height="60" as="geometry"/>
<mxGeometry x="630" y="600" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="18" value="&lt;div style=&quot;color: rgb(51 , 51 , 51) ; background-color: rgb(245 , 245 , 245) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;span style=&quot;color: #7a3e9d ; font-weight: bold&quot;&gt;WalkToRandomPosNode&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="510" y="420" width="120" height="60" as="geometry"/>
<mxGeometry x="700" y="680" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="20" value="&lt;div style=&quot;color: rgb(51 , 51 , 51) ; background-color: rgb(245 , 245 , 245) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;span style=&quot;color: #7a3e9d ; font-weight: bold&quot;&gt;WalkToTargetNode&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="710" y="320" width="120" height="60" as="geometry"/>
<mxGeometry x="800" y="600" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="21" value="&lt;div style=&quot;color: rgb(51 , 51 , 51) ; background-color: rgb(245 , 245 , 245) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;span style=&quot;color: #7a3e9d ; font-weight: bold&quot;&gt;AttackNode&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="890" y="320" width="120" height="60" as="geometry"/>
<mxGeometry x="870" y="680" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="27" value="&lt;div style=&quot;background-color: rgb(245 , 245 , 245) ; line-height: 18px&quot;&gt;&lt;div style=&quot;line-height: 18px&quot;&gt;&lt;font color=&quot;#7a3e9d&quot; face=&quot;menlo, monaco, courier new, monospace&quot;&gt;&lt;b&gt;WillBeAttacked&lt;/b&gt;&lt;/font&gt;&lt;br&gt;&lt;/div&gt;&lt;/div&gt;" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="240" y="490" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="29" value="&lt;div style=&quot;background-color: rgb(245 , 245 , 245) ; line-height: 18px&quot;&gt;&lt;div style=&quot;line-height: 18px&quot;&gt;&lt;font color=&quot;#7a3e9d&quot; face=&quot;menlo, monaco, courier new, monospace&quot;&gt;&lt;b&gt;Avoid&lt;/b&gt;&lt;/font&gt;&lt;br&gt;&lt;/div&gt;&lt;/div&gt;" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="740" y="270" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="38" style="edgeStyle=none;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="37" target="42" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="500" y="210" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="39" style="edgeStyle=none;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="37" target="3" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="37" value="&lt;div style=&quot;color: rgb(51 , 51 , 51) ; background-color: rgb(245 , 245 , 245) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;span style=&quot;color: #7a3e9d ; font-weight: bold&quot;&gt;ParallelNode&lt;/span&gt;&lt;/div&gt;" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="460" y="180" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="52" style="edgeStyle=none;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="42" target="51" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="42" value="&lt;div style=&quot;color: rgb(51 , 51 , 51) ; background-color: rgb(245 , 245 , 245) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;span style=&quot;color: #7a3e9d ; font-weight: bold&quot;&gt;InverterNode&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="370" y="300" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="49" style="edgeStyle=none;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="48" target="37" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="58" style="edgeStyle=none;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="48" target="57">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="48" value="&lt;div style=&quot;color: rgb(51 , 51 , 51) ; background-color: rgb(245 , 245 , 245) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;span style=&quot;color: #7a3e9d ; font-weight: bold&quot;&gt;SelectorNode&lt;/span&gt;&lt;/div&gt;" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="530" y="90" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="56" style="edgeStyle=none;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="51" target="27" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="63" style="edgeStyle=none;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="51" target="62">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="51" value="&lt;div style=&quot;color: rgb(51 , 51 , 51) ; background-color: rgb(245 , 245 , 245) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;span style=&quot;color: #7a3e9d ; font-weight: bold&quot;&gt;SequenceNode&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="310" y="410" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="53" value="&lt;font color=&quot;#7a3e9d&quot; face=&quot;menlo, monaco, courier new, monospace&quot;&gt;&lt;b&gt;InAttacking&lt;/b&gt;&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="310" y="650" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="60" style="edgeStyle=none;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="57" target="59">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="61" style="edgeStyle=none;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="57" target="29">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="57" value="&lt;div style=&quot;background-color: rgb(245 , 245 , 245) ; line-height: 18px&quot;&gt;&lt;div style=&quot;line-height: 18px&quot;&gt;&lt;font color=&quot;#7a3e9d&quot; face=&quot;menlo, monaco, courier new, monospace&quot;&gt;&lt;b&gt;LockedSequenceNode&lt;/b&gt;&lt;/font&gt;&lt;br&gt;&lt;/div&gt;&lt;/div&gt;" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="810" y="180" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="59" value="&lt;div style=&quot;background-color: rgb(245 , 245 , 245) ; line-height: 18px&quot;&gt;&lt;div style=&quot;line-height: 18px&quot;&gt;&lt;font color=&quot;#7a3e9d&quot; face=&quot;menlo, monaco, courier new, monospace&quot;&gt;&lt;b&gt;Wait&lt;/b&gt;&lt;/font&gt;&lt;br&gt;&lt;/div&gt;&lt;/div&gt;" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="880" y="270" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="64" style="edgeStyle=none;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="62" target="53">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="62" value="&lt;div style=&quot;color: rgb(51 , 51 , 51) ; background-color: rgb(245 , 245 , 245) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;span style=&quot;color: #7a3e9d ; font-weight: bold&quot;&gt;InverterNode&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="310" y="560" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="65" value="&lt;div style=&quot;background-color: rgb(245 , 245 , 245) ; font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;div style=&quot;font-family: &amp;#34;menlo&amp;#34; , &amp;#34;monaco&amp;#34; , &amp;#34;courier new&amp;#34; , monospace ; line-height: 18px&quot;&gt;&lt;font color=&quot;#7a3e9d&quot;&gt;&lt;b&gt;WaitNode&lt;/b&gt;&lt;/font&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="950" y="600" width="120" height="60" as="geometry"/>
</mxCell>
</root>
</mxGraphModel>