1 import 'babel-polyfill';
3 import Config
from './config';
7 import ApplyForceSystem
from './systems/apply_force';
8 import CreateCouplingLineSystem
from './systems/create_coupling_line';
9 import ControlMapperSystem
from './systems/control_mapper';
10 import DashSystem
from './systems/dash';
11 import DrawDashSystem
from './systems/draw_dash';
12 import ElasticSystem
from './systems/elastic';
13 import PhysicsWorldControlSystem
from './systems/physics_world_control';
14 import PhysicsToAttributesSystem
from './systems/physics_to_attributes';
15 import RenderSystem
from './systems/render';
16 import AttributesToRenderableSystem
from './systems/attributes_to_renderable';
20 import SumoFactory
from './factories/sumo';
22 // External Dependencies
24 import Serpentity
from '@serpentity/serpentity';
25 import { Application
} from 'pixi.js';
26 import { Engine
} from 'matter-js';
28 /* global window document */
31 kBackgroundColor: 0xd8c590,
32 kNoElementError: 'No element found. Cannot render.',
34 // Handler for the window load event. Initializes and runs the app.
38 const sumo
= new internals
.Sumo(Object
.assign({
39 element: document
.getElementById('sumo-app-entry-point')
49 * Sumo - main entry point. Attached to window->load
53 * @param {object} config the configuration to extend the object
55 * @property {HTMLElement} [element=null] the element in which to render.
56 * Required, will throw if not provided
57 * @property {Number} [fps=60] the fps target to maintain
58 * @property {Number} [verticalResolution=224] how many pixels to render in the vertical
59 * axis (gets scaled if the canvas is larger)
60 * @property {Array<Number>} [aspectRatio=[2.76, 1]] the aspect ratio experssed as
61 * an array of two numbers, where aspect ratio x:y is [x, y] (eg. [16, 9])
64 internals
.Sumo
= class Sumo
{
68 // These defaults can get overridden by config
70 this.aspectRatio
= [2.76, 1];
71 this.verticalResolution
= 224;
73 Object
.assign(this, config
);
76 throw new Error(internals
.kNoElementError
);
79 this._engine
= new Serpentity();
81 this._previousTime
= 0;
82 this._looping
= false;
84 // Initialization functions
85 this._initializeCanvas();
86 this._initializeMatter();
87 this._initializePixi();
88 this._initializeSystems();
89 this._initializeEntities();
93 * Starts the main loop. Resets the FPS (if you change it it won't go
94 * live until after you stop and start the loop)
102 this._looping
= true;
103 this._frameDuration
= 1000 / this.fps
;
104 window
.requestAnimationFrame(this._loop
.bind(this));
110 * @function pauseLoop
116 this._looping
= false;
119 // The main loop used above. Runs the serpentity update process and
120 // attempts to maintain FPS. The rest is handled by the engine.
124 if (!this._looping
) {
128 window
.requestAnimationFrame(this._loop
.bind(this));
130 const currentFrameDuration
= currentTime
- this._previousTime
;
132 if (currentFrameDuration
> this._frameDuration
) {
134 // We're sending the currentTime since it gives better results for
135 // this type of renderer, though usually we expect the delta
136 this._engine
.update(currentFrameDuration
);
137 this._previousTime
= currentTime
;
141 // Creates a canvas for rendering
143 _initializeCanvas() {
145 this._canvas
= document
.createElement('canvas');
146 this.element
.appendChild(this._canvas
);
147 this._resizeCanvas();
148 window
.addEventListener('resize', this._resizeCanvas
.bind(this));
151 // Initialize MatterJs
153 _initializeMatter() {
155 this._matterJs
= Engine
.create();
157 this._matterJs
.world
.gravity
.y
= 0;
164 this._pixi
= new Application({
165 backgroundColor: internals
.kBackgroundColor
,
167 width: this._canvas
.width
,
168 height: this._canvas
.height
172 // Resizes the canvas to a square the size of the smallest magnitude
177 let width
= window
.innerWidth
;
178 let height
= Math
.round(width
* this.aspectRatio
[1] / this.aspectRatio
[0]);
180 if (window
.innerHeight
< height
) {
181 height
= window
.innerHeight
;
182 width
= Math
.round(height
* this.aspectRatio
[0] / this.aspectRatio
[1]);
185 this._canvas
.style
.width
= `${width}px`;
186 this._canvas
.style
.height
= `${height}px`;
188 this._canvas
.width
= Math
.round(this.verticalResolution
* this.aspectRatio
[0] / this.aspectRatio
[1]);
189 this._canvas
.height
= this.verticalResolution
;
192 // Initializes the serpentity systems
194 _initializeSystems() {
196 this._engine
.addSystem(new ControlMapperSystem());
198 this._engine
.addSystem(new DashSystem());
200 this._engine
.addSystem(new ApplyForceSystem());
202 this._engine
.addSystem(new PhysicsWorldControlSystem({
203 engine: this._matterJs
206 this._engine
.addSystem(new ElasticSystem());
208 this._engine
.addSystem(new PhysicsToAttributesSystem());
210 this._engine
.addSystem(new AttributesToRenderableSystem());
212 this._engine
.addSystem(new CreateCouplingLineSystem());
214 this._engine
.addSystem(new DrawDashSystem());
216 this._engine
.addSystem(new RenderSystem({
217 application: this._pixi
221 // Initializes the serpentity entities
223 _initializeEntities() {
225 SumoFactory
.createArena(this._engine
, {
227 x: this.horizontalResolution
/ 2,
228 y: this.verticalResolution
/ 2
232 const sumoA
= SumoFactory
.createSumo(null, {
234 x: this.horizontalResolution
/ 2 - 100,
235 y: this.verticalResolution
/ 2
239 const sumoB
= SumoFactory
.createControllableSumo(null, {
241 x: this.horizontalResolution
/ 2 + 100,
242 y: this.verticalResolution
/ 2
246 const harness
= SumoFactory
.createHarness(null, {
248 x: this.horizontalResolution
/ 2,
249 y: this.verticalResolution
/ 2
253 SumoFactory
.createRubberBand(this._engine
, {
258 SumoFactory
.createRubberBand(this._engine
, {
263 // To keep the coupling behind, we'll manually add the sumos later
265 this._engine
.addEntity(sumoA
);
266 this._engine
.addEntity(sumoB
);
267 this._engine
.addEntity(harness
);
271 export default internals
.exports
= {};
274 window
.addEventListener('load', internals
.onLoad
);