UNPKG

5.68 kBJavaScriptView Raw
1"use strict";
2
3var ImageLoader = require("./image-loader");
4var Input = require("./input");
5var Scene = require("./scene");
6var SoundLoader = require("./sound-loader");
7
8function clone(obj) {
9 if (obj === undefined) {
10 return undefined;
11 }
12 return JSON.parse(JSON.stringify(obj));
13}
14function splitFilmStripAnimations(animations) {
15 Object.keys(animations).forEach(function(key) {
16 var firstFrame = animations[key][0];
17 if (firstFrame.filmstripFrames) {
18 splitFilmStripAnimation(animations, key);
19 }
20 });
21}
22function splitFilmStripAnimation(animations, key) {
23 var firstFrame = animations[key][0];
24 if (firstFrame.properties.image.sourceWidth % firstFrame.filmstripFrames != 0) {
25 console.warn("The \"" + key + "\" animation is " + firstFrame.properties.image.sourceWidth + " pixels wide and that is is not evenly divisible by " + firstFrame.filmstripFrames + " frames.");
26 }
27 for (var i = 0; i < firstFrame.filmstripFrames; i++) {
28 var frameWidth = firstFrame.properties.image.sourceWidth / firstFrame.filmstripFrames;
29 var newFrame = clone(firstFrame);
30 newFrame.properties.image.sourceX = frameWidth * i;
31 newFrame.properties.image.sourceWidth = frameWidth;
32 animations[key].push(newFrame);
33 }
34 animations[key].splice(0,1);
35}
36
37function Game(canvas, customRequire) {
38 this.animations = customRequire("./data/animations");
39 splitFilmStripAnimations(this.animations);
40 this.canvas = canvas;
41 this.context = canvas.getContext("2d");
42 this.entities = customRequire("./data/entities");
43 this.images = new ImageLoader();
44 this.images.loadFromManifest(customRequire("./data/images"));
45 this.input = new Input(customRequire("./data/inputs"), canvas);
46 this.require = customRequire;
47 this.scenes = customRequire("./data/scenes");
48 this.sounds = new SoundLoader();
49 this.sounds.loadFromManifest(customRequire("./data/sounds"));
50 this.systems = customRequire("./data/systems");
51 this.prefabs = customRequire("./data/prefabs");
52
53 this.scaleCanvasToCssSize();
54 window.addEventListener("resize", this.onCanvasResize.bind(this));
55
56 this.makeScenes(this.scenes);
57}
58Game.prototype.makeScenes = function(sceneList) {
59 Object.keys(sceneList).forEach(function(scene) {
60 if (sceneList[scene].first) {
61 this.scene = this.makeScene(scene, sceneList[scene], {});
62 }
63 }.bind(this));
64};
65Game.prototype.makeScene = function(name, sceneData, sceneArgs) {
66 var scene = new Scene();
67
68 var data = this.makeSceneData(scene.entities, sceneArgs);
69 scene.simulation.add(function() {
70 data.input.processUpdates();
71 });
72 this.installSystems(name, this.systems.simulation, scene.simulation, data);
73 this.installSystems(name, this.systems.renderer, scene.renderer, data);
74 scene.entities.load(clone(this.entities[name]));
75
76 if (typeof sceneData.onEnter === "string") {
77 var enterScript = this.require(sceneData.onEnter);
78 if (typeof enterScript === "function") {
79 enterScript = enterScript.bind(scene, data);
80 }
81 scene.onEnter = enterScript;
82 }
83 if (typeof sceneData.onExit === "string") {
84 var exitScript = this.require(sceneData.onExit);
85 if (typeof exitScript === "function") {
86 exitScript = exitScript.bind(scene, data);
87 }
88 scene.onExit = exitScript;
89 }
90
91 return scene;
92};
93Game.prototype.makeSceneData = function(entities, sceneArgs) {
94 return {
95 animations: this.animations,
96 arguments: sceneArgs || {},
97 canvas: this.canvas,
98 context: this.context,
99 entities: entities,
100 images: this.images,
101 input: this.input,
102 require: this.require,
103 scaleCanvasToCssSize: this.scaleCanvasToCssSize.bind(this),
104 scaleCanvasToFitRectangle: this.scaleCanvasToFitRectangle.bind(this),
105 sounds: this.sounds,
106 switchScene: this.switchScene.bind(this),
107 instantiatePrefab: this.instantiatePrefab.bind(this)
108 };
109};
110Game.prototype.installSystems = function(scene, systems, ecs, data) {
111 systems.forEach(function(system) {
112 if (system.scenes.indexOf(scene) === -1) {
113 return;
114 }
115 var script = this.require(system.name);
116 if (script === undefined) {
117 console.error("failed to load script", system.name);
118 }
119 script(ecs, data);
120 }.bind(this));
121};
122Game.prototype.switchScene = function(name, sceneArgs) {
123 if (this.scene !== undefined) {
124 this.scene.stop();
125 }
126 this.scene = this.makeScene(name, this.scenes[name], sceneArgs);
127 this.scene.start(this.context);
128};
129Game.prototype.onCanvasResize = function() {
130 this.resizer();
131};
132Game.prototype.scaleCanvasToCssSize = function() {
133 this.resizer = function() {
134 var canvasStyle = window.getComputedStyle(this.canvas);
135 var width = parseInt(canvasStyle.width);
136 var height = parseInt(canvasStyle.height);
137 this.canvas.width = width;
138 this.canvas.height = height;
139 }.bind(this);
140 this.resizer();
141};
142Game.prototype.scaleCanvasToFitRectangle = function(width, height) {
143 this.resizer = function() {
144 var canvasStyle = window.getComputedStyle(this.canvas);
145 var cssWidth = parseInt(canvasStyle.width);
146 var cssHeight = parseInt(canvasStyle.height);
147 var cssAspectRatio = cssWidth / cssHeight;
148
149 var desiredWidth = width;
150 var desiredHeight = height;
151 var desiredAspectRatio = width / height;
152 if (desiredAspectRatio > cssAspectRatio) {
153 desiredHeight = Math.floor(width / cssAspectRatio);
154 } else if (desiredAspectRatio < cssAspectRatio) {
155 desiredWidth = Math.floor(height * cssAspectRatio);
156 }
157
158 this.canvas.width = desiredWidth;
159 this.canvas.height = desiredHeight;
160 }.bind(this);
161 this.resizer();
162};
163Game.prototype.instantiatePrefab = function(name) {
164 var id = this.scene.entities.create();
165 var prefab = this.prefabs[name];
166 Object.keys(prefab).forEach(function(key) {
167 if (key === "id") {
168 return;
169 }
170 this.scene.entities.set(id, key, clone(prefab[key]));
171 }.bind(this));
172 return id;
173};
174
175module.exports = Game;