设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
查看: 2393|回复: 3
打印 上一主题 下一主题

[交流讨论] [无用研究]将显示对象与MV解耦

[复制链接]

Lv3.寻梦者

梦石
0
星屑
1912
在线时间
1554 小时
注册时间
2013-4-13
帖子
917
跳转到指定楼层
1
发表于 2020-6-14 19:36:11 | 只看该作者 |只看大图 回帖奖励 |正序浏览 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有帐号?注册会员

x
大家都知道能够显示在游戏画面的有Sprite和各种Window,
实际上这些类都是从PIXI.Container继承而来的,
当我们要自己设计一个可显示对象的时候, 其实可以从Container这个级别开始
虽然会失去很多预设功能, 不过这些都可以自己按需求加回去
另一个问题是几个平行的可显示对象互相交互也需要互相引用
这里通过引用一个订阅者, 解决了这个问题

下面是具体玩法:
JAVASCRIPT 代码复制
  1. // 模拟异步行为的等待
  2. const delay = (timeout) => {
  3.   return new Promise((resolve) => {
  4.     setTimeout(resolve, timeout);
  5.   });
  6. };
  7.  
  8. const buildTestObject = () => {
  9.   // 实例一个建造者
  10.   const builder = GameObject.builder();
  11.   // 读取Bitmap
  12.   const windowskin = ImageManager.loadSystem('Window');
  13.   const face = ImageManager.loadFace('Actor1');
  14.   // 随便弄俩精灵, 一个背景, 一个头像
  15.   windowBackSprite = new Sprite();
  16.   windowBackSprite.alpha = 192 / 255;
  17.   windowContentsSprite = new Sprite();
  18.   windowContentsSprite.bitmap = new Bitmap(500, 500);
  19.  
  20.   // 开始建造
  21.   builder
  22.     // 当一切加载完毕以后执行
  23.     // 这里初始化了绑定的数据和窗口大小
  24.     .setupHandler('start', (self) => {
  25.       console.log('start');
  26.       self.initData({ faceIndex: 0 });
  27.       self.x = 50;
  28.       self.y = 50;
  29.       self.width = 200;
  30.       self.height = 200;
  31.     })
  32.     // 每次更新的时候执行
  33.     // 从data里获取faceIndex
  34.     // 判断用户输入选择向左或者向右切换头像
  35.     .setupHandler('update', (self) => {
  36.       const { faceIndex } = self.getData();
  37.       if (Input.isRepeated('left')) {
  38.         self.setData({ faceIndex: (faceIndex + 7) % 8 });
  39.       }
  40.       if (Input.isRepeated('right')) {
  41.         self.setData({ faceIndex: (faceIndex + 1) % 8 });
  42.       }
  43.     })
  44.     // 初始化的时候触发, 会等待所有异步操作完毕
  45.     .setupHandler('create', async (self) => {
  46.       console.log('creating...');
  47.       await Promise.all([
  48.         new Promise((resolve) => {
  49.           windowskin.addLoadListener(resolve);
  50.         }),
  51.         new Promise((resolve) => {
  52.           face.addLoadListener(resolve);
  53.         }),
  54.       ]);
  55.       console.log('loaded...');
  56.       await delay(1000);
  57.       console.log('done!');
  58.     })
  59.     // 当更新绑定数据时候, initData不会触发change事件
  60.     // 判断faceIndex是否发生了改变
  61.     // 可以根据特定的值发生了变化来执行对应的操作
  62.     .setupHandler('change', (self, oldData) => {
  63.       if (oldData.faceIndex !== self.getData().faceIndex)
  64.         self.triggerEvent(self.getDrawHandler('face'));
  65.     })
  66.     // 添加一个精灵
  67.     .addSprite('windowskin', windowBackSprite, (self) => {
  68.       var w = self.width;
  69.       var h = self.height;
  70.       var bitmap = new Bitmap(w, h);
  71.       windowBackSprite.bitmap = bitmap;
  72.       windowBackSprite.setFrame(0, 0, w, h);
  73.       if (w > 0 && h > 0 && windowskin) {
  74.         var p = 96;
  75.         bitmap.blt(windowskin, 0, 0, p, p, 0, 0, w, h);
  76.       }
  77.     })
  78.     // 添加另一个精灵
  79.     // 会从绑定数据中读取信息
  80.     .addSprite('face', windowContentsSprite, (self) => {
  81.       windowContentsSprite.bitmap.clear();
  82.       var faceIndex = self.getData().faceIndex;
  83.       var x = 0;
  84.       var y = 0;
  85.       var width = Window_Base._faceWidth;
  86.       var height = Window_Base._faceHeight;
  87.       var bitmap = ImageManager.loadFace('Actor1');
  88.       var pw = Window_Base._faceWidth;
  89.       var ph = Window_Base._faceHeight;
  90.       var sw = Math.min(width, pw);
  91.       var sh = Math.min(height, ph);
  92.       var dx = Math.floor(x + Math.max(width - pw, 0) / 2);
  93.       var dy = Math.floor(y + Math.max(height - ph, 0) / 2);
  94.       var sx = (faceIndex % 4) * pw + (pw - sw) / 2;
  95.       var sy = Math.floor(faceIndex / 4) * ph + (ph - sh) / 2;
  96.       windowContentsSprite.bitmap.blt(
  97.         bitmap,
  98.         sx,
  99.         sy,
  100.         sw,
  101.         sh,
  102.         dx,
  103.         dy,
  104.         width,
  105.         height
  106.       );
  107.     });
  108.   // 完成建造
  109.   return builder.build();
  110. };


在控制台输入
const a = buildTestObject()
SceneManager._scene.addChild(a)
就可以看到效果了:



以下是当文档来看也是极好的Typescript版本
TYPESCRIPT 代码复制
  1. declare type Maybe<T> = T | null;
  2. /**
  3. * 事件响应, 可以返回一个Promise
  4. */
  5. type EventHandler = (self: GameObject, ...args: any[]) => void | Promise<any>;
  6. /**
  7. * 事件名
  8. */
  9. type EventName =
  10.   | 'create'
  11.   | 'terminate'
  12.   | 'start'
  13.   | 'update'
  14.   | 'change'
  15.   | 'draw'
  16.   | string;
  17. /**
  18. * 处理全局消息通信
  19. */
  20. class GlobalEventManager {
  21.   static listeners: Record<EventName, GameObject[]> = {};
  22.  
  23.   private static getListeners(eventName: EventName) {
  24.     const listeners = this.listeners[eventName] || [];
  25.     if (!listeners.length) this.listeners[eventName] = listeners;
  26.     return listeners;
  27.   }
  28.  
  29.   /**
  30.    * 订阅事件
  31.    */
  32.   public static subscribe(item: GameObject, eventName: EventName) {
  33.     const listeners = this.getListeners(eventName);
  34.     if (listeners.find((listener) => listener === item)) return;
  35.     listeners.push(item);
  36.   }
  37.  
  38.   /**
  39.    * 取消订阅
  40.    */
  41.   public static unsubscribe(item: GameObject, eventName: EventName) {
  42.     const listeners = this.getListeners(eventName);
  43.     const index = listeners.indexOf(item);
  44.     if (index >= 0) listeners.splice(index, 1);
  45.   }
  46.  
  47.   /**
  48.    * 取消全部订阅
  49.    */
  50.   public static removeListener(item: GameObject) {
  51.     Object.keys(this.listeners).forEach((eventName) => {
  52.       this.unsubscribe(item, eventName);
  53.     });
  54.   }
  55.  
  56.   /**
  57.    * 广播事件
  58.    */
  59.   public static dispatch(eventName: EventName, ...args: []) {
  60.     const listeners = this.listeners[eventName] || [];
  61.     listeners.forEach((item) => {
  62.       item.triggerEvent(eventName, ...args);
  63.     });
  64.   }
  65. }
  66.  
  67. class GameObjectBuilder<T = any> {
  68.   gameObject: GameObject<T>;
  69.   constructor() {
  70.     this.gameObject = new GameObject();
  71.   }
  72.  
  73.   setupHandler(eventName: EventName, eventHandler: EventHandler) {
  74.     this.gameObject.setupHandler(eventName, eventHandler);
  75.     return this;
  76.   }
  77.  
  78.   initData(data: Maybe<T>) {
  79.     this.gameObject.initData(data);
  80.     return this;
  81.   }
  82.  
  83.   addSprite(name: string, sprite: PIXI.Sprite, handler: EventHandler) {
  84.     this.gameObject.addSprite(name, sprite, handler);
  85.     return this;
  86.   }
  87.  
  88.   build() {
  89.     return this.gameObject;
  90.   }
  91. }
  92.  
  93. class GameObject<T = any> extends PIXI.Container {
  94.   static builder() {
  95.     return new GameObjectBuilder();
  96.   }
  97.   private _width: number;
  98.   private _height: number;
  99.   children: GameObject[] = [];
  100.   willCreate: boolean = true;
  101.   willTerminate: boolean = false;
  102.   isCreated: boolean = false;
  103.   isTerminated: boolean = false;
  104.   isStarted: boolean = false;
  105.   eventHandlers: Record<EventName, EventHandler> = {};
  106.   data: Maybe<T> = null;
  107.   sprites: Record<string, PIXI.Sprite> = {};
  108.  
  109.   /**
  110.    * 覆写PIXI默认的宽高, 防止图像拉伸
  111.    */
  112.   constructor(width = 0, height = 0) {
  113.     super();
  114.     this._width = width;
  115.     this._height = height;
  116.     Object.defineProperties(this, {
  117.       width: {
  118.         get: () => this._width,
  119.         set: (w) => {
  120.           this._width = w;
  121.           this.refresh();
  122.         },
  123.       },
  124.       height: {
  125.         get: () => this._height,
  126.         set: (h) => {
  127.           this._height = h;
  128.           this.refresh();
  129.         },
  130.       },
  131.     });
  132.   }
  133.  
  134.   /**
  135.    * 注册事件处理方法或异步方法
  136.    */
  137.   setupHandler(eventName: EventName, eventHandler: EventHandler) {
  138.     this.eventHandlers[eventName] = eventHandler;
  139.   }
  140.  
  141.   /**
  142.    * 移除已注册的方法
  143.    */
  144.   removeHandler(eventName: EventName) {
  145.     delete this.eventHandlers[eventName];
  146.   }
  147.  
  148.   /**
  149.    * 手动触发事件
  150.    */
  151.   triggerEvent(eventName: EventName, ...args: any[]): void | Promise<any> {
  152.     const handler = this.eventHandlers[eventName];
  153.     if (handler) return handler(this, ...args);
  154.   }
  155.  
  156.   /**
  157.    * 获取绘制事件名
  158.    */
  159.   getDrawHandler(name: string) {
  160.     return `draw${name.replace(/^./, (str) => str.toUpperCase())}`;
  161.   }
  162.  
  163.   /**
  164.    * 重绘全部精灵
  165.    */
  166.   refresh() {
  167.     Object.keys(this.sprites).forEach((name) => {
  168.       this.triggerEvent(this.getDrawHandler(name));
  169.     });
  170.   }
  171.  
  172.   /**
  173.    * 添加精灵
  174.    */
  175.   addSprite(name: string, sprite: PIXI.Sprite, handler: EventHandler) {
  176.     this.sprites[name] = sprite;
  177.     this.setupHandler(this.getDrawHandler(name), handler);
  178.     this.addChild(sprite);
  179.   }
  180.  
  181.   /**
  182.    * 初始化数据, 不会触发数据更新事件
  183.    */
  184.   initData(data: Maybe<T>) {
  185.     this.data = data;
  186.   }
  187.  
  188.   /**
  189.    * 获取数据
  190.    */
  191.   getData() {
  192.     return this.data;
  193.   }
  194.  
  195.   /**
  196.    * 数据绑定, 触发数据更新事件
  197.    */
  198.   setData(data: Maybe<T>) {
  199.     const oldData = this.data;
  200.     this.data = data;
  201.     this.triggerEvent('change', oldData);
  202.   }
  203.  
  204.   /**
  205.    * 第一次载入场景时触发, 用于处理异步行为
  206.    */
  207.   async onCreate() {
  208.     this.willCreate = false;
  209.     await this.triggerEvent('create');
  210.     this.isCreated = true;
  211.   }
  212.  
  213.   /**
  214.    * 完成初始化后触发, 用于初始化对象
  215.    */
  216.   onStart() {
  217.     this.triggerEvent('start');
  218.     this.refresh();
  219.     this.isStarted = true;
  220.   }
  221.  
  222.   /**
  223.    * 每一帧更新事件, 不要在这里重绘任何东西
  224.    */
  225.   onUpdate() {
  226.     this.triggerEvent('update');
  227.     this.updateChildren();
  228.   }
  229.  
  230.   /**
  231.    * 用来处理终止事件
  232.    */
  233.   async onTerminate() {
  234.     this.willTerminate = false;
  235.     await this.triggerEvent('terminate');
  236.     this.isTerminated = true;
  237.     GlobalEventManager.removeListener(this);
  238.   }
  239.  
  240.   /**
  241.    * 主循环
  242.    */
  243.   update() {
  244.     if (this.isStarted) {
  245.       this.onUpdate();
  246.     } else if (this.willCreate) {
  247.       this.onCreate();
  248.     } else if (
  249.       this.isCreated &&
  250.       this.children.every((child) => child.isCreated !== false)
  251.     ) {
  252.       this.onStart();
  253.     } else if (
  254.       this.willTerminate &&
  255.       this.children.every((child) => child.isTerminated !== false)
  256.     ) {
  257.       this.onTerminate();
  258.     }
  259.   }
  260.  
  261.   /**
  262.    * 更新子对象
  263.    */
  264.   updateChildren() {
  265.     this.children.forEach((child) => {
  266.       child.update();
  267.     });
  268.   }
  269.  
  270.   /**
  271.    * 终止对象
  272.    */
  273.   terminate() {
  274.     this.willTerminate = true;
  275.     this.children.forEach((child) => {
  276.       child.terminate();
  277.     });
  278.   }
  279. }


讲人话版JS:
JAVASCRIPT 代码复制
  1. "use strict";
  2. /**
  3.  * 处理全局消息通信
  4.  */
  5. class GlobalEventManager {
  6.     static getListeners(eventName) {
  7.         const listeners = this.listeners[eventName] || [];
  8.         if (!listeners.length)
  9.             this.listeners[eventName] = listeners;
  10.         return listeners;
  11.     }
  12.     /**
  13.      * 订阅事件
  14.      */
  15.     static subscribe(item, eventName) {
  16.         const listeners = this.getListeners(eventName);
  17.         if (listeners.find((listener) => listener === item))
  18.             return;
  19.         listeners.push(item);
  20.     }
  21.     /**
  22.      * 取消订阅
  23.      */
  24.     static unsubscribe(item, eventName) {
  25.         const listeners = this.getListeners(eventName);
  26.         const index = listeners.indexOf(item);
  27.         if (index >= 0)
  28.             listeners.splice(index, 1);
  29.     }
  30.     /**
  31.      * 取消全部订阅
  32.      */
  33.     static removeListener(item) {
  34.         Object.keys(this.listeners).forEach((eventName) => {
  35.             this.unsubscribe(item, eventName);
  36.         });
  37.     }
  38.     /**
  39.      * 广播事件
  40.      */
  41.     static dispatch(eventName, ...args) {
  42.         const listeners = this.listeners[eventName] || [];
  43.         listeners.forEach((item) => {
  44.             item.triggerEvent(eventName, ...args);
  45.         });
  46.     }
  47. }
  48. GlobalEventManager.listeners = {};
  49. class GameObjectBuilder {
  50.     constructor() {
  51.         this.gameObject = new GameObject();
  52.     }
  53.     setupHandler(eventName, eventHandler) {
  54.         this.gameObject.setupHandler(eventName, eventHandler);
  55.         return this;
  56.     }
  57.     initData(data) {
  58.         this.gameObject.initData(data);
  59.         return this;
  60.     }
  61.     addSprite(name, sprite, handler) {
  62.         this.gameObject.addSprite(name, sprite, handler);
  63.         return this;
  64.     }
  65.     build() {
  66.         return this.gameObject;
  67.     }
  68. }
  69. class GameObject extends PIXI.Container {
  70.     /**
  71.      * 覆写PIXI默认的宽高, 防止图像拉伸
  72.      */
  73.     constructor(width = 0, height = 0) {
  74.         super();
  75.         this.children = [];
  76.         this.willCreate = true;
  77.         this.willTerminate = false;
  78.         this.isCreated = false;
  79.         this.isTerminated = false;
  80.         this.isStarted = false;
  81.         this.eventHandlers = {};
  82.         this.data = null;
  83.         this.sprites = {};
  84.         this._width = width;
  85.         this._height = height;
  86.         Object.defineProperties(this, {
  87.             width: {
  88.                 get: () => this._width,
  89.                 set: (w) => {
  90.                     this._width = w;
  91.                     this.refresh();
  92.                 },
  93.             },
  94.             height: {
  95.                 get: () => this._height,
  96.                 set: (h) => {
  97.                     this._height = h;
  98.                     this.refresh();
  99.                 },
  100.             },
  101.         });
  102.     }
  103.     static builder() {
  104.         return new GameObjectBuilder();
  105.     }
  106.     /**
  107.      * 注册事件处理方法或异步方法
  108.      */
  109.     setupHandler(eventName, eventHandler) {
  110.         this.eventHandlers[eventName] = eventHandler;
  111.     }
  112.     /**
  113.      * 移除已注册的方法
  114.      */
  115.     removeHandler(eventName) {
  116.         delete this.eventHandlers[eventName];
  117.     }
  118.     /**
  119.      * 手动触发事件
  120.      */
  121.     triggerEvent(eventName, ...args) {
  122.         const handler = this.eventHandlers[eventName];
  123.         if (handler)
  124.             return handler(this, ...args);
  125.     }
  126.     /**
  127.      * 获取绘制事件名
  128.      */
  129.     getDrawHandler(name) {
  130.         return `draw${name.replace(/^./, (str) => str.toUpperCase())}`;
  131.     }
  132.     /**
  133.      * 重绘全部精灵
  134.      */
  135.     refresh() {
  136.         Object.keys(this.sprites).forEach((name) => {
  137.             this.triggerEvent(this.getDrawHandler(name));
  138.         });
  139.     }
  140.     /**
  141.      * 添加精灵
  142.      */
  143.     addSprite(name, sprite, handler) {
  144.         this.sprites[name] = sprite;
  145.         this.setupHandler(this.getDrawHandler(name), handler);
  146.         this.addChild(sprite);
  147.     }
  148.     /**
  149.      * 初始化数据, 不会触发数据更新事件
  150.      */
  151.     initData(data) {
  152.         this.data = data;
  153.     }
  154.     /**
  155.      * 获取数据
  156.      */
  157.     getData() {
  158.         return this.data;
  159.     }
  160.     /**
  161.      * 数据绑定, 触发数据更新事件
  162.      */
  163.     setData(data) {
  164.         const oldData = this.data;
  165.         this.data = data;
  166.         this.triggerEvent('change', oldData);
  167.     }
  168.     /**
  169.      * 第一次载入场景时触发, 用于处理异步行为
  170.      */
  171.     async onCreate() {
  172.         this.willCreate = false;
  173.         await this.triggerEvent('create');
  174.         this.isCreated = true;
  175.     }
  176.     /**
  177.      * 完成初始化后触发, 用于初始化对象
  178.      */
  179.     onStart() {
  180.         this.triggerEvent('start');
  181.         this.refresh();
  182.         this.isStarted = true;
  183.     }
  184.     /**
  185.      * 每一帧更新事件, 不要在这里重绘任何东西
  186.      */
  187.     onUpdate() {
  188.         this.triggerEvent('update');
  189.         this.updateChildren();
  190.     }
  191.     /**
  192.      * 用来处理终止事件
  193.      */
  194.     async onTerminate() {
  195.         this.willTerminate = false;
  196.         await this.triggerEvent('terminate');
  197.         this.isTerminated = true;
  198.         GlobalEventManager.removeListener(this);
  199.     }
  200.     /**
  201.      * 主循环
  202.      */
  203.     update() {
  204.         if (this.isStarted) {
  205.             this.onUpdate();
  206.         }
  207.         else if (this.willCreate) {
  208.             this.onCreate();
  209.         }
  210.         else if (this.isCreated &&
  211.             this.children.every((child) => child.isCreated !== false)) {
  212.             this.onStart();
  213.         }
  214.         else if (this.willTerminate &&
  215.             this.children.every((child) => child.isTerminated !== false)) {
  216.             this.onTerminate();
  217.         }
  218.     }
  219.     /**
  220.      * 更新子对象
  221.      */
  222.     updateChildren() {
  223.         this.children.forEach((child) => {
  224.             child.update();
  225.         });
  226.     }
  227.     /**
  228.      * 终止对象
  229.      */
  230.     terminate() {
  231.         this.willTerminate = true;
  232.         this.children.forEach((child) => {
  233.             child.terminate();
  234.         });
  235.     }
  236. }


放弃治疗es5版本:
JAVASCRIPT 代码复制
  1. "use strict";
  2. var __extends = (this && this.__extends) || (function () {
  3.     var extendStatics = function (d, b) {
  4.         extendStatics = Object.setPrototypeOf ||
  5.             ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
  6.             function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  7.         return extendStatics(d, b);
  8.     };
  9.     return function (d, b) {
  10.         extendStatics(d, b);
  11.         function __() { this.constructor = d; }
  12.         d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  13.     };
  14. })();
  15. var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
  16.     function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
  17.     return new (P || (P = Promise))(function (resolve, reject) {
  18.         function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
  19.         function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
  20.         function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
  21.         step((generator = generator.apply(thisArg, _arguments || [])).next());
  22.     });
  23. };
  24. var __generator = (this && this.__generator) || function (thisArg, body) {
  25.     var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
  26.     return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
  27.     function verb(n) { return function (v) { return step([n, v]); }; }
  28.     function step(op) {
  29.         if (f) throw new TypeError("Generator is already executing.");
  30.         while (_) try {
  31.             if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
  32.             if (y = 0, t) op = [op[0] & 2, t.value];
  33.             switch (op[0]) {
  34.                 case 0: case 1: t = op; break;
  35.                 case 4: _.label++; return { value: op[1], done: false };
  36.                 case 5: _.label++; y = op[1]; op = [0]; continue;
  37.                 case 7: op = _.ops.pop(); _.trys.pop(); continue;
  38.                 default:
  39.                     if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
  40.                     if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
  41.                     if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
  42.                     if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
  43.                     if (t[2]) _.ops.pop();
  44.                     _.trys.pop(); continue;
  45.             }
  46.             op = body.call(thisArg, _);
  47.         } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
  48.         if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
  49.     }
  50. };
  51. var __spreadArrays = (this && this.__spreadArrays) || function () {
  52.     for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
  53.     for (var r = Array(s), k = 0, i = 0; i < il; i++)
  54.         for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
  55.             r[k] = a[j];
  56.     return r;
  57. };
  58. /**
  59.  * 处理全局消息通信
  60.  */
  61. var GlobalEventManager = /** @class */ (function () {
  62.     function GlobalEventManager() {
  63.     }
  64.     GlobalEventManager.getListeners = function (eventName) {
  65.         var listeners = this.listeners[eventName] || [];
  66.         if (!listeners.length)
  67.             this.listeners[eventName] = listeners;
  68.         return listeners;
  69.     };
  70.     /**
  71.      * 订阅事件
  72.      */
  73.     GlobalEventManager.subscribe = function (item, eventName) {
  74.         var listeners = this.getListeners(eventName);
  75.         if (listeners.find(function (listener) { return listener === item; }))
  76.             return;
  77.         listeners.push(item);
  78.     };
  79.     /**
  80.      * 取消订阅
  81.      */
  82.     GlobalEventManager.unsubscribe = function (item, eventName) {
  83.         var listeners = this.getListeners(eventName);
  84.         var index = listeners.indexOf(item);
  85.         if (index >= 0)
  86.             listeners.splice(index, 1);
  87.     };
  88.     /**
  89.      * 取消全部订阅
  90.      */
  91.     GlobalEventManager.removeListener = function (item) {
  92.         var _this = this;
  93.         Object.keys(this.listeners).forEach(function (eventName) {
  94.             _this.unsubscribe(item, eventName);
  95.         });
  96.     };
  97.     /**
  98.      * 广播事件
  99.      */
  100.     GlobalEventManager.dispatch = function (eventName) {
  101.         var args = [];
  102.         for (var _i = 1; _i < arguments.length; _i++) {
  103.             args[_i - 1] = arguments[_i];
  104.         }
  105.         var listeners = this.listeners[eventName] || [];
  106.         listeners.forEach(function (item) {
  107.             item.triggerEvent.apply(item, __spreadArrays([eventName], args));
  108.         });
  109.     };
  110.     GlobalEventManager.listeners = {};
  111.     return GlobalEventManager;
  112. }());
  113. var GameObjectBuilder = /** @class */ (function () {
  114.     function GameObjectBuilder() {
  115.         this.gameObject = new GameObject();
  116.     }
  117.     GameObjectBuilder.prototype.setupHandler = function (eventName, eventHandler) {
  118.         this.gameObject.setupHandler(eventName, eventHandler);
  119.         return this;
  120.     };
  121.     GameObjectBuilder.prototype.initData = function (data) {
  122.         this.gameObject.initData(data);
  123.         return this;
  124.     };
  125.     GameObjectBuilder.prototype.addSprite = function (name, sprite, handler) {
  126.         this.gameObject.addSprite(name, sprite, handler);
  127.         return this;
  128.     };
  129.     GameObjectBuilder.prototype.build = function () {
  130.         return this.gameObject;
  131.     };
  132.     return GameObjectBuilder;
  133. }());
  134. var GameObject = /** @class */ (function (_super) {
  135.     __extends(GameObject, _super);
  136.     /**
  137.      * 覆写PIXI默认的宽高, 防止图像拉伸
  138.      */
  139.     function GameObject(width, height) {
  140.         if (width === void 0) { width = 0; }
  141.         if (height === void 0) { height = 0; }
  142.         var _this = _super.call(this) || this;
  143.         _this.children = [];
  144.         _this.willCreate = true;
  145.         _this.willTerminate = false;
  146.         _this.isCreated = false;
  147.         _this.isTerminated = false;
  148.         _this.isStarted = false;
  149.         _this.eventHandlers = {};
  150.         _this.data = null;
  151.         _this.sprites = {};
  152.         _this._width = width;
  153.         _this._height = height;
  154.         Object.defineProperties(_this, {
  155.             width: {
  156.                 get: function () { return _this._width; },
  157.                 set: function (w) {
  158.                     _this._width = w;
  159.                     _this.refresh();
  160.                 },
  161.             },
  162.             height: {
  163.                 get: function () { return _this._height; },
  164.                 set: function (h) {
  165.                     _this._height = h;
  166.                     _this.refresh();
  167.                 },
  168.             },
  169.         });
  170.         return _this;
  171.     }
  172.     GameObject.builder = function () {
  173.         return new GameObjectBuilder();
  174.     };
  175.     /**
  176.      * 注册事件处理方法或异步方法
  177.      */
  178.     GameObject.prototype.setupHandler = function (eventName, eventHandler) {
  179.         this.eventHandlers[eventName] = eventHandler;
  180.     };
  181.     /**
  182.      * 移除已注册的方法
  183.      */
  184.     GameObject.prototype.removeHandler = function (eventName) {
  185.         delete this.eventHandlers[eventName];
  186.     };
  187.     /**
  188.      * 手动触发事件
  189.      */
  190.     GameObject.prototype.triggerEvent = function (eventName) {
  191.         var args = [];
  192.         for (var _i = 1; _i < arguments.length; _i++) {
  193.             args[_i - 1] = arguments[_i];
  194.         }
  195.         var handler = this.eventHandlers[eventName];
  196.         if (handler)
  197.             return handler.apply(void 0, __spreadArrays([this], args));
  198.     };
  199.     /**
  200.      * 获取绘制事件名
  201.      */
  202.     GameObject.prototype.getDrawHandler = function (name) {
  203.         return "draw" + name.replace(/^./, function (str) { return str.toUpperCase(); });
  204.     };
  205.     /**
  206.      * 重绘全部精灵
  207.      */
  208.     GameObject.prototype.refresh = function () {
  209.         var _this = this;
  210.         Object.keys(this.sprites).forEach(function (name) {
  211.             _this.triggerEvent(_this.getDrawHandler(name));
  212.         });
  213.     };
  214.     /**
  215.      * 添加精灵
  216.      */
  217.     GameObject.prototype.addSprite = function (name, sprite, handler) {
  218.         this.sprites[name] = sprite;
  219.         this.setupHandler(this.getDrawHandler(name), handler);
  220.         this.addChild(sprite);
  221.     };
  222.     /**
  223.      * 初始化数据, 不会触发数据更新事件
  224.      */
  225.     GameObject.prototype.initData = function (data) {
  226.         this.data = data;
  227.     };
  228.     /**
  229.      * 获取数据
  230.      */
  231.     GameObject.prototype.getData = function () {
  232.         return this.data;
  233.     };
  234.     /**
  235.      * 数据绑定, 触发数据更新事件
  236.      */
  237.     GameObject.prototype.setData = function (data) {
  238.         var oldData = this.data;
  239.         this.data = data;
  240.         this.triggerEvent('change', oldData);
  241.     };
  242.     /**
  243.      * 第一次载入场景时触发, 用于处理异步行为
  244.      */
  245.     GameObject.prototype.onCreate = function () {
  246.         return __awaiter(this, void 0, void 0, function () {
  247.             return __generator(this, function (_a) {
  248.                 switch (_a.label) {
  249.                     case 0:
  250.                         this.willCreate = false;
  251.                         return [4 /*yield*/, this.triggerEvent('create')];
  252.                     case 1:
  253.                         _a.sent();
  254.                         this.isCreated = true;
  255.                         return [2 /*return*/];
  256.                 }
  257.             });
  258.         });
  259.     };
  260.     /**
  261.      * 完成初始化后触发, 用于初始化对象
  262.      */
  263.     GameObject.prototype.onStart = function () {
  264.         this.triggerEvent('start');
  265.         this.refresh();
  266.         this.isStarted = true;
  267.     };
  268.     /**
  269.      * 每一帧更新事件, 不要在这里重绘任何东西
  270.      */
  271.     GameObject.prototype.onUpdate = function () {
  272.         this.triggerEvent('update');
  273.         this.updateChildren();
  274.     };
  275.     /**
  276.      * 用来处理终止事件
  277.      */
  278.     GameObject.prototype.onTerminate = function () {
  279.         return __awaiter(this, void 0, void 0, function () {
  280.             return __generator(this, function (_a) {
  281.                 switch (_a.label) {
  282.                     case 0:
  283.                         this.willTerminate = false;
  284.                         return [4 /*yield*/, this.triggerEvent('terminate')];
  285.                     case 1:
  286.                         _a.sent();
  287.                         this.isTerminated = true;
  288.                         GlobalEventManager.removeListener(this);
  289.                         return [2 /*return*/];
  290.                 }
  291.             });
  292.         });
  293.     };
  294.     /**
  295.      * 主循环
  296.      */
  297.     GameObject.prototype.update = function () {
  298.         if (this.isStarted) {
  299.             this.onUpdate();
  300.         }
  301.         else if (this.willCreate) {
  302.             this.onCreate();
  303.         }
  304.         else if (this.isCreated &&
  305.             this.children.every(function (child) { return child.isCreated !== false; })) {
  306.             this.onStart();
  307.         }
  308.         else if (this.willTerminate &&
  309.             this.children.every(function (child) { return child.isTerminated !== false; })) {
  310.             this.onTerminate();
  311.         }
  312.     };
  313.     /**
  314.      * 更新子对象
  315.      */
  316.     GameObject.prototype.updateChildren = function () {
  317.         this.children.forEach(function (child) {
  318.             child.update();
  319.         });
  320.     };
  321.     /**
  322.      * 终止对象
  323.      */
  324.     GameObject.prototype.terminate = function () {
  325.         this.willTerminate = true;
  326.         this.children.forEach(function (child) {
  327.             child.terminate();
  328.         });
  329.     };
  330.     return GameObject;
  331. }(PIXI.Container));


对了, 你问这个东西现在有啥实际价值么?
答案是暂无
不过也许把建造函数封装好了, 能很快得实现按需要载入部分窗体的功能, 而不是每次从一个类继承一个新的开始魔改?

评分

参与人数 1+1 收起 理由
白嫩白嫩的 + 1 精品文章

查看全部评分

夏普的道具店

塞露提亚-道具屋的经营妙方同人作品
发布帖:点击这里

Lv4.逐梦者

梦石
0
星屑
7612
在线时间
1227 小时
注册时间
2008-12-14
帖子
555
3
发表于 2020-6-15 00:15:24 | 只看该作者
最大的价值,如果官方编辑器构建界面按这一套,配上可视化拖拽控件就好了。其实应该也不难,只是官方不想做。
需要购买本人MV插件必须先加wx好友。加不上wx就是本人忙,没时间卖。原则上太久以前的插件也不想卖,因为我也忘了,维护上会不给力。wx名:alskyif    本人插件地址:
   LCK_SRPG梦幻模拟战、火焰纹章类系统
   究极立绘ADV系统

   究极换装统合系统
   究极! 回想与CG系统
   消息文字的距离调整  
   自动返回上一张地图
回复 支持 反对

使用道具 举报

Lv3.寻梦者

梦石
0
星屑
1420
在线时间
159 小时
注册时间
2020-4-26
帖子
152
2
发表于 2020-6-14 22:07:52 | 只看该作者
好複雜啊,可以問一下用異步的方式建立一個視窗,不會有玩家離開場景了,視窗還沒建立好的情形嗎?

点评

如果不想用loading阻塞玩家体验的话, 那就提前在加载场景的时候把资源放进去吧...  发表于 2020-6-14 22:37
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2024-11-28 04:41

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表