]> git.r.bdr.sh - rbdr/sumo/blob - lib/sumo.js
da72991982c6ea6831699ac23d3eb005c686d8f4
[rbdr/sumo] / lib / sumo.js
1 import Serpentity from '@serpentity/serpentity';
2
3 /* global window document */
4
5 const internals = {
6 kNoElementError: 'No element found. Cannot render.',
7
8 // Handler for the window load event. Initializes and runs the app.
9
10 onLoad() {
11
12 const sumo = new internals.Sumo({
13 element: document.getElementById('sumo-app-entry-point')
14 });
15
16 sumo.startLoop();
17
18 internals.exports.sumo = sumo;
19 }
20 };
21
22 /**
23 * Sumo - main entry point. Attached to window->load
24 *
25 * @class Sumo
26 *
27 * @param {object} config the configuration to extend the object
28 *
29 * @property {HTMLElement} [element=null] the element in which to render.
30 * Required, will throw if not provided
31 * @property {Number} [fps=60] the fps target to maintain
32 * @property {Number} [verticalResolution=224] how many pixels to render in the vertical
33 * axis (gets scaled if the canvas is larger)
34 * @property {Array<Number>} [aspectRatio=[2.76, 1]] the aspect ratio experssed as
35 * an array of two numbers, where aspect ratio x:y is [x, y] (eg. [16, 9])
36 */
37
38 internals.Sumo = class Sumo {
39
40 constructor(config) {
41
42 this.fps = 60;
43 this.aspectRatio = [2.76, 1];
44 this.verticalResolution = 224;
45
46 Object.assign(this, config);
47
48 if (!this.element) {
49 throw new Error(internals.kNoElementError);
50 }
51
52 this._engine = new Serpentity();
53
54 this._previousTime = 0;
55 this._looping = false;
56
57 // Initialization functions
58 this._initializeCanvas();
59 this._initializeSystems();
60 this._initializeEntities();
61 }
62
63 /**
64 * Starts the main loop. Resets the FPS (if you change it it won't go
65 * live until after you stop and start the loop)
66 *
67 * @function startLoop
68 * @instance
69 * @memberof Sumo
70 */
71 startLoop() {
72
73 this._looping = true;
74 this._frameDuration = 1000 / this.fps;
75 window.requestAnimationFrame(this._loop.bind(this));
76 }
77
78 /**
79 * Pauses the loop
80 *
81 * @function pauseLoop
82 * @instance
83 * @memberof Sumo
84 */
85 pauseLoop() {
86
87 this._looping = false;
88 }
89
90 // The main loop used above. Runs the serpentity update process and
91 // attempts to maintain FPS. The rest is handled by the engine.
92
93 _loop(currentTime) {
94
95 if (!this._looping) {
96 return;
97 }
98
99 window.requestAnimationFrame(this._loop.bind(this));
100
101 const currentFrameDuration = currentTime - this._previousTime;
102
103 if (currentFrameDuration > this._frameDuration) {
104
105 // We're sending the currentTime since it gives better results for
106 // this type of renderer, though usually we expect the delta
107 this._engine.update(currentTime);
108 this._previousTime = currentTime;
109 }
110 }
111
112 // Creates a canvas for rendering
113
114 _initializeCanvas() {
115
116 this._canvas = document.createElement('canvas');
117 this.element.appendChild(this._canvas);
118 this._resizeCanvas();
119 window.addEventListener('resize', this._resizeCanvas.bind(this));
120 }
121
122 // Resizes the canvas to a square the size of the smallest magnitude
123 // of the window.
124
125 _resizeCanvas() {
126
127 let width = window.innerWidth;
128 let height = Math.round(width * this.aspectRatio[1] / this.aspectRatio[0]);
129
130 if (window.innerHeight < height) {
131 height = window.innerHeight;
132 width = Math.round(height * this.aspectRatio[0] / this.aspectRatio[1]);
133 }
134
135 this._canvas.style.width = `${width}px`;
136 this._canvas.style.height = `${height}px`;
137
138 this._canvas.width = Math.round(this.verticalResolution * this.aspectRatio[0] / this.aspectRatio[1]);
139 this._canvas.height = this.verticalResolution;
140 }
141
142 // Initializes the serpentity systems
143
144 _initializeSystems() {
145
146 }
147
148 // Initializes the serpentity entities
149
150 _initializeEntities() {
151
152 }
153 };
154
155 export default internals.exports = {};
156
157 // autorun.bat
158 window.addEventListener('load', internals.onLoad);