最新版ECS模块开发模板DEMO

This commit is contained in:
dgflash
2021-11-12 13:38:30 +08:00
parent 3b690e8068
commit dfd9fb2d61
25 changed files with 622 additions and 51 deletions

View File

@@ -0,0 +1,12 @@
{
"ver": "1.1.0",
"importer": "directory",
"imported": true,
"uuid": "a2c06fee-9cbe-4e3b-b9ff-a29cdd9e6646",
"files": [],
"subMetas": {},
"userData": {
"compressionType": {},
"isRemoteBundle": {}
}
}

View File

@@ -0,0 +1 @@
{"1":{"describe":"成功"},"2":{"describe":"服务器错误"},"3":{"describe":"数据库错误"}}

View File

@@ -0,0 +1,11 @@
{
"ver": "1.0.0",
"importer": "json",
"imported": true,
"uuid": "632275d6-db6d-4335-9d55-31da137fb8f6",
"files": [
".json"
],
"subMetas": {},
"userData": {}
}

View File

@@ -29,7 +29,7 @@
"_prefab": null,
"autoReleaseAssets": false,
"_globals": {
"__id__": 103
"__id__": 110
},
"_id": "ba0b085f-f8d5-40b0-9964-2fd25728d707"
},
@@ -239,7 +239,7 @@
"_active": true,
"_components": [
{
"__id__": 102
"__id__": 109
}
],
"_prefab": null,
@@ -3307,18 +3307,21 @@
"_children": [
{
"__id__": 94
},
{
"__id__": 96
}
],
"_active": true,
"_components": [
{
"__id__": 96
"__id__": 103
},
{
"__id__": 98
"__id__": 105
},
{
"__id__": 100
"__id__": 107
}
],
"_prefab": null,
@@ -3434,6 +3437,157 @@
"_targetTexture": null,
"_id": "91CjdhwCZBXZzNJCpJXp5K"
},
{
"__type__": "cc.Node",
"_name": "ecs_demo",
"_objFlags": 0,
"_parent": {
"__id__": 93
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 97
},
{
"__id__": 99
},
{
"__id__": 101
}
],
"_prefab": null,
"_lpos": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_lrot": {
"__type__": "cc.Quat",
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"_lscale": {
"__type__": "cc.Vec3",
"x": 1,
"y": 1,
"z": 1
},
"_layer": 33554432,
"_euler": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_id": "f9u+JQgktBsbnSB/sqaPqs"
},
{
"__type__": "cc.UITransform",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 96
},
"_enabled": true,
"__prefab": {
"__id__": 98
},
"_contentSize": {
"__type__": "cc.Size",
"width": 92.28,
"height": 50.4
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_id": "52HZUUX8hBMZE984hr/tvx"
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "c68UOAlNhN171Umca6yVvF"
},
{
"__type__": "cc.Label",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 96
},
"_enabled": true,
"__prefab": {
"__id__": 100
},
"_visFlags": 0,
"_customMaterial": null,
"_srcBlendFactor": 2,
"_dstBlendFactor": 4,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_string": "ecs_demo",
"_horizontalAlign": 1,
"_verticalAlign": 1,
"_actualFontSize": 20,
"_fontSize": 20,
"_fontFamily": "Arial",
"_lineHeight": 40,
"_overflow": 0,
"_enableWrapText": true,
"_font": null,
"_isSystemFontUsed": true,
"_isItalic": false,
"_isBold": false,
"_isUnderline": false,
"_underlineHeight": 2,
"_cacheMode": 0,
"_id": "4ehG+3nZhMyLG1O7ljUOeU"
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "2frm37uaJHQr0AEEaYyM82"
},
{
"__type__": "033c3XyXLlE/Is8frhruBf0",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 96
},
"_enabled": true,
"__prefab": null,
"movement": {
"__id__": 102
},
"_id": "fakFE2p7BAeqFlPCvlFVr3"
},
{
"__type__": "DemoViewMovementComp",
"acceleration": 1,
"_maxSpeed": 100,
"heading": {
"__type__": "cc.Vec3",
"x": 1,
"y": 1,
"z": 1
},
"targetHeading": {
"__type__": "cc.Vec3",
"x": 1,
"y": 1,
"z": 1
}
},
{
"__type__": "cc.UITransform",
"_name": "Canvas<UITransform>",
@@ -3443,7 +3597,7 @@
},
"_enabled": true,
"__prefab": {
"__id__": 97
"__id__": 104
},
"_contentSize": {
"__type__": "cc.Size",
@@ -3470,7 +3624,7 @@
},
"_enabled": true,
"__prefab": {
"__id__": 99
"__id__": 106
},
"_cameraComponent": {
"__id__": 95
@@ -3491,7 +3645,7 @@
},
"_enabled": true,
"__prefab": {
"__id__": 101
"__id__": 108
},
"_alignFlags": 45,
"_target": null,
@@ -3525,7 +3679,6 @@
"__id__": 10
},
"_enabled": true,
"__prefab": null,
"game": {
"__id__": 11
},
@@ -3537,16 +3690,16 @@
{
"__type__": "cc.SceneGlobals",
"ambient": {
"__id__": 104
"__id__": 111
},
"shadows": {
"__id__": 105
"__id__": 112
},
"_skybox": {
"__id__": 106
"__id__": 113
},
"fog": {
"__id__": 107
"__id__": 114
}
},
{

View File

@@ -1,11 +1,17 @@
/*
* @Author: dgflash
* @Date: 2021-07-03 16:13:17
* @LastEditors: dgflash
* @LastEditTime: 2021-11-12 13:36:16
*/
import { game, setDisplayStats, _decorator } from 'cc';
import { DEBUG } from 'cc/env';
import { engine } from './core/Engine';
import { LayerType, UIConfig } from './core/gui/layer/LayerManager';
import { Root } from './core/Root';
import { Demo } from './ecs/entity/Demo';
import { RootSystem } from './ecs/RootSystem';
const { ccclass } = _decorator;
const { ccclass, property } = _decorator;
export enum UIID {
UILoading = 0,
@@ -38,6 +44,22 @@ export class Main extends Root {
protected run() {
engine.gui.init(UICF);
engine.gui.open(UIID.UILoading);
this.ecs_demo();
}
/** 通过ECS设计通用业务组件来复用 */
private async ecs_demo() {
Demo.load(() => {
var a = new Demo();
a.init(1);
// 模块业务逻辑
a.login();
// 模块视图
a.show(this.node);
});
}
update(dt: number) {

View File

@@ -1,3 +1,9 @@
/*
* @Author: dgflash
* @Date: 2021-07-03 16:13:17
* @LastEditors: dgflash
* @LastEditTime: 2021-11-11 19:42:56
*/
import { Component, director, game, Game, log, Node, view, _decorator } from "cc";
import { config } from "../game/config/Config";
import { EngineMessage } from "./common/event/EngineMessage";
@@ -28,7 +34,7 @@ export class Root extends Component {
engine.init(this);
// 加载游戏配置
config.init(this.run);
config.init(this.run.bind(this));
}
/** 加载完引擎配置文件后执行 */

View File

@@ -2,7 +2,7 @@
* @Author: dgflash
* @Date: 2021-08-18 17:00:59
* @LastEditors: dgflash
* @LastEditTime: 2021-09-28 15:21:21
* @LastEditTime: 2021-11-12 11:59:32
*/
import { error, JsonAsset } from "cc";
@@ -13,36 +13,23 @@ import { resLoader } from "../common/loader/ResLoader";
var data: Map<string, any> = new Map();
export class JsonUtil {
static getData(name: string): any {
static get(name: string): any {
if (data.has(name))
return data.get(name);
else
return new Promise((resolve, reject) => {
var url = GameConfig.getConfigPath(name);
resLoader.load(url, JsonAsset, (err: Error | null, content: JsonAsset) => {
if (err) {
error(err.message);
}
data.set(name, content.json);
resolve(content.json);
});
});
}
static get(name: string): any {
return new Promise((resolve, reject) => {
if (data.has(name))
resolve(data.get(name));
else {
var url = GameConfig.getConfigPath(name);
resLoader.load(url, JsonAsset, (err: Error | null, content: JsonAsset) => {
if (err) {
error(err.message);
}
data.set(name, content.json);
resolve(content.json);
});
}
});
static load(name: string, callback: Function): void {
if (data.has(name))
callback(data.get(name));
else {
var url = GameConfig.getConfigPath(name);
resLoader.load(url, JsonAsset, (err: Error | null, content: JsonAsset) => {
if (err) {
error(err.message);
}
data.set(name, content.json);
callback(content.json)
});
}
}
}

View File

@@ -1,14 +1,16 @@
/*
* @Author: dgflash
* @Date: 2021-07-03 16:13:17
* @LastEditors: dgflash
* @LastEditTime: 2021-11-12 10:41:50
*/
import { ecs } from "../core/libs/ECS";
import { EcsDemoSystem } from "./system/EcsDemoSystem";
export class RootSystem extends ecs.RootSystem {
constructor() {
super();
// this.add(new AutoCreateEnemySystem());
// this.add(new AutoMoveToSystem());
// this.add(new EcsMgobeSystem());
// this.add(new EcsInputSystem());
// this.add(new EcsRotationSystem());
// this.add(new EcsPositionSystem());
this.add(new EcsDemoSystem());
}
}

View File

@@ -0,0 +1,37 @@
/*
* @Author: dgflash
* @Date: 2021-11-11 19:05:32
* @LastEditors: dgflash
* @LastEditTime: 2021-11-12 11:46:24
*/
import { Component, _decorator } from "cc";
import { ecs } from "../../core/libs/ECS";
const { ccclass, property } = _decorator;
/**
* ECS结合Cocos Creator组件
* 使用方法:
* 1、ECS结合Cocos Creator组件可独立形成一个ECS的复杂视图实例对象
* 2、对网络游戏优先有数据对象在才创建视图组件的流程在释放视图组件时不释放数据对象
*/
@ccclass('CCComp')
export abstract class CCComp extends Component implements ecs.IComp {
static tid: number = -1;
static compName: string;
canRecycle!: boolean;
ent!: ecs.Entity;
onLoad() {
this.ent = ecs.createEntity();
this.ent.add(this);
}
onDestroy() {
this.ent.destroy();
}
abstract reset(): void;
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.22",
"importer": "typescript",
"imported": true,
"uuid": "1329d483-ea72-4225-a71c-7f7a235b0dac",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,17 @@
/*
* @Author: dgflash
* @Date: 2021-11-12 10:47:04
* @LastEditors: dgflash
* @LastEditTime: 2021-11-12 11:18:56
*/
import { ecs } from "../../core/libs/ECS";
/** 登录组件 */
@ecs.register('DemoBllLogin')
export class DemoBllLoginComp extends ecs.Comp {
playerId: number = -1;
reset() {
this.playerId = -1;
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.22",
"importer": "typescript",
"imported": true,
"uuid": "f4c96747-a764-4a4f-9161-63a68ee8aecb",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,35 @@
/*
* @Author: dgflash
* @Date: 2021-11-12 10:02:31
* @LastEditors: dgflash
* @LastEditTime: 2021-11-12 10:47:38
*/
import { ecs } from "../../core/libs/ECS";
import { JsonUtil } from "../../core/utils/JsonUtil";
/** 静态数据表组件 */
@ecs.register('DemoModelTable')
export class DemoModelTableComp extends ecs.Comp {
static TableName: string = "NetCode";
/** 静态数据表 */
table: any;
/** 静态表中一条数据 */
data: any;
init(id: number) {
var table = JsonUtil.get(DemoModelTableComp.TableName);
this.data = table[id];
}
get describe(): string {
return this.data.describe;
}
reset() {
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.22",
"importer": "typescript",
"imported": true,
"uuid": "8d0c16b0-b4ff-4324-9bc1-2d75c78e9db1",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,41 @@
/*
* @Author: dgflash
* @Date: 2021-11-11 17:52:54
* @LastEditors: dgflash
* @LastEditTime: 2021-11-12 11:29:20
*/
import { _decorator } from "cc";
import { ecs } from "../../core/libs/ECS";
import { CCComp } from "./CCComp";
import { DemoViewMovementComp } from "./DemoViewMovementComp";
const { ccclass, property } = _decorator;
/**
* 视图层外观组件
* 组件自身即是ECS组件也是ECS实体实体上可添加实现界面逻辑的ECS组件代码
*/
@ccclass('DemoViewComp')
@ecs.register('DemoViewComp', false)
export class DemoViewComp extends CCComp {
@property({
type: DemoViewMovementComp
})
movement: DemoViewMovementComp = null!;
onLoad() {
super.onLoad();
this.ent.add(this.movement);
}
update(dt: number): void {
this.movement.update(dt);
this.node.position = this.movement.pos;
}
reset(): void {
this.movement = null!;
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.22",
"importer": "typescript",
"imported": true,
"uuid": "033c35f2-5cb9-44fc-8b3c-7eb86bb817f4",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,57 @@
/*
* @Author: dgflash
* @Date: 2021-11-11 19:12:25
* @LastEditors: dgflash
* @LastEditTime: 2021-11-12 10:47:52
*/
import { toDegree, v3, Vec3, _decorator } from "cc";
import { ecs } from "../../core/libs/ECS";
const { ccclass, property } = _decorator;
/** 视图逻辑组件 */
@ccclass('DemoViewMovementComp')
@ecs.register('DemoViewMovementComp')
export class DemoViewMovementComp extends ecs.Comp {
pos: Vec3 = v3();
angle: number = 0;
speed: number = 0;
@property
acceleration: number = 0;
@property
private _maxSpeed: number = 0;
@property
set maxSpeed(val: number) {
this._maxSpeed = val;
}
get maxSpeed() {
return this._maxSpeed;
}
@property
heading: Vec3 = v3();
@property
targetHeading: Vec3 = v3();
reset() {
}
/** 只处理数据逻辑的直接写在ECS组件里 */
update(dt: number) {
if (!Vec3.equals(this.heading, this.targetHeading, 0.01)) {
let outV3 = v3();
Vec3.subtract(outV3, this.targetHeading, this.heading);
outV3.multiplyScalar(0.025);
this.heading.add(outV3);
this.heading.normalize();
this.angle = toDegree(Math.atan2(this.heading.y, this.heading.x)) - 90;
}
this.speed = Math.min(this.speed + this.acceleration * dt, this._maxSpeed);
this.pos.add3f(this.heading.x * this.speed * dt, this.heading.y * this.speed * dt, 0);
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.22",
"importer": "typescript",
"imported": true,
"uuid": "8de4a716-cb33-4e3c-bff1-1a35d0d86b5d",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,50 @@
/*
* @Author: dgflash
* @Date: 2021-11-11 17:45:23
* @LastEditors: dgflash
* @LastEditTime: 2021-11-12 12:02:25
*/
import { find, Node } from "cc";
import { ecs } from "../../core/libs/ECS";
import { JsonUtil } from "../../core/utils/JsonUtil";
import { DemoBllLoginComp } from "../component/DemoBllLoginComp";
import { DemoModelTableComp } from "../component/DemoModelTableComp";
import { DemoViewComp } from "../component/DemoViewComp";
export class Demo extends ecs.Entity {
DemoModelTable!: DemoModelTableComp;
DemoBllLogin!: DemoBllLoginComp;
DemoView!: DemoViewComp;
/** 加载模块相关资源 */
static load(callback: Function) {
// 模块静态数据
JsonUtil.load(DemoModelTableComp.TableName, callback);
}
constructor() {
super();
this.addComponents(DemoModelTableComp);
}
/** 初始化数据 */
init(id: number) {
var mt = this.get(DemoModelTableComp);
mt.init(id);
console.log("静态数据", mt.describe);
}
/** 显示视图 */
show(parent: Node) {
var d = find("gui/ecs_demo", parent)!;
var dc = d.getComponent(DemoViewComp)!;
this.add(dc);
}
/** 登录逻辑 */
login() {
var dbl = this.add(DemoBllLoginComp);
dbl.playerId = 123456789;
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.22",
"importer": "typescript",
"imported": true,
"uuid": "c28b2b5b-353e-4128-8a45-a3e57826aec9",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,49 @@
import { ecs } from "../../core/libs/ECS";
import { DemoBllLoginComp } from "../component/DemoBllLoginComp";
import { Demo } from "../entity/Demo";
/*
* @Author: dgflash
* @Date: 2021-11-11 18:11:13
* @LastEditors: dgflash
* @LastEditTime: 2021-11-12 11:49:52
*/
export class DemoBllLoginSystem extends ecs.ComblockSystem implements ecs.IEntityEnterSystem {
filter(): ecs.IMatcher {
return ecs.allOf(DemoBllLoginComp);
}
entityEnter(entities: Demo[]): void {
for (let e of entities) {
console.log("用户登录", e.DemoBllLogin.playerId);
// 获取到的玩过数据存储到对应的ECS组件中提供其它组件使用
this.requestLoadPlayer(e.DemoBllLogin.playerId)
e.remove(DemoBllLoginComp);
}
}
update(entities: ecs.Entity[]): void {
}
/** 请求角色登录游戏 */
private requestLoadPlayer(playerId: number) {
// var params: any = {
// playerId: playerId,
// serverId: netConfig.lastLoginServer.id,
// gmUid: netConfig.dbid,
// sessionKey: netConfig.sessionKey,
// }
// var onComplete = {
// target: this,
// callback: (data: any) => {
// console.log(data);
// }
// }
// netChannel.game.req("LoginAction", "loadPlayer", params, onComplete);
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.22",
"importer": "typescript",
"imported": true,
"uuid": "51cdc2fc-19ac-4211-8e44-378964e89ebf",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,15 @@
import { ecs } from "../../core/libs/ECS";
import { DemoBllLoginSystem } from "./DemoBllLoginSystem";
/*
* @Author: dgflash
* @Date: 2021-11-11 18:14:52
* @LastEditors: dgflash
* @LastEditTime: 2021-11-12 10:50:28
*/
export class EcsDemoSystem extends ecs.System {
constructor() {
super();
this.add(new DemoBllLoginSystem());
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.22",
"importer": "typescript",
"imported": true,
"uuid": "ad41f606-de52-4753-9792-8a23e65d615d",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -2,7 +2,7 @@
* @Author: dgflash
* @Date: 2021-07-03 16:13:17
* @LastEditors: dgflash
* @LastEditTime: 2021-11-04 17:33:25
* @LastEditTime: 2021-11-12 10:16:59
*/
import { Logger } from "../../core/common/log/Logger";
@@ -18,6 +18,10 @@ export class GameConfig {
return this._data["config"]["version"];
}
public static getConfigPath(relative_path: string) {
return "config/game/" + relative_path;
}
/**
* 获取当前客户端支持的语言类型
*/