1 import 'babel-polyfill';
4 import ApplyForceSystem
from './systems/apply_force';
5 import CreateCouplingLineSystem
from './systems/create_coupling_line';
6 import ControlMapperSystem
from './systems/control_mapper';
7 import DashSystem
from './systems/dash';
8 import ElasticSystem
from './systems/elastic';
9 import PhysicsWorldControlSystem
from './systems/physics_world_control';
10 import PhysicsToAttributesSystem
from './systems/physics_to_attributes';
11 import RenderSystem
from './systems/render';
12 import AttributesToRenderableSystem
from './systems/attributes_to_renderable';
16 import SumoFactory
from './factories/sumo';
18 // External Dependencies
20 import Serpentity
from '@serpentity/serpentity';
21 import { Application
} from 'pixi.js';
22 import { Engine
} from 'matter-js';
24 /* global window document */
27 kBackgroundColor: 0xd8c590,
28 kNoElementError: 'No element found. Cannot render.',
30 // Handler for the window load event. Initializes and runs the app.
34 const sumo
= new internals
.Sumo({
35 element: document
.getElementById('sumo-app-entry-point')
40 internals
.exports
.sumo
= sumo
;
45 * Sumo - main entry point. Attached to window->load
49 * @param {object} config the configuration to extend the object
51 * @property {HTMLElement} [element=null] the element in which to render.
52 * Required, will throw if not provided
53 * @property {Number} [fps=60] the fps target to maintain
54 * @property {Number} [verticalResolution=224] how many pixels to render in the vertical
55 * axis (gets scaled if the canvas is larger)
56 * @property {Array<Number>} [aspectRatio=[2.76, 1]] the aspect ratio experssed as
57 * an array of two numbers, where aspect ratio x:y is [x, y] (eg. [16, 9])
60 internals
.Sumo
= class Sumo
{
65 this.aspectRatio
= [2.76, 1];
66 this.verticalResolution
= 224;
68 Object
.assign(this, config
);
71 throw new Error(internals
.kNoElementError
);
74 this._engine
= new Serpentity();
76 this._previousTime
= 0;
77 this._looping
= false;
79 // Initialization functions
80 this._initializeCanvas();
81 this._initializeMatter();
82 this._initializePixi();
83 this._initializeSystems();
84 this._initializeEntities();
88 * Starts the main loop. Resets the FPS (if you change it it won't go
89 * live until after you stop and start the loop)
98 this._frameDuration
= 1000 / this.fps
;
99 window
.requestAnimationFrame(this._loop
.bind(this));
105 * @function pauseLoop
111 this._looping
= false;
114 // The main loop used above. Runs the serpentity update process and
115 // attempts to maintain FPS. The rest is handled by the engine.
119 if (!this._looping
) {
123 window
.requestAnimationFrame(this._loop
.bind(this));
125 const currentFrameDuration
= currentTime
- this._previousTime
;
127 if (currentFrameDuration
> this._frameDuration
) {
129 // We're sending the currentTime since it gives better results for
130 // this type of renderer, though usually we expect the delta
131 this._engine
.update(currentFrameDuration
);
132 this._previousTime
= currentTime
;
136 // Creates a canvas for rendering
138 _initializeCanvas() {
140 this._canvas
= document
.createElement('canvas');
141 this.element
.appendChild(this._canvas
);
142 this._resizeCanvas();
143 window
.addEventListener('resize', this._resizeCanvas
.bind(this));
146 // Initialize MatterJs
148 _initializeMatter() {
150 this._matterJs
= Engine
.create();
152 this._matterJs
.world
.gravity
.y
= 0;
159 this._pixi
= new Application({
160 backgroundColor: internals
.kBackgroundColor
,
162 width: this._canvas
.width
,
163 height: this._canvas
.height
167 // Resizes the canvas to a square the size of the smallest magnitude
172 let width
= window
.innerWidth
;
173 let height
= Math
.round(width
* this.aspectRatio
[1] / this.aspectRatio
[0]);
175 if (window
.innerHeight
< height
) {
176 height
= window
.innerHeight
;
177 width
= Math
.round(height
* this.aspectRatio
[0] / this.aspectRatio
[1]);
180 this._canvas
.style
.width
= `${width}px`;
181 this._canvas
.style
.height
= `${height}px`;
183 this._canvas
.width
= Math
.round(this.verticalResolution
* this.aspectRatio
[0] / this.aspectRatio
[1]);
184 this._canvas
.height
= this.verticalResolution
;
187 // Initializes the serpentity systems
189 _initializeSystems() {
191 this._engine
.addSystem(new ControlMapperSystem());
193 this._engine
.addSystem(new DashSystem());
195 this._engine
.addSystem(new ApplyForceSystem());
197 this._engine
.addSystem(new PhysicsWorldControlSystem({
198 engine: this._matterJs
201 this._engine
.addSystem(new ElasticSystem());
203 this._engine
.addSystem(new PhysicsToAttributesSystem());
205 this._engine
.addSystem(new AttributesToRenderableSystem());
207 this._engine
.addSystem(new CreateCouplingLineSystem());
209 this._engine
.addSystem(new RenderSystem({
210 application: this._pixi
214 // Initializes the serpentity entities
216 _initializeEntities() {
218 const sumoA
= SumoFactory
.createSumo(null, {
225 const sumoB
= SumoFactory
.createControllableSumo(null, {
232 const harness
= SumoFactory
.createHarness(null, {
239 SumoFactory
.createRubberBand(this._engine
, {
244 SumoFactory
.createRubberBand(this._engine
, {
249 // To keep the coupling behind, we'll manually add the sumos later
251 this._engine
.addEntity(sumoA
);
252 this._engine
.addEntity(sumoB
);
253 this._engine
.addEntity(harness
);
257 export default internals
.exports
= {};
260 window
.addEventListener('load', internals
.onLoad
);