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 DetectPointsCollisionSystem
from './systems/detect_points_collision';
12 import DetectWinnerSystem
from './systems/detect_winner';
13 import DrawDashSystem
from './systems/draw_dash';
14 import DrawGrabSystem
from './systems/draw_grab';
15 import ElasticSystem
from './systems/elastic';
16 import GrabSystem
from './systems/grab';
17 import PhysicsWorldControlSystem
from './systems/physics_world_control';
18 import PhysicsToAttributesSystem
from './systems/physics_to_attributes';
19 import RenderPointsSystem
from './systems/render_points';
20 import RenderSystem
from './systems/render';
21 import RenderWinnerSystem
from './systems/render_winner';
22 import AttributesToRenderableSystem
from './systems/attributes_to_renderable';
26 import SumoFactory
from './factories/sumo';
28 // External Dependencies
30 import Serpentity
from '@serpentity/serpentity';
31 import { Application
} from 'pixi.js';
32 import { Engine
} from 'matter-js';
34 /* global window document */
37 kBackgroundColor: 0xd8c590,
38 kNoElementError: 'No element found. Cannot render.',
40 // Handler for the window load event. Initializes and runs the app.
44 const sumo
= new internals
.Sumo(Object
.assign({
45 element: document
.getElementById('sumo-app-entry-point')
55 * Sumo - main entry point. Attached to window->load
59 * @param {object} config the configuration to extend the object
61 * @property {HTMLElement} [element=null] the element in which to render.
62 * Required, will throw if not provided
63 * @property {Number} [fps=60] the fps target to maintain
64 * @property {Number} [verticalResolution=224] how many pixels to render in the vertical
65 * axis (gets scaled if the canvas is larger)
66 * @property {Array<Number>} [aspectRatio=[2.76, 1]] the aspect ratio experssed as
67 * an array of two numbers, where aspect ratio x:y is [x, y] (eg. [16, 9])
70 internals
.Sumo
= class Sumo
{
74 // These defaults can get overridden by config
76 this.aspectRatio
= [2.76, 1];
77 this.verticalResolution
= 224;
79 Object
.assign(this, config
);
82 throw new Error(internals
.kNoElementError
);
85 this._engine
= new Serpentity();
87 this._previousTime
= 0;
88 this._looping
= false;
90 // Initialization functions
91 this._initializeCanvas();
92 this._initializeMatter();
93 this._initializePixi();
94 this._initializeSystems();
95 this._initializeEntities();
99 * Starts the main loop. Resets the FPS (if you change it it won't go
100 * live until after you stop and start the loop)
102 * @function startLoop
108 this._looping
= true;
109 this._frameDuration
= 1000 / this.fps
;
110 window
.requestAnimationFrame(this._loop
.bind(this));
116 * @function pauseLoop
122 this._looping
= false;
125 // The main loop used above. Runs the serpentity update process and
126 // attempts to maintain FPS. The rest is handled by the engine.
130 if (!this._looping
) {
134 window
.requestAnimationFrame(this._loop
.bind(this));
136 const currentFrameDuration
= currentTime
- this._previousTime
;
138 if (currentFrameDuration
> this._frameDuration
) {
140 // We're sending the currentTime since it gives better results for
141 // this type of renderer, though usually we expect the delta
142 this._engine
.update(currentFrameDuration
);
143 this._previousTime
= currentTime
;
147 // Creates a canvas for rendering
149 _initializeCanvas() {
151 this._canvas
= document
.createElement('canvas');
152 this.element
.appendChild(this._canvas
);
153 this._resizeCanvas();
154 window
.addEventListener('resize', this._resizeCanvas
.bind(this));
157 // Initialize MatterJs
159 _initializeMatter() {
161 this._matterJs
= Engine
.create();
163 this._matterJs
.world
.gravity
.y
= 0;
170 this._pixi
= new Application({
171 backgroundColor: internals
.kBackgroundColor
,
173 width: this._canvas
.width
,
174 height: this._canvas
.height
178 // Resizes the canvas to a square the size of the smallest magnitude
183 let width
= window
.innerWidth
;
184 let height
= Math
.round(width
* this.aspectRatio
[1] / this.aspectRatio
[0]);
186 if (window
.innerHeight
< height
) {
187 height
= window
.innerHeight
;
188 width
= Math
.round(height
* this.aspectRatio
[0] / this.aspectRatio
[1]);
191 this._canvas
.style
.width
= `${width}px`;
192 this._canvas
.style
.height
= `${height}px`;
194 this._canvas
.width
= Math
.round(this.verticalResolution
* this.aspectRatio
[0] / this.aspectRatio
[1]);
195 this._canvas
.height
= this.verticalResolution
;
198 // Initializes the serpentity systems
200 _initializeSystems() {
202 this._engine
.addSystem(new ControlMapperSystem());
204 this._engine
.addSystem(new DashSystem());
206 this._engine
.addSystem(new GrabSystem({
207 engine: this._matterJs
210 this._engine
.addSystem(new ApplyForceSystem());
212 this._engine
.addSystem(new PhysicsWorldControlSystem({
213 engine: this._matterJs
216 this._engine
.addSystem(new DetectPointsCollisionSystem());
218 this._engine
.addSystem(new DetectWinnerSystem());
220 this._engine
.addSystem(new RenderPointsSystem({
221 application: this._pixi
224 this._engine
.addSystem(new RenderWinnerSystem({
225 application: this._pixi
228 this._engine
.addSystem(new ElasticSystem());
230 this._engine
.addSystem(new PhysicsToAttributesSystem());
232 this._engine
.addSystem(new AttributesToRenderableSystem());
234 this._engine
.addSystem(new CreateCouplingLineSystem());
236 this._engine
.addSystem(new DrawDashSystem());
238 this._engine
.addSystem(new DrawGrabSystem());
240 this._engine
.addSystem(new RenderSystem({
241 application: this._pixi
245 // Initializes the serpentity entities
247 _initializeEntities() {
249 SumoFactory
.createArena(this._engine
, {
251 x: this.horizontalResolution
/ 2,
252 y: this.verticalResolution
/ 2
256 const sumoA
= SumoFactory
.createPlayer1Sumo(null, {
258 x: this.horizontalResolution
/ 2 - 100,
259 y: this.verticalResolution
/ 2
263 const sumoB
= SumoFactory
.createPlayer2Sumo(null, {
265 x: this.horizontalResolution
/ 2 + 100,
266 y: this.verticalResolution
/ 2
270 const harness
= SumoFactory
.createHarness(null, {
272 x: this.horizontalResolution
/ 2,
273 y: this.verticalResolution
/ 2
277 SumoFactory
.createRubberBand(this._engine
, {
282 SumoFactory
.createRubberBand(this._engine
, {
289 SumoFactory
.createInvisibleBlock(this._engine
, {
290 width: this.horizontalResolution
* 2,
291 height: this.verticalResolution
* 0.1,
293 x: this.horizontalResolution
/ 2,
294 y: -this.verticalResolution
* 0.1
298 SumoFactory
.createInvisibleBlock(this._engine
, {
299 width: this.horizontalResolution
* 2,
300 height: this.verticalResolution
* 0.1,
302 x: this.horizontalResolution
/ 2,
303 y: this.verticalResolution
+ this.verticalResolution
* 0.1
309 SumoFactory
.createPointsCollider(this._engine
, {
310 collisionTarget: sumoA
,
312 height: this.verticalResolution
,
313 width: this.horizontalResolution
,
315 x: this.horizontalResolution
+ this.horizontalResolution
/ 2,
316 y: this.verticalResolution
/ 2
320 SumoFactory
.createPointsCollider(this._engine
, {
321 collisionTarget: sumoB
,
322 pointsTarget: 'blue',
323 height: this.verticalResolution
,
324 width: this.horizontalResolution
,
326 x: -this.horizontalResolution
/ 2,
327 y: this.verticalResolution
/ 2
332 SumoFactory
.createGameState(this._engine
);
334 // To keep the coupling behind, we'll manually add the sumos later
336 this._engine
.addEntity(sumoA
);
337 this._engine
.addEntity(sumoB
);
338 this._engine
.addEntity(harness
);
342 export default internals
.exports
= {};
345 window
.addEventListener('load', internals
.onLoad
);