UNPKG

13.5 kBJavaScriptView Raw
1"use strict";
2var __extends = (this && this.__extends) || (function () {
3 var extendStatics = Object.setPrototypeOf ||
4 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
5 function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
6 return function (d, b) {
7 extendStatics(d, b);
8 function __() { this.constructor = d; }
9 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
10 };
11})();
12Object.defineProperty(exports, "__esModule", { value: true });
13var SideralObject_1 = require("./../SideralObject");
14var Module_1 = require("./../Module");
15var index_1 = require("./../index");
16var Tool_1 = require("./../Tool");
17/**
18 * The engine of the game
19 * @class Game
20 * @extends SideralObject
21 */
22var Game = (function (_super) {
23 __extends(Game, _super);
24 /* LIFECYCLE */
25 /**
26 * @constructor
27 */
28 function Game() {
29 var _this = _super.call(this) || this;
30 /**
31 * Properties of the game
32 */
33 _this.props = {
34 width: 10,
35 height: 10,
36 fullSize: false,
37 backgroundColor: Tool_1.Color.transparent
38 };
39 /**
40 * Dom container of the game
41 */
42 _this.container = document.getElementById("sideral");
43 /**
44 * The current frame per second of the game
45 * @readonly
46 */
47 _this.fps = 60;
48 /**
49 * The current latency of the game (in ms)
50 * @readonly
51 */
52 _this.latency = 0;
53 /**
54 * The factor of time to avoid framerate dependance
55 * @readonly
56 */
57 _this.tick = 1;
58 /**
59 * The date of the current update in timestamp
60 * @readonly
61 */
62 _this.currentUpdate = 0;
63 /**
64 * The date of the last update in timestamp
65 * @readonly
66 */
67 _this.lastUpdate = 0;
68 /**
69 * Know if the game is currently running or not
70 */
71 _this.stopped = true;
72 /**
73 * Know if the game is loaded
74 * @readonly
75 */
76 _this.loaded = false;
77 /**
78 * Object to add when Game is ready
79 * @private
80 */
81 _this._addQueue = [];
82 /**
83 * Scenes to swap
84 */
85 _this._swapScenes = [];
86 _this._emptyDisplayObject = new index_1.PIXI.DisplayObject();
87 _this.setProps({
88 backgroundColor: Tool_1.Color.black
89 });
90 _this.context.game = _this;
91 _this.setLoadingScene(new Module_1.SceneLoading());
92 _this.signals.propChange.bind(["width", "height", "fullSize"], _this._resizeGame.bind(_this));
93 _this.signals.propChange.bind("backgroundColor", _this._onBackgroundColorChange.bind(_this));
94 return _this;
95 }
96 /**
97 * @override
98 */
99 Game.prototype.kill = function () {
100 _super.prototype.kill.call(this);
101 this.removeRenderer();
102 if (this._debounceResize) {
103 window.removeEventListener("resize", this._debounceResize);
104 this._debounceResize = null;
105 }
106 };
107 /**
108 * Update loop
109 * @param performance - Performance returned by the navigator
110 */
111 Game.prototype.update = function (performance) {
112 var _this = this;
113 if (this.stopped) {
114 return null;
115 }
116 performance = performance || window.performance.now();
117 requestAnimationFrame(this.update.bind(this));
118 // 100ms latency max
119 this.currentUpdate = performance;
120 this.latency = Tool_1.Util.limit(performance - this.lastUpdate, 8, 100);
121 this.fps = Math.floor(1000 / this.latency);
122 this.tick = 1000 / (this.fps * 1000);
123 this.tick = this.tick < 0 ? 0 : this.tick;
124 this.children.forEach(function (child) { return child.update(_this.tick); });
125 this.nextCycle();
126 var scenes = this.getScenes();
127 if (this.renderer) {
128 scenes.forEach(function (scene) { return _this.renderer.render(scene.container); });
129 if (!scenes.length) {
130 this.renderer.render(this._emptyDisplayObject);
131 }
132 }
133 this.lastUpdate = window.performance.now();
134 };
135 Game.prototype.nextCycle = function () {
136 var _this = this;
137 _super.prototype.nextCycle.call(this);
138 if (this.loaded) {
139 var queue = this._addQueue.slice(0);
140 this._addQueue = [];
141 queue.forEach(function (q) { return _super.prototype.add.call(_this, q.item, q.props); });
142 this._addQueue.forEach(function (queue) { return _super.prototype.add.call(_this, queue.item, queue.props); });
143 this._swapScenes.forEach(function (swap) { return _this._swapScene(swap); });
144 this._swapScenes = [];
145 if (this._loadingScene) {
146 this._loadingScene.kill();
147 this._loadingScene = null;
148 }
149 }
150 };
151 /* METHODS */
152 /**
153 * @override
154 */
155 Game.prototype.add = function (item, props) {
156 if (props === void 0) { props = {}; }
157 this._addQueue.push({ item: item, props: props });
158 return item;
159 };
160 /**
161 * Set a scene used for loading screen
162 * @param loadingScene - Scene to run when the game is loading
163 * @return The LoadingScene
164 */
165 Game.prototype.setLoadingScene = function (loadingScene) {
166 if (loadingScene && !(loadingScene instanceof Module_1.Scene)) {
167 throw new Error("Game.setLoadingScene: The loadingScene must be an instance of Scene.");
168 }
169 if (this._loadingScene) {
170 this._loadingScene.kill();
171 }
172 if (!loadingScene) {
173 this._loadingScene = null;
174 return null;
175 }
176 this._loadingScene = _super.prototype.add.call(this, loadingScene);
177 return this._loadingScene;
178 };
179 /**
180 * Load assets
181 * @param env - The environment to load
182 * @param loadingScene - Scene to use for loading
183 * @param onLoad - Callback to be called when assets is loaded
184 */
185 Game.prototype.loadAssets = function (env, loadingScene, onLoad) {
186 var _this = this;
187 Tool_1.Assets.load(env, function () {
188 var done = function () {
189 _this.loaded = true;
190 if (onLoad) {
191 onLoad();
192 }
193 };
194 if (_this._loadingScene) {
195 _this._loadingScene.onAssetsLoaded(done);
196 }
197 else {
198 done();
199 }
200 }, function (progress) { return _this._loadingScene && _this._loadingScene.signals.progress.dispatch(progress); });
201 };
202 /**
203 * Start the game loop
204 * @acess public
205 * @param width - width of the game
206 * @param height - height of the game
207 * @param container - container to attach the game
208 * @param onLoad - Callback to be called when the game is loaded
209 * @returns current instance
210 */
211 Game.prototype.start = function (width, height, container, onLoad) {
212 this.setProps({
213 width: width || this.props.width,
214 height: height || this.props.height
215 });
216 if (!this.props.fullSize && (!this.props.width || !this.props.height)) {
217 throw new Error("Engine.start: You must set 'width', 'height' and a 'container' container");
218 }
219 this.container = container || this.container;
220 this._swapRenderer();
221 this._resizeGame();
222 this._onBackgroundColorChange();
223 this.loadAssets(null, null, onLoad);
224 this.update();
225 return this;
226 };
227 /**
228 * Stop the current game
229 */
230 Game.prototype.stop = function () {
231 this.stopped = true;
232 this.removeRenderer();
233 };
234 /**
235 * resize the current canvas
236 */
237 Game.prototype.resize = function () {
238 if (!this.renderer) {
239 return null;
240 }
241 this.renderer.resize(this.props.width, this.props.height);
242 };
243 /**
244 * Remove the PIXI Renderer
245 * @param killCanvas - If true, the canvas DOM will be destroyed too
246 */
247 Game.prototype.removeRenderer = function (killCanvas) {
248 if (killCanvas === void 0) { killCanvas = true; }
249 if (!this.renderer) {
250 return null;
251 }
252 this.renderer.destroy(killCanvas);
253 this.renderer = null;
254 };
255 /**
256 * Enable keyboard events
257 * @param preventInputPropagation - If true, the event provided by the keyboard will not be propaged outside the Sideral engine
258 * @returns The current instance of Keyboard
259 */
260 Game.prototype.enableKeyboard = function (preventInputPropagation) {
261 this.keyboard = this.add(new SideralObject_1.Keyboard());
262 this.keyboard.preventInputPropagation = preventInputPropagation;
263 return this.keyboard;
264 };
265 /**
266 * Disable keyboard events
267 */
268 Game.prototype.disableKeyboard = function () {
269 if (this.keyboard) {
270 this.keyboard.kill();
271 }
272 this.keyboard = null;
273 };
274 /**
275 * Get all scenes from the current game
276 * @returns Scenes
277 */
278 Game.prototype.getScenes = function () {
279 return this.children.filter(function (child) { return child instanceof Module_1.Scene; }).filter(function (child) { return !child.killed; });
280 };
281 /**
282 * Attach the game to a dom
283 */
284 Game.prototype.attach = function (container) {
285 this.container = container || this.container;
286 if (!this.container) {
287 throw new Error("Game: before start your game, you must set a dom container.");
288 }
289 this.container.appendChild(this.renderer.view);
290 };
291 /**
292 * Swap a scene to the next Scene
293 * @param currentScene - The current scene to swap
294 * @param nextScene - The next Scene to swap
295 * @returns The next scene
296 */
297 Game.prototype.swapScene = function (currentScene, nextScene, color, duration, onComplete) {
298 if (duration === void 0) { duration = 500; }
299 if (currentScene && nextScene) {
300 this._swapScenes.push({ currentScene: currentScene, nextScene: nextScene, color: color, duration: duration, onComplete: onComplete });
301 }
302 return nextScene;
303 };
304 /* PRIVATE */
305 Game.prototype._swapScene = function (_a) {
306 var _this = this;
307 var currentScene = _a.currentScene, nextScene = _a.nextScene, color = _a.color, duration = _a.duration, onComplete = _a.onComplete;
308 if (!color) {
309 currentScene.kill();
310 _super.prototype.add.call(this, nextScene);
311 if (onComplete) {
312 onComplete(nextScene);
313 }
314 }
315 else {
316 currentScene.fade("out", color, duration, function () {
317 currentScene.kill();
318 _super.prototype.add.call(_this, nextScene);
319 nextScene.fade("in", color, duration, function () {
320 if (onComplete) {
321 onComplete(nextScene);
322 }
323 });
324 });
325 }
326 };
327 /**
328 * When width or height attributes change
329 * @private
330 */
331 Game.prototype._resizeGame = function () {
332 var _this = this;
333 if (!this.renderer) {
334 return null;
335 }
336 if (this.props.fullSize) {
337 this.setProps({
338 width: this.renderer.view.parentElement.clientWidth,
339 height: this.renderer.view.parentElement.clientHeight
340 });
341 }
342 this.getScenes().filter(function (scene) { return scene.props.sizeAuto; }).forEach(function (scene) {
343 scene.props.width = _this.props.width;
344 scene.props.height = _this.props.height;
345 });
346 if (!this.props.fullSize && this._debounceResize) {
347 window.removeEventListener("resize", this._debounceResize);
348 this._debounceResize = null;
349 }
350 if (this.props.fullSize && !this._debounceResize) {
351 window.addEventListener("resize", this._debounceResize = Tool_1.Util.debounce(this._resizeGame.bind(this), 250));
352 }
353 this.renderer.resize(this.props.width, this.props.height);
354 };
355 /**
356 * When background attribute changes
357 * @private
358 */
359 Game.prototype._onBackgroundColorChange = function () {
360 var color = Tool_1.Util.colorToDecimal(this.props.backgroundColor), transparent = Boolean(isNaN(color));
361 if (!transparent) {
362 this.renderer.backgroundColor = color;
363 }
364 if (transparent !== this.renderer.transparent) {
365 this._swapRenderer();
366 }
367 };
368 Game.prototype._swapRenderer = function () {
369 var transparent = !this.props.backgroundColor || this.props.backgroundColor === Tool_1.Color.transparent;
370 var view = null;
371 this.removeRenderer();
372 this.renderer = index_1.PIXI.autoDetectRenderer(this.props.width, this.props.height, {
373 autoResize: true,
374 transparent: transparent,
375 backgroundColor: transparent ? 0 : Tool_1.Util.colorToDecimal(this.props.backgroundColor),
376 roundPixels: false,
377 antialias: true
378 });
379 this.attach();
380 this.stopped = false;
381 };
382 return Game;
383}(SideralObject_1.SideralObject));
384exports.Game = Game;
385index_1.PIXI.utils.skipHello();