]> git.r.bdr.sh - rbdr/sumo/commitdiff
Render Sumo (#3)
authorRubén Beltrán del Río <redacted>
Sat, 21 Apr 2018 08:48:01 +0000 (03:48 -0500)
committerGitHub <redacted>
Sat, 21 Apr 2018 08:48:01 +0000 (03:48 -0500)
* Use corrected components

* Add renderable node

* Add render system

* Add sumo factory

* Add systems and entities to app

* Remove reference to weight / accel component

* Update dependencies, add pixi and babel-polyfill

* Use babel polyfill

* Add component to store pixi containers

* Add pixi container to the renderable support

* Update factories to produce renderables

* Update the renderable to use pixi

It also uses the new event emitters in serpentity 2.1.0

* Initialize pixi and pass it to renderable system

config/webpack.js
lib/components/pixi_container.js [new file with mode: 0644]
lib/factories/pixi.js [new file with mode: 0644]
lib/factories/sumo.js [new file with mode: 0644]
lib/nodes/renderable.js [new file with mode: 0644]
lib/sumo.js
lib/systems/render.js [new file with mode: 0644]
package-lock.json
package.json

index db1837a19222f95972f4978834fe1e4de71aadc5..34cccbd29080bd14648914bc7d7c144e8ba31dfe 100644 (file)
@@ -3,7 +3,7 @@
 const Path = require('path');
 
 module.exports = {
-  entry: './lib/sumo',
+  entry: ['babel-polyfill', './lib/sumo'],
 
   output: {
     path: Path.resolve(__dirname, '../assets'),
diff --git a/lib/components/pixi_container.js b/lib/components/pixi_container.js
new file mode 100644 (file)
index 0000000..5e5cb1f
--- /dev/null
@@ -0,0 +1,25 @@
+import { Component } from '@serpentity/serpentity';
+
+/**
+ * Component that stores a pixi container
+ *
+ * @extends {external:Serpentity.Component}
+ * @class PixiContainerComponent
+ * @param {object} config a configuration object to extend.
+ */
+export default class PixiContainerComponent extends Component {
+  constructor(config) {
+
+    super(config);
+
+    /**
+     * The properthy that holds the pixi container
+     *
+     * @property {external:PixiJs.Container} container
+     * @name container
+     * @instance
+     * @memberof PixiContainerComponent
+     */
+    this.container = this.container || null;
+  }
+};
diff --git a/lib/factories/pixi.js b/lib/factories/pixi.js
new file mode 100644 (file)
index 0000000..e3c1b5a
--- /dev/null
@@ -0,0 +1,66 @@
+import { Graphics } from 'pixi.js';
+
+/**
+ * Factory object that contains many methods to create prefab pixi
+ * objects
+ *
+ * @type object
+ * @name PixiFactory
+ */
+export default {
+
+  /**
+   * Creates a sumo container
+   *
+   * @function createSumo
+   * @memberof PixiFactory
+   * @return {external:CreateJs.Container} the created container
+   */
+  createSumo() {
+
+    const radius = 25;
+
+    // The body
+    const body = new Graphics();
+    body.beginFill(0x87c5ea)
+      .drawCircle(0, 0, radius)
+      .endFill();
+
+    // The mouth
+    const mouth = new Graphics();
+    mouth.lineStyle(10, 0xff0080, 1)
+      .arc(
+        0, 0, // center
+        radius * 0.6,
+        Math.PI / 6,
+        5 * Math.PI / 6
+      );
+
+    const leftEye = new Graphics();
+    leftEye.beginFill(0xffffff)
+      .drawCircle(-radius / 3 - radius / 8, -radius / 4, radius / 5)
+      .endFill();
+
+    const rightEye = new Graphics();
+    rightEye.beginFill(0xffffff)
+      .drawCircle(radius / 3 + radius / 8, -radius / 4, radius / 5);
+
+    const leftPupil = new Graphics();
+    leftPupil.beginFill(0x11)
+      .drawCircle(-radius / 3 - radius / 8, -radius / 4, radius / 10);
+
+    const rightPupil = new Graphics();
+    leftPupil.beginFill(0x11)
+      .drawCircle(radius / 3 + radius / 8, -radius / 4, radius / 10);
+
+    // The group
+    body.addChild(mouth);
+    body.addChild(leftEye);
+    body.addChild(rightEye);
+    body.addChild(leftPupil);
+    body.addChild(rightPupil);
+
+    return body;
+  }
+};
+
diff --git a/lib/factories/sumo.js b/lib/factories/sumo.js
new file mode 100644 (file)
index 0000000..b0e5416
--- /dev/null
@@ -0,0 +1,51 @@
+import { Entity } from '@serpentity/serpentity';
+
+import PositionComponent from '@serpentity/components.position';
+import PixiContainerComponent from '../components/pixi_container';
+import PixiFactory from '../factories/pixi';
+
+/**
+ * Factory object that contains many methods to create prefab entities.
+ *
+ * @type object
+ * @name SumoFactory
+ */
+export default {
+
+  /**
+   * Creates a sumo entity and adds it to the engine. Can override
+   * position in the config object
+   *
+   * @function createSumo
+   * @memberof SumoFactory
+   * @param {external:Serpentity} [engine] the serpentity engine to attach
+   * to. If not sent, it will not be attached.
+   * @param {object} [config] the config to override the entity, accepts
+   * the key `position` as an object with an x and y property.
+   * @return {external:Serpentity.Entity} the created entity
+   */
+  createSumo(engine, config = {}) {
+
+    const entity = new Entity();
+
+    entity.addComponent(new PositionComponent(config.position));
+
+    const container = config.container || {
+      container: PixiFactory.createSumo()
+    };
+
+    // Match the symbol position with the entity position on init
+    // Otherwise it's up to systems
+    const position = entity.getComponent(PositionComponent);
+    container.container.position.x = position.x;
+    container.container.position.y = position.y;
+
+    entity.addComponent(new PixiContainerComponent(container));
+
+    if (engine) {
+      engine.addEntity(entity);
+    }
+
+    return entity;
+  }
+};
diff --git a/lib/nodes/renderable.js b/lib/nodes/renderable.js
new file mode 100644 (file)
index 0000000..0a3a111
--- /dev/null
@@ -0,0 +1,27 @@
+import { Node } from '@serpentity/serpentity';
+
+import PixiContainerComponent from '../components/pixi_container';
+import PositionComponent from '@serpentity/components.position';
+
+/**
+ * Node identifying a renderable entity, should have position and a
+ * symbol to render
+ *
+ * @extends {external:Serpentity.Node}
+ * @class RenderableNode
+ */
+export default class RenderableNode extends Node {
+
+};
+
+/**
+ * Holds the types that are used to identify a wave entity
+ *
+ * @property {object} types
+ * @name types
+ * @memberof WaveNode
+ */
+RenderableNode.types = {
+  position: PositionComponent,
+  container: PixiContainerComponent
+};
index da72991982c6ea6831699ac23d3eb005c686d8f4..81f948f74848695144ca298d546e6a6b66714fa5 100644 (file)
@@ -1,8 +1,12 @@
+import RenderSystem from './systems/render';
+import SumoFactory from './factories/sumo';
 import Serpentity from '@serpentity/serpentity';
+import { Application } from 'pixi.js';
 
 /* global window document */
 
 const internals = {
+  kBackgroundColor: 0xd8c590,
   kNoElementError: 'No element found. Cannot render.',
 
   // Handler for the window load event. Initializes and runs the app.
@@ -56,6 +60,7 @@ internals.Sumo = class Sumo {
 
     // Initialization functions
     this._initializeCanvas();
+    this._initializePixi();
     this._initializeSystems();
     this._initializeEntities();
   }
@@ -119,6 +124,18 @@ internals.Sumo = class Sumo {
     window.addEventListener('resize', this._resizeCanvas.bind(this));
   }
 
+  // Initialize Pixi
+
+  _initializePixi() {
+
+    this._pixi = new Application({
+      backgroundColor: internals.kBackgroundColor,
+      view: this._canvas,
+      width: this._canvas.width,
+      height: this._canvas.height
+    });
+  }
+
   // Resizes the canvas to a square the size of the smallest magnitude
   // of the window.
 
@@ -143,12 +160,28 @@ internals.Sumo = class Sumo {
 
   _initializeSystems() {
 
+    this._engine.addSystem(new RenderSystem({
+      application: this._pixi
+    }));
   }
 
   // Initializes the serpentity entities
 
   _initializeEntities() {
 
+    SumoFactory.createSumo(this._engine, {
+      position: {
+        x: 50,
+        y: 50
+      }
+    });
+
+    SumoFactory.createSumo(this._engine, {
+      position: {
+        x: 309,
+        y: 112
+      }
+    });
   }
 };
 
diff --git a/lib/systems/render.js b/lib/systems/render.js
new file mode 100644 (file)
index 0000000..8d3d446
--- /dev/null
@@ -0,0 +1,99 @@
+import { System } from '@serpentity/serpentity';
+
+import RenderableNode from '../nodes/renderable';
+
+const internals = {
+  kNoPixiError: 'No pixi application passed to render system. Make sure you set the `application` key in the config object when initializing.'
+};
+
+/**
+ * Renders renderable objects to console
+ *
+ * @extends {external:Serpentity.System}
+ * @class RenderSystem
+ * @param {object} config a configuration object to extend.
+ */
+export default class RenderSystem extends System {
+
+  constructor(config = {}) {
+
+    super();
+
+    /**
+     * The node collection of renderable entities
+     *
+     * @property {external:Serpentity.NodeCollection} renderables
+     * @instance
+     * @memberof RenderSystem
+     */
+    this.renderables = null;
+
+    /**
+     * The pixi engine we will use to render
+     *
+     * @property {external:PixiJs.Application} renderables
+     * @instance
+     * @memberof RenderSystem
+     */
+    this._application = config.application;
+
+    if (!this._application) {
+      throw new Error(internals.kNoPixiError);
+    }
+  }
+
+  /**
+   * Initializes system when added. Requests renderable nodes and
+   * attaches to event listeners to add / remove them to pixi stage
+   *
+   * @function added
+   * @memberof RenderSystem
+   * @instance
+   * @param {external:Serpentity.Engine} engine the serpentity engine to
+   * which we are getting added
+   */
+  added(engine) {
+
+    this.renderables = engine.getNodes(RenderableNode);
+    this.renderables.on('nodeAdded', (event) => {
+
+      this._application.stage.addChild(event.node.container.container);
+    });
+    this.renderables.on('nodeRemoved', (event) => {
+
+      this._application.stage.removeChild(event.node.container.container);
+    });
+  }
+
+  /**
+   * Clears system resources when removed.
+   *
+   * @function removed
+   * @instance
+   * @memberof RenderSystem
+   */
+  removed() {
+
+    this.renderables.removeAllListeners('nodeAdded');
+    this.renderables.removeAllListeners('nodeRemoved');
+    this.renderables = null;
+  }
+
+  /**
+   * Runs on every update of the loop. Prints the location of every
+   * renderable
+   *
+   * @function update
+   * @instance
+   * @param {Number} currentFrameDuration the duration of the current
+   * frame
+   * @memberof RenderSystem
+   */
+  update(currentFrameDuration) {
+
+    for (const renderable of this.renderables) {
+      renderable.container.container.position.x = renderable.position.x;
+      renderable.container.container.position.y = renderable.position.y;
+    }
+  }
+};
index 8dc6d98fcc98cd0ba19085f6651ab4d42fe3b56b..43c41d36c429c5fd0b28bb8f454258ece88bafc5 100644 (file)
@@ -5,14 +5,22 @@
   "requires": true,
   "dependencies": {
     "@serpentity/components.debug": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/@serpentity/components.debug/-/components.debug-1.0.0.tgz",
-      "integrity": "sha1-1mPRCQcWxVf3ShZYRDZjijWIfj4="
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@serpentity/components.debug/-/components.debug-2.0.0.tgz",
+      "integrity": "sha512-IYFPQYuwhSSL6+jfQ5H9IVgkGwX2336Mowuk+8jK1t8Bqc373uZv6CPR3MSh/tc+Bi6bHEn+pZp1FMUxS8o12g=="
     },
-    "@serpentity/serpentity": {
+    "@serpentity/components.position": {
       "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/@serpentity/serpentity/-/serpentity-2.0.0.tgz",
-      "integrity": "sha1-MEbOJKQ80vXLUbaVnkhXqZ6Bbl4="
+      "resolved": "https://registry.npmjs.org/@serpentity/components.position/-/components.position-2.0.0.tgz",
+      "integrity": "sha512-umCLx12S3dV8d23bBSnB5CAvmqSjh9iCl2/JyOZmtOex2BkUUjIf2aqA3ZWVwpgoDmbPJMnejvghwuWHlkV4ww=="
+    },
+    "@serpentity/serpentity": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/@serpentity/serpentity/-/serpentity-2.1.0.tgz",
+      "integrity": "sha512-tt+WMauSRdi/bnem9pxHfoOtpi17RZjgB/tQuNCK8X6EMcoly5FgjJotpsa4FsjpWARJvq9P2zJFilNwYOZRYg==",
+      "requires": {
+        "events": "2.0.0"
+      }
     },
     "@sindresorhus/is": {
       "version": "0.7.0",
         "babel-types": "6.26.0"
       }
     },
+    "babel-polyfill": {
+      "version": "6.26.0",
+      "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz",
+      "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=",
+      "dev": true,
+      "requires": {
+        "babel-runtime": "6.26.0",
+        "core-js": "2.5.5",
+        "regenerator-runtime": "0.10.5"
+      },
+      "dependencies": {
+        "regenerator-runtime": {
+          "version": "0.10.5",
+          "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz",
+          "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=",
+          "dev": true
+        }
+      }
+    },
     "babel-preset-env": {
       "version": "1.6.1",
       "resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.6.1.tgz",
       "integrity": "sha512-XBaoWE9RW8pPdPQNibZsW2zh8TW6gcarXp1FZPwT8Uop8ScSNldJEWf2k9l3HeTqdrEwsOsFcq74RiJECW34yA==",
       "dev": true
     },
+    "bit-twiddle": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/bit-twiddle/-/bit-twiddle-1.0.2.tgz",
+      "integrity": "sha1-DGwfq+KyPRcXPZpht7cJPrnhdp4="
+    },
     "bluebird": {
       "version": "3.5.1",
       "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
         "stream-shift": "1.0.0"
       }
     },
+    "earcut": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.1.3.tgz",
+      "integrity": "sha512-AxdCdWUk1zzK/NuZ7e1ljj6IGC+VAdC3Qb7QQDsXpfNrc5IM8tL9nNXUmEGE6jRHTfZ10zhzRhtDmWVsR5pd3A=="
+    },
     "editions": {
       "version": "1.3.4",
       "resolved": "https://registry.npmjs.org/editions/-/editions-1.3.4.tgz",
       "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
       "dev": true
     },
+    "eventemitter3": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz",
+      "integrity": "sha1-teEHm1n7XhuidxwKmTvgYKWMmbo="
+    },
     "events": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
-      "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=",
-      "dev": true
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/events/-/events-2.0.0.tgz",
+      "integrity": "sha512-r/M5YkNg9zwI8QbSf7tsDWWJvO3PGwZXyG7GpFAxtMASnHL2eblFd7iHiGPtyGKKFPZ59S63NeX10Ws6WqGDcg=="
     },
     "evp_bytestokey": {
       "version": "1.0.3",
       "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
       "dev": true
     },
+    "ismobilejs": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/ismobilejs/-/ismobilejs-0.4.1.tgz",
+      "integrity": "sha1-Gl8SbHD+05yT2jgPpiy65XI+fcI="
+    },
     "isobject": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
       "integrity": "sha1-3z02Uqc/3ta5sLJBRub9BSNTRY4=",
       "dev": true
     },
+    "mini-signals": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/mini-signals/-/mini-signals-1.2.0.tgz",
+      "integrity": "sha1-RbCAE8X65RokqhqTXNMXye1yHXQ="
+    },
     "minimalistic-assert": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
         "vm-browserify": "0.0.4"
       },
       "dependencies": {
+        "events": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
+          "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=",
+          "dev": true
+        },
         "punycode": {
           "version": "1.4.1",
           "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
     "object-assign": {
       "version": "4.1.1",
       "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
-      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
-      "dev": true
+      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
     },
     "object-copy": {
       "version": "0.1.0",
       "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=",
       "dev": true
     },
+    "parse-uri": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/parse-uri/-/parse-uri-1.0.0.tgz",
+      "integrity": "sha1-KHLcwi8aeXrN4Vg9igrClVLdrCA="
+    },
     "pascalcase": {
       "version": "0.1.1",
       "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
         "pinkie": "2.0.4"
       }
     },
+    "pixi-gl-core": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/pixi-gl-core/-/pixi-gl-core-1.1.4.tgz",
+      "integrity": "sha1-i0tcQzsx5Bm8N53FZc4bg1qRs3I="
+    },
+    "pixi.js": {
+      "version": "4.7.3",
+      "resolved": "https://registry.npmjs.org/pixi.js/-/pixi.js-4.7.3.tgz",
+      "integrity": "sha512-uYCTtjYiqSpwN2kZLmjwAL+1yrdCL/pVI+waYlkVqAHBnuQCpOuGA/0UunbxZ4T13xVZ4wN+ftPlEjxWl0th3w==",
+      "requires": {
+        "bit-twiddle": "1.0.2",
+        "earcut": "2.1.3",
+        "eventemitter3": "2.0.3",
+        "ismobilejs": "0.4.1",
+        "object-assign": "4.1.1",
+        "pixi-gl-core": "1.1.4",
+        "remove-array-items": "1.0.0",
+        "resource-loader": "2.1.1"
+      }
+    },
     "pkg-dir": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz",
         }
       }
     },
+    "remove-array-items": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/remove-array-items/-/remove-array-items-1.0.0.tgz",
+      "integrity": "sha1-B79CyzMvTPboXq2DteToltIyayE="
+    },
     "remove-trailing-separator": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
       "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
       "dev": true
     },
+    "resource-loader": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/resource-loader/-/resource-loader-2.1.1.tgz",
+      "integrity": "sha512-jRMGYUfa4AGk9ib45Wxc93lobhQVoiCUAUkWqsbb/fhGPge97YT1S8aC0xBEQpolMsrdmB3o7SH8VmIEvIDOLA==",
+      "requires": {
+        "mini-signals": "1.2.0",
+        "parse-uri": "1.0.0"
+      }
+    },
     "responselike": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz",
index c7d00544dad53b0b140d61f4d28147625406fb0c..50f2a47bd91c7d997826893b5ee4a3f0dca2fc8e 100644 (file)
   },
   "homepage": "https://github.com/rbdr/sumo#readme",
   "dependencies": {
-    "@serpentity/components.debug": "^1.0.0",
-    "@serpentity/serpentity": "^2.0.0"
+    "@serpentity/components.debug": "^2.0.0",
+    "@serpentity/components.position": "^2.0.0",
+    "@serpentity/serpentity": "^2.1.0",
+    "pixi.js": "^4.7.3"
   },
   "browserslist": "last two versions",
   "devDependencies": {
     "babel-core": "^6.26.0",
+    "babel-polyfill": "^6.26.0",
     "babel-preset-env": "^1.6.1",
     "babel-loader": "^7.1.4",
     "code": "^5.2.0",