mirror of
https://github.com/kirikayakazuto/CocosCreator_ECS
synced 2024-12-24 02:39:26 +00:00
ECS Demo
This commit is contained in:
commit
91e741a895
51
.gitignore
vendored
Normal file
51
.gitignore
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
#/////////////////////////////////////////////////////////////////////////////
|
||||
# Fireball Projects
|
||||
#/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/library/
|
||||
/temp/
|
||||
/local/
|
||||
/build/
|
||||
|
||||
#/////////////////////////////////////////////////////////////////////////////
|
||||
# npm files
|
||||
#/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
npm-debug.log
|
||||
node_modules/
|
||||
|
||||
#/////////////////////////////////////////////////////////////////////////////
|
||||
# Logs and databases
|
||||
#/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
*.log
|
||||
*.sql
|
||||
*.sqlite
|
||||
|
||||
#/////////////////////////////////////////////////////////////////////////////
|
||||
# files for debugger
|
||||
#/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
*.sln
|
||||
*.pidb
|
||||
*.suo
|
||||
|
||||
#/////////////////////////////////////////////////////////////////////////////
|
||||
# OS generated files
|
||||
#/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
.DS_Store
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
|
||||
#/////////////////////////////////////////////////////////////////////////////
|
||||
# WebStorm files
|
||||
#/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
.idea/
|
||||
|
||||
#//////////////////////////
|
||||
# VS Code files
|
||||
#//////////////////////////
|
||||
|
||||
.vscode/
|
2
README.md
Executable file
2
README.md
Executable file
@ -0,0 +1,2 @@
|
||||
# hello-world
|
||||
Hello world new project template.
|
13
assets/Scene.meta
Executable file
13
assets/Scene.meta
Executable file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.3",
|
||||
"uuid": "29f52784-2fca-467b-92e7-8fd9ef8c57b7",
|
||||
"importer": "folder",
|
||||
"isBundle": false,
|
||||
"bundleName": "",
|
||||
"priority": 1,
|
||||
"compressionType": {},
|
||||
"optimizeHotUpdate": {},
|
||||
"inlineSpriteFrames": {},
|
||||
"isRemoteBundle": {},
|
||||
"subMetas": {}
|
||||
}
|
1313
assets/Scene/helloworld.fire
Executable file
1313
assets/Scene/helloworld.fire
Executable file
File diff suppressed because it is too large
Load Diff
8
assets/Scene/helloworld.fire.meta
Executable file
8
assets/Scene/helloworld.fire.meta
Executable file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"ver": "1.3.2",
|
||||
"uuid": "2d2f792f-a40c-49bb-a189-ed176a246e49",
|
||||
"importer": "scene",
|
||||
"asyncLoadAssets": false,
|
||||
"autoReleaseAssets": false,
|
||||
"subMetas": {}
|
||||
}
|
13
assets/Script.meta
Executable file
13
assets/Script.meta
Executable file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.3",
|
||||
"uuid": "4734c20c-0db8-4eb2-92ea-e692f4d70934",
|
||||
"importer": "folder",
|
||||
"isBundle": false,
|
||||
"bundleName": "",
|
||||
"priority": 1,
|
||||
"compressionType": {},
|
||||
"optimizeHotUpdate": {},
|
||||
"inlineSpriteFrames": {},
|
||||
"isRemoteBundle": {},
|
||||
"subMetas": {}
|
||||
}
|
13
assets/Script/Common.meta
Normal file
13
assets/Script/Common.meta
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.3",
|
||||
"uuid": "07d0024f-7d77-45fb-84e1-676ae4645108",
|
||||
"importer": "folder",
|
||||
"isBundle": false,
|
||||
"bundleName": "",
|
||||
"priority": 1,
|
||||
"compressionType": {},
|
||||
"optimizeHotUpdate": {},
|
||||
"inlineSpriteFrames": {},
|
||||
"isRemoteBundle": {},
|
||||
"subMetas": {}
|
||||
}
|
644
assets/Script/Common/BehaviorTree.ts
Normal file
644
assets/Script/Common/BehaviorTree.ts
Normal file
@ -0,0 +1,644 @@
|
||||
import { ComAttackable } from "../ECS/components/ComAttackable";
|
||||
import { ComCocosNode } from "../ECS/components/ComCocosNode";
|
||||
import { ComMonitor } from "../ECS/components/ComMonitor";
|
||||
import { ComMovable } from "../ECS/components/ComMovable";
|
||||
import { ComRoleConfig } from "../ECS/components/ComRoleConfig";
|
||||
import { ComTransform } from "../ECS/components/ComTransform";
|
||||
import { ECSWorld } from "../ECS/lib/ECSWorld";
|
||||
import { SysBehaviorTree } from "../ECS/systems/SysBehaviorTree";
|
||||
import { EventAttack, EventHPChange, EventHurt } from "../Struct/NodeEvent";
|
||||
export namespace BT {
|
||||
|
||||
export class BlackBoard {
|
||||
|
||||
}
|
||||
|
||||
export class ExecuteContext {
|
||||
executor: SysBehaviorTree;
|
||||
world: ECSWorld;
|
||||
bb: BlackBoard;
|
||||
|
||||
entity: number;
|
||||
dt: number;
|
||||
public init(executor: SysBehaviorTree, world: ECSWorld) {
|
||||
this.executor = executor;
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
public set(entity: number, dt: number, bb: BlackBoard) {
|
||||
this.entity = entity;
|
||||
this.dt = dt;
|
||||
this.bb = bb;
|
||||
}
|
||||
}
|
||||
|
||||
/** 节点状态 */
|
||||
export enum NodeState {
|
||||
Executing, // 执行中
|
||||
Success, // 成功
|
||||
Fail // 失败
|
||||
}
|
||||
|
||||
|
||||
/** 节点类型 */
|
||||
export enum NodeType {
|
||||
// 组合节点
|
||||
Sequence, // 顺序节点
|
||||
Selector, // 选择节点
|
||||
RandomSelector, // 随机选择节点
|
||||
Parallel, // 并行节点
|
||||
|
||||
// 修饰节点
|
||||
Inverter, // 逆变节点
|
||||
Success, // 成功节点
|
||||
Fail, // 失败节点
|
||||
Repeater, // 重复节点
|
||||
RetryTillSuccess, // 重复直到成功
|
||||
|
||||
// 叶子结点
|
||||
Wait, // 等待
|
||||
Action,
|
||||
WalkToPos,
|
||||
WalkToRandomPos, //
|
||||
WalkToTarget,
|
||||
Monitor, // 监视
|
||||
Attack,
|
||||
|
||||
EnoughAttr, // 死亡
|
||||
GoDeath, // 检查是否
|
||||
}
|
||||
|
||||
export class NodeBase {
|
||||
public type: NodeType;
|
||||
public state: NodeState = NodeState.Success;
|
||||
|
||||
constructor(type: NodeType) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
||||
/** 组合节点 */
|
||||
class CombineNode extends NodeBase {
|
||||
public children: NodeBase[] = [];
|
||||
|
||||
public constructor(type: NodeType, children: NodeBase[]) {
|
||||
super(type);
|
||||
this.children = children;
|
||||
}
|
||||
}
|
||||
|
||||
/** 依次执行子节点, 遇到执行失败的则退出并返回失败, 全部执行成功则返回成功 */
|
||||
export class SequenceNode extends CombineNode {
|
||||
public currIdx = 0;
|
||||
public ignoreFailure = false;
|
||||
|
||||
constructor(children: NodeBase[], ignoreFailture = false) {
|
||||
super(NodeType.Sequence, children);
|
||||
this.ignoreFailure = ignoreFailture;
|
||||
}
|
||||
}
|
||||
|
||||
/** 依次执行子节点, 遇到执行成功的则退出并返回成功, 全部执行失败则返回失败 */
|
||||
export class SelectorNode extends CombineNode {
|
||||
public currIdx:number = -1;
|
||||
|
||||
constructor(children: NodeBase[], ) {
|
||||
super(NodeType.Selector, children);
|
||||
}
|
||||
}
|
||||
|
||||
/** 根据权重随机选择执行某个子节点 */
|
||||
export class RandomSelectorNode extends CombineNode {
|
||||
public weights: number[]; // 权重
|
||||
public currIdx = -1; // 选中的节点
|
||||
constructor(children: NodeBase[], weigets?: number[]) {
|
||||
super(NodeType.RandomSelector, children);
|
||||
this.weights = weigets ? weigets : new Array(children.length).fill(1);
|
||||
}
|
||||
}
|
||||
|
||||
/** 并行执行所有子节点, 全部执行完毕后返回 */
|
||||
export class ParallelNode extends CombineNode {
|
||||
public ignoreFailture = true;
|
||||
constructor(children: NodeBase[], ignoreFailture: boolean) {
|
||||
super(NodeType.Parallel, children);
|
||||
this.ignoreFailture = ignoreFailture;
|
||||
}
|
||||
}
|
||||
|
||||
/** 修饰节点 */
|
||||
class DecoratorNode extends NodeBase {
|
||||
public child: NodeBase = null;
|
||||
public constructor(type: NodeType, child: NodeBase) {
|
||||
super(type);
|
||||
this.child = child;
|
||||
}
|
||||
}
|
||||
|
||||
/** 返回子节点执行结果的取反值 */
|
||||
export class InverterNode extends DecoratorNode {
|
||||
constructor(child: NodeBase) {
|
||||
super(NodeType.Inverter, child);
|
||||
}
|
||||
}
|
||||
|
||||
/** 子节点执行完毕后, 必定返回成功 */
|
||||
export class SuccessNode extends DecoratorNode {
|
||||
constructor(child: NodeBase) {
|
||||
super(NodeType.Success, child);
|
||||
}
|
||||
}
|
||||
|
||||
/** 子节点执行完毕后, 必定返回失败 */
|
||||
export class FailNode extends DecoratorNode {
|
||||
constructor(child: NodeBase) {
|
||||
super(NodeType.Fail, child);
|
||||
}
|
||||
}
|
||||
|
||||
/** 子节点执行重复repeatCount次后返回成功 */
|
||||
export class RepeaterNode extends DecoratorNode {
|
||||
public repeatCount = 1;
|
||||
public currRepeatCount = 0;
|
||||
public mustSuccess = false; // 子节点必须支持成功才增加重复次数
|
||||
constructor(child: NodeBase, repeatCount: number, mustSuccess = false) {
|
||||
super(NodeType.Repeater, child);
|
||||
this.repeatCount = repeatCount;
|
||||
this.mustSuccess = mustSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
/** 子节点重复执行直到返回成功 */
|
||||
export class RetryTillSuccess extends DecoratorNode {
|
||||
timeout: number; // 超时时间
|
||||
countDown: number; // 剩余时间
|
||||
constructor(child: NodeBase, timeout:number) {
|
||||
super(NodeType.RetryTillSuccess, child);
|
||||
this.timeout = timeout;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** 叶子结点 */
|
||||
export class WaitNode extends NodeBase {
|
||||
public waitSeconds:number;
|
||||
public countDown:number;
|
||||
|
||||
constructor(seconds:number) {
|
||||
super(NodeType.Wait);
|
||||
this.waitSeconds = seconds;
|
||||
}
|
||||
}
|
||||
|
||||
/** 移动到目标位置后 返回成功 */
|
||||
export class WalkToPosNode extends NodeBase {
|
||||
public speed:number;
|
||||
public targetPos: cc.Vec2;
|
||||
constructor(speed: number, pos: cc.Vec2) {
|
||||
super(NodeType.WalkToPos);
|
||||
this.speed = speed;
|
||||
this.targetPos = pos;
|
||||
}
|
||||
}
|
||||
|
||||
export class WalkToRandomPosNode extends NodeBase {
|
||||
public speed: number;
|
||||
public size: cc.Size;
|
||||
constructor(speed: number, size: cc.Size) {
|
||||
super(NodeType.WalkToRandomPos);
|
||||
this.speed = speed;
|
||||
this.size = size;
|
||||
}
|
||||
}
|
||||
|
||||
export class WalkToTargetNode extends NodeBase {
|
||||
public speed: number;
|
||||
constructor(speed: number) {
|
||||
super(NodeType.WalkToTarget);
|
||||
this.speed = speed;
|
||||
}
|
||||
}
|
||||
|
||||
export class MonitorNode extends NodeBase {
|
||||
constructor() {
|
||||
super(NodeType.Monitor);
|
||||
}
|
||||
}
|
||||
|
||||
export class AttackNode extends NodeBase {
|
||||
constructor(waitSeconds: number) {
|
||||
super(NodeType.Attack);
|
||||
}
|
||||
}
|
||||
|
||||
export class EnoughAttrNode extends NodeBase {
|
||||
public com: {prototype: any};
|
||||
public attr: string;
|
||||
public value: number;
|
||||
constructor(com: {prototype: any}, attr: string, value: number) {
|
||||
super(NodeType.EnoughAttr);
|
||||
this.com = com;
|
||||
this.attr = attr;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
export class GoDeathNode extends NodeBase {
|
||||
public waitSeconds: number;
|
||||
public countDown: number;
|
||||
constructor(waitSeconds: number) {
|
||||
super(NodeType.GoDeath);
|
||||
this.waitSeconds = waitSeconds;
|
||||
}
|
||||
}
|
||||
|
||||
class NodeHandler {
|
||||
onEnter:(node: NodeBase, context: ExecuteContext) => void;
|
||||
onUpdate:(node: NodeBase, context: ExecuteContext) => void;
|
||||
}
|
||||
|
||||
export const NodeHandlers : NodeHandler[] = [];
|
||||
|
||||
/** Sequence node */
|
||||
NodeHandlers[NodeType.Sequence] = {
|
||||
onEnter(node: SequenceNode, context: ExecuteContext) : void {
|
||||
node.currIdx = 0;
|
||||
context.executor.onEnterBTNode(node.children[node.currIdx], context);
|
||||
node.state = NodeState.Executing;
|
||||
},
|
||||
onUpdate(node: SequenceNode, context: ExecuteContext) : void {
|
||||
if(node.state !== NodeState.Executing) return ;
|
||||
if(node.currIdx < 0 || node.currIdx >= node.children.length) {
|
||||
// 越界了, 不应该发生, 直接认为是失败了
|
||||
node.state = NodeState.Fail;
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
/** Selector node */
|
||||
NodeHandlers[NodeType.Selector] = {
|
||||
onEnter(node: SelectorNode, context: ExecuteContext) : void {
|
||||
node.currIdx = 0;
|
||||
context.executor.onEnterBTNode(node.children[node.currIdx], context);
|
||||
node.state = NodeState.Executing;
|
||||
},
|
||||
onUpdate(node: SelectorNode, context: ExecuteContext) : void {
|
||||
if(node.state !== NodeState.Executing) return ;
|
||||
if(node.currIdx < 0 || node.currIdx >= node.children.length) {
|
||||
// 越界了, 认为是失败了
|
||||
node.state = NodeState.Fail;
|
||||
return;
|
||||
}
|
||||
|
||||
context.executor.updateBTNode(node.children[node.currIdx], context);
|
||||
let state = node.children[node.currIdx].state;
|
||||
if(state == NodeState.Executing) return;
|
||||
|
||||
// 执行到最后一个都失败了, 那边selector失败了
|
||||
if(state === NodeState.Fail && node.currIdx == node.children.length-1) {
|
||||
node.state = NodeState.Fail;
|
||||
return;
|
||||
}
|
||||
if(state == NodeState.Success) {
|
||||
node.state = NodeState.Success;
|
||||
return ;
|
||||
}
|
||||
context.executor.onEnterBTNode(node.children[++node.currIdx], context);
|
||||
}
|
||||
};
|
||||
|
||||
/** Selector node */
|
||||
NodeHandlers[NodeType.RandomSelector] = {
|
||||
onEnter(node: RandomSelectorNode, context: ExecuteContext) : void {
|
||||
// 根据权重随机获取idx
|
||||
let totalWeight = 0;
|
||||
for(const weight of node.weights) {
|
||||
totalWeight += weight;
|
||||
}
|
||||
let randomWeight = Math.random() * totalWeight;
|
||||
for(let i=0; i<node.weights.length; i++) {
|
||||
randomWeight -= node.weights[i];
|
||||
if(randomWeight <= 0) {
|
||||
node.currIdx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
context.executor.onEnterBTNode(node.children[node.currIdx], context);
|
||||
node.state = NodeState.Executing;
|
||||
},
|
||||
onUpdate(node: RandomSelectorNode, context: ExecuteContext) : void {
|
||||
if(node.state !== NodeState.Executing) return ;
|
||||
let n = node.children[node.currIdx];
|
||||
context.executor.updateBTNode(n, context);
|
||||
node.state = n.state;
|
||||
}
|
||||
};
|
||||
|
||||
/** Parallel node */
|
||||
NodeHandlers[NodeType.Parallel] = {
|
||||
onEnter(node: ParallelNode, context: ExecuteContext) : void {
|
||||
for(const n of node.children) {
|
||||
context.executor.onEnterBTNode(n, context);
|
||||
}
|
||||
node.state = NodeState.Executing;
|
||||
},
|
||||
onUpdate(node: ParallelNode, context: ExecuteContext) : void {
|
||||
if(node.state !== NodeState.Executing) return ;
|
||||
let end = true;
|
||||
for(const child of node.children) {
|
||||
context.executor.updateBTNode(child, context);
|
||||
if(child.state === NodeState.Executing) {
|
||||
end = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(child.state == NodeState.Fail) {
|
||||
node.state = NodeState.Fail;
|
||||
return ;
|
||||
}
|
||||
}
|
||||
if(end) {
|
||||
node.state = NodeState.Success;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/** Inverter node */
|
||||
NodeHandlers[NodeType.Inverter] = {
|
||||
onEnter(node: InverterNode, context: ExecuteContext) : void {
|
||||
context.executor.onEnterBTNode(node.child, context);
|
||||
node.state = NodeState.Executing;
|
||||
},
|
||||
onUpdate(node: InverterNode, context: ExecuteContext) : void {
|
||||
context.executor.updateBTNode(node.child, context);
|
||||
if(node.child.state === NodeState.Executing) return ;
|
||||
if(node.child.state == NodeState.Success) node.state = NodeState.Fail;
|
||||
if(node.child.state == NodeState.Fail) node.state = NodeState.Success;
|
||||
}
|
||||
};
|
||||
|
||||
/** Success node */
|
||||
NodeHandlers[NodeType.Success] = {
|
||||
onEnter(node: SuccessNode, context: ExecuteContext) : void {
|
||||
context.executor.onEnterBTNode(node.child, context);
|
||||
node.state = NodeState.Executing;
|
||||
},
|
||||
onUpdate(node: SuccessNode, context: ExecuteContext) : void {
|
||||
if(node.state !== NodeState.Executing) return ;
|
||||
context.executor.updateBTNode(node.child, context);
|
||||
if(node.child.state === NodeState.Executing) return ;
|
||||
node.state = NodeState.Success;
|
||||
}
|
||||
};
|
||||
|
||||
/** Fail node */
|
||||
NodeHandlers[NodeType.Fail] = {
|
||||
onEnter(node: FailNode, context: ExecuteContext) : void {
|
||||
context.executor.onEnterBTNode(node.child, context);
|
||||
node.state = NodeState.Executing;
|
||||
},
|
||||
onUpdate(node: FailNode, context: ExecuteContext) : void {
|
||||
if(node.state !== NodeState.Executing) return ;
|
||||
context.executor.updateBTNode(node.child, context);
|
||||
if(node.child.state === NodeState.Executing) return ;
|
||||
node.state = NodeState.Fail;
|
||||
}
|
||||
};
|
||||
|
||||
/** Repeater node */
|
||||
NodeHandlers[NodeType.Repeater] = {
|
||||
onEnter(node: RepeaterNode, context: ExecuteContext) : void {
|
||||
node.currRepeatCount = 0;
|
||||
context.executor.onEnterBTNode(node.child, context);
|
||||
node.state = NodeState.Executing;
|
||||
},
|
||||
onUpdate(node: RepeaterNode, context: ExecuteContext) : void {
|
||||
if(node.state !== NodeState.Executing) return ;
|
||||
context.executor.updateBTNode(node.child, context);
|
||||
if(node.child.state === NodeState.Executing) return ;
|
||||
if(!node.mustSuccess || node.child.state == NodeState.Success) node.currRepeatCount ++;
|
||||
if(node.currRepeatCount >= node.repeatCount) {
|
||||
node.state = NodeState.Success;
|
||||
return ;
|
||||
}
|
||||
context.executor.onEnterBTNode(node.child, context);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** RetryTillSuccess node */
|
||||
NodeHandlers[NodeType.RetryTillSuccess] = {
|
||||
onEnter(node: RetryTillSuccess, context: ExecuteContext) : void {
|
||||
node.countDown = node.timeout;
|
||||
context.executor.onEnterBTNode(node.child, context);
|
||||
node.state = NodeState.Executing;
|
||||
},
|
||||
|
||||
onUpdate(node: RetryTillSuccess, context: ExecuteContext) : void {
|
||||
if(node.state !== NodeState.Executing) return ;
|
||||
node.countDown -= context.dt;
|
||||
|
||||
context.executor.updateBTNode(node.child, context);
|
||||
if(node.child.state === NodeState.Executing) return ;
|
||||
|
||||
if(node.child.state == NodeState.Success) {
|
||||
node.state = NodeState.Success;
|
||||
return ;
|
||||
}
|
||||
|
||||
if(node.countDown > 0) {
|
||||
context.executor.onEnterBTNode(node.child, context);
|
||||
return ;
|
||||
}
|
||||
node.state = NodeState.Fail;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** Wait node */
|
||||
NodeHandlers[NodeType.Wait] = {
|
||||
onEnter(node: WaitNode, context: ExecuteContext) : void {
|
||||
node.countDown = node.waitSeconds;
|
||||
node.state = NodeState.Executing;
|
||||
},
|
||||
onUpdate(node: WaitNode, context: ExecuteContext) : void {
|
||||
if(node.state !== NodeState.Executing) return ;
|
||||
node.countDown -= context.dt;
|
||||
if(node.countDown <= 0) {
|
||||
node.state = NodeState.Success;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/** Wait node */
|
||||
NodeHandlers[NodeType.WalkToPos] = {
|
||||
onEnter(node: WalkToPosNode, 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;
|
||||
comMovable.points.push(cc.v2(comTrans.x, comTrans.y), node.targetPos);
|
||||
comMovable.speed = node.speed;
|
||||
comMovable.speedDirty = true;
|
||||
node.state = NodeState.Executing;
|
||||
comMovable.running = false;
|
||||
},
|
||||
onUpdate(node: WalkToPosNode, context: ExecuteContext) : void {
|
||||
if(node.state !== NodeState.Executing) return ;
|
||||
let comMovable = context.world.getComponent(context.entity, ComMovable);
|
||||
if(comMovable.points.length == 0 || comMovable.pointIdx < 0 || comMovable.pointIdx >= comMovable.points.length) {
|
||||
node.state = BT.NodeState.Success;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/** WalkToRandomPos node */
|
||||
NodeHandlers[NodeType.WalkToRandomPos] = {
|
||||
onEnter(node: WalkToRandomPosNode, 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 targetX = node.size.width * Math.random() - node.size.width/2;
|
||||
let targetY = node.size.height * Math.random() - node.size.height/2;
|
||||
comMovable.points.push(cc.v2(comTrans.x, comTrans.y), cc.v2(targetX, targetY));
|
||||
comMovable.speed = node.speed;
|
||||
comMovable.speedDirty = true;
|
||||
node.state = NodeState.Executing;
|
||||
comMovable.running = false;
|
||||
},
|
||||
onUpdate(node: WalkToPosNode, context: ExecuteContext) : void {
|
||||
if(node.state !== NodeState.Executing) return ;
|
||||
let comMovable = context.world.getComponent(context.entity, ComMovable);
|
||||
if(comMovable.points.length == 0 || comMovable.pointIdx < 0 || comMovable.pointIdx >= comMovable.points.length) {
|
||||
node.state = BT.NodeState.Success;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/** WalkToTarget node */
|
||||
NodeHandlers[NodeType.WalkToTarget] = {
|
||||
onEnter(node: WalkToTargetNode, context: ExecuteContext) : void {
|
||||
let comTrans = context.world.getComponent(context.entity, ComTransform);
|
||||
let comMovable = context.world.getComponent(context.entity, ComMovable);
|
||||
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;
|
||||
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;
|
||||
node.state = NodeState.Executing;
|
||||
comMovable.running = false;
|
||||
|
||||
},
|
||||
onUpdate(node: WalkToTargetNode, context: ExecuteContext) : void {
|
||||
if(node.state !== NodeState.Executing) return ;
|
||||
let comTrans = context.world.getComponent(context.entity, ComTransform);
|
||||
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) {
|
||||
node.state = BT.NodeState.Success;
|
||||
return ;
|
||||
}
|
||||
if(comMonitor.others.length <= 0) {
|
||||
node.state = BT.NodeState.Fail;
|
||||
return ;
|
||||
}
|
||||
let target = context.world.getComponent(comMonitor.others[0], ComTransform);
|
||||
let xOffdet = Math.sign(comTrans.x - target.x) * 10;
|
||||
comMovable.points[1].x = target.x + xOffdet;
|
||||
comMovable.points[1].y = target.y;
|
||||
}
|
||||
};
|
||||
|
||||
/** Monitor node */
|
||||
NodeHandlers[NodeType.Monitor] = {
|
||||
onEnter(node: MonitorNode, context: ExecuteContext) : void {
|
||||
let comMonitor = context.world.getComponent(context.entity, ComMonitor);
|
||||
if(!comMonitor) return ;
|
||||
node.state = NodeState.Executing;
|
||||
},
|
||||
onUpdate(node: MonitorNode, context: ExecuteContext) : void {
|
||||
let comMonitor = context.world.getComponent(context.entity, ComMonitor);
|
||||
node.state = comMonitor.others.length > 0 ? BT.NodeState.Success : BT.NodeState.Fail;
|
||||
}
|
||||
};
|
||||
|
||||
/** Monitor node */
|
||||
NodeHandlers[NodeType.Attack] = {
|
||||
onEnter(node: AttackNode, context: ExecuteContext) : void {
|
||||
node.state = NodeState.Executing;
|
||||
|
||||
let comCocosNode = context.world.getComponent(context.entity, ComCocosNode);
|
||||
if(!comCocosNode.loaded) return ;
|
||||
|
||||
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.hurtFrame = 0.5;
|
||||
comAttackable.mustAttackFrame = 0.6;
|
||||
comAttackable.attack = 10;
|
||||
},
|
||||
onUpdate(node: AttackNode, context: ExecuteContext) : void {
|
||||
if(node.state !== NodeState.Executing) return ;
|
||||
let comAttackable = context.world.getComponent(context.entity, ComAttackable);
|
||||
|
||||
if(comAttackable.countDown <= 0) {
|
||||
node.state = NodeState.Success;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/** EnoughAttr node */
|
||||
NodeHandlers[NodeType.EnoughAttr] = {
|
||||
onEnter(node: EnoughAttrNode, context: ExecuteContext) : void {
|
||||
let com = context.world.getComponent(context.entity, node.com);
|
||||
if(!com) return ;
|
||||
node.state = NodeState.Executing;
|
||||
},
|
||||
onUpdate(node: EnoughAttrNode, context: ExecuteContext) : void {
|
||||
let com = context.world.getComponent(context.entity, node.com);
|
||||
if(!com) return ;
|
||||
node.state = com[node.attr] >= node.value ? NodeState.Success : NodeState.Fail;
|
||||
}
|
||||
};
|
||||
|
||||
/** GoDeath node */
|
||||
NodeHandlers[NodeType.GoDeath] = {
|
||||
onEnter(node: GoDeathNode, context: ExecuteContext) : void {
|
||||
node.countDown = node.waitSeconds;
|
||||
node.state = NodeState.Executing;
|
||||
},
|
||||
onUpdate(node: GoDeathNode, context: ExecuteContext) : void {
|
||||
if(node.countDown <= 0) {
|
||||
node.state = NodeState.Success;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
10
assets/Script/Common/BehaviorTree.ts.meta
Normal file
10
assets/Script/Common/BehaviorTree.ts.meta
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "6cd218b5-3651-451d-90b5-5765b038f824",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
297
assets/Script/Common/CocosHelper.ts
Normal file
297
assets/Script/Common/CocosHelper.ts
Normal file
@ -0,0 +1,297 @@
|
||||
export class LoadProgress {
|
||||
public url: string;
|
||||
public completedCount: number;
|
||||
public totalCount: number;
|
||||
public item: any;
|
||||
public cb?: Function;
|
||||
}
|
||||
|
||||
/** 一些cocos api 的封装, promise函数统一加上sync后缀 */
|
||||
export default class CocosHelper {
|
||||
|
||||
public static async callInNextTick() {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
resolve(true);
|
||||
}, 0);
|
||||
})
|
||||
}
|
||||
|
||||
/** 加载进度 */
|
||||
public static loadProgress = new LoadProgress();
|
||||
|
||||
/** 等待时间, 秒为单位 */
|
||||
public static sleepSync = function(dur: number): Promise<boolean> {
|
||||
return new Promise((resolve, reject) => {
|
||||
cc.Canvas.instance.scheduleOnce(() => {
|
||||
resolve(true);
|
||||
}, dur);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param target
|
||||
* @param repeat -1,表示永久执行
|
||||
* @param tweens
|
||||
*/
|
||||
public static async runRepeatTweenSync(target: any, repeat: number, ...tweens: cc.Tween[]) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let selfTween = cc.tween(target);
|
||||
for(const tmpTween of tweens) {
|
||||
selfTween = selfTween.then(tmpTween);
|
||||
}
|
||||
if(repeat < 0) {
|
||||
cc.tween(target).repeatForever(selfTween).start();
|
||||
}else {
|
||||
cc.tween(target).repeat(repeat, selfTween).call(() => {
|
||||
resolve(true);
|
||||
}).start();
|
||||
}
|
||||
});
|
||||
}
|
||||
/** 同步的tween */
|
||||
public static async runTweenSync(target: any, ...tweens: cc.Tween[]): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
let selfTween = cc.tween(target);
|
||||
for(const tmpTween of tweens) {
|
||||
selfTween = selfTween.then(tmpTween);
|
||||
}
|
||||
selfTween.call(() => {
|
||||
resolve();
|
||||
}).start();
|
||||
});
|
||||
}
|
||||
/** 停止tween */
|
||||
public stopTween(target: any) {
|
||||
cc.Tween.stopAllByTarget(target);
|
||||
}
|
||||
public stopTweenByTag(tag: number) {
|
||||
cc.Tween.stopAllByTag(tag);
|
||||
}
|
||||
/** 同步的动作, 在2.4.x action已经被废弃了, 不建议使用 */
|
||||
public static async runActionSync(node: cc.Node, ...actions: cc.FiniteTimeAction[]) {
|
||||
if(!actions || actions.length <= 0) return ;
|
||||
return new Promise((resolve, reject) => {
|
||||
actions.push(cc.callFunc(() => {
|
||||
resolve(true);
|
||||
}));
|
||||
node.runAction(cc.sequence(actions));
|
||||
});
|
||||
}
|
||||
|
||||
/** 同步的动画 */
|
||||
public static async runAnimSync(node: cc.Node, animName?: string | number) {
|
||||
let anim = node.getComponent(cc.Animation);
|
||||
if(!anim) return ;
|
||||
let clip: cc.AnimationClip = null;
|
||||
if(!animName) clip = anim.defaultClip;
|
||||
else {
|
||||
let clips = anim.getClips();
|
||||
if(typeof(animName) === "number") {
|
||||
clip = clips[animName];
|
||||
}else if(typeof(animName) === "string") {
|
||||
for(let i=0; i<clips.length; i++) {
|
||||
if(clips[i].name === animName) {
|
||||
clip = clips[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!clip) return ;
|
||||
await CocosHelper.sleepSync(clip.duration);
|
||||
}
|
||||
|
||||
/** 加载资源异常时抛出错误 */
|
||||
public static loadResThrowErrorSync<T>(url: string, type: typeof cc.Asset, onProgress?: (completedCount: number, totalCount: number, item: any) => void): Promise<T> {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static _loadingMap: {[key: string]: Function[]} = {};
|
||||
public static loadRes<T>(url: string, type: typeof cc.Asset, callback: Function ) {
|
||||
if(this._loadingMap[url]) {
|
||||
this._loadingMap[url].push(callback);
|
||||
return ;
|
||||
}
|
||||
this._loadingMap[url] = [callback];
|
||||
this.loadResSync<T>(url, type).then((data: any) => {
|
||||
let arr = this._loadingMap[url];
|
||||
for(const func of arr) {
|
||||
func(data);
|
||||
}
|
||||
this._loadingMap[url] = null;
|
||||
delete this._loadingMap[url];
|
||||
});
|
||||
}
|
||||
/** 加载资源 */
|
||||
public static loadResSync<T>(url: string, type: typeof cc.Asset, onProgress?: (completedCount: number, totalCount: number, item: any) => void): Promise<T>{
|
||||
return new Promise((resolve, reject) => {
|
||||
if(!onProgress) onProgress = this._onProgress;
|
||||
cc.resources.load(url, type, onProgress, (err, asset: any) => {
|
||||
if (err) {
|
||||
cc.error(`${url} [资源加载] 错误 ${err}`);
|
||||
resolve(null);
|
||||
}else {
|
||||
resolve(asset);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 加载进度
|
||||
* cb方法 其实目的是可以将loader方法的progress
|
||||
*/
|
||||
private static _onProgress(completedCount: number, totalCount: number, item: any) {
|
||||
CocosHelper.loadProgress.completedCount = completedCount;
|
||||
CocosHelper.loadProgress.totalCount = totalCount;
|
||||
CocosHelper.loadProgress.item = item;
|
||||
CocosHelper.loadProgress.cb && CocosHelper.loadProgress.cb(completedCount, totalCount, item);
|
||||
}
|
||||
/**
|
||||
* 寻找子节点
|
||||
*/
|
||||
public static findChildInNode(nodeName: string, rootNode: cc.Node): cc.Node {
|
||||
if(rootNode.name == nodeName) {
|
||||
return rootNode;
|
||||
}
|
||||
for(let i=0; i<rootNode.childrenCount; i++) {
|
||||
let node = this.findChildInNode(nodeName, rootNode.children[i]);
|
||||
if(node) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** 获得Component的类名 */
|
||||
public static getComponentName(com: Function) {
|
||||
let arr = com.name.match(/<.*>$/);
|
||||
if(arr && arr.length > 0) {
|
||||
return arr[0].slice(1, -1);
|
||||
}
|
||||
return com.name;
|
||||
}
|
||||
/** 加载bundle */
|
||||
public static loadBundleSync(url: string, options: any): Promise<cc.AssetManager.Bundle> {
|
||||
return new Promise((resolve, reject) => {
|
||||
cc.assetManager.loadBundle(url, options, (err: Error, bundle: cc.AssetManager.Bundle) => {
|
||||
if(!err) {
|
||||
cc.error(`加载bundle失败, url: ${url}, err:${err}`);
|
||||
resolve(null);
|
||||
}else {
|
||||
resolve(bundle);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** 路径是相对分包文件夹路径的相对路径 */
|
||||
public static loadAssetFromBundleSync(bundleName: string, url: string) {
|
||||
let bundle = cc.assetManager.getBundle(bundleName);
|
||||
if(!bundle) {
|
||||
cc.error(`加载bundle中的资源失败, 未找到bundle, bundleUrl:${bundleName}`);
|
||||
return null;
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
bundle.load(url, (err, asset: cc.Asset | cc.Asset[]) => {
|
||||
if(err) {
|
||||
cc.error(`加载bundle中的资源失败, 未找到asset, url:${url}, err:${err}`);
|
||||
resolve(null);
|
||||
}else {
|
||||
resolve(asset);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** 通过路径加载资源, 如果这个资源在bundle内, 会先加载bundle, 在解开bundle获得对应的资源 */
|
||||
public static loadAssetSync(url: string) {
|
||||
return new Promise((resolve, reject) => {
|
||||
cc.resources.load(url, (err, assets: cc.Asset | cc.Asset[]) => {
|
||||
if(!err) {
|
||||
cc.error(`加载asset失败, url:${url}, err: ${err}`);
|
||||
resolve(null);
|
||||
}else {
|
||||
this.addRef(assets);
|
||||
resolve(assets);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
/** 释放资源 */
|
||||
public static releaseAsset(assets: cc.Asset | cc.Asset[]) {
|
||||
this.decRes(assets);
|
||||
}
|
||||
/** 增加引用计数 */
|
||||
private static addRef(assets: cc.Asset | cc.Asset[]) {
|
||||
if(assets instanceof Array) {
|
||||
for(const a of assets) {
|
||||
a.addRef();
|
||||
}
|
||||
}else {
|
||||
assets.addRef();
|
||||
}
|
||||
}
|
||||
/** 减少引用计数, 当引用计数减少到0时,会自动销毁 */
|
||||
private static decRes(assets: cc.Asset | cc.Asset[]) {
|
||||
if(assets instanceof Array) {
|
||||
for(const a of assets) {
|
||||
a.decRef();
|
||||
}
|
||||
}else {
|
||||
assets.decRef();
|
||||
}
|
||||
}
|
||||
|
||||
/** 截图 */
|
||||
public static captureScreen(camera: cc.Camera, prop?: cc.Node | cc.Rect) {
|
||||
let newTexture = new cc.RenderTexture();
|
||||
let oldTexture = camera.targetTexture;
|
||||
let rect: cc.Rect = cc.rect(0, 0, cc.visibleRect.width, cc.visibleRect.height);
|
||||
if(prop) {
|
||||
if(prop instanceof cc.Node) {
|
||||
rect = prop.getBoundingBoxToWorld();
|
||||
}else {
|
||||
rect = prop;
|
||||
}
|
||||
}
|
||||
newTexture.initWithSize(cc.visibleRect.width, cc.visibleRect.height, cc.game['_renderContext'].STENCIL_INDEX8);
|
||||
camera.targetTexture = newTexture;
|
||||
camera.render();
|
||||
camera.targetTexture = oldTexture;
|
||||
|
||||
let buffer = new ArrayBuffer(rect.width * rect.height * 4);
|
||||
let data = new Uint8Array(buffer);
|
||||
newTexture.readPixels(data, rect.x, rect.y, rect.width, rect.height);
|
||||
return data;
|
||||
}
|
||||
|
||||
public static tweenFloat(from: number, to: number, duration: number, onUpdate: (t: number) => void, onComplete?: Function, autoStart: boolean = true) {
|
||||
let o: Record<string, number> = { _value: from };
|
||||
Object.defineProperty(o, 'value', {
|
||||
get: () => o._value,
|
||||
set: (v: number) => { o._value = v; onUpdate && onUpdate(o._value); },
|
||||
});
|
||||
let tween = cc.tween(o).to(duration, { value: to }).call(onComplete);
|
||||
if (autoStart) {
|
||||
tween.start();
|
||||
}
|
||||
return tween;
|
||||
}
|
||||
|
||||
public static tweenVec2(from: cc.Vec2, to: cc.Vec2, duration: number, onUpdate: (t: cc.Vec2) => void, onComplete?: Function, autoStart: boolean = true) {
|
||||
let o: Record<string, cc.Vec2> = {_value: from};
|
||||
Object.defineProperty(o, 'value', {
|
||||
get: () => o._value,
|
||||
set: (v: cc.Vec2) => { o._value = v; onUpdate && onUpdate(o._value); },
|
||||
});
|
||||
let tween = cc.tween(o).to(duration, { value: to }).call(onComplete);
|
||||
if (autoStart) {
|
||||
tween.start();
|
||||
}
|
||||
return tween;
|
||||
}
|
||||
|
||||
}
|
||||
|
10
assets/Script/Common/CocosHelper.ts.meta
Normal file
10
assets/Script/Common/CocosHelper.ts.meta
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "dc730152-9513-4cfe-b6f9-8d6cfdfc0e23",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
77
assets/Script/Common/FrameAnimation.ts
Normal file
77
assets/Script/Common/FrameAnimation.ts
Normal file
@ -0,0 +1,77 @@
|
||||
const {ccclass, property} = cc._decorator;
|
||||
|
||||
@ccclass('FrameConfig')
|
||||
class FrameConfig {
|
||||
@property(cc.Integer) frames: number = 0; //
|
||||
@property(cc.Integer) frameInterval = 1; // 帧数
|
||||
|
||||
offsetFrame = 0; // 偏移量
|
||||
}
|
||||
|
||||
@ccclass
|
||||
export default class FrameAnimation extends cc.Component {
|
||||
|
||||
@property(cc.Sprite) sprite: cc.Sprite = null;
|
||||
@property(cc.SpriteAtlas) spriteAtlas: cc.SpriteAtlas = null;
|
||||
@property(FrameConfig) frameConfigs: FrameConfig[] = [];
|
||||
|
||||
@property(cc.Boolean) playOnLoad = false;
|
||||
@property(cc.Boolean) loop = false;
|
||||
@property(cc.Integer) defaultConfig = 0;
|
||||
|
||||
private _passInterval = 0;
|
||||
private _currFrame = 0;
|
||||
private _currFrameConfig: FrameConfig = null;
|
||||
private _playing = false;
|
||||
private _loop = false;
|
||||
private _callback: Function;
|
||||
|
||||
start () {
|
||||
if(!this.sprite) this.sprite = this.getComponent(cc.Sprite);
|
||||
|
||||
let offset = 0;
|
||||
for(const config of this.frameConfigs) {
|
||||
config.offsetFrame += offset;
|
||||
offset += config.frames;
|
||||
}
|
||||
|
||||
this._loop = this.loop;
|
||||
|
||||
if(this.playOnLoad) {
|
||||
this._currFrameConfig = this.frameConfigs[this.defaultConfig];
|
||||
this._playing = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
play(configIdx: number, loop: boolean, callback?: Function) {
|
||||
this._currFrameConfig = this.frameConfigs[configIdx];
|
||||
this._loop = loop;
|
||||
this._currFrame = 0;
|
||||
this._playing = true;
|
||||
this._callback = callback;
|
||||
}
|
||||
|
||||
stop() {
|
||||
this._playing = false;
|
||||
}
|
||||
|
||||
update (dt: number) {
|
||||
if(!this._playing) return ;
|
||||
|
||||
this._passInterval ++;
|
||||
if(this._passInterval < this._currFrameConfig.frameInterval) return ;
|
||||
this._passInterval = 0;
|
||||
|
||||
this.sprite.spriteFrame = this.spriteAtlas.getSpriteFrames()[this._currFrameConfig.offsetFrame + this._currFrame];
|
||||
this._currFrame ++;
|
||||
|
||||
if(this._currFrame < this._currFrameConfig.frames) return ;
|
||||
|
||||
if(this._loop) this._currFrame = 0;
|
||||
else {
|
||||
this._playing = false;
|
||||
this._callback && this._callback();
|
||||
}
|
||||
}
|
||||
}
|
10
assets/Script/Common/FrameAnimation.ts.meta
Normal file
10
assets/Script/Common/FrameAnimation.ts.meta
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "60f21b10-95a9-4650-83ae-ff5522171c04",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
13
assets/Script/Core.meta
Normal file
13
assets/Script/Core.meta
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.3",
|
||||
"uuid": "5e76ac49-9cf7-4eba-9b00-da0cbbdf8778",
|
||||
"importer": "folder",
|
||||
"isBundle": false,
|
||||
"bundleName": "",
|
||||
"priority": 1,
|
||||
"compressionType": {},
|
||||
"optimizeHotUpdate": {},
|
||||
"inlineSpriteFrames": {},
|
||||
"isRemoteBundle": {},
|
||||
"subMetas": {}
|
||||
}
|
79
assets/Script/Core/ECSController.ts
Normal file
79
assets/Script/Core/ECSController.ts
Normal file
@ -0,0 +1,79 @@
|
||||
import { BT } from "../Common/BehaviorTree";
|
||||
import { ComAttackable } from "../ECS/components/ComAttackable";
|
||||
import { ComBeAttacked } from "../ECS/components/ComBeAttacked";
|
||||
import { ComBehaviorTree } from "../ECS/components/ComBehaviorTree";
|
||||
import { ComCocosNode } from "../ECS/components/ComCocosNode";
|
||||
import { ComMonitor } from "../ECS/components/ComMonitor";
|
||||
import { ComMovable } from "../ECS/components/ComMovable";
|
||||
import { ComNodeConfig } from "../ECS/components/ComNodeConfig";
|
||||
import { ComRoleConfig } from "../ECS/components/ComRoleConfig";
|
||||
import { ComTransform } from "../ECS/components/ComTransform";
|
||||
import { ECSWorld } from "../ECS/lib/ECSWorld";
|
||||
|
||||
export class ECSController<T extends ECSWorld> {
|
||||
public world: T;
|
||||
public createRoleEntity(name: string) {
|
||||
let entity = this.world.createEntity();
|
||||
|
||||
// 添加nodeconfig
|
||||
let comMap = this.world.addComponent(entity, ComNodeConfig);
|
||||
comMap.id = 1;
|
||||
comMap.layer = 0;
|
||||
comMap.prefabUrl = `${name}/${name}`;
|
||||
|
||||
// 添加transform
|
||||
let comTrans = this.world.addComponent(entity, ComTransform);
|
||||
comTrans.x = 0;
|
||||
comTrans.y = 0;
|
||||
|
||||
// 添加behavior tree
|
||||
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);
|
||||
|
||||
comBehavior.root = root;
|
||||
|
||||
let comMovable = this.world.addComponent(entity, ComMovable);
|
||||
comMovable.pointIdx = -1;
|
||||
comMovable.running = false;
|
||||
|
||||
let comMonitor = this.world.addComponent(entity, ComMonitor);
|
||||
comMonitor.lookLen = 350;
|
||||
comMonitor.lookSize = 300;
|
||||
comMonitor.aroundLen = 100;
|
||||
|
||||
let comRoleConfig = this.world.addComponent(entity, ComRoleConfig);
|
||||
comRoleConfig.maxHP = 100;
|
||||
comRoleConfig.lastHP = 100;
|
||||
comRoleConfig.nowHP = 100;
|
||||
comRoleConfig.attack = 10;
|
||||
comRoleConfig.team = name == 'Biker' ? 1 : 2;
|
||||
|
||||
let comAttackable = this.world.addComponent(entity, ComAttackable);
|
||||
comAttackable.dirty = false;
|
||||
comAttackable.countDown = 0;
|
||||
|
||||
let comBeAttack = this.world.addComponent(entity, ComBeAttacked);
|
||||
|
||||
|
||||
return entity;
|
||||
}
|
||||
}
|
10
assets/Script/Core/ECSController.ts.meta
Normal file
10
assets/Script/Core/ECSController.ts.meta
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "f4905a62-50f2-4508-8932-c2446dc9ee16",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
21
assets/Script/Core/EventProcess.ts
Normal file
21
assets/Script/Core/EventProcess.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { EventBase } from "../Struct/NodeEvent";
|
||||
|
||||
const {ccclass, property} = cc._decorator;
|
||||
|
||||
@ccclass
|
||||
export class EventProcess extends cc.Component {
|
||||
public onAttach(): void {
|
||||
|
||||
}
|
||||
|
||||
public onDetach(): void {
|
||||
|
||||
}
|
||||
|
||||
public processEvent(event: EventBase): void {
|
||||
|
||||
}
|
||||
|
||||
public sync(x: number, y: number, dir: cc.Vec2) {
|
||||
}
|
||||
}
|
10
assets/Script/Core/EventProcess.ts.meta
Normal file
10
assets/Script/Core/EventProcess.ts.meta
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "421fe0f3-34ce-4d96-8ede-370f051cdb61",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
78
assets/Script/Core/RoleEventProcess.ts
Normal file
78
assets/Script/Core/RoleEventProcess.ts
Normal file
@ -0,0 +1,78 @@
|
||||
import CocosHelper from "../Common/CocosHelper";
|
||||
import FrameAnimation from "../Common/FrameAnimation";
|
||||
import { EventBase, EventDeath, EventHPChange, EventType } from "../Struct/NodeEvent";
|
||||
import { EventProcess } from "./EventProcess";
|
||||
|
||||
const {ccclass, property} = cc._decorator;
|
||||
|
||||
@ccclass
|
||||
export default class RoleEventProcess extends EventProcess {
|
||||
|
||||
@property(cc.Animation) anim: cc.Animation = null;
|
||||
|
||||
start () {
|
||||
|
||||
}
|
||||
|
||||
onAttach(): void {
|
||||
|
||||
}
|
||||
|
||||
onDetach(): void {
|
||||
|
||||
}
|
||||
|
||||
processEvent(event: EventBase): void {
|
||||
let _reset = (name: string) => {
|
||||
this.anim.on(cc.Animation.EventType.FINISHED, () => {
|
||||
this.anim.play(name);
|
||||
}, this);
|
||||
}
|
||||
switch(event.type) {
|
||||
case EventType.Stand:
|
||||
this.anim.play('stand');
|
||||
break;
|
||||
case EventType.Run:
|
||||
this.anim.play('run');
|
||||
break;
|
||||
case EventType.Attack:
|
||||
this.anim.play('punch');
|
||||
_reset('stand');
|
||||
break;
|
||||
case EventType.Hurt:
|
||||
this.anim.play('hurt');
|
||||
_reset('stand');
|
||||
break;
|
||||
case EventType.Death:
|
||||
this.anim.play('death');
|
||||
this.anim.on(cc.Animation.EventType.FINISHED, () => {
|
||||
(event as EventDeath).callback();
|
||||
}, this);
|
||||
break;
|
||||
case EventType.HPChange:
|
||||
this._changeHP(event as EventHPChange);
|
||||
break;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private _changeHP(event: EventHPChange) {
|
||||
let progressBar = this.node.getChildByName("HP").getComponent(cc.ProgressBar);
|
||||
let from = event.lastHP / event.maxHP;
|
||||
let to = event.nowHP / event.maxHP;
|
||||
CocosHelper.tweenFloat(from, to, 0.2, (v) => {
|
||||
progressBar.progress = v;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public sync(x: number, y: number, dir: cc.Vec2) {
|
||||
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;
|
||||
}
|
||||
|
||||
// update (dt) {}
|
||||
}
|
10
assets/Script/Core/RoleEventProcess.ts.meta
Normal file
10
assets/Script/Core/RoleEventProcess.ts.meta
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "d38f8101-a4d4-422a-95ce-643759bfe803",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
13
assets/Script/ECS.meta
Normal file
13
assets/Script/ECS.meta
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.3",
|
||||
"uuid": "bf25ebfe-4ae5-4c18-8033-bb2bc7293a03",
|
||||
"importer": "folder",
|
||||
"isBundle": false,
|
||||
"bundleName": "",
|
||||
"priority": 1,
|
||||
"compressionType": {},
|
||||
"optimizeHotUpdate": {},
|
||||
"inlineSpriteFrames": {},
|
||||
"isRemoteBundle": {},
|
||||
"subMetas": {}
|
||||
}
|
13
assets/Script/ECS/components.meta
Executable file
13
assets/Script/ECS/components.meta
Executable file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.3",
|
||||
"uuid": "3878b852-fe53-405d-a5bf-3978aedd9ce7",
|
||||
"importer": "folder",
|
||||
"isBundle": false,
|
||||
"bundleName": "",
|
||||
"priority": 1,
|
||||
"compressionType": {},
|
||||
"optimizeHotUpdate": {},
|
||||
"inlineSpriteFrames": {},
|
||||
"isRemoteBundle": {},
|
||||
"subMetas": {}
|
||||
}
|
15
assets/Script/ECS/components/ComAttackable.ts
Normal file
15
assets/Script/ECS/components/ComAttackable.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { ComType, EntityIndex } from "../lib/Const";
|
||||
import { ECSComponent } from "../lib/ECSComponent";
|
||||
|
||||
@ECSComponent(ComType.ComAttackable)
|
||||
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 hurtArea: cc.Vec2; // 攻击区域
|
||||
}
|
10
assets/Script/ECS/components/ComAttackable.ts.meta
Normal file
10
assets/Script/ECS/components/ComAttackable.ts.meta
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "7ee555b4-eed0-4207-81f5-41b51bb3bd73",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
7
assets/Script/ECS/components/ComBeAttacked.ts
Normal file
7
assets/Script/ECS/components/ComBeAttacked.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { ComType } from "../lib/Const";
|
||||
import { ECSComponent } from "../lib/ECSComponent";
|
||||
|
||||
@ECSComponent(ComType.ComBeAttacked)
|
||||
export class ComBeAttacked {
|
||||
|
||||
}
|
10
assets/Script/ECS/components/ComBeAttacked.ts.meta
Normal file
10
assets/Script/ECS/components/ComBeAttacked.ts.meta
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "c3d913ea-e619-4f5e-bb18-3fe947505dda",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
9
assets/Script/ECS/components/ComBehaviorTree.ts
Normal file
9
assets/Script/ECS/components/ComBehaviorTree.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { BT } from "../../Common/BehaviorTree";
|
||||
import { ComType } from "../lib/Const";
|
||||
import { ECSComponent } from "../lib/ECSComponent";
|
||||
|
||||
@ECSComponent(ComType.ComBehaviorTree)
|
||||
export class ComBehaviorTree {
|
||||
public root: BT.NodeBase = null;
|
||||
public bb: BT.BlackBoard = new BT.BlackBoard();
|
||||
}
|
10
assets/Script/ECS/components/ComBehaviorTree.ts.meta
Normal file
10
assets/Script/ECS/components/ComBehaviorTree.ts.meta
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "a529fff3-0126-4e53-a4c7-e5ddb6d76976",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
10
assets/Script/ECS/components/ComCocosNode.ts
Normal file
10
assets/Script/ECS/components/ComCocosNode.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { EventBase } from "../../Struct/NodeEvent";
|
||||
import { ComType } from "../lib/Const";
|
||||
import { ECSComponent } from "../lib/ECSComponent";
|
||||
|
||||
@ECSComponent(ComType.ComCocosNode)
|
||||
export class ComCocosNode {
|
||||
public node: cc.Node = null;
|
||||
public loaded = false;
|
||||
public events: EventBase[] = [];
|
||||
}
|
10
assets/Script/ECS/components/ComCocosNode.ts.meta
Normal file
10
assets/Script/ECS/components/ComCocosNode.ts.meta
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "e75ab1ce-3260-45cb-975a-9c4c1ab72f94",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
10
assets/Script/ECS/components/ComMonitor.ts
Normal file
10
assets/Script/ECS/components/ComMonitor.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { ComType, EntityIndex } from "../lib/Const";
|
||||
import { ECSComponent } from "../lib/ECSComponent";
|
||||
|
||||
@ECSComponent(ComType.ComMonitor)
|
||||
export class ComMonitor {
|
||||
public lookLen = 0;
|
||||
public lookSize = 0;
|
||||
public aroundLen = 0;
|
||||
public others: EntityIndex[] = [];
|
||||
}
|
10
assets/Script/ECS/components/ComMonitor.ts.meta
Normal file
10
assets/Script/ECS/components/ComMonitor.ts.meta
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "274fabed-397f-4950-b691-2c6b6b894c9f",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
12
assets/Script/ECS/components/ComMovable.ts
Executable file
12
assets/Script/ECS/components/ComMovable.ts
Executable file
@ -0,0 +1,12 @@
|
||||
import { ComType } from "../lib/Const";
|
||||
import { ECSComponent } from "../lib/ECSComponent";
|
||||
|
||||
@ECSComponent(ComType.ComMovable)
|
||||
export class ComMovable {
|
||||
public running = false;
|
||||
public speed = 0;
|
||||
public points: cc.Vec2[] = [];
|
||||
public pointIdx = 0;
|
||||
|
||||
public speedDirty = false;
|
||||
}
|
10
assets/Script/ECS/components/ComMovable.ts.meta
Executable file
10
assets/Script/ECS/components/ComMovable.ts.meta
Executable file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "773fd91d-89d6-499e-9488-3d85f11938a1",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
9
assets/Script/ECS/components/ComNodeConfig.ts
Normal file
9
assets/Script/ECS/components/ComNodeConfig.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { ComType } from "../lib/Const";
|
||||
import { ECSComponent } from "../lib/ECSComponent";
|
||||
|
||||
@ECSComponent(ComType.ComNodeConfig)
|
||||
export class ComNodeConfig {
|
||||
id = 0; // 唯一标识
|
||||
prefabUrl = ''
|
||||
layer = 0; // 层级
|
||||
}
|
10
assets/Script/ECS/components/ComNodeConfig.ts.meta
Normal file
10
assets/Script/ECS/components/ComNodeConfig.ts.meta
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "ef2ff8f3-8ffa-49f6-8e55-b8ba0284a095",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
16
assets/Script/ECS/components/ComRoleConfig.ts
Normal file
16
assets/Script/ECS/components/ComRoleConfig.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { ComType } from "../lib/Const";
|
||||
import { ECSComponent } from "../lib/ECSComponent";
|
||||
|
||||
|
||||
@ECSComponent(ComType.ComRoleConfig)
|
||||
export class ComRoleConfig {
|
||||
public team: number;
|
||||
public maxHP: number;
|
||||
public lastHP: number;
|
||||
public nowHP: number;
|
||||
public HPDirty: boolean;
|
||||
|
||||
public attack: number;
|
||||
|
||||
public moveSpeed: number;
|
||||
}
|
10
assets/Script/ECS/components/ComRoleConfig.ts.meta
Normal file
10
assets/Script/ECS/components/ComRoleConfig.ts.meta
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "a0036aea-32a4-4b9b-a587-5262ea4cedf7",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
11
assets/Script/ECS/components/ComTransform.ts
Normal file
11
assets/Script/ECS/components/ComTransform.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { ComType } from "../lib/Const";
|
||||
import { ECSComponent } from "../lib/ECSComponent";
|
||||
|
||||
@ECSComponent(ComType.ComTransform)
|
||||
export class ComTransform {
|
||||
public dir = cc.v2(1, 0); //方向向量
|
||||
public x = 0;
|
||||
public y = 0;
|
||||
public width = 0;
|
||||
public height = 0;
|
||||
}
|
10
assets/Script/ECS/components/ComTransform.ts.meta
Normal file
10
assets/Script/ECS/components/ComTransform.ts.meta
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "0bb2991a-84c5-4b22-ade6-59d2e7e97252",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
13
assets/Script/ECS/lib.meta
Executable file
13
assets/Script/ECS/lib.meta
Executable file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.3",
|
||||
"uuid": "fa6ac7d5-2bad-42ee-90ba-44147985428d",
|
||||
"importer": "folder",
|
||||
"isBundle": false,
|
||||
"bundleName": "",
|
||||
"priority": 1,
|
||||
"compressionType": {},
|
||||
"optimizeHotUpdate": {},
|
||||
"inlineSpriteFrames": {},
|
||||
"isRemoteBundle": {},
|
||||
"subMetas": {}
|
||||
}
|
16
assets/Script/ECS/lib/Const.ts
Normal file
16
assets/Script/ECS/lib/Const.ts
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
export type EntityIndex = number;
|
||||
|
||||
export type ComPoolIndex = number;
|
||||
|
||||
export enum ComType {
|
||||
ComCocosNode = 0,
|
||||
ComMovable = 1,
|
||||
ComNodeConfig = 2,
|
||||
ComBehaviorTree = 3,
|
||||
ComTransform = 4,
|
||||
ComMonitor = 5,
|
||||
ComRoleConfig = 6,
|
||||
ComAttackable = 7,
|
||||
ComBeAttacked = 8
|
||||
}
|
10
assets/Script/ECS/lib/Const.ts.meta
Executable file
10
assets/Script/ECS/lib/Const.ts.meta
Executable file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "ce38ec2f-50f5-4f7a-ad24-48a576032322",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
36
assets/Script/ECS/lib/ECSComponent.ts
Executable file
36
assets/Script/ECS/lib/ECSComponent.ts
Executable file
@ -0,0 +1,36 @@
|
||||
import { ComType, EntityIndex } from "./Const";
|
||||
|
||||
/** 构造函数 */
|
||||
export interface ECSComConstructor extends Function {
|
||||
new(): any;
|
||||
}
|
||||
|
||||
export interface ECSTypedComConstructor<T> extends ECSComConstructor {
|
||||
new():T;
|
||||
}
|
||||
|
||||
/** 通过type存取 构造函数 */
|
||||
const ComConsMap: {[key: number]: ECSComConstructor} = cc.js.createMap();
|
||||
function RegistComConstructor(comType: ComType, func: ECSComConstructor) {
|
||||
ComConsMap[comType] = func;
|
||||
}
|
||||
export function GetComConstructor(comType: ComType) {
|
||||
return ComConsMap[comType];
|
||||
}
|
||||
|
||||
/** 通过构造函数存取 type */
|
||||
function SetComConstructorType(comCons: ECSComConstructor, type: ComType) {
|
||||
comCons['__type__'] = type;
|
||||
}
|
||||
export function GetComConstructorType<T>(comCons: {prototype: T}): ComType {
|
||||
return comCons['__type__'];
|
||||
}
|
||||
|
||||
/** ECSComponent */
|
||||
export function ECSComponent(type: ComType) {
|
||||
return function(func: ECSComConstructor) {
|
||||
SetComConstructorType(func, type);
|
||||
RegistComConstructor(type, func);
|
||||
};
|
||||
}
|
||||
|
10
assets/Script/ECS/lib/ECSComponent.ts.meta
Executable file
10
assets/Script/ECS/lib/ECSComponent.ts.meta
Executable file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "58b062eb-ce1e-49dd-8520-15713b92a51f",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
35
assets/Script/ECS/lib/ECSComponentPool.ts
Executable file
35
assets/Script/ECS/lib/ECSComponentPool.ts
Executable file
@ -0,0 +1,35 @@
|
||||
import { ComPoolIndex } from "./Const";
|
||||
import { ECSTypedComConstructor } from "./ECSComponent";
|
||||
|
||||
/**
|
||||
* 组件池
|
||||
*/
|
||||
export class ECSComponentPool<T> {
|
||||
private _componentConstructor: ECSTypedComConstructor<T>;
|
||||
public constructor(comCons: ECSTypedComConstructor<T>) {
|
||||
this._componentConstructor = comCons;
|
||||
}
|
||||
|
||||
private _components: T[] = []; // components
|
||||
private _reservedIdxs: ComPoolIndex[] = []; // 缓存的component idx
|
||||
|
||||
|
||||
public get(idx: ComPoolIndex): T {
|
||||
return this._components[idx];
|
||||
}
|
||||
|
||||
public alloc(): ComPoolIndex {
|
||||
if(this._reservedIdxs.length > 0) {
|
||||
let ret = this._reservedIdxs.pop();
|
||||
this._componentConstructor.apply(this._components[ret]); // 重置对象
|
||||
return ret;
|
||||
}
|
||||
let newInstance = new this._componentConstructor();
|
||||
this._components.push(newInstance);
|
||||
return this._components.length - 1;
|
||||
}
|
||||
|
||||
public free(idx: ComPoolIndex) {
|
||||
this._reservedIdxs.push(idx);
|
||||
}
|
||||
}
|
10
assets/Script/ECS/lib/ECSComponentPool.ts.meta
Executable file
10
assets/Script/ECS/lib/ECSComponentPool.ts.meta
Executable file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "a40c60fb-7834-4de4-b1e9-6a346dd68e60",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
67
assets/Script/ECS/lib/ECSEntity.ts
Executable file
67
assets/Script/ECS/lib/ECSEntity.ts
Executable file
@ -0,0 +1,67 @@
|
||||
import {ECSWorld} from "./ECSWorld"
|
||||
import {ECSComConstructor, GetComConstructorType } from "./ECSComponent";
|
||||
import { ComPoolIndex, ComType } from "./Const";
|
||||
import { ECSComponentPool } from "./ECSComponentPool";
|
||||
|
||||
/** 实体 */
|
||||
export class Entity {
|
||||
public id: number; // 唯一标识
|
||||
public index: number; //
|
||||
public dead: boolean; //
|
||||
|
||||
// 实体上的组件, 存放的是ComponentPool的index
|
||||
private _components: Array<ComPoolIndex> = new Array<ComPoolIndex>(Object.keys(ComType).length/2).fill(-1);
|
||||
|
||||
private _world: ECSWorld = null;
|
||||
public get world(): ECSWorld {
|
||||
return this._world;
|
||||
}
|
||||
public set world(world: ECSWorld) {
|
||||
this._world = world;
|
||||
}
|
||||
|
||||
/** 获取实体上的组件 */
|
||||
public getComponent<T>(typeOrFunc: ComType | {prototype: T}): ComPoolIndex {
|
||||
let type = typeof typeOrFunc == 'number' ? typeOrFunc : GetComConstructorType(typeOrFunc);
|
||||
let comPoolIdx = this._components[type];
|
||||
if(comPoolIdx == -1) return -1;
|
||||
return comPoolIdx;
|
||||
}
|
||||
|
||||
/** 添加组件 */
|
||||
public addComponent<T>(func: {prototype: T}): ComPoolIndex {
|
||||
let type = GetComConstructorType(func);
|
||||
if(this._components[type] !== -1) {
|
||||
return this._components[type];
|
||||
}
|
||||
let comPoolIdx = this._components[type] = this._world.getComponentPool(func).alloc();
|
||||
this._world.setEntityDirty(this);
|
||||
return comPoolIdx;
|
||||
}
|
||||
|
||||
/** 移除组件 */
|
||||
public removeComponent<T extends ECSComConstructor>(func: ECSComConstructor, dirty = true) {
|
||||
let comPoolIdx = this._components[GetComConstructorType(func)];
|
||||
if(comPoolIdx == -1) {
|
||||
console.error(`[ECSEntity]: removeComponent error, type: ${GetComConstructorType(func)}`);
|
||||
return false;
|
||||
}
|
||||
this._components[GetComConstructorType(func)] = -1;
|
||||
this._world.getComponentPool<ECSComponentPool<T>>(func).free(comPoolIdx);
|
||||
dirty && this._world.setEntityDirty(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** 移除所有组件 */
|
||||
public removeAllComponents(dirty: boolean) {
|
||||
for(let type = 0; type < this._components.length; type++) {
|
||||
let comPoolIdx = this._components[type];
|
||||
if(comPoolIdx == -1) continue;
|
||||
this._world.getComponentPool<ECSComponentPool<any>>(type).free(comPoolIdx);
|
||||
}
|
||||
this._components.fill(-1);
|
||||
if(dirty) {
|
||||
this._world.setEntityDirty(this);
|
||||
}
|
||||
}
|
||||
}
|
10
assets/Script/ECS/lib/ECSEntity.ts.meta
Executable file
10
assets/Script/ECS/lib/ECSEntity.ts.meta
Executable file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "f6eafcbc-0cee-4a3d-90a7-d1d89d934869",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
67
assets/Script/ECS/lib/ECSFillter.ts
Executable file
67
assets/Script/ECS/lib/ECSFillter.ts
Executable file
@ -0,0 +1,67 @@
|
||||
import { ComType, EntityIndex } from "./Const";
|
||||
import { Entity } from "./ECSEntity";
|
||||
import { ECSWorld } from "./ECSWorld";
|
||||
|
||||
export class ECSFillter {
|
||||
private _world: ECSWorld = null;
|
||||
|
||||
private _entitiesMap = new Map<EntityIndex, boolean>();
|
||||
|
||||
private _acceptComTypes: ComType[] = []; // 接收的组件类型
|
||||
private _rejectComTypes: ComType[] = []; // 拒绝的组件类型
|
||||
|
||||
public constructor(world: ECSWorld, accepts?: ComType[], rejects?: ComType[]) {
|
||||
this._world = world;
|
||||
this._acceptComTypes = accepts && accepts.length > 0 ? accepts : this._acceptComTypes;
|
||||
this._rejectComTypes = rejects && rejects.length > 0 ? rejects : this._rejectComTypes;
|
||||
}
|
||||
|
||||
public get entities() {
|
||||
return this._entitiesMap;
|
||||
}
|
||||
|
||||
public onEntityEnter(entity: EntityIndex) {
|
||||
if(this._entitiesMap.has(entity)) {
|
||||
console.warn(`[ECSFillter]: addEntity entity is had ${entity}`);
|
||||
return true;
|
||||
}
|
||||
this._entitiesMap.set(entity, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
public onEntityLeave(entity: EntityIndex) {
|
||||
if(!this._entitiesMap.has(entity)) {
|
||||
console.warn(`[ECSFillter]: removeEntity entity not had ${entity}`);
|
||||
return true;
|
||||
}
|
||||
this._entitiesMap.delete(entity);
|
||||
}
|
||||
|
||||
public walk(callback?: (entity: number) => boolean) {
|
||||
this._entitiesMap.forEach((value, entity) => {
|
||||
callback(entity);
|
||||
});
|
||||
}
|
||||
|
||||
public isAccept(entity: Entity) {
|
||||
for(let i = 0; i < this._acceptComTypes.length; i++) {
|
||||
if(entity.getComponent(this._acceptComTypes[i]) == -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for(let i = 0; i < this._rejectComTypes.length; i++) {
|
||||
if(entity.getComponent(this._rejectComTypes[i]) !== -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public isContains(entity: number) {
|
||||
return this._entitiesMap.has(entity);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
10
assets/Script/ECS/lib/ECSFillter.ts.meta
Executable file
10
assets/Script/ECS/lib/ECSFillter.ts.meta
Executable file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "a2265ecd-3751-461b-9d2f-755ccc56c3da",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
14
assets/Script/ECS/lib/ECSSystem.ts
Executable file
14
assets/Script/ECS/lib/ECSSystem.ts
Executable file
@ -0,0 +1,14 @@
|
||||
import { ECSWorld } from "./ECSWorld";
|
||||
|
||||
export abstract class ECSSystem {
|
||||
/** 连接 */
|
||||
public abstract onAdd(world: ECSWorld): void;
|
||||
/** 断开连接 */
|
||||
public abstract onRemove(world: ECSWorld): void;
|
||||
/** 添加实体 */
|
||||
public abstract onEntityEnter(world: ECSWorld, entity: number): void;
|
||||
/** */
|
||||
public abstract onEntityLeave(world: ECSWorld, entity: number): void;
|
||||
/** 更新 */
|
||||
public abstract onUpdate(world: ECSWorld, dt: number): void;
|
||||
}
|
10
assets/Script/ECS/lib/ECSSystem.ts.meta
Executable file
10
assets/Script/ECS/lib/ECSSystem.ts.meta
Executable file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "925b6e67-1234-4933-a867-339843b9a663",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
203
assets/Script/ECS/lib/ECSWorld.ts
Executable file
203
assets/Script/ECS/lib/ECSWorld.ts
Executable file
@ -0,0 +1,203 @@
|
||||
import { Entity } from "./ECSEntity"
|
||||
import { ECSFillter } from "./ECSFillter"
|
||||
import { ECSComConstructor, GetComConstructor as GetComConstructor, GetComConstructorType } from "./ECSComponent";
|
||||
import { ECSSystem } from "./ECSSystem";
|
||||
import { ComPoolIndex, ComType, EntityIndex } from "./Const";
|
||||
import { ECSComponentPool } from "./ECSComponentPool";
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export class ECSWorld {
|
||||
private _systems: ECSSystem[] = []; // world内所有的system
|
||||
private _entities: Entity[] = []; // world内所有的entity
|
||||
private _reservedIds: number[] = []; // 缓存
|
||||
|
||||
private _componentPools: ECSComponentPool<any>[] = [];
|
||||
private _fillters = new Map<string, ECSFillter>();
|
||||
|
||||
private _entitiesToDelete: number[] = [];
|
||||
private _entityIdSeed: number = 0;
|
||||
|
||||
/** 获取ComponentPool */
|
||||
public getComponentPool<T>(typeOrFunc: ComType | {prototype: T}): ECSComponentPool<T> {
|
||||
let type = typeof typeOrFunc == "number" ? typeOrFunc : GetComConstructorType(typeOrFunc);
|
||||
if(!this._componentPools[type]) {
|
||||
this._componentPools[type] = new ECSComponentPool<T>(GetComConstructor(type));
|
||||
}
|
||||
return this._componentPools[type] as any;
|
||||
}
|
||||
|
||||
/** 添加system */
|
||||
public addSystem(system: ECSSystem) {
|
||||
this._systems.push(system);
|
||||
system.onAdd(this);
|
||||
for(let i = 0; i < this._entities.length; i++) {
|
||||
if(this._entities[i].id !== -1) {
|
||||
system.onEntityEnter(this, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 移除system */
|
||||
public removeSystem(system: ECSSystem) {
|
||||
system.onRemove(this);
|
||||
for(let i = 0; i < this._entities.length; i++) {
|
||||
if(this._entities[i].id !== -1) {
|
||||
system.onEntityLeave(this, i);
|
||||
}
|
||||
}
|
||||
for(let i = this._systems.length - 1; i >= 0; i--) {
|
||||
if(this._systems[i] == system) {
|
||||
this._systems.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 创建实体 */
|
||||
public createEntity(): number {
|
||||
let entity: Entity = null;
|
||||
let index = -1;
|
||||
if(this._reservedIds.length > 0) {
|
||||
index = this._reservedIds.pop();
|
||||
entity = this._entities[index];
|
||||
}else {
|
||||
entity = new Entity();
|
||||
index = this._entities.length;
|
||||
this._entities.push(entity);
|
||||
}
|
||||
entity.id = this._entityIdSeed++;
|
||||
entity.world = this;
|
||||
entity.index = index;
|
||||
entity.dead = false;
|
||||
for(let system of this._systems) {
|
||||
system.onEntityEnter(this, entity.index);
|
||||
}
|
||||
return entity.index;
|
||||
}
|
||||
|
||||
/** 移除实体 */
|
||||
public removeEntity(entity: EntityIndex): boolean {
|
||||
if(entity <= 0) return false;
|
||||
if(!this._entities[entity] || this._entities[entity].dead) {
|
||||
console.warn(`[ECSWorld] removeEntity entity is removed`);
|
||||
return false;
|
||||
}
|
||||
this._entities[entity].dead = true;
|
||||
this._entitiesToDelete.push(entity);
|
||||
|
||||
this._fillters.forEach((fillter, key) => {
|
||||
fillter.isContains(entity) && fillter.onEntityLeave(entity);
|
||||
});
|
||||
for(let system of this._systems) {
|
||||
system.onEntityLeave(this, entity);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public getComponent<T>(entity: EntityIndex, com: {prototype: T}) {
|
||||
if(!this._entities[entity]) return null;
|
||||
let comPoolIdx = this._entities[entity].getComponent(com);
|
||||
return this.getComponentPool<T>(com).get(comPoolIdx);
|
||||
}
|
||||
|
||||
public removeComponent(entity: EntityIndex, com: ECSComConstructor) {
|
||||
if(!this._entities[entity]) return ;
|
||||
this._entities[entity].removeComponent(com);
|
||||
}
|
||||
|
||||
public addComponent<T>(entity: EntityIndex, com: {prototype: T}) {
|
||||
if(!this._entities[entity]) return null;
|
||||
let comPoolIdx = this._entities[entity].addComponent(com);
|
||||
return this.getComponentPool<T>(com).get(comPoolIdx)
|
||||
}
|
||||
|
||||
public getSingletonComponent<T>(com: {prototype: T}): T {
|
||||
let entity = this._entities[0];
|
||||
let comPoolIdx = entity.getComponent(<ECSComConstructor>com);
|
||||
let pool = this.getComponentPool<T>(com);
|
||||
if(comPoolIdx >= 0) return pool.get(comPoolIdx);
|
||||
return pool.get(entity.addComponent(com));
|
||||
}
|
||||
|
||||
public setEntityDirty(entity: Entity): void {
|
||||
this._fillters.forEach((fillter, key) => {
|
||||
let accept = !entity.dead && fillter.isAccept(entity);
|
||||
if(accept != fillter.isContains(entity.index)) {
|
||||
accept ? fillter.onEntityEnter(entity.index) : fillter.onEntityLeave(entity.index);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public getEntityId(entity: EntityIndex) : number {
|
||||
return this._entities[entity].id;
|
||||
}
|
||||
|
||||
public getFilter(fillterKey: string): ECSFillter {
|
||||
if(this._fillters.has(fillterKey)) {
|
||||
return this._fillters.get(fillterKey);
|
||||
}
|
||||
let [acceptStr, rejectStr] = fillterKey.split("-");
|
||||
let accept = acceptStr && acceptStr.length > 0 ? acceptStr.split(',').map(Number) : null;
|
||||
let reject = rejectStr && rejectStr.length > 0 ? rejectStr.split(',').map(Number) : null;
|
||||
let fillter = new ECSFillter(this, accept, reject);
|
||||
this._fillters.set(fillterKey, fillter);
|
||||
// 将当期的entity放入fillter
|
||||
for(let i=1; i<this._entities.length; i++) {
|
||||
const entity = this._entities[i];
|
||||
if(fillter.isAccept(entity)) {
|
||||
fillter.onEntityEnter(entity.index);
|
||||
}
|
||||
}
|
||||
return fillter;
|
||||
}
|
||||
|
||||
public update(dt:number) {
|
||||
for(let system of this._systems) {
|
||||
system.onUpdate(this, dt);
|
||||
}
|
||||
if(this._entitiesToDelete.length > 0) {
|
||||
this._realRemoveEntity();
|
||||
}
|
||||
}
|
||||
|
||||
private _realRemoveEntity() {
|
||||
for(let entityIdx of this._entitiesToDelete) {
|
||||
this._entities[entityIdx].removeAllComponents(false);
|
||||
this._entities[entityIdx].id = -1;
|
||||
this._reservedIds.push(entityIdx);
|
||||
}
|
||||
this._entitiesToDelete.length = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export function GenFillterKey(accepts: ECSComConstructor[], rejects?: ECSComConstructor[]) {
|
||||
let acceptTypes: ComType[] = [];
|
||||
let rejectTypes: ComType[] = [];
|
||||
|
||||
if(accepts && accepts.length > 0) {
|
||||
for(let i = 0; i < accepts.length; i++) {
|
||||
acceptTypes[i] = GetComConstructorType(accepts[i]);
|
||||
}
|
||||
}
|
||||
if(rejects && rejects.length > 0) {
|
||||
for(let i = 0; i < rejects.length; i++) {
|
||||
rejectTypes[i] = GetComConstructorType(rejects[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if(acceptTypes.length < 0) {
|
||||
console.error(`[ECSWorld]: GenFillterKey 必须要有accpters`);
|
||||
return "";
|
||||
}
|
||||
|
||||
acceptTypes.sort();
|
||||
rejectTypes.sort();
|
||||
|
||||
let key = Array.prototype.join.call(acceptTypes, ",");
|
||||
if(!rejectTypes || rejectTypes.length <= 0) return key;
|
||||
key += '-';
|
||||
key += Array.prototype.join.call(rejectTypes, ",");
|
||||
return key;
|
||||
}
|
10
assets/Script/ECS/lib/ECSWorld.ts.meta
Executable file
10
assets/Script/ECS/lib/ECSWorld.ts.meta
Executable file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "decf2eee-3ef7-456d-bd8c-8d4eaa63e617",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
13
assets/Script/ECS/systems.meta
Normal file
13
assets/Script/ECS/systems.meta
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.3",
|
||||
"uuid": "db93b255-0e1f-4c8a-adc8-d3d2fca077cc",
|
||||
"importer": "folder",
|
||||
"isBundle": false,
|
||||
"bundleName": "",
|
||||
"priority": 1,
|
||||
"compressionType": {},
|
||||
"optimizeHotUpdate": {},
|
||||
"inlineSpriteFrames": {},
|
||||
"isRemoteBundle": {},
|
||||
"subMetas": {}
|
||||
}
|
71
assets/Script/ECS/systems/SysAttack.ts
Normal file
71
assets/Script/ECS/systems/SysAttack.ts
Normal file
@ -0,0 +1,71 @@
|
||||
import { ComAttackable } from "../components/ComAttackable";
|
||||
import { ComBeAttacked } from "../components/ComBeAttacked";
|
||||
import { ComRoleConfig } from "../components/ComRoleConfig";
|
||||
import { ComTransform } from "../components/ComTransform";
|
||||
import { ECSSystem } from "../lib/ECSSystem";
|
||||
import { ECSWorld, GenFillterKey } from "../lib/ECSWorld";
|
||||
|
||||
const FILTER_ATTACKABLE = GenFillterKey([ComAttackable]);
|
||||
const FILTER_BEATTACKED = GenFillterKey([ComBeAttacked]);
|
||||
export class SysAttack extends ECSSystem {
|
||||
/** 连接 */
|
||||
public onAdd(world: ECSWorld): void {
|
||||
|
||||
}
|
||||
/** 断开连接 */
|
||||
public onRemove(world: ECSWorld): void {
|
||||
|
||||
}
|
||||
/** 添加实体 */
|
||||
public onEntityEnter(world: ECSWorld, entity: number): void {
|
||||
|
||||
}
|
||||
/** */
|
||||
public onEntityLeave(world: ECSWorld, entity: number): void {
|
||||
|
||||
}
|
||||
/** 更新 */
|
||||
public onUpdate(world: ECSWorld, dt: number): void {
|
||||
let filter = world.getFilter(FILTER_ATTACKABLE);
|
||||
filter.walk((entity: number) => {
|
||||
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.mustAttackFrame)
|
||||
if(comAttackable.dirty && comAttackable.countDown <= comAttackable.hurtFrame) {
|
||||
comAttackable.dirty = false;
|
||||
world.getFilter(FILTER_BEATTACKED).walk((entityOther: number) => {
|
||||
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 ;
|
||||
comRoleConfigOther.lastHP = comRoleConfigOther.nowHP;
|
||||
comRoleConfigOther.nowHP -= comAttackable.attack;
|
||||
comRoleConfigOther.HPDirty = true;
|
||||
|
||||
// 打断对方的攻击动作
|
||||
let comAttackableOther = world.getComponent(entityOther, ComAttackable);
|
||||
if(!comAttackableOther || comAttackableOther.countDown <= 0) return ;
|
||||
if(comAttackableOther.countDown >= comAttackableOther.mustAttackFrame) {
|
||||
comAttackableOther.dirty = false;
|
||||
}
|
||||
|
||||
comAttackable.countDown = 0.25;
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
10
assets/Script/ECS/systems/SysAttack.ts.meta
Normal file
10
assets/Script/ECS/systems/SysAttack.ts.meta
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "780c245c-45f2-47ae-a01a-b61dcfb3ab3e",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
65
assets/Script/ECS/systems/SysBehaviorTree.ts
Normal file
65
assets/Script/ECS/systems/SysBehaviorTree.ts
Normal file
@ -0,0 +1,65 @@
|
||||
import { BT } from "../../Common/BehaviorTree";
|
||||
import { ComBehaviorTree } from "../components/ComBehaviorTree";
|
||||
import { ECSSystem } from "../lib/ECSSystem";
|
||||
import { ECSWorld, GenFillterKey } from "../lib/ECSWorld";
|
||||
|
||||
|
||||
|
||||
const FILTER_BEHAVIORTREE = GenFillterKey([ComBehaviorTree]);
|
||||
|
||||
const Context = new BT.ExecuteContext();
|
||||
|
||||
export class SysBehaviorTree extends ECSSystem {
|
||||
|
||||
/** 连接 */
|
||||
public onAdd(world: ECSWorld): void{
|
||||
Context.init(this, world);
|
||||
}
|
||||
/** 断开连接 */
|
||||
public onRemove(world: ECSWorld): void {
|
||||
|
||||
}
|
||||
/** 添加实体 */
|
||||
public onEntityEnter(world: ECSWorld, entity: number): void {
|
||||
|
||||
}
|
||||
|
||||
/** */
|
||||
public onEntityLeave(world: ECSWorld, entity: number): void {
|
||||
|
||||
}
|
||||
|
||||
/** 更新 */
|
||||
public onUpdate(world: ECSWorld, dt: number): void {
|
||||
Context.executor = this;
|
||||
Context.dt = dt;
|
||||
Context.world = world;
|
||||
|
||||
world.getFilter(FILTER_BEHAVIORTREE).walk((entity: number) => {
|
||||
let comBehavior = world.getComponent(entity, ComBehaviorTree);
|
||||
Context.set(entity, dt, comBehavior.bb);
|
||||
if(comBehavior.root.state !== BT.NodeState.Executing) {
|
||||
this.onEnterBTNode(comBehavior.root, Context);
|
||||
}else {
|
||||
this.updateBTNode(comBehavior.root, Context);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
/** 进入节点 */
|
||||
public onEnterBTNode(node: BT.NodeBase, context: BT.ExecuteContext) {
|
||||
let handler = BT.NodeHandlers[node.type];
|
||||
handler.onEnter(node, context);
|
||||
}
|
||||
|
||||
/** 更新节点状态 */
|
||||
public updateBTNode(node: BT.NodeBase, context: BT.ExecuteContext) {
|
||||
let handler = BT.NodeHandlers[node.type];
|
||||
handler.onUpdate(node, context);
|
||||
}
|
||||
|
||||
public canExecuteBTNode(node: BT.NodeBase, context: BT.ExecuteContext) : boolean {
|
||||
return true;
|
||||
}
|
||||
}
|
10
assets/Script/ECS/systems/SysBehaviorTree.ts.meta
Normal file
10
assets/Script/ECS/systems/SysBehaviorTree.ts.meta
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "1b6bd6b5-cb8e-46e8-8052-8ed53e75a2e5",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
96
assets/Script/ECS/systems/SysCocosView.ts
Executable file
96
assets/Script/ECS/systems/SysCocosView.ts
Executable file
@ -0,0 +1,96 @@
|
||||
import CocosHelper from "../../Common/CocosHelper";
|
||||
import { ComNodeConfig } from "../components/ComNodeConfig";
|
||||
import { ComCocosNode } from "../components/ComCocosNode";
|
||||
import { ECSSystem } from "../lib/ECSSystem";
|
||||
import { ECSWorld, GenFillterKey } from "../lib/ECSWorld";
|
||||
import { ComTransform } from "../components/ComTransform";
|
||||
import { EventProcess } from "../../Core/EventProcess";
|
||||
import { ComRoleConfig } from "../components/ComRoleConfig";
|
||||
|
||||
export interface ITouchProcessor {
|
||||
onTouchStart(worldPos: cc.Vec2, world: ECSWorld): void;
|
||||
onTouchMove?(worldPos: cc.Vec2, world: ECSWorld): void;
|
||||
onTouchEnd?(worldPos: cc.Vec2, world: ECSWorld): void;
|
||||
onTouchCancel?(worldPos: cc.Vec2, world: ECSWorld): void;
|
||||
}
|
||||
|
||||
const FILTER_COCOS_NODE = GenFillterKey([ComNodeConfig], [ComCocosNode]);
|
||||
const FILTER_NODE_EVENT = GenFillterKey([ComCocosNode, ComTransform]);
|
||||
export class SysCocosView extends ECSSystem implements ITouchProcessor {
|
||||
|
||||
onTouchStart(worldPos: cc.Vec2, world: ECSWorld): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
onAdd(world: ECSWorld) {
|
||||
|
||||
}
|
||||
|
||||
onRemove(world: ECSWorld) {
|
||||
|
||||
}
|
||||
|
||||
onEntityEnter(world: ECSWorld, entity: number) {
|
||||
|
||||
}
|
||||
|
||||
onEntityLeave(world: ECSWorld, entity: number) {
|
||||
|
||||
}
|
||||
|
||||
onUpdate(world:ECSWorld, dt:number) {
|
||||
world.getFilter(FILTER_COCOS_NODE).walk((entity: number) => {
|
||||
let comNodeConfig = world.getComponent(entity, ComNodeConfig);
|
||||
let comView = world.addComponent(entity, ComCocosNode);
|
||||
|
||||
let comRoleConfig = world.getComponent(entity, ComRoleConfig);
|
||||
this._loadView(world, entity, comNodeConfig).then((node: cc.Node) => {
|
||||
console.log('load view success');
|
||||
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
world.getFilter(FILTER_NODE_EVENT).walk((entity: number) => {
|
||||
let comCocosNode = world.getComponent(entity, ComCocosNode);
|
||||
if(!comCocosNode.loaded) return ;
|
||||
let eventProcess = comCocosNode.node.getComponent(EventProcess);
|
||||
if(!eventProcess) return ;
|
||||
|
||||
let comTrans = world.getComponent(entity, ComTransform);
|
||||
eventProcess.sync(comTrans.x, comTrans.y, comTrans.dir);
|
||||
while(comCocosNode.events.length) {
|
||||
let event = comCocosNode.events.shift();
|
||||
eventProcess.processEvent(event);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private async _loadView(world: ECSWorld, entity: number, nodeConfig: ComNodeConfig) {
|
||||
let prefab = await CocosHelper.loadResSync<cc.Prefab>(nodeConfig.prefabUrl, cc.Prefab);
|
||||
if(!prefab) {
|
||||
cc.warn(`加载失败: ${nodeConfig.prefabUrl}`);
|
||||
return;
|
||||
}
|
||||
let comView = world.getComponent(entity, ComCocosNode);
|
||||
if(comView.node) { // 销毁当前node
|
||||
this.destoryView(comView.node);
|
||||
}
|
||||
let layers = cc.find('Canvas/Layers');
|
||||
if(!layers) return ;
|
||||
|
||||
let node = cc.instantiate(prefab);
|
||||
node.parent = layers.getChildByName(`${nodeConfig.layer}`);
|
||||
comView.node = node;
|
||||
comView.loaded = true;
|
||||
return node;
|
||||
}
|
||||
|
||||
private destoryView(node: cc.Node) {
|
||||
node.removeFromParent();
|
||||
node.destroy();
|
||||
}
|
||||
}
|
10
assets/Script/ECS/systems/SysCocosView.ts.meta
Normal file
10
assets/Script/ECS/systems/SysCocosView.ts.meta
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "e4f95950-b571-48dd-8c95-7808eef0c336",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
82
assets/Script/ECS/systems/SysMonitor.ts
Normal file
82
assets/Script/ECS/systems/SysMonitor.ts
Normal file
@ -0,0 +1,82 @@
|
||||
import { ComMonitor } from "../components/ComMonitor";
|
||||
import { ComRoleConfig } from "../components/ComRoleConfig";
|
||||
import { ComTransform } from "../components/ComTransform";
|
||||
import { ECSSystem } from "../lib/ECSSystem";
|
||||
import { ECSWorld, GenFillterKey } from "../lib/ECSWorld";
|
||||
|
||||
const FILTER_MONITOR = GenFillterKey([ComRoleConfig, ComTransform, ComMonitor]);
|
||||
export class SysMonitor extends ECSSystem {
|
||||
/** 连接 */
|
||||
public onAdd(world: ECSWorld): void {
|
||||
|
||||
}
|
||||
/** 断开连接 */
|
||||
public onRemove(world: ECSWorld): void {
|
||||
|
||||
}
|
||||
/** 添加实体 */
|
||||
public onEntityEnter(world: ECSWorld, entity: number): void {
|
||||
|
||||
}
|
||||
/** */
|
||||
public onEntityLeave(world: ECSWorld, entity: number): void {
|
||||
let filter = world.getFilter(FILTER_MONITOR);
|
||||
// 判断当前monitor是否
|
||||
filter.entities.forEach((value: boolean, otherEntity: number) => {
|
||||
let comMonitor = world.getComponent(otherEntity, ComMonitor);
|
||||
if(!comMonitor) return ;
|
||||
for(let i=comMonitor.others.length-1; i>=0; i--) {
|
||||
if(comMonitor.others[i] == entity) {
|
||||
comMonitor.others.splice(i);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
/** 更新 */
|
||||
public onUpdate(world: ECSWorld, dt: number): void {
|
||||
let filter = world.getFilter(FILTER_MONITOR);
|
||||
filter.walk((entity: number) => {
|
||||
let comMonitor = world.getComponent(entity, ComMonitor);
|
||||
let comTrans = world.getComponent(entity, ComTransform);
|
||||
let comRoleConfig = world.getComponent(entity, ComRoleConfig);
|
||||
|
||||
// 判断当前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);
|
||||
}
|
||||
}
|
||||
|
||||
if(comMonitor.others.indexOf(otherEntity) == -1 && _check(comTransOther)) {
|
||||
comMonitor.others.push(otherEntity);
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 判断一个点是否在三角形内
|
||||
function isInTriangle(point: cc.Vec2, triA: cc.Vec2, triB: cc.Vec2, triC: cc.Vec2) {
|
||||
let AB = triB.sub(triA), AC = triC.sub(triA), BC = triC.sub(triB), AD = point.sub(triA), BD = point.sub(triB);
|
||||
//@ts-ignore
|
||||
return (AB.cross(AC) >= 0 ^ AB.cross(AD) < 0) && (AB.cross(AC) >= 0 ^ AC.cross(AD) >= 0) && (BC.cross(AB) > 0 ^ BC.cross(BD) >= 0);
|
||||
}
|
10
assets/Script/ECS/systems/SysMonitor.ts.meta
Normal file
10
assets/Script/ECS/systems/SysMonitor.ts.meta
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "0b207deb-ff30-4fbe-aca7-2f77f299569d",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
70
assets/Script/ECS/systems/SysMovable.ts
Normal file
70
assets/Script/ECS/systems/SysMovable.ts
Normal file
@ -0,0 +1,70 @@
|
||||
import { ComCocosNode as ComCocosNode } from "../components/ComCocosNode";
|
||||
import { ComMovable } from "../components/ComMovable";
|
||||
import { ComTransform } from "../components/ComTransform";
|
||||
import { ECSSystem } from "../lib/ECSSystem";
|
||||
import { ECSWorld, GenFillterKey as GenFilterKey } from "../lib/ECSWorld";
|
||||
|
||||
const FILTER_MOVE = GenFilterKey([ComMovable, ComTransform, ComCocosNode]);
|
||||
export class SysMovable extends ECSSystem {
|
||||
/** 连接 */
|
||||
public onAdd(world: ECSWorld): void{
|
||||
|
||||
}
|
||||
/** 断开连接 */
|
||||
public onRemove(world: ECSWorld): void {
|
||||
|
||||
}
|
||||
/** 添加实体 */
|
||||
public onEntityEnter(world: ECSWorld, entity: number): void {
|
||||
|
||||
}
|
||||
|
||||
/** */
|
||||
public onEntityLeave(world: ECSWorld, entity:number): void {
|
||||
|
||||
}
|
||||
|
||||
/** 更新 */
|
||||
public onUpdate(world: ECSWorld, dt:number): void {
|
||||
world.getFilter(FILTER_MOVE).walk((entity: number) => {
|
||||
let comMovable = world.getComponent(entity, ComMovable);
|
||||
let comTrans = world.getComponent(entity, ComTransform);
|
||||
|
||||
if(comMovable.speed <= 0 || comMovable.pointIdx >= comMovable.points.length) {
|
||||
return ;
|
||||
}
|
||||
|
||||
if(!comMovable.running) {
|
||||
comMovable.running = true;
|
||||
}
|
||||
|
||||
let moveLen = comMovable.speed * dt;
|
||||
while(moveLen > 0 && comMovable.pointIdx < comMovable.points.length) {
|
||||
let nextPoint = comMovable.points[comMovable.pointIdx];
|
||||
let offsetX = nextPoint.x - comTrans.x;
|
||||
let offsetY = nextPoint.y - comTrans.y;
|
||||
let offsetLen = Math.sqrt(offsetX * offsetX + offsetY * offsetY);
|
||||
if(offsetLen <= moveLen) {
|
||||
moveLen -= offsetLen;
|
||||
comTrans.x = nextPoint.x;
|
||||
comTrans.y = nextPoint.y;
|
||||
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;
|
||||
|
||||
moveLen = -1;
|
||||
}
|
||||
|
||||
if(comMovable.pointIdx >= comMovable.points.length) {
|
||||
comMovable.speed = 0;
|
||||
comMovable.speedDirty = true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
10
assets/Script/ECS/systems/SysMovable.ts.meta
Normal file
10
assets/Script/ECS/systems/SysMovable.ts.meta
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "6f024564-9b8c-47ad-95eb-eca4afd96720",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
69
assets/Script/ECS/systems/SysRoleState.ts
Normal file
69
assets/Script/ECS/systems/SysRoleState.ts
Normal file
@ -0,0 +1,69 @@
|
||||
import { EventDeath, EventHPChange, EventHurt, EventRun, EventStand } from "../../Struct/NodeEvent";
|
||||
import { ComBehaviorTree } from "../components/ComBehaviorTree";
|
||||
import { ComCocosNode } from "../components/ComCocosNode";
|
||||
import { ComMonitor } from "../components/ComMonitor";
|
||||
import { ComMovable } from "../components/ComMovable";
|
||||
import { ComNodeConfig } from "../components/ComNodeConfig";
|
||||
import { ComRoleConfig } from "../components/ComRoleConfig";
|
||||
import { ECSSystem } from "../lib/ECSSystem";
|
||||
import { ECSWorld, GenFillterKey } from "../lib/ECSWorld";
|
||||
|
||||
const FILTER_ROLE_NODE = GenFillterKey([ComCocosNode, ComRoleConfig]);
|
||||
export class SysRoleState extends ECSSystem {
|
||||
/** 连接 */
|
||||
public onAdd(world: ECSWorld): void {
|
||||
|
||||
}
|
||||
/** 断开连接 */
|
||||
public onRemove(world: ECSWorld): void {
|
||||
|
||||
}
|
||||
/** 添加实体 */
|
||||
public onEntityEnter(world: ECSWorld, entity: number): void {
|
||||
|
||||
}
|
||||
/** */
|
||||
public onEntityLeave(world: ECSWorld, entity: number): void {
|
||||
|
||||
}
|
||||
/** 更新 */
|
||||
public onUpdate(world: ECSWorld, dt: number): void {
|
||||
world.getFilter(FILTER_ROLE_NODE).walk((entity: number) => {
|
||||
let comCocosNode = world.getComponent(entity, ComCocosNode);
|
||||
if(!comCocosNode.loaded) return ;
|
||||
let comRoleConfig = world.getComponent(entity, ComRoleConfig);
|
||||
let comMovable = world.getComponent(entity, ComMovable);
|
||||
|
||||
if(comMovable && comMovable.speedDirty) {
|
||||
comMovable.speedDirty = false;
|
||||
if(comMovable.speed > 0) {
|
||||
comCocosNode.events.push(new EventRun());
|
||||
}else {
|
||||
comCocosNode.events.push(new EventStand());
|
||||
}
|
||||
}
|
||||
|
||||
if(comRoleConfig && comRoleConfig.HPDirty) {
|
||||
comCocosNode.events.push(new EventHPChange(comRoleConfig.maxHP, comRoleConfig.lastHP, comRoleConfig.nowHP));
|
||||
if(comRoleConfig.lastHP > comRoleConfig.nowHP) {
|
||||
comCocosNode.events.push(new EventHurt());
|
||||
}
|
||||
if(comRoleConfig.nowHP <= 0) {
|
||||
comCocosNode.events.push(new EventDeath(() => {
|
||||
world.removeComponent(entity, ComNodeConfig);
|
||||
world.removeComponent(entity, ComCocosNode);
|
||||
world.removeEntity(entity);
|
||||
comCocosNode.node.destroy();
|
||||
}));
|
||||
world.removeComponent(entity, ComBehaviorTree);
|
||||
world.removeComponent(entity, ComMonitor);
|
||||
world.removeComponent(entity, ComMovable);
|
||||
world.removeComponent(entity, ComRoleConfig);
|
||||
}
|
||||
comRoleConfig.HPDirty = false;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
10
assets/Script/ECS/systems/SysRoleState.ts.meta
Normal file
10
assets/Script/ECS/systems/SysRoleState.ts.meta
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "b679be6f-54ac-4790-99ff-41e3993bf130",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
13
assets/Script/ECS/worlds.meta
Normal file
13
assets/Script/ECS/worlds.meta
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.3",
|
||||
"uuid": "00fbfe49-b0ae-426b-ae03-f11fba4ce919",
|
||||
"importer": "folder",
|
||||
"isBundle": false,
|
||||
"bundleName": "",
|
||||
"priority": 1,
|
||||
"compressionType": {},
|
||||
"optimizeHotUpdate": {},
|
||||
"inlineSpriteFrames": {},
|
||||
"isRemoteBundle": {},
|
||||
"subMetas": {}
|
||||
}
|
5
assets/Script/ECS/worlds/WorldCocosView.ts
Normal file
5
assets/Script/ECS/worlds/WorldCocosView.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { ECSWorld } from "../lib/ECSWorld";
|
||||
|
||||
export class WorldCocosView extends ECSWorld {
|
||||
|
||||
}
|
10
assets/Script/ECS/worlds/WorldCocosView.ts.meta
Normal file
10
assets/Script/ECS/worlds/WorldCocosView.ts.meta
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "2bbeb931-7f40-48e4-937d-13006b7f016b",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
81
assets/Script/Main.ts
Normal file
81
assets/Script/Main.ts
Normal file
@ -0,0 +1,81 @@
|
||||
import { ECSController } from "./Core/ECSController";
|
||||
import { ECSWorld } from "./ECS/lib/ECSWorld";
|
||||
import { SysAttack } from "./ECS/systems/SysAttack";
|
||||
import { SysBehaviorTree } from "./ECS/systems/SysBehaviorTree";
|
||||
import { ITouchProcessor, SysCocosView } from "./ECS/systems/SysCocosView";
|
||||
import { SysMonitor } from "./ECS/systems/SysMonitor";
|
||||
import { SysMovable } from "./ECS/systems/SysMovable";
|
||||
import { SysRoleState } from "./ECS/systems/SysRoleState";
|
||||
import { WorldCocosView } from "./ECS/worlds/WorldCocosView";
|
||||
|
||||
const {ccclass, property} = cc._decorator;
|
||||
|
||||
@ccclass
|
||||
export default class Main extends cc.Component {
|
||||
private _world: ECSWorld = null;
|
||||
private _touchHandler: ITouchProcessor[] = [];
|
||||
|
||||
private ecsController = new ECSController();
|
||||
start () {
|
||||
this.ecsController.world = this._world = new WorldCocosView();
|
||||
this._world.createEntity(); // 创建0号实体
|
||||
this._world.addSystem(new SysBehaviorTree()); // 行为树
|
||||
this._world.addSystem(new SysMovable()); // 移动
|
||||
this._world.addSystem(new SysMonitor()); // 监视
|
||||
this._world.addSystem(new SysAttack()); // 攻击系统
|
||||
this._world.addSystem(new SysRoleState()); // role state
|
||||
this._world.addSystem(new SysCocosView()); // cocos view
|
||||
|
||||
this.regiestTouchEvent();
|
||||
|
||||
}
|
||||
|
||||
onClick1() {
|
||||
this.ecsController.createRoleEntity("Biker");
|
||||
}
|
||||
|
||||
onClick2() {
|
||||
this.ecsController.createRoleEntity("Cyborg");
|
||||
}
|
||||
|
||||
protected update(dt: number): void {
|
||||
if(this._world) this._world.update(dt);
|
||||
}
|
||||
|
||||
private regiestTouchEvent() {
|
||||
this.node.on(cc.Node.EventType.TOUCH_START, this._onTouchStart, this);
|
||||
this.node.on(cc.Node.EventType.TOUCH_MOVE, this._onTouchMove, this);
|
||||
this.node.on(cc.Node.EventType.TOUCH_END, this._onTouchEnd, this);
|
||||
this.node.on(cc.Node.EventType.TOUCH_CANCEL, this._onTouchCancel, this);
|
||||
}
|
||||
|
||||
private _onTouchStart(e: cc.Event.EventTouch) {
|
||||
for(let i = 0; i < this._touchHandler.length; i++) {
|
||||
this._touchHandler[i].onTouchStart(e.getLocation(), this._world);
|
||||
}
|
||||
}
|
||||
private _onTouchMove() {
|
||||
|
||||
}
|
||||
private _onTouchEnd() {
|
||||
|
||||
}
|
||||
private _onTouchCancel() {
|
||||
|
||||
}
|
||||
|
||||
public regiestTouchHandler(handler: ITouchProcessor) {
|
||||
this._touchHandler.push(handler);
|
||||
}
|
||||
|
||||
public unRegiestTouchHandler(handler:ITouchProcessor) {
|
||||
for(let i = this._touchHandler.length - 1; i >= 0; i--) {
|
||||
if(this._touchHandler[i] == handler) {
|
||||
this._touchHandler.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
10
assets/Script/Main.ts.meta
Normal file
10
assets/Script/Main.ts.meta
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "e1b90feb-a217-4493-849d-9a611900d683",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
13
assets/Script/Struct.meta
Normal file
13
assets/Script/Struct.meta
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.3",
|
||||
"uuid": "e2f8f29f-d6d0-4172-802f-80e64a869ccf",
|
||||
"importer": "folder",
|
||||
"isBundle": false,
|
||||
"bundleName": "",
|
||||
"priority": 1,
|
||||
"compressionType": {},
|
||||
"optimizeHotUpdate": {},
|
||||
"inlineSpriteFrames": {},
|
||||
"isRemoteBundle": {},
|
||||
"subMetas": {}
|
||||
}
|
6
assets/Script/Struct/Direction.ts
Normal file
6
assets/Script/Struct/Direction.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export enum Direction {
|
||||
Up,
|
||||
Down,
|
||||
Left,
|
||||
Right
|
||||
}
|
10
assets/Script/Struct/Direction.ts.meta
Normal file
10
assets/Script/Struct/Direction.ts.meta
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "436daff0-c505-45e0-b0ea-d804b6ef7fac",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
59
assets/Script/Struct/NodeEvent.ts
Normal file
59
assets/Script/Struct/NodeEvent.ts
Normal file
@ -0,0 +1,59 @@
|
||||
export enum EventType {
|
||||
Stand,
|
||||
Run,
|
||||
Attack,
|
||||
Hurt,
|
||||
HPChange,
|
||||
Death
|
||||
}
|
||||
|
||||
export class EventBase {
|
||||
type: EventType;
|
||||
constructor(type:number) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
||||
export class EventStand extends EventBase {
|
||||
constructor() {
|
||||
super(EventType.Stand);
|
||||
}
|
||||
}
|
||||
|
||||
export class EventRun extends EventBase {
|
||||
constructor() {
|
||||
super(EventType.Run);
|
||||
}
|
||||
}
|
||||
|
||||
export class EventAttack extends EventBase {
|
||||
constructor() {
|
||||
super(EventType.Attack);
|
||||
}
|
||||
}
|
||||
|
||||
export class EventHurt extends EventBase {
|
||||
constructor() {
|
||||
super(EventType.Hurt);
|
||||
}
|
||||
}
|
||||
|
||||
export class EventDeath extends EventBase {
|
||||
callback: Function;
|
||||
constructor(cb: Function) {
|
||||
super(EventType.Death);
|
||||
this.callback = cb;
|
||||
}
|
||||
}
|
||||
|
||||
export class EventHPChange extends EventBase {
|
||||
public lastHP: number;
|
||||
public nowHP: number;
|
||||
public maxHP: number;
|
||||
constructor(maxHP: number, lastHP: number, nowHP: number) {
|
||||
super(EventType.HPChange);
|
||||
this.maxHP = maxHP;
|
||||
this.lastHP = lastHP;
|
||||
this.nowHP = nowHP;
|
||||
}
|
||||
}
|
10
assets/Script/Struct/NodeEvent.ts.meta
Normal file
10
assets/Script/Struct/NodeEvent.ts.meta
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"ver": "1.1.0",
|
||||
"uuid": "8bdaf2f1-e01a-449c-88ab-e35aa4741b9c",
|
||||
"importer": "typescript",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
13
assets/Texture.meta
Executable file
13
assets/Texture.meta
Executable file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.3",
|
||||
"uuid": "7b81d4e8-ec84-4716-968d-500ac1d78a54",
|
||||
"importer": "folder",
|
||||
"isBundle": false,
|
||||
"bundleName": "",
|
||||
"priority": 1,
|
||||
"compressionType": {},
|
||||
"optimizeHotUpdate": {},
|
||||
"inlineSpriteFrames": {},
|
||||
"isRemoteBundle": {},
|
||||
"subMetas": {}
|
||||
}
|
BIN
assets/Texture/HelloWorld.png
Executable file
BIN
assets/Texture/HelloWorld.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 37 KiB |
38
assets/Texture/HelloWorld.png.meta
Executable file
38
assets/Texture/HelloWorld.png.meta
Executable file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"ver": "2.3.7",
|
||||
"uuid": "6aa0aa6a-ebee-4155-a088-a687a6aadec4",
|
||||
"importer": "texture",
|
||||
"type": "sprite",
|
||||
"wrapMode": "clamp",
|
||||
"filterMode": "bilinear",
|
||||
"premultiplyAlpha": false,
|
||||
"genMipmaps": false,
|
||||
"packable": true,
|
||||
"width": 195,
|
||||
"height": 270,
|
||||
"platformSettings": {},
|
||||
"subMetas": {
|
||||
"HelloWorld": {
|
||||
"ver": "1.0.6",
|
||||
"uuid": "31bc895a-c003-4566-a9f3-2e54ae1c17dc",
|
||||
"importer": "sprite-frame",
|
||||
"rawTextureUuid": "6aa0aa6a-ebee-4155-a088-a687a6aadec4",
|
||||
"trimType": "none",
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 0,
|
||||
"trimY": 0,
|
||||
"width": 195,
|
||||
"height": 270,
|
||||
"rawWidth": 195,
|
||||
"rawHeight": 270,
|
||||
"borderTop": 0,
|
||||
"borderBottom": 0,
|
||||
"borderLeft": 0,
|
||||
"borderRight": 0,
|
||||
"subMetas": {}
|
||||
}
|
||||
}
|
||||
}
|
BIN
assets/Texture/singleColor.png
Normal file
BIN
assets/Texture/singleColor.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 82 B |
38
assets/Texture/singleColor.png.meta
Executable file
38
assets/Texture/singleColor.png.meta
Executable file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"ver": "2.3.7",
|
||||
"uuid": "a8027877-d8d6-4645-97a0-52d4a0123dba",
|
||||
"importer": "texture",
|
||||
"type": "sprite",
|
||||
"wrapMode": "clamp",
|
||||
"filterMode": "bilinear",
|
||||
"premultiplyAlpha": false,
|
||||
"genMipmaps": false,
|
||||
"packable": true,
|
||||
"width": 2,
|
||||
"height": 2,
|
||||
"platformSettings": {},
|
||||
"subMetas": {
|
||||
"singleColor": {
|
||||
"ver": "1.0.6",
|
||||
"uuid": "410fb916-8721-4663-bab8-34397391ace7",
|
||||
"importer": "sprite-frame",
|
||||
"rawTextureUuid": "a8027877-d8d6-4645-97a0-52d4a0123dba",
|
||||
"trimType": "none",
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 0,
|
||||
"trimY": 0,
|
||||
"width": 2,
|
||||
"height": 2,
|
||||
"rawWidth": 2,
|
||||
"rawHeight": 2,
|
||||
"borderTop": 0,
|
||||
"borderBottom": 0,
|
||||
"borderLeft": 0,
|
||||
"borderRight": 0,
|
||||
"subMetas": {}
|
||||
}
|
||||
}
|
||||
}
|
13
assets/resources.meta
Normal file
13
assets/resources.meta
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.3",
|
||||
"uuid": "95da9891-fc56-4ff7-a3a8-7193d87b5173",
|
||||
"importer": "folder",
|
||||
"isBundle": true,
|
||||
"bundleName": "resources",
|
||||
"priority": 8,
|
||||
"compressionType": {},
|
||||
"optimizeHotUpdate": {},
|
||||
"inlineSpriteFrames": {},
|
||||
"isRemoteBundle": {},
|
||||
"subMetas": {}
|
||||
}
|
13
assets/resources/Biker.meta
Normal file
13
assets/resources/Biker.meta
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.3",
|
||||
"uuid": "a2761368-1fe6-41a6-a672-089f0f06e26f",
|
||||
"importer": "folder",
|
||||
"isBundle": false,
|
||||
"bundleName": "",
|
||||
"priority": 1,
|
||||
"compressionType": {},
|
||||
"optimizeHotUpdate": {},
|
||||
"inlineSpriteFrames": {},
|
||||
"isRemoteBundle": {},
|
||||
"subMetas": {}
|
||||
}
|
492
assets/resources/Biker/Biker.prefab
Normal file
492
assets/resources/Biker/Biker.prefab
Normal file
@ -0,0 +1,492 @@
|
||||
[
|
||||
{
|
||||
"__type__": "cc.Prefab",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"data": {
|
||||
"__id__": 1
|
||||
},
|
||||
"optimizationPolicy": 0,
|
||||
"asyncLoadAssets": false,
|
||||
"readonly": false
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "Biker",
|
||||
"_objFlags": 0,
|
||||
"_parent": null,
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 2
|
||||
},
|
||||
{
|
||||
"__id__": 6
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 13
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 14
|
||||
},
|
||||
"_opacity": 255,
|
||||
"_color": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 255,
|
||||
"g": 255,
|
||||
"b": 255,
|
||||
"a": 255
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 0,
|
||||
"height": 0
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
},
|
||||
"_trs": {
|
||||
"__type__": "TypedArray",
|
||||
"ctor": "Float64Array",
|
||||
"array": [
|
||||
-447.33,
|
||||
-180.474,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1
|
||||
]
|
||||
},
|
||||
"_eulerAngles": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_skewX": 0,
|
||||
"_skewY": 0,
|
||||
"_is3DNode": false,
|
||||
"_groupIndex": 0,
|
||||
"groupIndex": 0,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "sp",
|
||||
"_objFlags": 0,
|
||||
"_parent": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 3
|
||||
},
|
||||
{
|
||||
"__id__": 4
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 5
|
||||
},
|
||||
"_opacity": 255,
|
||||
"_color": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 255,
|
||||
"g": 255,
|
||||
"b": 255,
|
||||
"a": 255
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 48,
|
||||
"height": 48
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
},
|
||||
"_trs": {
|
||||
"__type__": "TypedArray",
|
||||
"ctor": "Float64Array",
|
||||
"array": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
3,
|
||||
3,
|
||||
1
|
||||
]
|
||||
},
|
||||
"_eulerAngles": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_skewX": 0,
|
||||
"_skewY": 0,
|
||||
"_is3DNode": false,
|
||||
"_groupIndex": 0,
|
||||
"groupIndex": 0,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Sprite",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"node": {
|
||||
"__id__": 2
|
||||
},
|
||||
"_enabled": true,
|
||||
"_materials": [
|
||||
{
|
||||
"__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432"
|
||||
}
|
||||
],
|
||||
"_srcBlendFactor": 770,
|
||||
"_dstBlendFactor": 771,
|
||||
"_spriteFrame": {
|
||||
"__uuid__": "6a868846-77bb-4cd0-befb-52a3dfd16822"
|
||||
},
|
||||
"_type": 0,
|
||||
"_sizeMode": 1,
|
||||
"_fillType": 0,
|
||||
"_fillCenter": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"_fillStart": 0,
|
||||
"_fillRange": 0,
|
||||
"_isTrimmedMode": true,
|
||||
"_atlas": null,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Animation",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"node": {
|
||||
"__id__": 2
|
||||
},
|
||||
"_enabled": true,
|
||||
"_defaultClip": {
|
||||
"__uuid__": "da671d3b-78c7-475c-9896-f0fe061c1840"
|
||||
},
|
||||
"_clips": [
|
||||
{
|
||||
"__uuid__": "6ee5314b-888f-409e-902e-26749cad0015"
|
||||
},
|
||||
{
|
||||
"__uuid__": "41ff0c6a-d2e8-4c9b-b789-bc4d370f7306"
|
||||
},
|
||||
{
|
||||
"__uuid__": "61a5270f-7761-498d-bbec-b994abd2c8a5"
|
||||
},
|
||||
{
|
||||
"__uuid__": "1cac62f0-3a28-49cd-928f-3411415323b9"
|
||||
},
|
||||
{
|
||||
"__uuid__": "62e0fbf7-19ce-44b3-a6b6-d24a24f0bdbd"
|
||||
},
|
||||
{
|
||||
"__uuid__": "da671d3b-78c7-475c-9896-f0fe061c1840"
|
||||
},
|
||||
{
|
||||
"__uuid__": "28fe88ff-4bc8-4075-8e33-036bc8590ed4"
|
||||
}
|
||||
],
|
||||
"playOnLoad": true,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "32/npSD/5H0La6j9teJEMf",
|
||||
"sync": false
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "HP",
|
||||
"_objFlags": 0,
|
||||
"_parent": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 7
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 10
|
||||
},
|
||||
{
|
||||
"__id__": 11
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 12
|
||||
},
|
||||
"_opacity": 255,
|
||||
"_color": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 255,
|
||||
"g": 255,
|
||||
"b": 255,
|
||||
"a": 255
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 50,
|
||||
"height": 10
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
},
|
||||
"_trs": {
|
||||
"__type__": "TypedArray",
|
||||
"ctor": "Float64Array",
|
||||
"array": [
|
||||
-30,
|
||||
43.706,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1
|
||||
]
|
||||
},
|
||||
"_eulerAngles": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_skewX": 0,
|
||||
"_skewY": 0,
|
||||
"_is3DNode": false,
|
||||
"_groupIndex": 0,
|
||||
"groupIndex": 0,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "value",
|
||||
"_objFlags": 512,
|
||||
"_parent": {
|
||||
"__id__": 6
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 8
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 9
|
||||
},
|
||||
"_opacity": 255,
|
||||
"_color": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 255,
|
||||
"g": 0,
|
||||
"b": 0,
|
||||
"a": 255
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 50,
|
||||
"height": 10
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0,
|
||||
"y": 0.5
|
||||
},
|
||||
"_trs": {
|
||||
"__type__": "TypedArray",
|
||||
"ctor": "Float64Array",
|
||||
"array": [
|
||||
-25,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1
|
||||
]
|
||||
},
|
||||
"_eulerAngles": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_skewX": 0,
|
||||
"_skewY": 0,
|
||||
"_is3DNode": false,
|
||||
"_groupIndex": 0,
|
||||
"groupIndex": 0,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Sprite",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"node": {
|
||||
"__id__": 7
|
||||
},
|
||||
"_enabled": true,
|
||||
"_materials": [
|
||||
{
|
||||
"__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432"
|
||||
}
|
||||
],
|
||||
"_srcBlendFactor": 770,
|
||||
"_dstBlendFactor": 771,
|
||||
"_spriteFrame": {
|
||||
"__uuid__": "67e68bc9-dad5-4ad9-a2d8-7e03d458e32f"
|
||||
},
|
||||
"_type": 1,
|
||||
"_sizeMode": 0,
|
||||
"_fillType": 0,
|
||||
"_fillCenter": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"_fillStart": 0,
|
||||
"_fillRange": 0,
|
||||
"_isTrimmedMode": true,
|
||||
"_atlas": null,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "89xzFFRJFFJJux2bcfP/16",
|
||||
"sync": false
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Sprite",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"node": {
|
||||
"__id__": 6
|
||||
},
|
||||
"_enabled": true,
|
||||
"_materials": [
|
||||
{
|
||||
"__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432"
|
||||
}
|
||||
],
|
||||
"_srcBlendFactor": 770,
|
||||
"_dstBlendFactor": 771,
|
||||
"_spriteFrame": {
|
||||
"__uuid__": "88e79fd5-96b4-4a77-a1f4-312467171014"
|
||||
},
|
||||
"_type": 1,
|
||||
"_sizeMode": 0,
|
||||
"_fillType": 0,
|
||||
"_fillCenter": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"_fillStart": 0,
|
||||
"_fillRange": 0,
|
||||
"_isTrimmedMode": true,
|
||||
"_atlas": null,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.ProgressBar",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"node": {
|
||||
"__id__": 6
|
||||
},
|
||||
"_enabled": true,
|
||||
"_N$totalLength": 50,
|
||||
"_N$barSprite": {
|
||||
"__id__": 8
|
||||
},
|
||||
"_N$mode": 0,
|
||||
"_N$progress": 1,
|
||||
"_N$reverse": false,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "6f4u0eKrBLg6uBBF8XiS5j",
|
||||
"sync": false
|
||||
},
|
||||
{
|
||||
"__type__": "d38f8EBpNRCKpXOZDdZv+gD",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"anim": {
|
||||
"__id__": 4
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "",
|
||||
"sync": false
|
||||
}
|
||||
]
|
9
assets/resources/Biker/Biker.prefab.meta
Normal file
9
assets/resources/Biker/Biker.prefab.meta
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.3.2",
|
||||
"uuid": "e3f2d00f-b307-4c62-93ae-b968945b1b9f",
|
||||
"importer": "prefab",
|
||||
"optimizationPolicy": "AUTO",
|
||||
"asyncLoadAssets": false,
|
||||
"readonly": false,
|
||||
"subMetas": {}
|
||||
}
|
13
assets/resources/Biker/anims.meta
Normal file
13
assets/resources/Biker/anims.meta
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.3",
|
||||
"uuid": "6dabbe66-aa6b-4573-9fa1-3da50292f5a1",
|
||||
"importer": "folder",
|
||||
"isBundle": false,
|
||||
"bundleName": "",
|
||||
"priority": 1,
|
||||
"compressionType": {},
|
||||
"optimizeHotUpdate": {},
|
||||
"inlineSpriteFrames": {},
|
||||
"isRemoteBundle": {},
|
||||
"subMetas": {}
|
||||
}
|
61
assets/resources/Biker/anims/attack.anim
Normal file
61
assets/resources/Biker/anims/attack.anim
Normal file
@ -0,0 +1,61 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "attack",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 1.0166666666666666,
|
||||
"sample": 60,
|
||||
"speed": 1,
|
||||
"wrapMode": 1,
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "36974693-ddd3-43de-994b-2f87d650afab"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.16666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "e5b7949e-ab1a-485a-8652-81db128e6d2d"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.3333333333333333,
|
||||
"value": {
|
||||
"__uuid__": "70703165-d081-4711-9156-ec570fb12db9"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.5,
|
||||
"value": {
|
||||
"__uuid__": "4ccbf914-5142-4ba7-80f6-46a3503c4afe"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.6666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "e7d042b9-f49a-4495-bb62-fcae6fa39cb3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.8333333333333334,
|
||||
"value": {
|
||||
"__uuid__": "24dc980d-2426-41b9-91a7-9a664bd2f6b0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 1,
|
||||
"value": {
|
||||
"__uuid__": "36974693-ddd3-43de-994b-2f87d650afab"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
6
assets/resources/Biker/anims/attack.anim.meta
Normal file
6
assets/resources/Biker/anims/attack.anim.meta
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"ver": "2.1.2",
|
||||
"uuid": "6ee5314b-888f-409e-902e-26749cad0015",
|
||||
"importer": "animation-clip",
|
||||
"subMetas": {}
|
||||
}
|
55
assets/resources/Biker/anims/death.anim
Normal file
55
assets/resources/Biker/anims/death.anim
Normal file
@ -0,0 +1,55 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "death",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 0.85,
|
||||
"sample": 60,
|
||||
"speed": 1,
|
||||
"wrapMode": 1,
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "f5476f9b-3eac-4003-a7d9-868fbeb659fa"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.16666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "0d4a7d9d-533a-4b37-a48d-bc4b4b5d3409"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.3333333333333333,
|
||||
"value": {
|
||||
"__uuid__": "1051eefe-7216-45c1-8f10-673f9dae689f"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.5,
|
||||
"value": {
|
||||
"__uuid__": "dde16e39-67b3-427e-8c49-53c00fb59dc7"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.6666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "555da2d0-cb33-416b-95fc-4e21b3979e7b"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.8333333333333334,
|
||||
"value": {
|
||||
"__uuid__": "297a317b-d3f4-4495-a907-2d120eb45f93"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
6
assets/resources/Biker/anims/death.anim.meta
Normal file
6
assets/resources/Biker/anims/death.anim.meta
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"ver": "2.1.2",
|
||||
"uuid": "41ff0c6a-d2e8-4c9b-b789-bc4d370f7306",
|
||||
"importer": "animation-clip",
|
||||
"subMetas": {}
|
||||
}
|
37
assets/resources/Biker/anims/hurt.anim
Normal file
37
assets/resources/Biker/anims/hurt.anim
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "hurt",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 0.18333333333333332,
|
||||
"sample": 60,
|
||||
"speed": 1,
|
||||
"wrapMode": 1,
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "4d3d9c32-a3e4-462c-9bd6-0e23c769bdb0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.08333333333333333,
|
||||
"value": {
|
||||
"__uuid__": "877bb390-9e8f-4426-ae29-630095004e6d"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.16666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "4d3d9c32-a3e4-462c-9bd6-0e23c769bdb0"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
6
assets/resources/Biker/anims/hurt.anim.meta
Normal file
6
assets/resources/Biker/anims/hurt.anim.meta
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"ver": "2.1.2",
|
||||
"uuid": "28fe88ff-4bc8-4075-8e33-036bc8590ed4",
|
||||
"importer": "animation-clip",
|
||||
"subMetas": {}
|
||||
}
|
61
assets/resources/Biker/anims/punch.anim
Normal file
61
assets/resources/Biker/anims/punch.anim
Normal file
@ -0,0 +1,61 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "punch",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 1.0166666666666666,
|
||||
"sample": 60,
|
||||
"speed": 1,
|
||||
"wrapMode": 1,
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "f180d226-0504-4b60-ae35-40d47deac85a"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.16666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "4328e236-573e-49e1-9922-523be4bbcffd"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.3333333333333333,
|
||||
"value": {
|
||||
"__uuid__": "443d0757-6fe2-4834-b162-26d77092ee5c"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.5,
|
||||
"value": {
|
||||
"__uuid__": "5b9ea29e-14bd-4376-be56-7641d93cdd45"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.6666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "bf94064d-b1ae-42e6-8dce-c1bedea66e07"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.8333333333333334,
|
||||
"value": {
|
||||
"__uuid__": "7501f2da-6a8b-4a10-9908-ec67aff429f4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 1,
|
||||
"value": {
|
||||
"__uuid__": "f180d226-0504-4b60-ae35-40d47deac85a"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
6
assets/resources/Biker/anims/punch.anim.meta
Normal file
6
assets/resources/Biker/anims/punch.anim.meta
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"ver": "2.1.2",
|
||||
"uuid": "61a5270f-7761-498d-bbec-b994abd2c8a5",
|
||||
"importer": "animation-clip",
|
||||
"subMetas": {}
|
||||
}
|
61
assets/resources/Biker/anims/run.anim
Normal file
61
assets/resources/Biker/anims/run.anim
Normal file
@ -0,0 +1,61 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "run",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 1.0166666666666666,
|
||||
"sample": 60,
|
||||
"speed": 1,
|
||||
"wrapMode": 2,
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "541e4c96-93f5-4ccd-8d1b-b9e386d143c1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.16666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "e61ec58b-4144-437a-b053-090890f3fb81"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.3333333333333333,
|
||||
"value": {
|
||||
"__uuid__": "e7ae4439-ebc8-49eb-9ff6-8d255c822619"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.5,
|
||||
"value": {
|
||||
"__uuid__": "15102378-3270-4f81-a975-9fde0a542fdb"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.6666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "a6252eac-25e4-4b98-8b85-05c4ba8e7641"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.8333333333333334,
|
||||
"value": {
|
||||
"__uuid__": "24a57346-5b93-4131-832b-ed6fdc48ec16"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 1,
|
||||
"value": {
|
||||
"__uuid__": "541e4c96-93f5-4ccd-8d1b-b9e386d143c1"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
6
assets/resources/Biker/anims/run.anim.meta
Normal file
6
assets/resources/Biker/anims/run.anim.meta
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"ver": "2.1.2",
|
||||
"uuid": "1cac62f0-3a28-49cd-928f-3411415323b9",
|
||||
"importer": "animation-clip",
|
||||
"subMetas": {}
|
||||
}
|
61
assets/resources/Biker/anims/run_attack.anim
Normal file
61
assets/resources/Biker/anims/run_attack.anim
Normal file
@ -0,0 +1,61 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "run_attack",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 1.0166666666666666,
|
||||
"sample": 60,
|
||||
"speed": 1,
|
||||
"wrapMode": 1,
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "6589b771-3f5a-491e-8bc2-881a7462e3f7"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.16666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "9a7da8fb-e686-4cec-baf9-4fbfd24cb6a0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.3333333333333333,
|
||||
"value": {
|
||||
"__uuid__": "b06d453f-86ed-4630-bc36-73c0a97a2767"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.5,
|
||||
"value": {
|
||||
"__uuid__": "5a2a0b48-ed3b-4d7e-9896-6085d0a48464"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.6666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "bc238bda-b094-4257-8a60-c8b54d69cb9a"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.8333333333333334,
|
||||
"value": {
|
||||
"__uuid__": "5e70746a-2039-42d2-b514-53c793c70ba7"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 1,
|
||||
"value": {
|
||||
"__uuid__": "6589b771-3f5a-491e-8bc2-881a7462e3f7"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
6
assets/resources/Biker/anims/run_attack.anim.meta
Normal file
6
assets/resources/Biker/anims/run_attack.anim.meta
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"ver": "2.1.2",
|
||||
"uuid": "62e0fbf7-19ce-44b3-a6b6-d24a24f0bdbd",
|
||||
"importer": "animation-clip",
|
||||
"subMetas": {}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user