├── .gitignore
├── .npmignore
├── README.md
├── config
├── mocha-loader.js
├── webpack.config.js
├── webpack.mocha.js
├── webpack.parts.js
└── webpack.prod.js
├── gamee
├── dist
│ ├── gamee-js.js
│ ├── gamee-js.js.map
│ ├── gamee-js.min.js
│ └── gamee-js.min.js.map
├── libs
│ ├── bullet.js
│ └── shims.js
├── src
│ ├── core.js
│ ├── game_controllers.js
│ ├── gameeAPI.js
│ ├── index.js
│ └── platform_bridge.js
└── tests
│ ├── api.test.js
│ ├── dummy.test.js
│ ├── framework-integrity.test.js
│ └── index.js
├── jsdoc.conf.json
├── package-lock.json
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by https://www.gitignore.io
2 |
3 | ### Node ###
4 | # Logs
5 | logs
6 | *.log
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 |
13 | # Directory for instrumented libs generated by jscoverage/JSCover
14 | lib-cov
15 |
16 | # Coverage directory used by tools like istanbul
17 | coverage
18 |
19 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
20 | .grunt
21 |
22 | # Compiled binary addons (http://nodejs.org/api/addons.html)
23 | build/Release
24 |
25 | # Dependency directory
26 | # Commenting this out is preferred by some people, see
27 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-
28 | node_modules
29 |
30 | # Users Environment Variables
31 | .lock-wscript
32 |
33 |
34 | ### Bower ###
35 | bower_components
36 |
37 |
38 | ### Linux ###
39 | *~
40 |
41 | # KDE directory preferences
42 | .directory
43 |
44 |
45 | ### vim ###
46 | [._]*.s[a-w][a-z]
47 | [._]s[a-w][a-z]
48 | *.un~
49 | Session.vim
50 | .netrwhist
51 | *~
52 |
53 | ## documentation files
54 |
55 | gamee/docs
56 |
57 | ## packed samples
58 |
59 | projects-dist
60 | projects-build
61 |
62 | ## IDE
63 | .vscode
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | gamee/dist
2 | .idea
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # GAMEE JS
2 |
3 | GAMEE is a social platform full of HTML5 games. Our goal is to make the games playable everywhere. You can play in the mobile apps (Android, iOS), bots (Telegram, Kik, Facebook Messenger) or directly on web.
4 |
5 | GAMEE JS is our Javascript framework for connecting HTML5 game to [GAMEE](http://www.gameeapp.com/) platform.
6 |
7 | Documentation is currently located on [Github wiki](https://github.com/gameeapp/gamee-js/wiki)
8 |
9 | ## Usage
10 |
11 | Download the minified framework located in [gamee/dist/gamee-js.min.js](https://github.com/gameeapp/gamee-js/blob/master/gamee/dist/gamee-js.min.js) and include it in your ```index.html``` file.
12 |
13 | ```html
14 |
15 | ```
16 |
17 | ### Usage with NPM and Webpack
18 |
19 | Install the framework with command ```npm install gamee-js```. Then use:
20 |
21 | ```javascript
22 | import { gamee } from "gamee-js"
23 | ```
24 |
25 | in your files.
26 |
27 | ## Previous versions (and changelogs)
28 |
29 | [https://github.com/gameeapp/gamee-js/releases](https://github.com/gameeapp/gamee-js/releases)
30 |
31 | ## Contribute
32 |
33 | If you want to contribute, please feel free to use [Github issue tracker](https://github.com/gameeapp/gamee-js/issues) of this repository.
34 |
35 | ## Build framework on your own
36 |
37 | ```bash
38 | git clone git@github.com:gameeapp/gamee-js.git
39 | ```
40 |
41 | ```bash
42 | npm install
43 |
44 | # run test with mocha in CLI
45 | npm test
46 |
47 | # HRM test with mocha in browser
48 | npm test:mocha:watch
49 |
50 | # realtime building
51 | npm watch
52 |
53 | # one time build
54 | npm b:dist
55 | ```
56 |
57 | ## Contact
58 |
59 | If you would like to publish your HTML5 game on the Gamee platform, please contact us on hello@gameeapp.com
60 |
61 |
--------------------------------------------------------------------------------
/config/mocha-loader.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const config = require('./base')
3 |
4 | config.devServer = {
5 | host: 'localhost',
6 | port: '3001'
7 | }
8 |
9 | const index = path.resolve(__dirname, '../client/__tests__/index.js')
10 |
11 | config.entry = {
12 | test: [`mocha!${index}`]
13 | }
14 |
15 | config.output.publicPath = 'http://localhost:3001/'
16 |
17 | module.exports = config
--------------------------------------------------------------------------------
/config/webpack.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function (env) {
2 | return require(`./webpack.${env}.js`)
3 | }
--------------------------------------------------------------------------------
/config/webpack.mocha.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const merge = require('webpack-merge');
3 |
4 | const parts = require('./webpack.parts');
5 |
6 | module.exports = merge([
7 | parts.devServer(),
8 | parts.page({
9 | title: 'Mocha demo',
10 | entry: {
11 | tests: path.join(__dirname, '../gamee/tests')
12 | },
13 | }),
14 | ]);
--------------------------------------------------------------------------------
/config/webpack.parts.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | const HtmlWebpackPlugin = require('html-webpack-plugin');
4 |
5 | exports.devServer = ({ host, port } = {}) => ({
6 | devServer: {
7 | historyApiFallback: true,
8 | stats: 'errors-only',
9 | host, // Defaults to `localhost`
10 | port: 3001, // Defaults to 8080
11 | overlay: {
12 | errors: true,
13 | warnings: true,
14 | },
15 | },
16 | });
17 |
18 | exports.page = ({
19 | path = '',
20 | template = require.resolve(
21 | 'html-webpack-plugin/default_index.ejs'
22 | ),
23 | title,
24 | entry,
25 | chunks,
26 | } = {}) => ({
27 | entry,
28 | plugins: [
29 | new HtmlWebpackPlugin({
30 | chunks,
31 | filename: `${path && path + '/'}index.html`,
32 | template,
33 | title,
34 | }),
35 | ],
36 | });
--------------------------------------------------------------------------------
/config/webpack.prod.js:
--------------------------------------------------------------------------------
1 | const path = require('path'),
2 | webpack = require('webpack')
3 |
4 | module.exports = {
5 | devtool: '#source-map',
6 |
7 | entry: {
8 | "gamee-js": "./gamee/src/index.js",
9 | "gamee-js.min": "./gamee/src/index.js",
10 | },
11 |
12 | module: {
13 | rules: [
14 | {
15 | test: /\.js$/,
16 | exclude: /(node_modules|bower_components)/,
17 | use: {
18 | loader: 'babel-loader',
19 | options: {
20 | presets: ['env']
21 | }
22 | }
23 | }
24 | ]
25 | },
26 |
27 | output: {
28 | // dont set this or context will be `gamee.gamee.emitter` etc.
29 | // library: 'gamee',
30 | libraryTarget: 'umd',
31 | path: path.resolve(__dirname, '../gamee/dist'),
32 | filename: '[name].js'
33 | },
34 |
35 | plugins: [
36 | new webpack.LoaderOptionsPlugin({
37 | minimize: true,
38 | debug: false
39 | }),
40 | new webpack.BannerPlugin({
41 | banner: `@preserve build time ${new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '')}`
42 | }),
43 | new webpack.optimize.UglifyJsPlugin({
44 | include: /\.min\.js$/,
45 | sourceMap: true,
46 | beautify: false,
47 | mangle: {
48 | screw_ie8: true,
49 | keep_fnames: true,
50 | toplevel: true,
51 | except: ["OneButtonController",
52 | "TwoButtonController",
53 | "FourButtonController",
54 | "FiveButtonController",
55 | "SixButtonController",
56 | "FourArrowController",
57 | "TouchController",
58 | "JoystickController",
59 | "JoystickButtonController",
60 | "TwoArrowsTwoButtonsController",
61 | "TwoArrowsOneButtonController",
62 | "TwoActionButtonsController"] // this will make objects reserved words, so it wont be minified and its constructor is visible in IDE and debugger
63 | },
64 | compress: {
65 | screw_ie8: true,
66 | sequences: true,
67 | properties: true,
68 | dead_code: true,
69 | drop_debugger: true,
70 | drop_console: true,
71 | conditionals: true,
72 | comparisons: true
73 | },
74 | comments: "some"
75 | })
76 | ],
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/gamee/dist/gamee-js.js:
--------------------------------------------------------------------------------
1 | /*! @preserve build time 2019-08-27 08:54:59 */
2 | (function webpackUniversalModuleDefinition(root, factory) {
3 | if(typeof exports === 'object' && typeof module === 'object')
4 | module.exports = factory();
5 | else if(typeof define === 'function' && define.amd)
6 | define([], factory);
7 | else {
8 | var a = factory();
9 | for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
10 | }
11 | })(this, function() {
12 | return /******/ (function(modules) { // webpackBootstrap
13 | /******/ // The module cache
14 | /******/ var installedModules = {};
15 | /******/
16 | /******/ // The require function
17 | /******/ function __webpack_require__(moduleId) {
18 | /******/
19 | /******/ // Check if module is in cache
20 | /******/ if(installedModules[moduleId]) {
21 | /******/ return installedModules[moduleId].exports;
22 | /******/ }
23 | /******/ // Create a new module (and put it into the cache)
24 | /******/ var module = installedModules[moduleId] = {
25 | /******/ i: moduleId,
26 | /******/ l: false,
27 | /******/ exports: {}
28 | /******/ };
29 | /******/
30 | /******/ // Execute the module function
31 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
32 | /******/
33 | /******/ // Flag the module as loaded
34 | /******/ module.l = true;
35 | /******/
36 | /******/ // Return the exports of the module
37 | /******/ return module.exports;
38 | /******/ }
39 | /******/
40 | /******/
41 | /******/ // expose the modules object (__webpack_modules__)
42 | /******/ __webpack_require__.m = modules;
43 | /******/
44 | /******/ // expose the module cache
45 | /******/ __webpack_require__.c = installedModules;
46 | /******/
47 | /******/ // identity function for calling harmony imports with the correct context
48 | /******/ __webpack_require__.i = function(value) { return value; };
49 | /******/
50 | /******/ // define getter function for harmony exports
51 | /******/ __webpack_require__.d = function(exports, name, getter) {
52 | /******/ if(!__webpack_require__.o(exports, name)) {
53 | /******/ Object.defineProperty(exports, name, {
54 | /******/ configurable: false,
55 | /******/ enumerable: true,
56 | /******/ get: getter
57 | /******/ });
58 | /******/ }
59 | /******/ };
60 | /******/
61 | /******/ // getDefaultExport function for compatibility with non-harmony modules
62 | /******/ __webpack_require__.n = function(module) {
63 | /******/ var getter = module && module.__esModule ?
64 | /******/ function getDefault() { return module['default']; } :
65 | /******/ function getModuleExports() { return module; };
66 | /******/ __webpack_require__.d(getter, 'a', getter);
67 | /******/ return getter;
68 | /******/ };
69 | /******/
70 | /******/ // Object.prototype.hasOwnProperty.call
71 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
72 | /******/
73 | /******/ // __webpack_public_path__
74 | /******/ __webpack_require__.p = "";
75 | /******/
76 | /******/ // Load entry module and return exports
77 | /******/ return __webpack_require__(__webpack_require__.s = 6);
78 | /******/ })
79 | /************************************************************************/
80 | /******/ ([
81 | /* 0 */
82 | /***/ (function(module, exports, __webpack_require__) {
83 |
84 | "use strict";
85 |
86 |
87 | Object.defineProperty(exports, "__esModule", {
88 | value: true
89 | });
90 | exports.CustomEmitter = CustomEmitter;
91 | exports.wrapKeyEvent = wrapKeyEvent;
92 | /**
93 | * @class CustomEvent
94 | */
95 | (function shimCustomEvent() {
96 | try {
97 | var ce = new window.CustomEvent('test');
98 | ce.preventDefault();
99 | if (ce.defaultPrevented !== true) {
100 | // IE has problems with .preventDefault() on custom events
101 | // http://stackoverflow.com/questions/23349191
102 | throw new Error('Could not prevent default');
103 | }
104 | } catch (e) {
105 | var CustomEvent = function CustomEvent(event, params) {
106 | var evt, origPrevent;
107 | params = params || {
108 | bubbles: false,
109 | cancelable: false,
110 | detail: undefined
111 | };
112 |
113 | evt = document.createEvent("CustomEvent");
114 | evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
115 | origPrevent = evt.preventDefault;
116 | evt.preventDefault = function () {
117 | origPrevent.call(this);
118 | try {
119 | Object.defineProperty(this, 'defaultPrevented', {
120 | get: function get() {
121 | return true;
122 | }
123 | });
124 | } catch (e) {
125 | this.defaultPrevented = true;
126 | }
127 | };
128 | return evt;
129 | };
130 |
131 | CustomEvent.prototype = window.Event.prototype;
132 | window.CustomEvent = CustomEvent; // expose definition to window
133 | }
134 | })();
135 |
136 | //addEventListener polyfill 1.0 / Eirik Backer / MIT Licence
137 | (function (win, doc) {
138 | if (win.addEventListener) return; //No need to polyfill
139 |
140 | function docHijack(p) {
141 | var old = doc[p];doc[p] = function (v) {
142 | return addListen(old(v));
143 | };
144 | }
145 | function addEvent(on, fn, self) {
146 | return (self = this).attachEvent('on' + on, function (e) {
147 | e = e || win.event;
148 | e.preventDefault = e.preventDefault || function () {
149 | e.returnValue = false;
150 | };
151 | e.stopPropagation = e.stopPropagation || function () {
152 | e.cancelBubble = true;
153 | };
154 | fn.call(self, e);
155 | });
156 | }
157 | function addListen(obj, i) {
158 | i = obj.length;
159 | if (i) {
160 | while (i--) {
161 | obj[i].addEventListener = addEvent;
162 | }
163 | } else {
164 | obj.addEventListener = addEvent;
165 | }
166 | return obj;
167 | }
168 |
169 | addListen([doc, win]);
170 | if ('Element' in win) win.Element.prototype.addEventListener = addEvent; //IE8
171 | else {
172 | //IE < 8
173 | doc.attachEvent('onreadystatechange', function () {
174 | addListen(doc.all);
175 | }); //Make sure we also init at domReady
176 | docHijack('getElementsByTagName');
177 | docHijack('getElementById');
178 | docHijack('createElement');
179 | addListen(doc.all);
180 | }
181 | })(window, document);
182 |
183 | // naomik event emiter http://stackoverflow.com/a/24216547/1866147
184 | // usage:
185 | // function Example() {
186 | // CustomEmitter.call(this);
187 | // }
188 |
189 | // // run it
190 | // var e = new Example();
191 |
192 | // e.addEventListener("something", function (event) {
193 | // console.log(event)
194 | // });
195 |
196 | // e.dispatchEvent(new Event("something"));
197 | function CustomEmitter() {
198 | var eventTarget = document.createDocumentFragment();
199 |
200 | function delegate(method) {
201 | this[method] = eventTarget[method].bind(eventTarget);
202 | }
203 |
204 | ["addEventListener", "dispatchEvent", "removeEventListener"].forEach(delegate, this);
205 | }
206 |
207 | /** ### wrapKeyEvent
208 | *
209 | * Handle old IE event differences for key events
210 | *
211 | * @param {Function} fn callback
212 | */
213 | function wrapKeyEvent(fn) {
214 | return function (ev) {
215 | if (!ev || !ev.keyCode) {
216 | if (!ev) {
217 | ev = window.event;
218 | }
219 |
220 | if (ev.which) {
221 | ev.keyCode = ev.which;
222 | }
223 | }
224 |
225 | return fn(ev);
226 | };
227 | }
228 |
229 | /***/ }),
230 | /* 1 */
231 | /***/ (function(module, exports, __webpack_require__) {
232 |
233 | "use strict";
234 | /* WEBPACK VAR INJECTION */(function(global) {
235 |
236 | Object.defineProperty(exports, "__esModule", {
237 | value: true
238 | });
239 | exports.validateDataType = exports.DataTypeException = exports.core = undefined;
240 |
241 | var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
242 |
243 | var _game_controllers = __webpack_require__(5);
244 |
245 | var controllers = _interopRequireWildcard(_game_controllers);
246 |
247 | var _shims = __webpack_require__(0);
248 |
249 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
250 |
251 | // unlock audio
252 | // overrides native AudioContext & webkitAudioContext
253 | (function () {
254 | // this works as a constructor
255 | var overloadedAudioContext = function overloadedAudioContext(type) {
256 | var ctx = new type();
257 |
258 | // add audio resume to function on touchstart
259 | if (ctx.state === 'suspended') {
260 |
261 | var resume = function resume() {
262 |
263 | // Check if hack is necessary. Only occurs in iOS6+ devices
264 | // and only when you first boot the iPhone, or play a audio/video
265 | // with a different sample rate
266 | if (/(iPhone|iPad)/i.test(navigator.userAgent)) {
267 | var buffer = ctx.createBuffer(1, 1, 44100);
268 | var dummy = ctx.createBufferSource();
269 | dummy.buffer = buffer;
270 | dummy.connect(ctx.destination);
271 | dummy.start(0);
272 | dummy.disconnect();
273 | }
274 |
275 | ctx.resume();
276 | setTimeout(function () {
277 | if (ctx.state === 'running') {
278 | document.body.removeEventListener(['touchcancel', 'touchend', 'touchenter', 'touchleave', 'touchmove', 'touchstart', 'mouseenter', 'mouseover', 'mousemove', 'mousedown', 'mouseup'].join(" "), resume, false);
279 | }
280 | }, 0);
281 | };
282 |
283 | // only touchend will work, but hey, we tried...
284 | // https://github.com/WebAudio/web-audio-api/issues/836
285 | // https://www.chromestatus.com/feature/6406908126691328
286 | document.body.addEventListener(['touchcancel', 'touchend', 'touchenter', 'touchleave', 'touchmove', 'touchstart', 'mouseenter', 'mouseover', 'mousemove', 'mousedown', 'mouseup'].join(" "), resume, false);
287 | }
288 | // allowed in JS to return different type of the object in the constructor
289 | return ctx;
290 | };
291 |
292 | try {
293 | if (typeof window.AudioContext !== 'undefined') {
294 | window.AudioContext = overloadedAudioContext.bind(null, window.AudioContext);
295 | } else if (typeof webkitAudioContext !== 'undefined') {
296 | window.webkitAudioContext = overloadedAudioContext.bind(null, window.webkitAudioContext);
297 | }
298 | } catch (e) {
299 | // throw error in async part
300 | setTimeout(function () {
301 | throw e;
302 | }, 0);
303 | }
304 | })();
305 |
306 | /**
307 | * @class core
308 | */
309 | var core = exports.core = function () {
310 |
311 | // # Gamee.js
312 | //
313 | // This file defines and expose a public API for games to communicate
314 | // with Gamee*.
315 | //
316 | // Also it handles some requirements when Gamee is run in an desktop
317 | // environment.
318 | //
319 | // \* _later in the document Gamee will be referred as GameeApp to not
320 | // be mistaken for word game_
321 | //
322 | // ** _GameeWebApp will refer to Gamee which is running in a desktop
323 | // browser_
324 |
325 | /** an empty function */
326 | var noop = function noop() {};
327 |
328 | var cache = {};
329 |
330 | /** internal variables/constants (uppercase) coupled inside separate object for potential easy referencing */
331 | var internals = {
332 | VERSION: "2.4.0", // version of the gamee library
333 | CAPABILITIES: ["ghostMode", "saveState", "replay", "socialData", "rewardedAds", "coins", "logEvents", "playerData", "share", "gems"], // supported capabilities
334 | variant: 0, // for automating communication with server
335 | soundUnlocked: false,
336 | onReady: noop, // for intercepting real onReady because of behind the scenes variant handling
337 | onGameStart: noop // for intercepting real onGameStart because of unlocking sound
338 | };
339 |
340 | /** ## gamee
341 | *
342 | * GameeApp interface for games. It is exposed as a `gamee` global
343 | * object and games should only use its public methods and
344 | * properties to communicate with the GameeApp.
345 | *
346 | * _There is also [$gameeNative](gamee_native.js.html) global object
347 | * which handles internal parts of the communication._
348 | */
349 | var core = {};
350 |
351 | //
352 | // ## Signaling game state
353 | //
354 | // The game should signal the GameeApp its status (playing/game-over)
355 | // and current score.
356 | //
357 |
358 | /** ### gamee.gameeInit
359 | *
360 | * Must be called first before any other gamee calls
361 | * returns controller object the same way requestController did previously
362 | * ctrlType/ctrlOpts - requested control type + options
363 | * capabilities -> array of strings representing supported features:
364 | * after the initialization onReady is invoked and after that game can use the api
365 | */
366 | core.gameeInit = function (ctrlType, ctrlOpts, capabilities, cb) {
367 | var silentMode = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
368 |
369 | // let's validate the array here, so that all backends can benefit from it
370 | var allOk = true,
371 | cap = {};
372 | if (capabilities !== undefined && Array.isArray(capabilities)) {
373 | for (var i = 0; i < capabilities.length; i++) {
374 | if (typeof capabilities[i] !== "string" || internals.CAPABILITIES.indexOf(capabilities[i]) === -1) allOk = false;
375 | cap[capabilities[i]] = true;
376 | }
377 | } else allOk = false;
378 |
379 | if (!allOk) throw "Capabilities array passed to gameeInit is void, malformed or unsupported capabilites requested.";
380 | // TODO remove
381 | // gameeNative.gameeInit(core, internals.VERSION, ctrlType, allOk ? capabilities : []);
382 |
383 | this.native.createRequest("init", {
384 | version: internals.VERSION,
385 | controller: ctrlType,
386 | capabilities: cap
387 | }, function (responseData) {
388 | // remember capabilities of the game
389 | cache.capabilities = cap;
390 | //
391 | // // Mute gamee-js console output
392 | // cache.silentMode = silentMode;
393 |
394 | // might fail if controller of this type doesnt exist
395 | var error = null;
396 | try {
397 | if (this.native.platform === "web") {
398 | responseData.controller = core.controller.requestController(ctrlType, { enableKeyboard: true });
399 | this._bindKeyboardTriggers(responseData.controller);
400 | } else {
401 | responseData.controller = core.controller.requestController(ctrlType, {});
402 | }
403 | } catch (err) {
404 | error = err;
405 | }
406 |
407 | cb(error, responseData);
408 | }.bind(this));
409 | // TODO remove
410 | // return core.controller.requestController(ctrlType, ctrlOpts);
411 | };
412 |
413 | core._bindKeyboardTriggers = function (controller) {
414 | global.addEventListener('message', function (ev) {
415 | switch (ev.data[0]) {
416 | case 'button_button_down':
417 | controller.trigger("keydown", { button: "button" });
418 | break;
419 |
420 | case 'button_button_up':
421 | controller.trigger("keyup", { button: "button" });
422 | break;
423 |
424 | case 'button_left_up':
425 | controller.trigger("keyup", { button: "left" });
426 | break;
427 |
428 | case 'button_left_down':
429 | controller.trigger("keydown", { button: "left" });
430 | break;
431 |
432 | case 'button_right_down':
433 | controller.trigger("keydown", { button: "right" });
434 | break;
435 |
436 | case 'button_right_up':
437 | controller.trigger("keyup", { button: "right" });
438 | break;
439 |
440 | case 'button_up_down':
441 | controller.trigger("keydown", { button: "up" });
442 | break;
443 |
444 | case 'button_up_up':
445 | controller.trigger("keyup", { button: "up" });
446 | break;
447 |
448 | case 'button_down_down':
449 | controller.trigger("keydown", { button: "down" });
450 | break;
451 |
452 | case 'button_down_up':
453 | controller.trigger("keyup", { button: "down" });
454 | break;
455 |
456 | case 'button_a_down':
457 | controller.trigger("keydown", { button: "A" });
458 | break;
459 |
460 | case 'button_a_up':
461 | controller.trigger("keyup", { button: "A" });
462 | break;
463 |
464 | case 'button_b_down':
465 | controller.trigger("keydown", { button: "B" });
466 | break;
467 |
468 | case 'button_b_up':
469 | controller.trigger("keyup", { button: "B" });
470 | break;
471 | }
472 | });
473 | };
474 |
475 | /** ### gamee.gameLoadingProgress
476 | *
477 | * Indicates how much content is already loaded in %.
478 | */
479 | core.gameLoadingProgress = function () {
480 | var percentageSoFar = 0;
481 |
482 | return function (percentage) {
483 | if (typeof percentage !== "number" || percentage < 0 || percentage > 100) throw "Percentage passed to gameLoadingProgress out of bounds or not a number.";else if (percentage > percentageSoFar) {
484 | percentageSoFar = percentage;
485 | this.native.createRequest("gameLoadingProgress", { percentage: percentage });
486 | }
487 | };
488 | }();
489 |
490 | /** ### gamee.gameReady
491 | *
492 | * Notifies platform game can accept start command.
493 | */
494 | core.gameReady = function () {
495 | this.native.createRequest("gameReady");
496 | };
497 |
498 | /** ### gamee.gameStart
499 | *
500 | * Indicates that game is ready to be started (even after restart).
501 | */
502 | // core.gameStart = function () {
503 | // gameeNative.gameLoadingProgress(100); // FB requires this
504 | // gameeNative.gameStart(gamee);
505 | // };
506 |
507 | /** ### gamee.updateScore
508 | *
509 | * sends score to UI
510 | */
511 | core.updateScore = function (score, opt_ghostSign) {
512 | if (typeof score !== "number") throw "Score passed to updateScore is not a number.";
513 | var data = {
514 | score: parseInt(score, 10)
515 | };
516 | if (opt_ghostSign) {
517 | data.ghostSign = true;
518 | }
519 | this.native.createRequest("updateScore", data);
520 | // core.native.createRequest(method, requestData, callback);
521 | };
522 |
523 | /** ### gamee.gameOver
524 | *
525 | * Indicates the game has ended, the game is waiting for subsequent onGameStart.
526 | * Data has the same format as data received in onReady callback.
527 | * Data must be string = responsibility for turning data structure into string is left to the game!
528 | */
529 | core.gameOver = function (opt_replayData, opt_saveState, opt_hideOverlay) {
530 | opt_hideOverlay = opt_hideOverlay !== undefined ? opt_hideOverlay : false;
531 | // var allOk = ((data !== undefined) && (typeof data === "string")) || (data === undefined);
532 | // if (!allOk) console.error("Data provided to gameOver function must be string.");
533 | // gameeNative.gameOver(gamee, internals.variant, allOk ? data : "");
534 | var requestData = {};
535 | if (opt_replayData) {
536 | if (!opt_replayData.hasOwnProperty("variant")) {
537 | opt_replayData.variant = "";
538 | }
539 | if (!opt_replayData.hasOwnProperty("data")) {
540 | throw "Replay data must have `data` property";
541 | }
542 | requestData.replayData = opt_replayData;
543 | }
544 | requestData.hideOverlay = opt_hideOverlay;
545 |
546 | if (opt_saveState) {
547 | requestData.state = opt_saveState;
548 | }
549 |
550 | core.native.createRequest("gameOver", requestData);
551 | };
552 |
553 | /** ### gamee.gameSave
554 | *
555 | * Player has requested saving current game's state
556 | * data must be string = responsibility for turning data structure into string is left to game!
557 | * share must be expression evaluating to either true or false; it indicates, whether the game progress should be shared on feed
558 | */
559 | core.gameSave = function (data, share) {
560 |
561 | if (!cache.capabilities.saveState) throw "Save State not supported, you must add the capability on gamee.Init";
562 |
563 | core.native.createRequest("saveState", { state: data, share: share });
564 | };
565 |
566 | core.requestSocial = function (cb, numberOfPlayers) {
567 |
568 | if (!cache.capabilities.socialData) throw "Social Data not supported, you must add the capability on gamee.Init";
569 |
570 | this.native.createRequest("requestSocial", numberOfPlayers, function (responseData) {
571 | cb(null, responseData);
572 | });
573 | };
574 |
575 | core.logEvent = function (eventName, eventValue) {
576 |
577 | if (!cache.capabilities.logEvents) throw "Log Events not supported, you must add the capability on gamee.Init";
578 |
579 | //var valuesToLogString = JSON.stringify(eventValue)
580 |
581 | this.native.createRequest("logEvent", { eventName: eventName, eventValue: eventValue }, function (error) {
582 | if (error) {
583 | throw error;
584 | }
585 | });
586 | };
587 |
588 | core.requestBattleData = function (cb) {
589 | this.native.createRequest("requestBattleData", undefined, function (responseData) {
590 | cb(null, responseData);
591 | });
592 | };
593 |
594 | core.requestPlayerReplay = function (userID, cb) {
595 |
596 | if (!cache.capabilities.replay) throw "Replays not supported, you must add the capability on gamee.Init";
597 |
598 | this.native.createRequest("requestPlayerReplay", { userID: userID }, function (responseData) {
599 | cb(null, responseData);
600 | });
601 | };
602 |
603 | core.requestPlayerSaveState = function (userID, cb) {
604 | this.native.createRequest("requestPlayerSaveState", { userID: userID }, function (responseData) {
605 | cb(null, responseData);
606 | });
607 | };
608 |
609 | core.purchaseItemWithCoins = function (options, cb, oldMethod) {
610 |
611 | if (!cache.capabilities.coins) throw "Coins purchases not supported, you must add the capability on gamee.Init";
612 |
613 | if (options) {
614 | var propertiesList = ["coinsCost", "itemName"];
615 | propertiesList.forEach(function (property) {
616 | if (!options.hasOwnProperty(property)) throw "Purchase Options must have `" + property + "` property";
617 | });
618 | }
619 |
620 | if (!this.isSilentModeEnabled()) {
621 | console.log(options);
622 | }
623 |
624 | var method = "purchaseItemWithCoins";
625 | if (oldMethod !== undefined && oldMethod === true) {
626 | method = "purchaseItem";
627 | }
628 | this.native.createRequest(method, options, function (responseData) {
629 | cb(null, responseData);
630 | });
631 | };
632 |
633 | core.purchaseItemWithGems = function (options, cb) {
634 |
635 | if (!cache.capabilities.gems) throw "Gems purchases not supported, you must add the capability on gamee.Init";
636 |
637 | if (options) {
638 | var propertiesList = ["gemsCost", "itemName"];
639 | propertiesList.forEach(function (property) {
640 | if (!options.hasOwnProperty(property)) throw "Purchase options must have `" + property + "` property";
641 | });
642 | }
643 |
644 | if (!this.isSilentModeEnabled()) {
645 | console.log(options);
646 | }
647 |
648 | this.native.createRequest("purchaseItemWithGems", options, function (responseData) {
649 | cb(null, responseData);
650 | });
651 | };
652 |
653 | core.share = function (options, cb) {
654 |
655 | if (!cache.capabilities.share) throw "Share option not supported, you must add the capability on gamee.Init";
656 |
657 | if (options) {
658 | var propertiesList = ["destination"];
659 | propertiesList.forEach(function (property) {
660 | if (!options.hasOwnProperty(property)) throw "Share Options must have `" + property + "` property";
661 | });
662 | }
663 |
664 | if (!this.isSilentModeEnabled()) {
665 | console.log(options);
666 | }
667 |
668 | this.native.createRequest("share", options, function (responseData) {
669 | cb(null, responseData);
670 | });
671 | };
672 |
673 | core.loadRewardedVideo = function (cb) {
674 |
675 | if (!cache.capabilities.rewardedAds) throw "Rewarded Ads not supported, you must add the capability on gamee.Init";
676 |
677 | this.native.createRequest("loadRewardedVideo", function (responseData) {
678 | cb(null, responseData);
679 | });
680 | };
681 |
682 | core.showRewardedVideo = function (cb) {
683 |
684 | if (!cache.capabilities.rewardedAds) throw "Rewarded Ads not supported, you must add the capability on gamee.Init";
685 |
686 | this.native.createRequest("showRewardedVideo", function (responseData) {
687 | cb(null, responseData);
688 | });
689 | };
690 |
691 | core.requestPlayerData = function (cb, userID) {
692 |
693 | if (!cache.capabilities.playerData) throw "Player Data not supported, you must add the capability on gamee.Init";
694 |
695 | var options = undefined;
696 | if (userID) {
697 | options = { userID: userID };
698 | }
699 |
700 | this.native.createRequest("requestPlayerData", options, function (responseData) {
701 | cb(null, responseData);
702 | });
703 | };
704 |
705 | core.startSignal = function (data) {
706 | var error;
707 |
708 | if (data.replay && !cache.capabilities.replay) error = "Game doesn't support replay. ";
709 |
710 | if (data.ghostMode && !cache.capabilities.ghostMode) error = "Game doesn't support ghost Mode. ";
711 |
712 | return error;
713 | };
714 | //
715 | // ## Private objects and methods
716 | // These are internal objects in closed scope. Good to know about them
717 | // when debugging.
718 |
719 | //
720 | // ## gamee.controller
721 | //
722 | // Namespace where the methods for controller are published.
723 | //
724 |
725 | /**
726 | * TODO transform this into instance of gamee class
727 | */
728 | core.controller = {
729 | /** ### mainController
730 | *
731 | * Current controller.
732 | */
733 | mainController: null,
734 |
735 | /** ### requestController
736 | *
737 | * Factory method to create a controller. It creates the controller
738 | * and signals to GameeApp which type the game requires
739 | *
740 | * You should called this method once before calling
741 | * `gamee.gameStart()`.
742 | *
743 | * @param {String} type type of controller (see [controllerTypes](#controllertypes))
744 | * @param {Object} [opts] optional controller options
745 | * {'enableKeyboard': .., 'buttons': ...}
746 | * @param {boolean} [opts.enableKeyboard] enable the keyboard
747 | * @param {Object} [opts.buttons] remap buttons {'oldKey': 'newKey',
748 | * 'left': 'break' ..}
749 | */
750 | requestController: function requestController(type, opts) {
751 | if (type === "FullScreen") return null;
752 |
753 | var controller = createController(type, opts);
754 |
755 | this.mainController = controller;
756 |
757 | return controller;
758 | },
759 |
760 | /** ### additionalController
761 | *
762 | * Construct an additional controller. Sometimes games require a
763 | * different controller depending on platform (eg. touch on mobile,
764 | e but Four Buttons on desktop)
765 | *
766 | * **This is currently supported only for GameeWebApp** as a way to
767 | * have alternate keybinding. The game should request a type used
768 | * for mobile platform and then some other as *additionalController*
769 | * if alternate keybinding is needed;
770 | */
771 | // TODO remove this function
772 | additionalController: function additionalController(type, opts) {
773 | var controller = createController(type, opts);
774 | gameeNative.additionalController(type);
775 |
776 | return controller;
777 | },
778 |
779 | /** ### trigger
780 | *
781 | * Triggers and event for the controller
782 | *
783 | * This is called by GameeApp to trigger the *keydown*, *keyup*
784 | * events. For more info see [Controller](#controller)
785 | *
786 | * @param {String} eventName name of the event
787 | * @param {*} [data,...] data to pass for the event
788 | *
789 | */
790 | trigger: function trigger() {
791 | var i;
792 |
793 | if (this.mainController) {
794 | this.mainController.trigger.apply(this.mainController, arguments);
795 | } else {
796 | throw new Error('No controller present');
797 | }
798 | }
799 | };
800 |
801 | /** ### core._keydown
802 | *
803 | * A helper function to listen for `keydown` events on window object.
804 | *
805 | * @param {Function} fn callback to handle the event
806 | */
807 | core._keydown = function (fn) {
808 | global.addEventListener('keydown', (0, _shims.wrapKeyEvent)(fn));
809 | };
810 |
811 | /** ### core._keyup
812 | *
813 | * A helper function to listen for `keyup` events on window object.
814 | *
815 | * @param {Function} fn callback to handle the event
816 | */
817 | core._keyup = function (fn) {
818 | global.addEventListener('keyup', (0, _shims.wrapKeyEvent)(fn));
819 | };
820 |
821 | /** ### createController
822 | *
823 | * Function to create a controller.
824 | *
825 | * *see [requestController](#requestcontroller)
826 | *
827 | * @param {String} type
828 | * @param {Object} [opts]
829 | * @returns {Controller} controller
830 | */
831 | function createController(type, opts) {
832 | var btn, controller;
833 |
834 | if (!controllerTypes[type]) {
835 | throw new Error('Unsupported controller type, ' + type);
836 | }
837 |
838 | opts = opts || {};
839 |
840 | controller = new controllerTypes[type]();
841 |
842 | if (opts.enableKeyboard) {
843 | controller.enableKeyboard(core);
844 | }
845 |
846 | if (opts.buttons) {
847 | for (btn in opts.buttons) {
848 | controller.remapButton(btn, opts.buttons[btn]);
849 | }
850 | }
851 |
852 | return controller;
853 | }
854 |
855 | /** ### controllerTypes
856 | *
857 | * List of controller types and their coresponding classes.
858 | *
859 | * *see [Controllers](#controllers) for more info*
860 | * @requires Controller
861 | */
862 | var controllerTypes = {
863 | 'OneButton': controllers.OneButtonController,
864 | 'TwoButtons': controllers.TwoButtonController,
865 | 'FourButtons': controllers.FourButtonController,
866 | 'FiveButtons': controllers.FiveButtonController,
867 | 'SixButtons': controllers.SixButtonController,
868 | 'FourArrows': controllers.FourArrowController,
869 | 'Touch': controllers.TouchController,
870 | 'Joystick': controllers.JoystickController,
871 | 'JoystickWithButton': controllers.JoystickButtonController,
872 | 'TwoArrowsTwoButtons': controllers.TwoArrowsTwoButtonsController,
873 | 'TwoArrowsOneButton': controllers.TwoArrowsOneButtonController,
874 | 'TwoActionButtons': controllers.TwoActionButtonsController
875 | };
876 |
877 | core.registerPlatform = function (platformAPI) {
878 | // platformAPI.addEventListener()
879 | // TODO ?
880 | };
881 |
882 | /**
883 | * Is true mute all console outputs
884 | * @return {boolean}
885 | */
886 | core.isSilentModeEnabled = function () {
887 | return cache.silentMode;
888 | };
889 |
890 | return core;
891 | }();
892 |
893 | var DataTypeException = exports.DataTypeException = function DataTypeException(expected, present, argument, method) {
894 | this.expected = expected;
895 | this.present = present;
896 | this.method = method;
897 | this.argument = argument;
898 | this.message = "Invalid data type in method " + this.method + ", argument " + this.argument + " is expected to be " + this.expected + ", but found " + this.present;
899 | };
900 |
901 | var validateDataType = exports.validateDataType = function validateDataType(testedInput, expectedType, argument, originMethod) {
902 | switch (expectedType) {
903 |
904 | case "array":
905 | if (!Array.isArray(testedInput)) throw new DataTypeException(expectedType, typeof testedInput === "undefined" ? "undefined" : _typeof(testedInput), argument, originMethod);
906 | break;
907 |
908 | default:
909 | if ((typeof testedInput === "undefined" ? "undefined" : _typeof(testedInput)) !== expectedType) throw new DataTypeException(expectedType, typeof testedInput === "undefined" ? "undefined" : _typeof(testedInput), argument, originMethod);
910 | }
911 | };
912 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(7)))
913 |
914 | /***/ }),
915 | /* 2 */
916 | /***/ (function(module, exports, __webpack_require__) {
917 |
918 | "use strict";
919 |
920 |
921 | Object.defineProperty(exports, "__esModule", {
922 | value: true
923 | });
924 | exports.Gamee = exports.GameeEmitter = undefined;
925 |
926 | var _core = __webpack_require__(1);
927 |
928 | var _shims = __webpack_require__(0);
929 |
930 | /**
931 | * gameeAPI module desc
932 | * @module gameeAPI
933 | */
934 |
935 | /**
936 | * Emit events
937 | * @class GameeEmitter
938 | * @extends CustomEmitter
939 | */
940 | var GameeEmitter = exports.GameeEmitter = function GameeEmitter() {
941 | _shims.CustomEmitter.call(this);
942 | };
943 |
944 | /**
945 | * @class Gamee
946 | * @requires core
947 | *
948 | */
949 | var Gamee = exports.Gamee = function Gamee(platform) {
950 | /**
951 | * @instance
952 | *
953 | * @fires gameeAPI:GameeEmitter~start
954 | * @fires gameeAPI:GameeEmitter~mute
955 | * @fires gameeAPI:GameeEmitter~unmute
956 | * @fires gameeAPI:GameeEmitter~pause
957 | * @fires gameeAPI:GameeEmitter~unpause
958 | * @fires gameeAPI:GameeEmitter~ghostHide
959 | * @fires gameeAPI:GameeEmitter~ghostShow
960 | */
961 | this.emitter = new GameeEmitter();
962 | this._platform = platform;
963 | };
964 |
965 | Gamee.prototype = function () {
966 |
967 | var cbError = function cbError(err) {
968 | if (err) {
969 | throw "Error " + err.toString();
970 | }
971 | };
972 |
973 | return {
974 | _controller: _core.core.controller,
975 | /**
976 | * gameInit
977 | * @memberof Gamee
978 | * @param {string} controllType
979 | * @param {object} controllOpts
980 | * @param {string[]} capabilities
981 | * @param {gameInitCallback} cb
982 | * @param {boolean} silentMode
983 | */
984 | gameInit: function gameInit(controllType, controllOpts, capabilities, cb) {
985 | var silentMode = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
986 |
987 | (0, _core.validateDataType)(controllType, "string", "controllType", "gamee.updateScore");
988 | (0, _core.validateDataType)(controllOpts, "object", "controllOpts", "gamee.gameInit");
989 | (0, _core.validateDataType)(capabilities, "array", "capabilities", "gamee.gameInit");
990 | (0, _core.validateDataType)(cb, "function", "cb", "gamee.gameInit");
991 | (0, _core.validateDataType)(silentMode, "boolean", "silentMode", "gamee.gameInit");
992 | var result = _core.core.gameeInit(controllType, controllOpts, capabilities, cb, silentMode);
993 | // cb(null, result);
994 | },
995 |
996 | /**
997 | * gameLoadingProgress
998 | *
999 | * gamee.gameLoadingProgress()
1000 | *
1001 | * @memberof Gamee
1002 | * @param {number} percentage current loading progress
1003 | * @param {Gamee~voidCallback} [opt_cb]
1004 | *
1005 | */
1006 | gameLoadingProgress: function gameLoadingProgress(percentage, opt_cb) {
1007 | (0, _core.validateDataType)(percentage, "number", "percentage", "gamee.gameLoadingProgress");
1008 | opt_cb = opt_cb || cbError;
1009 | (0, _core.validateDataType)(opt_cb, "function", "opt_cb", "gamee.gameLoadingProgress");
1010 | _core.core.gameLoadingProgress(percentage);
1011 | opt_cb(null);
1012 | },
1013 |
1014 | /**
1015 | * gameReady
1016 | *
1017 | * @memberof Gamee
1018 | * @param {Gamee~voidCallback} [opt_cb]
1019 | */
1020 | gameReady: function gameReady(opt_cb) {
1021 | opt_cb = opt_cb || cbError;
1022 | (0, _core.validateDataType)(opt_cb, "function", "opt_cb", "gamee.gameReady");
1023 | _core.core.gameReady();
1024 | opt_cb(null);
1025 | },
1026 |
1027 | /**
1028 | * gameSave
1029 | *
1030 | * NOTE: There are 2 signatures for this function
1031 | *
1032 | * gamee.gameSave(data, opt_cb)
1033 | * gamee.gameSave(data, opt_share, opt_cb)
1034 | *
1035 | * @memberof Gamee
1036 | * @param {String} data current ingame progress
1037 | * @param {Boolean} [opt_share=false]
1038 | * @param {Gamee~voidCallback} [opt_cb]
1039 | *
1040 | */
1041 | gameSave: function gameSave(data, opt_share, opt_cb) {
1042 | var share = false,
1043 | cb;
1044 | (0, _core.validateDataType)(data, "string", "data", "gamee.gameSave");
1045 | if (typeof opt_share === 'function') opt_cb = opt_share;else if (typeof opt_share !== "undefined") (0, _core.validateDataType)(opt_share, "boolean", "opt_share", "gamee.gameSave");
1046 |
1047 | opt_cb = opt_cb || cbError;
1048 | (0, _core.validateDataType)(opt_cb, "function", "opt_cb", "gamee.gameSave");
1049 | _core.core.gameSave(data, share);
1050 | opt_cb(null);
1051 | },
1052 |
1053 | /**
1054 | * getPlatform
1055 | *
1056 | * @memberof Gamee
1057 | * @returns {string} platform type can be android | ios | web | fb
1058 | */
1059 | getPlatform: function getPlatform() {
1060 | return this._platform;
1061 | },
1062 |
1063 | /**
1064 | * updateScore
1065 | *
1066 | * @memberof Gamee
1067 | * @param {number} score
1068 | * @param {boolean} [opt_ghostSign=false] If true, score will be updated for ghost instead.
1069 | * @param {Gamee~voidCallback} [opt_cb]
1070 | */
1071 | updateScore: function updateScore(score, opt_ghostSign, opt_cb) {
1072 | (0, _core.validateDataType)(score, "number", "score", "gamee.updateScore");
1073 | if (typeof opt_ghostSign === "function") opt_cb = opt_ghostSign;else if (typeof opt_ghostSign !== "undefined") (0, _core.validateDataType)(opt_ghostSign, "boolean", "opt_ghostSign", "gamee.updateScore");
1074 |
1075 | opt_cb = opt_cb || cbError;
1076 | (0, _core.validateDataType)(opt_cb, "function", "opt_cb", "gamee.updateScore");
1077 | _core.core.updateScore(score, opt_ghostSign);
1078 | opt_cb(null);
1079 | },
1080 |
1081 | /**
1082 | * gameOver
1083 | *
1084 | * @memberof Gamee
1085 | * @param {Gamee~ReplayData} [opt_replayData]
1086 | * @param {Gamee~voidCallback} [opt_cb]
1087 | * @param {Gamee~object} [opt_saveState]
1088 | * @param {Gamee~boolean} [opt_hideOverlay]
1089 | */
1090 | gameOver: function gameOver(opt_replayData, opt_cb, opt_saveState, opt_hideOverlay) {
1091 | if (typeof opt_replayData === "function") opt_cb = opt_replayData;else if (typeof opt_replayData !== "undefined") (0, _core.validateDataType)(opt_replayData, "object", "opt_replayData", "gamee.gameOver");
1092 |
1093 | if (typeof opt_hideOverlay !== 'undefined') {
1094 | (0, _core.validateDataType)(opt_hideOverlay, "boolean", "opt_hideOverlay", "gamee.gameOver");
1095 | }
1096 |
1097 | opt_cb = opt_cb || cbError;
1098 | (0, _core.validateDataType)(opt_cb, "function", "opt_cb", "gamee.gameOver");
1099 | _core.core.gameOver(opt_replayData, opt_saveState, opt_hideOverlay);
1100 | opt_cb(null);
1101 | },
1102 |
1103 | /**
1104 | * requestSocialData
1105 | *
1106 | * @memberof Gamee
1107 | * @param {Gamee~requestSocialDataCallback} cb
1108 | * @param {number} numberOfPlayers
1109 | */
1110 | requestSocial: function requestSocial(cb, numberOfPlayers) {
1111 | (0, _core.validateDataType)(cb, "function", "cb", "gamee.requestSocial");
1112 |
1113 | // functionality supposed to be removed once we do update for iOS
1114 | var data = _core.core.requestSocial(function (error, responseData) {
1115 | var modifiedResponse = !responseData.hasOwnProperty("socialData") ? { socialData: responseData } : responseData;
1116 | cb(null, modifiedResponse);
1117 | }, numberOfPlayers);
1118 |
1119 | // var data = core.requestSocial(cb);
1120 | //cb(null, data);
1121 | },
1122 |
1123 | /**
1124 | * logEvent
1125 | *
1126 | * @memberof Gamee
1127 | * @param {string} eventName
1128 | * @param {string} eventValue
1129 | */
1130 | logEvent: function logEvent(eventName, eventValue) {
1131 |
1132 | (0, _core.validateDataType)(eventName, "string", "eventName", "gamee.logEvent");
1133 |
1134 | if (!eventName || eventName.length > 24) {
1135 | console.error("eventName parameter cant be null and can only contain up to 24 characters");
1136 | return;
1137 | }
1138 |
1139 | (0, _core.validateDataType)(eventValue, "string", "eventValue", "gamee.logEvent");
1140 |
1141 | if (!eventValue || eventValue.length > 160) {
1142 | console.error("eventValue parameter cant be null and can only contain up to 160 characters");
1143 | return;
1144 | }
1145 |
1146 | _core.core.logEvent(eventName, eventValue);
1147 | },
1148 |
1149 | /**
1150 | * requestBattleData
1151 | *
1152 | * @memberof Gamee
1153 | * @param {Gamee~requestBattleDataDataCallback} cb
1154 | */
1155 | requestBattleData: function requestBattleData(cb) {
1156 | (0, _core.validateDataType)(cb, "function", "cb", "gamee.requestBattleData");
1157 |
1158 | _core.core.requestBattleData(cb);
1159 | },
1160 |
1161 | /**
1162 | * requestPlayerReplay
1163 | *
1164 | * @memberof Gamee
1165 | * @param {number} userID
1166 | * @param {Gamee~requestPlayerReplayDataCallback} cb
1167 | */
1168 | requestPlayerReplay: function requestPlayerReplay(userID, cb) {
1169 |
1170 | (0, _core.validateDataType)(userID, "number", "userID", "gamee.requestPlayerReplay");
1171 | (0, _core.validateDataType)(cb, "function", "cb", "gamee.requestPlayerReplay");
1172 |
1173 | _core.core.requestPlayerReplay(userID, cb);
1174 | },
1175 |
1176 | /**
1177 | * requestPlayerSaveState
1178 | *
1179 | * @memberof Gamee
1180 | * @param {number} userID
1181 | * @param {Gamee~requestPlayerSaveStateDataCallback} cb
1182 | */
1183 | requestPlayerSaveState: function requestPlayerSaveState(userID, cb) {
1184 |
1185 | (0, _core.validateDataType)(userID, "number", "userID", "gamee.requestPlayerSaveState");
1186 | (0, _core.validateDataType)(cb, "function", "cb", "gamee.requestPlayerSaveState");
1187 |
1188 | _core.core.requestPlayerSaveState(userID, cb);
1189 | },
1190 |
1191 | /*
1192 | *purchaseItem
1193 | *@member of Gamee
1194 | *@param {object} purchaseDetails
1195 | *@param {Gamee~purchaseItemDataCallback} cb
1196 | */
1197 | purchaseItem: function purchaseItem(purchaseDetails, cb) {
1198 |
1199 | (0, _core.validateDataType)(purchaseDetails, "object", "purchaseDetails", "gamee.purchaseItem");
1200 | (0, _core.validateDataType)(cb, "function", "cb", "gamee.purchaseItem");
1201 |
1202 | _core.core.purchaseItemWithCoins(purchaseDetails, cb, true);
1203 | },
1204 |
1205 | /*
1206 | *purchaseItemWithCoins
1207 | *@member of Gamee
1208 | *@param {object} purchaseDetails
1209 | *@param {Gamee~purchaseItemDataCallback} cb
1210 | */
1211 | purchaseItemWithCoins: function purchaseItemWithCoins(purchaseDetails, cb) {
1212 | (0, _core.validateDataType)(purchaseDetails, "object", "purchaseDetails", "gamee.purchaseItemWithCoins");
1213 | (0, _core.validateDataType)(cb, "function", "cb", "gamee.purchaseItemWithCoins");
1214 |
1215 | _core.core.purchaseItemWithCoins(purchaseDetails, cb);
1216 | },
1217 |
1218 | /*
1219 | *purchaseItemWithGems
1220 | *@member of Gamee
1221 | *@param {object} purchaseDetails
1222 | *@param {Gamee~purchaseItemWithGemsDataCallback} cb
1223 | */
1224 | purchaseItemWithGems: function purchaseItemWithGems(purchaseDetails, cb) {
1225 |
1226 | (0, _core.validateDataType)(purchaseDetails, "object", "purchaseDetails", "gamee.purchaseItemWithGems");
1227 | (0, _core.validateDataType)(cb, "function", "cb", "gamee.purchaseItemWithGems");
1228 |
1229 | _core.core.purchaseItemWithGems(purchaseDetails, cb);
1230 | },
1231 |
1232 | /*share
1233 | *@member of Gamee
1234 | *@param {object} shareDetails
1235 | *@param {Gamee~shareDataCallback} cb
1236 | */
1237 | share: function share(shareDetails, cb) {
1238 | (0, _core.validateDataType)(shareDetails, "object", "shareDetails", "gamee.share");
1239 | (0, _core.validateDataType)(cb, "function", "cb", "gamee.share");
1240 |
1241 | _core.core.share(shareDetails, cb);
1242 | },
1243 |
1244 | /*
1245 | *loadRewardedVideo
1246 | *@member of Gamee
1247 | *@param {Gamee~loadRewardedVideo} cb
1248 | */
1249 | loadRewardedVideo: function loadRewardedVideo(cb) {
1250 |
1251 | (0, _core.validateDataType)(cb, "function", "cb", "gamee.loadRewardedVideo");
1252 | _core.core.loadRewardedVideo(cb);
1253 | },
1254 |
1255 | /*
1256 | *showRewardedVideo
1257 | *@member of Gamee
1258 | *@param{Gamee~showRewardedVideo} cb
1259 | */
1260 | showRewardedVideo: function showRewardedVideo(cb) {
1261 |
1262 | (0, _core.validateDataType)(cb, "function", "cb", "gamee.showRewardedVideo");
1263 | _core.core.showRewardedVideo(cb);
1264 | },
1265 |
1266 | /**
1267 | *requestPlayerData
1268 | *@member of Gamee
1269 | *@param{Gamee~requestPlayerData} cb
1270 | * @param {number} userID
1271 | */
1272 | requestPlayerData: function requestPlayerData(cb, userID) {
1273 |
1274 | (0, _core.validateDataType)(cb, "function", "cb", "gamee.requestPlayerData");
1275 | if (userID !== undefined) {
1276 | (0, _core.validateDataType)(userID, "number", "userId", "gamee.requestPlayerData");
1277 | }
1278 | _core.core.requestPlayerData(cb, userID);
1279 | }
1280 | };
1281 |
1282 | /**
1283 | *
1284 | * @typedef ReplayData
1285 | * @param {string} variant
1286 | * @param {string} data
1287 | */
1288 |
1289 | /**
1290 | * This callback is displayed as part of the Requester class.
1291 | * @callback Gamee~voidCallback
1292 | * @param {string} responseCode
1293 | */
1294 |
1295 | /**
1296 | * This callback is displayed as part of the Requester class.
1297 | * @callback Gamee~gameInitCallback
1298 | * @param {object} data
1299 | * @param {string} responseCode
1300 | */
1301 |
1302 | /**
1303 | * This callback is displayed as part of the Requester class.
1304 | * @callback Gamee~requestSocialDataCallback
1305 | * @param {object} data
1306 | * @param {string} responseCode
1307 | */
1308 | }();
1309 |
1310 | /**
1311 | * Signals that game should start as normal|replay|ghost game.
1312 | * Signal means there is no overlay over the game.
1313 | * This signal is also being used for game restart. If previous
1314 | * instance of the game was running, it should be terminated without
1315 | * any additional calls and current progress should be tossed.
1316 | * @event gameeAPI:GameeEmitter~start
1317 | * @type {object}
1318 | * @property {EventDetailStart} detail - Common property of events
1319 | */
1320 |
1321 | /**
1322 | * Data carried with start event.
1323 | * @typedef EventDetailStart
1324 | * @property {Gamee~voidCallback} callback - called after finishing task
1325 | * @property {boolean} [opt_resetState=false] - if true, game must delete current progress and saved progress
1326 | * @property {boolean} [opt_replay] - if true, game must run in replay mode
1327 | * @property {boolean} [opt_ghostMode] - if true, game must run in ghost mode
1328 | */
1329 |
1330 | /**
1331 | * After that signal, game must silent all sounds immediately.
1332 | * Game must remain silent until unmute signal occures.
1333 | * @event gameeAPI:GameeEmitter~mute
1334 | * @type {object}
1335 | * @property {EventDetailVoid} detail - Common property of events
1336 | */
1337 |
1338 | /**
1339 | * After unmute signal, game can play sounds again.
1340 | * @event gameeAPI:GameeEmitter~unmute
1341 | * @type {object}
1342 | * @property {EventDetailVoid} detail - Common property of events
1343 | */
1344 |
1345 | /**
1346 | * Pause signal means there appeared overlay over the game. Player
1347 | * is unable to reach the context of the game anymore. So game should
1348 | * pause all its acctions immediately.
1349 | * @event gameeAPI:GameeEmitter~pause
1350 | * @type {object}
1351 | * @property {EventDetailVoid} detail - Common property of events
1352 | */
1353 |
1354 | /**
1355 | * Unpause signal means there is no overlay over the game anymore.
1356 | * Game should continue with all previous actions.
1357 | * @event gameeAPI:GameeEmitter~unpause
1358 | * @type {object}
1359 | * @property {EventDetailVoid} detail - Common property of events
1360 | */
1361 |
1362 | /**
1363 | * Signal ghostHide can appear only if game is running in ghost mode.
1364 | * Game should hide ghost behavior and look like exactly as game without
1365 | * the ghost (if this is possible).
1366 | * @event gameeAPI:GameeEmitter~ghostHide
1367 | * @type {object}
1368 | * @property {EventDetailVoid} detail - Common property of events
1369 | */
1370 |
1371 | /**
1372 | * Signal ghostShow can appear only if game is running in ghost mode.
1373 | * Game should show ghost again if it was hidden. If ghost died or ended
1374 | * while it was hidden, game should point that out, so the player can understand
1375 | * why the ghost is not visible anymore.
1376 | * @event gameeAPI:GameeEmitter~ghostShow
1377 | * @type {object}
1378 | * @property {EventDetailVoid} detail - Common property of events
1379 | */
1380 |
1381 | /**
1382 | * Data carried with various events. Contains only callback method.
1383 | * @typedef {object} EventDetailVoid
1384 | * @property {Gamee~voidCallback} callback - call after finishing task
1385 | */
1386 |
1387 | /**
1388 | * @type {function}
1389 | * @param {MyEvent} e - The observable event.
1390 | * @listens gameeAPI:GameeEmitter~event:snowball
1391 | */
1392 |
1393 | /***/ }),
1394 | /* 3 */
1395 | /***/ (function(module, exports, __webpack_require__) {
1396 |
1397 | "use strict";
1398 |
1399 |
1400 | Object.defineProperty(exports, "__esModule", {
1401 | value: true
1402 | });
1403 | exports.PlatformAPI = undefined;
1404 |
1405 | var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
1406 |
1407 | exports.PlatformBridge = PlatformBridge;
1408 | exports.PostMessageBridge = PostMessageBridge;
1409 | exports.MobileBridge = MobileBridge;
1410 |
1411 | var _core = __webpack_require__(1);
1412 |
1413 | /**
1414 | *
1415 | * @requires core
1416 | *
1417 | * @typedef PlatformAPI
1418 | * @param {EventTarget} emitter
1419 | * @param {function} _pause
1420 | * @param {function} _resume
1421 | * @param {function} _ghostShow
1422 | * @param {function} _ghostHide
1423 | * @param {function} _mute
1424 | * @param {function} _unmute
1425 | * @param {function} _start
1426 | */
1427 | var PlatformAPI = exports.PlatformAPI = {
1428 | emitter: null,
1429 | pause: function pause(cb) {
1430 | var event = new CustomEvent('pause', {
1431 | detail: {
1432 | callback: cb
1433 | }
1434 | });
1435 | this.emitter.dispatchEvent(event);
1436 | },
1437 | resume: function resume(cb) {
1438 | var event = new CustomEvent('resume', {
1439 | detail: {
1440 | callback: cb
1441 | }
1442 | });
1443 | this.emitter.dispatchEvent(event);
1444 | },
1445 | ghostShow: function ghostShow(cb) {
1446 | var event = new CustomEvent('ghostShow', {
1447 | detail: {
1448 | callback: cb
1449 | }
1450 | });
1451 | this.emitter.dispatchEvent(event);
1452 | },
1453 | ghostHide: function ghostHide(cb) {
1454 | var event = new CustomEvent('ghostHide', {
1455 | detail: {
1456 | callback: cb
1457 | }
1458 | });
1459 | this.emitter.dispatchEvent(event);
1460 | },
1461 | mute: function mute(cb) {
1462 | var event = new CustomEvent('mute', {
1463 | detail: {
1464 | callback: cb
1465 | }
1466 | });
1467 | this.emitter.dispatchEvent(event);
1468 | },
1469 | unmute: function unmute(cb) {
1470 | var event = new CustomEvent('unmute', {
1471 | detail: {
1472 | callback: cb
1473 | }
1474 | });
1475 | this.emitter.dispatchEvent(event);
1476 | },
1477 | start: function start(data, cb) {
1478 | var event = new CustomEvent('start', {
1479 | detail: {
1480 | callback: cb
1481 | }
1482 | });
1483 |
1484 | var error = _core.core.startSignal(data);
1485 | if (error) {
1486 | cb(error);
1487 | return;
1488 | }
1489 |
1490 | if (data.replay) event.detail.opt_replay = true;
1491 | if (data.ghostMode) event.detail.opt_ghostMode = true;
1492 | if (data.resetState) event.detail.opt_resetState = true;
1493 | if (data.replayData) {
1494 | event.detail.replayData = data.replayData;
1495 | }
1496 |
1497 | this.emitter.dispatchEvent(event);
1498 | }
1499 | };
1500 |
1501 | /**
1502 | * @class PlatformBridge
1503 | *
1504 | */
1505 | function PlatformBridge() {
1506 | this.requests = {};
1507 | this.platform = "";
1508 | this._init();
1509 | }
1510 |
1511 | PlatformBridge.prototype = {
1512 | instCount: 0,
1513 | _init: function _init() {},
1514 | createRequest: function createRequest(method, opt_requestData, opt_callback) {
1515 | if (!this.validateMethod(method)) return;
1516 | if (typeof opt_requestData === 'function') {
1517 | opt_callback = opt_requestData;
1518 | opt_requestData = undefined;
1519 | }
1520 |
1521 | var messId = this.instCount++;
1522 |
1523 | if (typeof opt_callback !== 'undefined') {
1524 | this.requests[messId] = opt_callback;
1525 | }
1526 |
1527 | var preparedObject = {
1528 | request: {
1529 | method: method,
1530 | messageId: messId,
1531 | data: null
1532 | }
1533 | };
1534 |
1535 | this.doCall(preparedObject, opt_requestData);
1536 | },
1537 | validateMethod: function validateMethod(method) {
1538 | return method === "gameLoadingProgress" ? false : true;
1539 | },
1540 | /**
1541 | * @abstract
1542 | */
1543 | doCall: function doCall(preparedObject, requestData) {
1544 | throw "Not implemented";
1545 | },
1546 | _callback: function _callback(id, responseData) {
1547 | var cb = this.requests[id];
1548 | delete this.requests[id];
1549 | if (cb) cb(responseData);
1550 | },
1551 | /**
1552 | * @abstract
1553 | */
1554 | doResponse: function doResponse(preparedObject, responseData) {
1555 | throw "Not implemented";
1556 | }
1557 | };
1558 |
1559 | /**
1560 | * @class PostMessageBridge
1561 | * @requires PlatformBridge
1562 | */
1563 | function PostMessageBridge(endpoint) {
1564 | this._gameeWin = endpoint;
1565 | PlatformBridge.call(this);
1566 | this.platform = "web";
1567 | }
1568 |
1569 | PostMessageBridge.prototype = Object.create(PlatformBridge.prototype);
1570 | PostMessageBridge.prototype.constructor = PostMessageBridge;
1571 |
1572 | PostMessageBridge.prototype._init = function () {
1573 |
1574 | window.addEventListener('message', function (ev) {
1575 | // if(ev.origin === "source we want")
1576 | // console.log("_triggerMessage detail: " + ev.detail);
1577 | // console.log("_triggerMessage data: " + ev.data);
1578 | var data;
1579 | if (_typeof(ev.detail) === "object" && typeof ev.detail !== null) {
1580 | data = ev.detail;
1581 | } else if (_typeof(ev.data) === "object") {
1582 | data = ev.data;
1583 | } else {
1584 | // message is not from native platform
1585 | return;
1586 | }
1587 |
1588 | if (!_core.core.isSilentModeEnabled()) {
1589 | console.log(JSON.stringify(data, null, 4) + ' data');
1590 | }
1591 | // this is request
1592 | if (data.request && data.request.method && typeof data.request.messageId !== "undefined") {
1593 | this._resolveAPICall(data.request.method, data.request.messageId, data.request.data);
1594 | }
1595 | // this is reponse
1596 | else if (data.response && typeof data.response.messageId !== "undefined") {
1597 | if (data.error) throw data.error;
1598 | this._callback(data.response.messageId, data.response.data);
1599 | }
1600 | // else this message target is not this framework
1601 | }.bind(this), false);
1602 | };
1603 |
1604 | PostMessageBridge.prototype.doCall = function (preparedObject, requestData) {
1605 | if ((typeof requestData === 'undefined' ? 'undefined' : _typeof(requestData)) === "object") {
1606 | preparedObject.request.data = requestData || {};
1607 | }
1608 | this._gameeWin.postMessage(preparedObject, "*");
1609 | };
1610 |
1611 | PostMessageBridge.prototype.doResponse = function (messageId, responseData) {
1612 | var preparedObject = {
1613 | version: this.version,
1614 | response: {
1615 | messageId: messageId
1616 | }
1617 | };
1618 |
1619 | if (responseData) preparedObject.data = responseData;
1620 |
1621 | this._gameeWin.postMessage(preparedObject, "*");
1622 | };
1623 |
1624 | PostMessageBridge.prototype._resolveAPICall = function (method, messageId, opt_data) {
1625 | var cb = this.doResponse.bind(this, messageId);
1626 |
1627 | switch (method) {
1628 | case "pause":
1629 | PlatformAPI.pause(cb);
1630 | break;
1631 | case "resume":
1632 | PlatformAPI.resume(cb);
1633 | break;
1634 | case "mute":
1635 | PlatformAPI.mute(cb);
1636 | break;
1637 | case "unmute":
1638 | PlatformAPI.unmute(cb);
1639 | break;
1640 | case "ghostShow":
1641 | PlatformAPI.ghostShow(cb);
1642 | break;
1643 | case "ghostHide":
1644 | PlatformAPI.ghostHide(cb);
1645 | break;
1646 | case "start":
1647 | if (!opt_data) {
1648 | throw "Method _start missing params";
1649 | }
1650 | PlatformAPI.start(opt_data, cb);
1651 | break;
1652 | default:
1653 | if (!_core.core.isSilentModeEnabled()) {
1654 | console.error("Unknown method call");
1655 | }
1656 | }
1657 | };
1658 |
1659 | /**
1660 | * @class MobileBridge
1661 | * @requires PlatformBridge
1662 | *
1663 | */
1664 | function MobileBridge(device) {
1665 | this.device = device;
1666 | PostMessageBridge.call(this);
1667 | this.platform = "mobile";
1668 | }
1669 |
1670 | MobileBridge.prototype = Object.create(PostMessageBridge.prototype);
1671 | MobileBridge.prototype.constructor = MobileBridge;
1672 |
1673 | MobileBridge.prototype._init = function () {
1674 | PostMessageBridge.prototype._init.call(this);
1675 | if (this.device === "ios") {
1676 | this._gameeWin = webkit.messageHandlers.callbackHandler;
1677 | } else if (this.device === "android") {
1678 | this._gameeWin = _toDevice;
1679 | } else {
1680 | throw "Unknown device used in webkit bridge";
1681 | }
1682 |
1683 | window._triggerMessage = function (data) {
1684 | try {
1685 | data = JSON.parse(data); // message is custom message from IOS/android platform
1686 | } catch (err) {
1687 | throw "Couldn't parse message from native app: \n" + data + "\n" + err;
1688 | }
1689 | if (!_core.core.isSilentModeEnabled()) {
1690 | console.log(JSON.stringify(data, null, 4));
1691 | }
1692 | this.dispatchEvent(new CustomEvent("message", { detail: data }));
1693 | }.bind(window);
1694 | };
1695 |
1696 | MobileBridge.prototype.doCall = function (preparedObject, requestData) {
1697 | if ((typeof requestData === 'undefined' ? 'undefined' : _typeof(requestData)) === "object") {
1698 | preparedObject.request.data = requestData || {};
1699 | }
1700 |
1701 | if (this.device === "android") // stringify data for android devices, but not for ios
1702 | preparedObject = JSON.stringify(preparedObject);
1703 |
1704 | this._gameeWin.postMessage(preparedObject, "*");
1705 | };
1706 |
1707 | /***/ }),
1708 | /* 4 */
1709 | /***/ (function(module, exports, __webpack_require__) {
1710 |
1711 | "use strict";
1712 |
1713 |
1714 | Object.defineProperty(exports, "__esModule", {
1715 | value: true
1716 | });
1717 |
1718 | var BulletClass = function BulletClass() {
1719 | var _self = this,
1720 | _events = {};
1721 |
1722 | _self.on = function (event, fn, once) {
1723 | if (arguments.length < 2 || typeof event !== "string" || typeof fn !== "function") return;
1724 |
1725 | var fnString = fn.toString();
1726 |
1727 | // if the named event object already exists in the dictionary...
1728 | if (typeof _events[event] !== "undefined") {
1729 | // add a callback object to the named event object if one doesn't already exist.
1730 | if (typeof _events[event].callbacks[fnString] === "undefined") {
1731 | _events[event].callbacks[fnString] = {
1732 | cb: fn,
1733 | once: !!once
1734 | };
1735 | } else if (typeof once === "boolean") {
1736 | // the function already exists, so update it's 'once' value.
1737 | _events[event].callbacks[fnString].once = once;
1738 | }
1739 | } else {
1740 | // create a new event object in the dictionary with the specified name and callback.
1741 | _events[event] = {
1742 | callbacks: {}
1743 | };
1744 |
1745 | _events[event].callbacks[fnString] = { cb: fn, once: !!once };
1746 | }
1747 | };
1748 |
1749 | _self.once = function (event, fn) {
1750 | _self.on(event, fn, true);
1751 | };
1752 |
1753 | _self.off = function (event, fn) {
1754 | if (typeof event !== "string" || typeof _events[event] === "undefined") return;
1755 |
1756 | // remove just the function, if passed as a parameter and in the dictionary.
1757 | if (typeof fn === "function") {
1758 | var fnString = fn.toString(),
1759 | fnToRemove = _events[event].callbacks[fnString];
1760 |
1761 | if (typeof fnToRemove !== "undefined") {
1762 | // delete the callback object from the dictionary.
1763 | delete _events[event].callbacks[fnString];
1764 | }
1765 | } else {
1766 | // delete all functions in the dictionary that are
1767 | // registered to this event by deleting the named event object.
1768 | delete _events[event];
1769 | }
1770 | };
1771 |
1772 | _self.trigger = function (event, data) {
1773 | if (typeof event !== "string" || typeof _events[event] === "undefined") return;
1774 |
1775 | for (var fnString in _events[event].callbacks) {
1776 | var callbackObject = _events[event].callbacks[fnString];
1777 |
1778 | if (typeof callbackObject.cb === "function") callbackObject.cb(data);
1779 | if (typeof callbackObject.once === "boolean" && callbackObject.once === true) _self.off(event, callbackObject.cb);
1780 | }
1781 | };
1782 | };
1783 |
1784 | var Bullet = exports.Bullet = new BulletClass();
1785 |
1786 | /***/ }),
1787 | /* 5 */
1788 | /***/ (function(module, exports, __webpack_require__) {
1789 |
1790 | "use strict";
1791 |
1792 |
1793 | Object.defineProperty(exports, "__esModule", {
1794 | value: true
1795 | });
1796 | exports.BulletClass = undefined;
1797 | exports.Button = Button;
1798 | exports.Controller = Controller;
1799 | exports.OneButtonController = OneButtonController;
1800 | exports.TwoButtonController = TwoButtonController;
1801 | exports.TwoActionButtonsController = TwoActionButtonsController;
1802 | exports.FourButtonController = FourButtonController;
1803 | exports.FiveButtonController = FiveButtonController;
1804 | exports.SixButtonController = SixButtonController;
1805 | exports.TwoArrowsOneButtonController = TwoArrowsOneButtonController;
1806 | exports.TwoArrowsTwoButtonsController = TwoArrowsTwoButtonsController;
1807 | exports.FourArrowController = FourArrowController;
1808 | exports.TouchController = TouchController;
1809 | exports.JoystickController = JoystickController;
1810 | exports.JoystickButtonController = JoystickButtonController;
1811 |
1812 | var _bullet = __webpack_require__(4);
1813 |
1814 | /**
1815 | * @module game_controllers
1816 | */
1817 |
1818 | /** ## Bullet
1819 | *
1820 | * [Bullet.js](https://github.com/munkychop/bullet) is used as pub/sub
1821 | * library.
1822 | *
1823 | * The controller and its buttons are instance of Bullet.
1824 | */
1825 | var BulletClass = exports.BulletClass = _bullet.Bullet.constructor;
1826 |
1827 | /** ## Button
1828 | *
1829 | * Represenation of a controller button. It is a child of
1830 | * [Bullet](https://github.com/munkychop/bullet), so you can
1831 | * subscribe for events triggered on it.
1832 | *
1833 | * @class Button
1834 | * @param {String} key name of the button
1835 | * @param {Number} keyCode keycode for the key to represent the button
1836 | * on keyboard
1837 | */
1838 | function Button(key, keyCode) {
1839 | var self = this;
1840 |
1841 | BulletClass.call(this);
1842 |
1843 | this._pressed = true;
1844 |
1845 | this.key = key;
1846 | this.keyCode = keyCode;
1847 |
1848 | this.on('keydown', function () {
1849 | self._pressed = true;
1850 | });
1851 |
1852 | this.on('keyup', function () {
1853 | self._pressed = false;
1854 | });
1855 | }
1856 |
1857 | Button.prototype = Object.create(BulletClass.constructor.prototype);
1858 | Button.constructor = Button;
1859 |
1860 | /** ### isDown
1861 | *
1862 | * Ask if the button is currently pressed.
1863 | *
1864 | * @return {Boolean} true if the button is currently pressed
1865 | */
1866 | Button.prototype.isDown = function () {
1867 | return this._pressed;
1868 | };
1869 |
1870 | /** ## Controller
1871 | *
1872 | * Controller has a collection of [buttons](#buttons).
1873 | * It is a child of
1874 | * [Bullet](https://github.com/munkychop/bullet), so you can
1875 | * subscribe for events triggered on it.
1876 | *
1877 | * Controllers will get all the events for its buttons so you can
1878 | * listen for them globaly from controller or individualy on every
1879 | * button.
1880 | *
1881 | * ```javascript
1882 | * controller.on('keydown', function(data) {
1883 | * console.log('button ' + data.button + ' is pressed');
1884 | * });
1885 | *
1886 | * controller.buttons.left.on('keydown', function() {
1887 | * console.log('button left is pressed');
1888 | * });
1889 | * ```
1890 | *
1891 | * @class Controller
1892 | */
1893 | function Controller() {
1894 | var self = this;
1895 |
1896 | BulletClass.call(this);
1897 |
1898 | // ### buttons
1899 | //
1900 | // Map of controller's [buttons](#button) by their name.
1901 | //
1902 | // ```javascript
1903 | // controller.buttons.left // Button('left', ..)
1904 | // ```
1905 | this.buttons = {};
1906 |
1907 | // ### buttonAlias
1908 | //
1909 | // Map of remapped buttons.
1910 | //
1911 | // *see [remapButton](#remapbutton) for more info*
1912 | //
1913 | this.buttonAlias = {};
1914 |
1915 | // Events prefixed with *$* are private, sent from GameeApp ment
1916 | // to be handled before resended as *public (non-prefixed)*
1917 | // event.
1918 | //
1919 | // They should be not used in games as they can change in the future.
1920 | this.on('$keydown', function (data) {
1921 | if (data.button && self.buttonAlias[data.button]) {
1922 | data.button = self.buttonAlias[data.button];
1923 | }
1924 |
1925 | self.trigger('keydown', data);
1926 | });
1927 |
1928 | this.on('$keyup', function (data) {
1929 | if (data.button && self.buttonAlias[data.button]) {
1930 | data.button = self.buttonAlias[data.button];
1931 | }
1932 |
1933 | self.trigger('keyup', data);
1934 | });
1935 |
1936 | // By default GameeApp will trigger *keydown* and *keyup* events for
1937 | // the controller for every button presses/released.
1938 | //
1939 | // The controller then handles the event and triggers the event for
1940 | // the coresponding button.
1941 | //
1942 | // It expexts a `data` argument which should have a property `button`
1943 | // with the name of button.
1944 | this.on('keydown', function (data) {
1945 | if (!data.button || !self.buttons[data.button]) {
1946 | return;
1947 | }
1948 |
1949 | self.buttons[data.button].trigger('keydown');
1950 | });
1951 |
1952 | this.on('keyup', function (data) {
1953 | if (!data.button || !self.buttons[data.button]) {
1954 | return;
1955 | }
1956 |
1957 | self.buttons[data.button].trigger('keyup');
1958 | });
1959 | }
1960 |
1961 | Controller.prototype = Object.create(BulletClass.constructor.prototype);
1962 | Controller.constructor = Controller;
1963 |
1964 | /** ### addButton
1965 | *
1966 | * Add button to the controller.
1967 | *
1968 | * @param {Button} button a [Button](#button) instance
1969 | */
1970 | Controller.prototype.addButton = function (button) {
1971 | this.buttons[button.key] = button;
1972 | };
1973 |
1974 | /** ### enableKeyboard
1975 | *
1976 | * Enable keyboard controlls. It will attach event listeners to the
1977 | * *window* object for every button and trigger their *keydown* /
1978 | * *keyup* event for the controller.
1979 | */
1980 | Controller.prototype.enableKeyboard = function (gamee) {
1981 | var key,
1982 | button,
1983 | keyCodes = {},
1984 | self = this;
1985 |
1986 | for (key in this.buttons) {
1987 | button = this.buttons[key];
1988 |
1989 | if (button.keyCode) {
1990 | keyCodes[button.keyCode] = button;
1991 | }
1992 | }
1993 |
1994 | gamee._keydown(function (ev) {
1995 | var button = keyCodes[ev.keyCode];
1996 |
1997 | if (!button) {
1998 | return;
1999 | }
2000 |
2001 | ev.preventDefault();
2002 | self.trigger('keydown', { button: button.key });
2003 | });
2004 |
2005 | gamee._keyup(function (ev) {
2006 | var button = keyCodes[ev.keyCode];
2007 |
2008 | if (!button) {
2009 | return;
2010 | }
2011 |
2012 | ev.preventDefault();
2013 | self.trigger('keyup', { button: button.key });
2014 | });
2015 | };
2016 |
2017 | /** ### remapButton
2018 | *
2019 | * Remap the names of the controller's buttons. Controllers have their
2020 | * button names set (left, right, A, B), but sometimes in context of
2021 | * the game a different names are desired.
2022 | *
2023 | * ```javascript
2024 | * var controller = gamee.controller.requestController('TwoButtons');
2025 | * controller.remapButton('left', 'throttle');
2026 | * controller.remapButton('right', 'break');
2027 | *
2028 | * controller.buttons.throttle.on('keydown', ..);
2029 | * ```
2030 | *
2031 | * @param {String} oldName button name we want to change
2032 | * @param {String} newName new button name
2033 | */
2034 | Controller.prototype.remapButton = function (oldName, newName) {
2035 |
2036 | // handle old code
2037 | if (newName.name) {
2038 | newName = newName.name;
2039 | }
2040 |
2041 | if (this.buttons[oldName]) {
2042 | this.buttonAlias[oldName] = newName.name;
2043 |
2044 | this.buttons[newName.name] = this.buttons[oldName];
2045 |
2046 | delete this.buttons[oldName];
2047 | } else {
2048 | throw Error('Button ' + oldName + ' was not found in controller');
2049 | }
2050 | };
2051 |
2052 | // ## Controllers
2053 |
2054 | /** ### OneButtonController
2055 | *
2056 | * Controller with only one button.
2057 | * @class OneButtonController
2058 | */
2059 | function OneButtonController() {
2060 | Controller.call(this);
2061 |
2062 | // * __name__: 'button'
2063 | // * __key__: spacebar
2064 | this.addButton(new Button('button', 32));
2065 | }
2066 | OneButtonController.prototype = Object.create(Controller.prototype);
2067 | OneButtonController.prototype.constructor = OneButtonController;
2068 |
2069 | /** ### TwoButtonController
2070 | *
2071 | * Controller with two buttons
2072 | * @class TwoButtonController
2073 | */
2074 | function TwoButtonController() {
2075 | Controller.call(this);
2076 |
2077 | // * __name__: 'left'
2078 | // * __key__: left arrow
2079 | this.addButton(new Button('left', 37));
2080 |
2081 | // * __name__: 'right'
2082 | // * __key__: righ arrow
2083 | this.addButton(new Button('right', 39));
2084 | }
2085 | TwoButtonController.prototype = Object.create(Controller.prototype);
2086 | TwoButtonController.prototype.constructor = TwoButtonController;
2087 |
2088 | /** ### TwoActionButtonsController
2089 | *
2090 | * Controller with two action buttons (A,B)
2091 | * @class TwoActionButtonsController
2092 | */
2093 | function TwoActionButtonsController() {
2094 | Controller.call(this);
2095 |
2096 | // * __name__: 'left'
2097 | // * __key__: left arrow
2098 | this.addButton(new Button('A', 32));
2099 |
2100 | // * __name__: 'right'
2101 | // * __key__: righ arrow
2102 | this.addButton(new Button('B', 17));
2103 | }
2104 | TwoActionButtonsController.prototype = Object.create(Controller.prototype);
2105 | TwoActionButtonsController.prototype.constructor = TwoActionButtonsController;
2106 |
2107 | /** ### FourButtonController
2108 | *
2109 | * Controller with four buttons
2110 | * @class FourButtonController
2111 | */
2112 | function FourButtonController() {
2113 | Controller.call(this);
2114 |
2115 | // * __name__: 'up'
2116 | // * __key__: left arrow
2117 | this.addButton(new Button('up', 38));
2118 |
2119 | // * __name__: 'left'
2120 | // * __key__: left arrow
2121 | this.addButton(new Button('left', 37));
2122 |
2123 | // * __name__: 'right'
2124 | // * __key__: righ arrow
2125 | this.addButton(new Button('right', 39));
2126 |
2127 | // * __name__: 'A'
2128 | // * __key__: spacebar
2129 | this.addButton(new Button('A', 32));
2130 | }
2131 | FourButtonController.prototype = Object.create(Controller.prototype);
2132 | FourButtonController.prototype.constructor = FourButtonController;
2133 |
2134 | /** ### FiveButtonController
2135 | *
2136 | * Controller with five buttons
2137 | * @class FiveButtonController
2138 | */
2139 | function FiveButtonController() {
2140 | Controller.call(this);
2141 |
2142 | // * __name__: 'up'
2143 | // * __key__: left arrow
2144 | this.addButton(new Button('up', 38));
2145 |
2146 | // * __name__: 'left'
2147 | // * __key__: left arrow
2148 | this.addButton(new Button('left', 37));
2149 |
2150 | // * __name__: 'right'
2151 | // * __key__: righ arrow
2152 | this.addButton(new Button('right', 39));
2153 |
2154 | // * __name__: 'down'
2155 | // * __key__: down arrow
2156 | this.addButton(new Button('down', 40));
2157 |
2158 | // * __name__: 'A'
2159 | // * __key__: spacebar
2160 | this.addButton(new Button('A', 32));
2161 | }
2162 | FiveButtonController.prototype = Object.create(Controller.prototype);
2163 | FiveButtonController.prototype.constructor = FiveButtonController;
2164 |
2165 | /** ### SixButtonController
2166 | *
2167 | * Controller with six buttons
2168 | * @class SixButtonController
2169 | */
2170 | function SixButtonController() {
2171 | Controller.call(this);
2172 |
2173 | // * __name__: 'up'
2174 | // * __key__: left arrow
2175 | this.addButton(new Button('up', 38));
2176 |
2177 | // * __name__: 'left'
2178 | // * __key__: left arrow
2179 | this.addButton(new Button('left', 37));
2180 |
2181 | // * __name__: 'right'
2182 | // * __key__: righ arrow
2183 | this.addButton(new Button('right', 39));
2184 |
2185 | // * __name__: 'down'
2186 | // * __key__: down arrow
2187 | this.addButton(new Button('down', 40));
2188 |
2189 | // * __name__: 'A'
2190 | // * __key__: spacebar
2191 | this.addButton(new Button('A', 32));
2192 |
2193 | // * __name__: 'B'
2194 | // * __key__: ctrl
2195 | this.addButton(new Button('B', 17));
2196 | }
2197 | SixButtonController.prototype = Object.create(Controller.prototype);
2198 | SixButtonController.prototype.constructor = SixButtonController;
2199 |
2200 | /** ### TwoArrowsOneButtonController
2201 | *
2202 | * Controller with two arrows and one action button
2203 | * @class TwoArrowsOneButtonController
2204 | */
2205 | function TwoArrowsOneButtonController() {
2206 | Controller.call(this);
2207 |
2208 | // * __name__: 'left'
2209 | // * __key__: left arrow
2210 | this.addButton(new Button('left', 37));
2211 |
2212 | // * __name__: 'right'
2213 | // * __key__: righ arrow
2214 | this.addButton(new Button('right', 39));
2215 |
2216 | // * __name__: 'A'
2217 | // * __key__: spacebar
2218 | this.addButton(new Button('A', 32));
2219 | }
2220 | TwoArrowsOneButtonController.prototype = Object.create(Controller.prototype);
2221 | TwoArrowsOneButtonController.prototype.constructor = TwoArrowsOneButtonController;
2222 |
2223 | /** ### TwoArrowsTwoButtonsController
2224 | *
2225 | * Controller with two arrows and two action buttons
2226 | * @class TwoArrowsTwoButtonsController
2227 | */
2228 | function TwoArrowsTwoButtonsController() {
2229 | Controller.call(this);
2230 |
2231 | // * __name__: 'left'
2232 | // * __key__: left arrow
2233 | this.addButton(new Button('left', 37));
2234 |
2235 | // * __name__: 'right'
2236 | // * __key__: righ arrow
2237 | this.addButton(new Button('right', 39));
2238 |
2239 | // * __name__: 'A'
2240 | // * __key__: spacebar
2241 | this.addButton(new Button('A', 32));
2242 |
2243 | // * __name__: 'B'
2244 | // * __key__: ctrl
2245 | this.addButton(new Button('B', 17));
2246 | }
2247 | TwoArrowsTwoButtonsController.prototype = Object.create(Controller.prototype);
2248 | TwoArrowsTwoButtonsController.prototype.constructor = TwoArrowsTwoButtonsController;
2249 |
2250 | /** ### FourArrowController
2251 | *
2252 | * Controller with four arrow buttons
2253 | * @class FourArrowController
2254 | */
2255 | function FourArrowController() {
2256 | Controller.call(this);
2257 |
2258 | // * __name__: 'up'
2259 | // * __key__: left arrow
2260 | this.addButton(new Button('up', 38));
2261 |
2262 | // * __name__: 'left'
2263 | // * __key__: left arrow
2264 | this.addButton(new Button('left', 37));
2265 |
2266 | // * __name__: 'right'
2267 | // * __key__: righ arrow
2268 | this.addButton(new Button('right', 39));
2269 |
2270 | // * __name__: 'down'
2271 | // * __key__: down arrow
2272 | this.addButton(new Button('down', 40));
2273 | }
2274 | FourArrowController.prototype = Object.create(Controller.prototype);
2275 | FourArrowController.prototype.constructor = FourArrowController;
2276 |
2277 | /** ### TouchController
2278 | *
2279 | * This controller has no buttons. Instead it has a touchpad which
2280 | * triggers *touchstart*, *touchend*, *touchmove*, *touchcancel*,
2281 | * *touchend* events (similar to
2282 | * [Touch event types](https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent#Touch_event_types))
2283 | *
2284 | * The position of the touch is in the `data.position` argument as a
2285 | * *x* and *y* with the values between [0, 0] for the left top corner
2286 | * and [1, 1] for the bottom right corner ([0.5, 0.5] is the center).
2287 | *
2288 | * ```javascript
2289 | * controller = gamee.controller.requestController('Touch');
2290 | *
2291 | * controller.on('touchstart', function(data) {
2292 | * if (data.position.x < 0.5 && data.position.y < 0.5) {
2293 | * console.log('touch in the top left quadrant');
2294 | * }
2295 | * })
2296 | * ```
2297 | * @class TouchController
2298 | */
2299 | function TouchController() {
2300 | var self = this;
2301 |
2302 | Controller.call(this);
2303 |
2304 | this.on("$touchstart", function (data) {
2305 | self.trigger('touchstart', data);
2306 | });
2307 |
2308 | this.on("$touchend", function (data) {
2309 | self.trigger('touchend', data);
2310 | });
2311 |
2312 | this.on("$touchmove", function (data) {
2313 | self.trigger('touchmove', data);
2314 | });
2315 |
2316 | this.on("$touchleave", function (data) {
2317 | self.trigger('touchleave', data);
2318 | });
2319 |
2320 | this.on("$touchcancel", function (data) {
2321 | self.trigger('touchcancel', data);
2322 | });
2323 | }
2324 | TouchController.prototype = Object.create(TouchController.prototype);
2325 | TouchController.prototype.constructor = TouchController;
2326 |
2327 | /** ### JoystickController
2328 | *
2329 | * JoystickController emits `change` event, after the position of the
2330 | * joystick is changed.
2331 | *
2332 | * The position of the joystick is in the property `x` and `y`. The
2333 | * position on axis is between <-1, 1> (for x -1 is max left
2334 | * position, 1 max right position). [0.0, 0.0] is the center.
2335 | *
2336 | * ```javascript
2337 | * joystick = gamee.controller.requestController('Joystick');
2338 | *
2339 | * joystick.on('change', function() {
2340 | * new_x = joystick.x;
2341 | * nex_y = joystick.y;
2342 | * })
2343 | * ```
2344 | * @class JoystickController
2345 | */
2346 | function JoystickController() {
2347 | var self = this;
2348 |
2349 | Controller.call(this);
2350 |
2351 | // x axis
2352 | this.x = 0;
2353 | // y axis
2354 | this.y = 0;
2355 |
2356 | this.on("$change", function (data) {
2357 | self.x = data.position.x;
2358 | self.y = data.position.y;
2359 |
2360 | self.trigger("change", data);
2361 | });
2362 | }
2363 | JoystickController.prototype = Object.create(Controller.prototype);
2364 | JoystickController.prototype.constructor = JoystickController;
2365 |
2366 | /** ### JoystickButtonController
2367 | *
2368 | * JoystickButtonController is a `JoystickController` with one button.
2369 | *
2370 | * ```javascript
2371 | * joystick = gamee.controller.requestController('JoystickWithButton');
2372 | *
2373 | * joystick.on('change', function() {
2374 | * new_x = joystick.x;
2375 | * nex_y = joystick.y;
2376 | * })
2377 | *
2378 | * joystick.buttons.button.on('keydown', callback)
2379 | * // or simply
2380 | * joystick.on('keydown', callback)
2381 | * ```
2382 | * @class JoystickButtonController
2383 | */
2384 | function JoystickButtonController() {
2385 | var self = this;
2386 |
2387 | JoystickController.call(this);
2388 |
2389 | // * __name__: 'button'
2390 | // * __key__: spacebar
2391 | this.addButton(new Button('button', 32));
2392 | }
2393 | JoystickButtonController.prototype = Object.create(JoystickController.prototype);
2394 | JoystickButtonController.prototype.constructor = JoystickButtonController;
2395 |
2396 | /***/ }),
2397 | /* 6 */
2398 | /***/ (function(module, exports, __webpack_require__) {
2399 |
2400 | "use strict";
2401 |
2402 |
2403 | Object.defineProperty(exports, "__esModule", {
2404 | value: true
2405 | });
2406 | exports.gamee = undefined;
2407 |
2408 | __webpack_require__(0);
2409 |
2410 | var _gameeAPI = __webpack_require__(2);
2411 |
2412 | var _core = __webpack_require__(1);
2413 |
2414 | var _platform_bridge = __webpack_require__(3);
2415 |
2416 | /**
2417 | * Instance of gamee object with API for developers.
2418 | * Internal functions becomes private this way
2419 | *
2420 | * @requires Gamee
2421 | */
2422 | var gamee = exports.gamee = undefined;
2423 |
2424 | /**
2425 | * Resolves what platform is being used and make instance of platform API.
2426 | *
2427 | * @requires PlatformBridge
2428 | */
2429 | var platformBridge = function () {
2430 |
2431 | var platformBridge,
2432 | platformType = "web";
2433 |
2434 | // Reslove Gamee enviroment
2435 | /* current user agent */
2436 | var userAgent = navigator.userAgent.toLowerCase();
2437 |
2438 | if (/iphone|ipod|ipad/.test(userAgent)) {
2439 | // test ios device
2440 | // user agent is use to determine current enviroment
2441 |
2442 | // Test if window with game have a parent (loading in iframe)
2443 | if (window.self !== window.top) {
2444 | platformType = "web";
2445 | } else {
2446 | platformType = "ios";
2447 | }
2448 | } else if (/gamee\/[0-9\.]+$/.test(userAgent)) {
2449 | // test android app
2450 | // TODO do you really test android like that?
2451 | platformType = "android";
2452 | } else if (window.parent) {
2453 | // TODO doesnt make sence, parent always exists!!
2454 | platformType = "web";
2455 | } else if (window.parent && window.parent.gameeSimulator) {
2456 | // TODO doesnt make sence, parent always exist?
2457 | platformType = "web";
2458 | }
2459 |
2460 | exports.gamee = gamee = new _gameeAPI.Gamee(platformType);
2461 |
2462 | window.gamee = gamee;
2463 |
2464 | switch (platformType) {
2465 | case "web":
2466 | if (window.parent === window) {
2467 | console.error("Gamee must run in iframe on web platform");
2468 | }
2469 | platformBridge = new _platform_bridge.PostMessageBridge(window.parent);
2470 | break;
2471 | case "ios":
2472 | platformBridge = new _platform_bridge.MobileBridge("ios");
2473 | break;
2474 | case "android":
2475 | platformBridge = new _platform_bridge.MobileBridge("android");
2476 | break;
2477 | default:
2478 | throw "Can't identify the platform";
2479 | }
2480 | return platformBridge;
2481 | }();
2482 |
2483 | _core.core.PlatformAPI = _platform_bridge.PlatformAPI;
2484 | _core.core.native = platformBridge;
2485 |
2486 | _platform_bridge.PlatformAPI.emitter = gamee.emitter;
2487 |
2488 | function loadScript(url, callback) {
2489 | // Adding the script tag to the head as suggested before
2490 | var head = document.getElementsByTagName('head')[0];
2491 | var script = document.createElement('script');
2492 | script.src = url;
2493 |
2494 | // Then bind the event to the callback function.
2495 | // There are several events for cross browser compatibility.
2496 | script.onreadystatechange = callback;
2497 | script.onload = callback;
2498 |
2499 | // Fire the loading
2500 | head.appendChild(script);
2501 | }
2502 |
2503 | /***/ }),
2504 | /* 7 */
2505 | /***/ (function(module, exports) {
2506 |
2507 | var g;
2508 |
2509 | // This works in non-strict mode
2510 | g = (function() {
2511 | return this;
2512 | })();
2513 |
2514 | try {
2515 | // This works if eval is allowed (see CSP)
2516 | g = g || Function("return this")() || (1,eval)("this");
2517 | } catch(e) {
2518 | // This works if the window reference is available
2519 | if(typeof window === "object")
2520 | g = window;
2521 | }
2522 |
2523 | // g can still be undefined, but nothing to do about it...
2524 | // We return undefined, instead of nothing here, so it's
2525 | // easier to handle this case. if(!global) { ...}
2526 |
2527 | module.exports = g;
2528 |
2529 |
2530 | /***/ })
2531 | /******/ ]);
2532 | });
2533 | //# sourceMappingURL=gamee-js.js.map
--------------------------------------------------------------------------------
/gamee/dist/gamee-js.min.js:
--------------------------------------------------------------------------------
1 | /*! @preserve build time 2019-08-27 08:54:59 */
2 | !function(t,e){if("object"==typeof exports&&"object"==typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var o=e();for(var n in o)("object"==typeof exports?exports:t)[n]=o[n]}}(this,function(){return function(t){function __webpack_require__(o){if(e[o])return e[o].exports;var n=e[o]={i:o,l:!1,exports:{}};return t[o].call(n.exports,n,n.exports,__webpack_require__),n.l=!0,n.exports}var e={};return __webpack_require__.m=t,__webpack_require__.c=e,__webpack_require__.i=function(t){return t},__webpack_require__.d=function(t,e,o){__webpack_require__.o(t,e)||Object.defineProperty(t,e,{configurable:!1,enumerable:!0,get:o})},__webpack_require__.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return __webpack_require__.d(e,"a",e),e},__webpack_require__.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},__webpack_require__.p="",__webpack_require__(__webpack_require__.s=6)}([function(t,e,o){"use strict";function CustomEmitter(){function delegate(e){this[e]=t[e].bind(t)}var t=document.createDocumentFragment();["addEventListener","dispatchEvent","removeEventListener"].forEach(delegate,this)}function wrapKeyEvent(t){return function(e){return e&&e.keyCode||(e||(e=window.event),e.which&&(e.keyCode=e.which)),t(e)}}Object.defineProperty(e,"__esModule",{value:!0}),e.CustomEmitter=CustomEmitter,e.wrapKeyEvent=wrapKeyEvent,function(){try{var t=new window.CustomEvent("test");if(t.preventDefault(),!0!==t.defaultPrevented)throw new Error("Could not prevent default")}catch(t){var e=function(t,e){var o,n;return e=e||{bubbles:!1,cancelable:!1,detail:void 0},o=document.createEvent("CustomEvent"),o.initCustomEvent(t,e.bubbles,e.cancelable,e.detail),n=o.preventDefault,o.preventDefault=function(){n.call(this);try{Object.defineProperty(this,"defaultPrevented",{get:function(){return!0}})}catch(t){this.defaultPrevented=!0}},o};e.prototype=window.Event.prototype,window.CustomEvent=e}}(),function(t,e){function docHijack(t){var o=e[t];e[t]=function(t){return addListen(o(t))}}function addEvent(e,o,n){return(n=this).attachEvent("on"+e,function(e){e=e||t.event,e.preventDefault=e.preventDefault||function(){e.returnValue=!1},e.stopPropagation=e.stopPropagation||function(){e.cancelBubble=!0},o.call(n,e)})}function addListen(t,e){if(e=t.length)for(;e--;)t[e].addEventListener=addEvent;else t.addEventListener=addEvent;return t}t.addEventListener||(addListen([e,t]),"Element"in t?t.Element.prototype.addEventListener=addEvent:(e.attachEvent("onreadystatechange",function(){addListen(e.all)}),docHijack("getElementsByTagName"),docHijack("getElementById"),docHijack("createElement"),addListen(e.all)))}(window,document)},function(t,e,o){"use strict";(function(t){Object.defineProperty(e,"__esModule",{value:!0}),e.validateDataType=e.DataTypeException=e.core=void 0;var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},r=o(5),a=function(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var o in t)Object.prototype.hasOwnProperty.call(t,o)&&(e[o]=t[o]);return e.default=t,e}(r),i=o(0);!function(){var t=function(t){var e=new t;if("suspended"===e.state){var o=function resume(){if(/(iPhone|iPad)/i.test(navigator.userAgent)){var t=e.createBuffer(1,1,44100),o=e.createBufferSource();o.buffer=t,o.connect(e.destination),o.start(0),o.disconnect()}e.resume(),setTimeout(function(){"running"===e.state&&document.body.removeEventListener(["touchcancel","touchend","touchenter","touchleave","touchmove","touchstart","mouseenter","mouseover","mousemove","mousedown","mouseup"].join(" "),resume,!1)},0)};document.body.addEventListener(["touchcancel","touchend","touchenter","touchleave","touchmove","touchstart","mouseenter","mouseover","mousemove","mousedown","mouseup"].join(" "),o,!1)}return e};try{void 0!==window.AudioContext?window.AudioContext=t.bind(null,window.AudioContext):"undefined"!=typeof webkitAudioContext&&(window.webkitAudioContext=t.bind(null,window.webkitAudioContext))}catch(t){setTimeout(function(){throw t},0)}}();var u=(e.core=function(){function createController(t,e){var o,n;if(!u[t])throw new Error("Unsupported controller type, "+t);if(e=e||{},n=new u[t],e.enableKeyboard&&n.enableKeyboard(r),e.buttons)for(o in e.buttons)n.remapButton(o,e.buttons[o]);return n}var e=function(){},o={},n={VERSION:"2.4.0",CAPABILITIES:["ghostMode","saveState","replay","socialData","rewardedAds","coins","logEvents","playerData","share","gems"],variant:0,soundUnlocked:!1,onReady:e,onGameStart:e},r={};r.gameeInit=function(t,e,a,i){var u=(arguments.length>4&&void 0!==arguments[4]&&arguments[4],!0),s={};if(void 0!==a&&Array.isArray(a))for(var l=0;l100)throw"Percentage passed to gameLoadingProgress out of bounds or not a number.";e>t&&(t=e,this.native.createRequest("gameLoadingProgress",{percentage:e}))}}(),r.gameReady=function(){this.native.createRequest("gameReady")},r.updateScore=function(t,e){if("number"!=typeof t)throw"Score passed to updateScore is not a number.";var o={score:parseInt(t,10)};e&&(o.ghostSign=!0),this.native.createRequest("updateScore",o)},r.gameOver=function(t,e,o){o=void 0!==o&&o;var n={};if(t){if(t.hasOwnProperty("variant")||(t.variant=""),!t.hasOwnProperty("data"))throw"Replay data must have `data` property";n.replayData=t}n.hideOverlay=o,e&&(n.state=e),r.native.createRequest("gameOver",n)},r.gameSave=function(t,e){if(!o.capabilities.saveState)throw"Save State not supported, you must add the capability on gamee.Init";r.native.createRequest("saveState",{state:t,share:e})},r.requestSocial=function(t,e){if(!o.capabilities.socialData)throw"Social Data not supported, you must add the capability on gamee.Init";this.native.createRequest("requestSocial",e,function(e){t(null,e)})},r.logEvent=function(t,e){if(!o.capabilities.logEvents)throw"Log Events not supported, you must add the capability on gamee.Init";this.native.createRequest("logEvent",{eventName:t,eventValue:e},function(t){if(t)throw t})},r.requestBattleData=function(t){this.native.createRequest("requestBattleData",void 0,function(e){t(null,e)})},r.requestPlayerReplay=function(t,e){if(!o.capabilities.replay)throw"Replays not supported, you must add the capability on gamee.Init";this.native.createRequest("requestPlayerReplay",{userID:t},function(t){e(null,t)})},r.requestPlayerSaveState=function(t,e){this.native.createRequest("requestPlayerSaveState",{userID:t},function(t){e(null,t)})},r.purchaseItemWithCoins=function(t,e,n){if(!o.capabilities.coins)throw"Coins purchases not supported, you must add the capability on gamee.Init";if(t){["coinsCost","itemName"].forEach(function(e){if(!t.hasOwnProperty(e))throw"Purchase Options must have `"+e+"` property"})}this.isSilentModeEnabled();var r="purchaseItemWithCoins";void 0!==n&&!0===n&&(r="purchaseItem"),this.native.createRequest(r,t,function(t){e(null,t)})},r.purchaseItemWithGems=function(t,e){if(!o.capabilities.gems)throw"Gems purchases not supported, you must add the capability on gamee.Init";if(t){["gemsCost","itemName"].forEach(function(e){if(!t.hasOwnProperty(e))throw"Purchase options must have `"+e+"` property"})}this.isSilentModeEnabled(),this.native.createRequest("purchaseItemWithGems",t,function(t){e(null,t)})},r.share=function(t,e){if(!o.capabilities.share)throw"Share option not supported, you must add the capability on gamee.Init";if(t){["destination"].forEach(function(e){if(!t.hasOwnProperty(e))throw"Share Options must have `"+e+"` property"})}this.isSilentModeEnabled(),this.native.createRequest("share",t,function(t){e(null,t)})},r.loadRewardedVideo=function(t){if(!o.capabilities.rewardedAds)throw"Rewarded Ads not supported, you must add the capability on gamee.Init";this.native.createRequest("loadRewardedVideo",function(e){t(null,e)})},r.showRewardedVideo=function(t){if(!o.capabilities.rewardedAds)throw"Rewarded Ads not supported, you must add the capability on gamee.Init";this.native.createRequest("showRewardedVideo",function(e){t(null,e)})},r.requestPlayerData=function(t,e){if(!o.capabilities.playerData)throw"Player Data not supported, you must add the capability on gamee.Init";var n=void 0;e&&(n={userID:e}),this.native.createRequest("requestPlayerData",n,function(e){t(null,e)})},r.startSignal=function(t){var e;return t.replay&&!o.capabilities.replay&&(e="Game doesn't support replay. "),t.ghostMode&&!o.capabilities.ghostMode&&(e="Game doesn't support ghost Mode. "),e},r.controller={mainController:null,requestController:function(t,e){if("FullScreen"===t)return null;var o=createController(t,e);return this.mainController=o,o},additionalController:function(t,e){var o=createController(t,e);return gameeNative.additionalController(t),o},trigger:function(){if(!this.mainController)throw new Error("No controller present");this.mainController.trigger.apply(this.mainController,arguments)}},r._keydown=function(e){t.addEventListener("keydown",(0,i.wrapKeyEvent)(e))},r._keyup=function(e){t.addEventListener("keyup",(0,i.wrapKeyEvent)(e))};var u={OneButton:a.OneButtonController,TwoButtons:a.TwoButtonController,FourButtons:a.FourButtonController,FiveButtons:a.FiveButtonController,SixButtons:a.SixButtonController,FourArrows:a.FourArrowController,Touch:a.TouchController,Joystick:a.JoystickController,JoystickWithButton:a.JoystickButtonController,TwoArrowsTwoButtons:a.TwoArrowsTwoButtonsController,TwoArrowsOneButton:a.TwoArrowsOneButtonController,TwoActionButtons:a.TwoActionButtonsController};return r.registerPlatform=function(t){},r.isSilentModeEnabled=function(){return o.silentMode},r}(),e.DataTypeException=function(t,e,o,n){this.expected=t,this.present=e,this.method=n,this.argument=o,this.message="Invalid data type in method "+this.method+", argument "+this.argument+" is expected to be "+this.expected+", but found "+this.present});e.validateDataType=function(t,e,o,r){switch(e){case"array":if(!Array.isArray(t))throw new u(e,void 0===t?"undefined":n(t),o,r);break;default:if((void 0===t?"undefined":n(t))!==e)throw new u(e,void 0===t?"undefined":n(t),o,r)}}}).call(e,o(7))},function(t,e,o){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.Gamee=e.GameeEmitter=void 0;var n=o(1),r=o(0),a=e.GameeEmitter=function(){r.CustomEmitter.call(this)};(e.Gamee=function(t){this.emitter=new a,this._platform=t}).prototype=function(){var t=function(t){if(t)throw"Error "+t.toString()};return{_controller:n.core.controller,gameInit:function(t,e,o,r){var a=arguments.length>4&&void 0!==arguments[4]&&arguments[4];(0,n.validateDataType)(t,"string","controllType","gamee.updateScore"),(0,n.validateDataType)(e,"object","controllOpts","gamee.gameInit"),(0,n.validateDataType)(o,"array","capabilities","gamee.gameInit"),(0,n.validateDataType)(r,"function","cb","gamee.gameInit"),(0,n.validateDataType)(a,"boolean","silentMode","gamee.gameInit"),n.core.gameeInit(t,e,o,r,a)},gameLoadingProgress:function(e,o){(0,n.validateDataType)(e,"number","percentage","gamee.gameLoadingProgress"),o=o||t,(0,n.validateDataType)(o,"function","opt_cb","gamee.gameLoadingProgress"),n.core.gameLoadingProgress(e),o(null)},gameReady:function(e){e=e||t,(0,n.validateDataType)(e,"function","opt_cb","gamee.gameReady"),n.core.gameReady(),e(null)},gameSave:function(e,o,r){(0,n.validateDataType)(e,"string","data","gamee.gameSave"),"function"==typeof o?r=o:void 0!==o&&(0,n.validateDataType)(o,"boolean","opt_share","gamee.gameSave"),r=r||t,(0,n.validateDataType)(r,"function","opt_cb","gamee.gameSave"),n.core.gameSave(e,!1),r(null)},getPlatform:function(){return this._platform},updateScore:function(e,o,r){(0,n.validateDataType)(e,"number","score","gamee.updateScore"),"function"==typeof o?r=o:void 0!==o&&(0,n.validateDataType)(o,"boolean","opt_ghostSign","gamee.updateScore"),r=r||t,(0,n.validateDataType)(r,"function","opt_cb","gamee.updateScore"),n.core.updateScore(e,o),r(null)},gameOver:function(e,o,r,a){"function"==typeof e?o=e:void 0!==e&&(0,n.validateDataType)(e,"object","opt_replayData","gamee.gameOver"),void 0!==a&&(0,n.validateDataType)(a,"boolean","opt_hideOverlay","gamee.gameOver"),o=o||t,(0,n.validateDataType)(o,"function","opt_cb","gamee.gameOver"),n.core.gameOver(e,r,a),o(null)},requestSocial:function(t,e){(0,n.validateDataType)(t,"function","cb","gamee.requestSocial"),n.core.requestSocial(function(e,o){var n=o.hasOwnProperty("socialData")?o:{socialData:o};t(null,n)},e)},logEvent:function(t,e){(0,n.validateDataType)(t,"string","eventName","gamee.logEvent"),!t||t.length>24||((0,n.validateDataType)(e,"string","eventValue","gamee.logEvent"),!e||e.length>160||n.core.logEvent(t,e))},requestBattleData:function(t){(0,n.validateDataType)(t,"function","cb","gamee.requestBattleData"),n.core.requestBattleData(t)},requestPlayerReplay:function(t,e){(0,n.validateDataType)(t,"number","userID","gamee.requestPlayerReplay"),(0,n.validateDataType)(e,"function","cb","gamee.requestPlayerReplay"),n.core.requestPlayerReplay(t,e)},requestPlayerSaveState:function(t,e){(0,n.validateDataType)(t,"number","userID","gamee.requestPlayerSaveState"),(0,n.validateDataType)(e,"function","cb","gamee.requestPlayerSaveState"),n.core.requestPlayerSaveState(t,e)},purchaseItem:function(t,e){(0,n.validateDataType)(t,"object","purchaseDetails","gamee.purchaseItem"),(0,n.validateDataType)(e,"function","cb","gamee.purchaseItem"),n.core.purchaseItemWithCoins(t,e,!0)},purchaseItemWithCoins:function(t,e){(0,n.validateDataType)(t,"object","purchaseDetails","gamee.purchaseItemWithCoins"),(0,n.validateDataType)(e,"function","cb","gamee.purchaseItemWithCoins"),n.core.purchaseItemWithCoins(t,e)},purchaseItemWithGems:function(t,e){(0,n.validateDataType)(t,"object","purchaseDetails","gamee.purchaseItemWithGems"),(0,n.validateDataType)(e,"function","cb","gamee.purchaseItemWithGems"),n.core.purchaseItemWithGems(t,e)},share:function(t,e){(0,n.validateDataType)(t,"object","shareDetails","gamee.share"),(0,n.validateDataType)(e,"function","cb","gamee.share"),n.core.share(t,e)},loadRewardedVideo:function(t){(0,n.validateDataType)(t,"function","cb","gamee.loadRewardedVideo"),n.core.loadRewardedVideo(t)},showRewardedVideo:function(t){(0,n.validateDataType)(t,"function","cb","gamee.showRewardedVideo"),n.core.showRewardedVideo(t)},requestPlayerData:function(t,e){(0,n.validateDataType)(t,"function","cb","gamee.requestPlayerData"),void 0!==e&&(0,n.validateDataType)(e,"number","userId","gamee.requestPlayerData"),n.core.requestPlayerData(t,e)}}}()},function(t,e,o){"use strict";function PlatformBridge(){this.requests={},this.platform="",this._init()}function PostMessageBridge(t){this._gameeWin=t,PlatformBridge.call(this),this.platform="web"}function MobileBridge(t){this.device=t,PostMessageBridge.call(this),this.platform="mobile"}Object.defineProperty(e,"__esModule",{value:!0}),e.PlatformAPI=void 0;var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t};e.PlatformBridge=PlatformBridge,e.PostMessageBridge=PostMessageBridge,e.MobileBridge=MobileBridge;var r=o(1),a=e.PlatformAPI={emitter:null,pause:function(t){var e=new CustomEvent("pause",{detail:{callback:t}});this.emitter.dispatchEvent(e)},resume:function(t){var e=new CustomEvent("resume",{detail:{callback:t}});this.emitter.dispatchEvent(e)},ghostShow:function(t){var e=new CustomEvent("ghostShow",{detail:{callback:t}});this.emitter.dispatchEvent(e)},ghostHide:function(t){var e=new CustomEvent("ghostHide",{detail:{callback:t}});this.emitter.dispatchEvent(e)},mute:function(t){var e=new CustomEvent("mute",{detail:{callback:t}});this.emitter.dispatchEvent(e)},unmute:function(t){var e=new CustomEvent("unmute",{detail:{callback:t}});this.emitter.dispatchEvent(e)},start:function(t,e){var o=new CustomEvent("start",{detail:{callback:e}}),n=r.core.startSignal(t);if(n)return void e(n);t.replay&&(o.detail.opt_replay=!0),t.ghostMode&&(o.detail.opt_ghostMode=!0),t.resetState&&(o.detail.opt_resetState=!0),t.replayData&&(o.detail.replayData=t.replayData),this.emitter.dispatchEvent(o)}};PlatformBridge.prototype={instCount:0,_init:function(){},createRequest:function(t,e,o){if(this.validateMethod(t)){"function"==typeof e&&(o=e,e=void 0);var n=this.instCount++;void 0!==o&&(this.requests[n]=o);var r={request:{method:t,messageId:n,data:null}};this.doCall(r,e)}},validateMethod:function(t){return"gameLoadingProgress"!==t},doCall:function(t,e){throw"Not implemented"},_callback:function(t,e){var o=this.requests[t];delete this.requests[t],o&&o(e)},doResponse:function(t,e){throw"Not implemented"}},PostMessageBridge.prototype=Object.create(PlatformBridge.prototype),PostMessageBridge.prototype.constructor=PostMessageBridge,PostMessageBridge.prototype._init=function(){window.addEventListener("message",function(t){var e;if("object"===n(t.detail)&&null!==typeof t.detail)e=t.detail;else{if("object"!==n(t.data))return;e=t.data}if(r.core.isSilentModeEnabled(),e.request&&e.request.method&&void 0!==e.request.messageId)this._resolveAPICall(e.request.method,e.request.messageId,e.request.data);else if(e.response&&void 0!==e.response.messageId){if(e.error)throw e.error;this._callback(e.response.messageId,e.response.data)}}.bind(this),!1)},PostMessageBridge.prototype.doCall=function(t,e){"object"===(void 0===e?"undefined":n(e))&&(t.request.data=e||{}),this._gameeWin.postMessage(t,"*")},PostMessageBridge.prototype.doResponse=function(t,e){var o={version:this.version,response:{messageId:t}};e&&(o.data=e),this._gameeWin.postMessage(o,"*")},PostMessageBridge.prototype._resolveAPICall=function(t,e,o){var n=this.doResponse.bind(this,e);switch(t){case"pause":a.pause(n);break;case"resume":a.resume(n);break;case"mute":a.mute(n);break;case"unmute":a.unmute(n);break;case"ghostShow":a.ghostShow(n);break;case"ghostHide":a.ghostHide(n);break;case"start":if(!o)throw"Method _start missing params";a.start(o,n);break;default:r.core.isSilentModeEnabled()}},MobileBridge.prototype=Object.create(PostMessageBridge.prototype),MobileBridge.prototype.constructor=MobileBridge,MobileBridge.prototype._init=function(){if(PostMessageBridge.prototype._init.call(this),"ios"===this.device)this._gameeWin=webkit.messageHandlers.callbackHandler;else{if("android"!==this.device)throw"Unknown device used in webkit bridge";this._gameeWin=_toDevice}window._triggerMessage=function(t){try{t=JSON.parse(t)}catch(e){throw"Couldn't parse message from native app: \n"+t+"\n"+e}r.core.isSilentModeEnabled(),this.dispatchEvent(new CustomEvent("message",{detail:t}))}.bind(window)},MobileBridge.prototype.doCall=function(t,e){"object"===(void 0===e?"undefined":n(e))&&(t.request.data=e||{}),"android"===this.device&&(t=JSON.stringify(t)),this._gameeWin.postMessage(t,"*")}},function(t,e,o){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var n=function(){var t=this,e={};t.on=function(t,o,n){if(!(arguments.length<2||"string"!=typeof t||"function"!=typeof o)){var r=o.toString();void 0!==e[t]?void 0===e[t].callbacks[r]?e[t].callbacks[r]={cb:o,once:!!n}:"boolean"==typeof n&&(e[t].callbacks[r].once=n):(e[t]={callbacks:{}},e[t].callbacks[r]={cb:o,once:!!n})}},t.once=function(e,o){t.on(e,o,!0)},t.off=function(t,o){if("string"==typeof t&&void 0!==e[t])if("function"==typeof o){var n=o.toString(),r=e[t].callbacks[n];void 0!==r&&delete e[t].callbacks[n]}else delete e[t]},t.trigger=function(o,n){if("string"==typeof o&&void 0!==e[o])for(var r in e[o].callbacks){var a=e[o].callbacks[r];"function"==typeof a.cb&&a.cb(n),"boolean"==typeof a.once&&!0===a.once&&t.off(o,a.cb)}}};e.Bullet=new n},function(t,e,o){"use strict";function Button(t,e){var o=this;r.call(this),this._pressed=!0,this.key=t,this.keyCode=e,this.on("keydown",function(){o._pressed=!0}),this.on("keyup",function(){o._pressed=!1})}function Controller(){var t=this;r.call(this),this.buttons={},this.buttonAlias={},this.on("$keydown",function(e){e.button&&t.buttonAlias[e.button]&&(e.button=t.buttonAlias[e.button]),t.trigger("keydown",e)}),this.on("$keyup",function(e){e.button&&t.buttonAlias[e.button]&&(e.button=t.buttonAlias[e.button]),t.trigger("keyup",e)}),this.on("keydown",function(e){e.button&&t.buttons[e.button]&&t.buttons[e.button].trigger("keydown")}),this.on("keyup",function(e){e.button&&t.buttons[e.button]&&t.buttons[e.button].trigger("keyup")})}function OneButtonController(){Controller.call(this),this.addButton(new Button("button",32))}function TwoButtonController(){Controller.call(this),this.addButton(new Button("left",37)),this.addButton(new Button("right",39))}function TwoActionButtonsController(){Controller.call(this),this.addButton(new Button("A",32)),this.addButton(new Button("B",17))}function FourButtonController(){Controller.call(this),this.addButton(new Button("up",38)),this.addButton(new Button("left",37)),this.addButton(new Button("right",39)),this.addButton(new Button("A",32))}function FiveButtonController(){Controller.call(this),this.addButton(new Button("up",38)),this.addButton(new Button("left",37)),this.addButton(new Button("right",39)),this.addButton(new Button("down",40)),this.addButton(new Button("A",32))}function SixButtonController(){Controller.call(this),this.addButton(new Button("up",38)),this.addButton(new Button("left",37)),this.addButton(new Button("right",39)),this.addButton(new Button("down",40)),this.addButton(new Button("A",32)),this.addButton(new Button("B",17))}function TwoArrowsOneButtonController(){Controller.call(this),this.addButton(new Button("left",37)),this.addButton(new Button("right",39)),this.addButton(new Button("A",32))}function TwoArrowsTwoButtonsController(){Controller.call(this),this.addButton(new Button("left",37)),this.addButton(new Button("right",39)),this.addButton(new Button("A",32)),this.addButton(new Button("B",17))}function FourArrowController(){Controller.call(this),this.addButton(new Button("up",38)),this.addButton(new Button("left",37)),this.addButton(new Button("right",39)),this.addButton(new Button("down",40))}function TouchController(){var t=this;Controller.call(this),this.on("$touchstart",function(e){t.trigger("touchstart",e)}),this.on("$touchend",function(e){t.trigger("touchend",e)}),this.on("$touchmove",function(e){t.trigger("touchmove",e)}),this.on("$touchleave",function(e){t.trigger("touchleave",e)}),this.on("$touchcancel",function(e){t.trigger("touchcancel",e)})}function JoystickController(){var t=this;Controller.call(this),this.x=0,this.y=0,this.on("$change",function(e){t.x=e.position.x,t.y=e.position.y,t.trigger("change",e)})}function JoystickButtonController(){JoystickController.call(this),this.addButton(new Button("button",32))}Object.defineProperty(e,"__esModule",{value:!0}),e.BulletClass=void 0,e.Button=Button,e.Controller=Controller,e.OneButtonController=OneButtonController,e.TwoButtonController=TwoButtonController,e.TwoActionButtonsController=TwoActionButtonsController,e.FourButtonController=FourButtonController,e.FiveButtonController=FiveButtonController,e.SixButtonController=SixButtonController,e.TwoArrowsOneButtonController=TwoArrowsOneButtonController,e.TwoArrowsTwoButtonsController=TwoArrowsTwoButtonsController,e.FourArrowController=FourArrowController,e.TouchController=TouchController,e.JoystickController=JoystickController,e.JoystickButtonController=JoystickButtonController;var n=o(4),r=e.BulletClass=n.Bullet.constructor;Button.prototype=Object.create(r.constructor.prototype),Button.constructor=Button,Button.prototype.isDown=function(){return this._pressed},Controller.prototype=Object.create(r.constructor.prototype),Controller.constructor=Controller,Controller.prototype.addButton=function(t){this.buttons[t.key]=t},Controller.prototype.enableKeyboard=function(t){var e,o,n={},r=this;for(e in this.buttons)o=this.buttons[e],o.keyCode&&(n[o.keyCode]=o);t._keydown(function(t){var e=n[t.keyCode];e&&(t.preventDefault(),r.trigger("keydown",{button:e.key}))}),t._keyup(function(t){var e=n[t.keyCode];e&&(t.preventDefault(),r.trigger("keyup",{button:e.key}))})},Controller.prototype.remapButton=function(t,e){if(e.name&&(e=e.name),!this.buttons[t])throw Error("Button "+t+" was not found in controller");this.buttonAlias[t]=e.name,this.buttons[e.name]=this.buttons[t],delete this.buttons[t]},OneButtonController.prototype=Object.create(Controller.prototype),OneButtonController.prototype.constructor=OneButtonController,TwoButtonController.prototype=Object.create(Controller.prototype),TwoButtonController.prototype.constructor=TwoButtonController,TwoActionButtonsController.prototype=Object.create(Controller.prototype),TwoActionButtonsController.prototype.constructor=TwoActionButtonsController,FourButtonController.prototype=Object.create(Controller.prototype),FourButtonController.prototype.constructor=FourButtonController,FiveButtonController.prototype=Object.create(Controller.prototype),FiveButtonController.prototype.constructor=FiveButtonController,SixButtonController.prototype=Object.create(Controller.prototype),SixButtonController.prototype.constructor=SixButtonController,TwoArrowsOneButtonController.prototype=Object.create(Controller.prototype),TwoArrowsOneButtonController.prototype.constructor=TwoArrowsOneButtonController,TwoArrowsTwoButtonsController.prototype=Object.create(Controller.prototype),TwoArrowsTwoButtonsController.prototype.constructor=TwoArrowsTwoButtonsController,FourArrowController.prototype=Object.create(Controller.prototype),FourArrowController.prototype.constructor=FourArrowController,TouchController.prototype=Object.create(TouchController.prototype),TouchController.prototype.constructor=TouchController,JoystickController.prototype=Object.create(Controller.prototype),JoystickController.prototype.constructor=JoystickController,JoystickButtonController.prototype=Object.create(JoystickController.prototype),JoystickButtonController.prototype.constructor=JoystickButtonController},function(t,e,o){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.gamee=void 0,o(0);var n=o(2),r=o(1),a=o(3),i=e.gamee=void 0,u=function(){var t,o="web",r=navigator.userAgent.toLowerCase();switch(/iphone|ipod|ipad/.test(r)?o=window.self!==window.top?"web":"ios":/gamee\/[0-9\.]+$/.test(r)?o="android":window.parent?o="web":window.parent&&window.parent.gameeSimulator&&(o="web"),e.gamee=i=new n.Gamee(o),window.gamee=i,o){case"web":window.parent,window,t=new a.PostMessageBridge(window.parent);break;case"ios":t=new a.MobileBridge("ios");break;case"android":t=new a.MobileBridge("android");break;default:throw"Can't identify the platform"}return t}();r.core.PlatformAPI=a.PlatformAPI,r.core.native=u,a.PlatformAPI.emitter=i.emitter},function(t,e){var o;o=function(){return this}();try{o=o||Function("return this")()||(0,eval)("this")}catch(t){"object"==typeof window&&(o=window)}t.exports=o}])});
3 | //# sourceMappingURL=gamee-js.min.js.map
--------------------------------------------------------------------------------
/gamee/libs/bullet.js:
--------------------------------------------------------------------------------
1 |
2 | var BulletClass = function () {
3 | var _self = this,
4 | _events = {};
5 |
6 | _self.on = function (event, fn, once) {
7 | if (arguments.length < 2 ||
8 | typeof event !== "string" ||
9 | typeof fn !== "function") return;
10 |
11 | var fnString = fn.toString();
12 |
13 | // if the named event object already exists in the dictionary...
14 | if (typeof _events[event] !== "undefined") {
15 | // add a callback object to the named event object if one doesn't already exist.
16 | if (typeof _events[event].callbacks[fnString] === "undefined") {
17 | _events[event].callbacks[fnString] = {
18 | cb: fn,
19 | once: !!once
20 | };
21 | }
22 | else if (typeof once === "boolean") {
23 | // the function already exists, so update it's 'once' value.
24 | _events[event].callbacks[fnString].once = once;
25 | }
26 | }
27 | else {
28 | // create a new event object in the dictionary with the specified name and callback.
29 | _events[event] = {
30 | callbacks: {}
31 | };
32 |
33 | _events[event].callbacks[fnString] = { cb: fn, once: !!once };
34 | }
35 | };
36 |
37 | _self.once = function (event, fn) {
38 | _self.on(event, fn, true);
39 | };
40 |
41 | _self.off = function (event, fn) {
42 | if (typeof event !== "string" ||
43 | typeof _events[event] === "undefined") return;
44 |
45 | // remove just the function, if passed as a parameter and in the dictionary.
46 | if (typeof fn === "function") {
47 | var fnString = fn.toString(),
48 | fnToRemove = _events[event].callbacks[fnString];
49 |
50 | if (typeof fnToRemove !== "undefined") {
51 | // delete the callback object from the dictionary.
52 | delete _events[event].callbacks[fnString];
53 | }
54 | }
55 | else {
56 | // delete all functions in the dictionary that are
57 | // registered to this event by deleting the named event object.
58 | delete _events[event];
59 | }
60 | };
61 |
62 | _self.trigger = function (event, data) {
63 | if (typeof event !== "string" ||
64 | typeof _events[event] === "undefined") return;
65 |
66 | for (var fnString in _events[event].callbacks) {
67 | var callbackObject = _events[event].callbacks[fnString];
68 |
69 | if (typeof callbackObject.cb === "function") callbackObject.cb(data);
70 | if (typeof callbackObject.once === "boolean" && callbackObject.once === true) _self.off(event, callbackObject.cb);
71 | }
72 | };
73 |
74 | };
75 |
76 |
77 | export var Bullet = new BulletClass();
--------------------------------------------------------------------------------
/gamee/libs/shims.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @class CustomEvent
3 | */
4 | (function shimCustomEvent() {
5 | try {
6 | var ce = new window.CustomEvent('test');
7 | ce.preventDefault();
8 | if (ce.defaultPrevented !== true) {
9 | // IE has problems with .preventDefault() on custom events
10 | // http://stackoverflow.com/questions/23349191
11 | throw new Error('Could not prevent default');
12 | }
13 | } catch (e) {
14 | var CustomEvent = function (event, params) {
15 | var evt, origPrevent;
16 | params = params || {
17 | bubbles: false,
18 | cancelable: false,
19 | detail: undefined
20 | };
21 |
22 | evt = document.createEvent("CustomEvent");
23 | evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
24 | origPrevent = evt.preventDefault;
25 | evt.preventDefault = function () {
26 | origPrevent.call(this);
27 | try {
28 | Object.defineProperty(this, 'defaultPrevented', {
29 | get: function () {
30 | return true;
31 | }
32 | });
33 | } catch (e) {
34 | this.defaultPrevented = true;
35 | }
36 | };
37 | return evt;
38 | };
39 |
40 | CustomEvent.prototype = window.Event.prototype;
41 | window.CustomEvent = CustomEvent; // expose definition to window
42 | }
43 | })();
44 |
45 | //addEventListener polyfill 1.0 / Eirik Backer / MIT Licence
46 | (function (win, doc) {
47 | if (win.addEventListener) return; //No need to polyfill
48 |
49 | function docHijack(p) { var old = doc[p]; doc[p] = function (v) { return addListen(old(v)); }; }
50 | function addEvent(on, fn, self) {
51 | return (self = this).attachEvent('on' + on, function (e) {
52 | e = e || win.event;
53 | e.preventDefault = e.preventDefault || function () { e.returnValue = false; };
54 | e.stopPropagation = e.stopPropagation || function () { e.cancelBubble = true; };
55 | fn.call(self, e);
56 | });
57 | }
58 | function addListen(obj, i) {
59 | i = obj.length;
60 | if (i) {
61 | while (i--)
62 | obj[i].addEventListener = addEvent;
63 | } else {
64 | obj.addEventListener = addEvent;
65 | }
66 | return obj;
67 | }
68 |
69 | addListen([doc, win]);
70 | if ('Element' in win) win.Element.prototype.addEventListener = addEvent; //IE8
71 | else { //IE < 8
72 | doc.attachEvent('onreadystatechange', function () { addListen(doc.all); }); //Make sure we also init at domReady
73 | docHijack('getElementsByTagName');
74 | docHijack('getElementById');
75 | docHijack('createElement');
76 | addListen(doc.all);
77 | }
78 | })(window, document);
79 |
80 | // naomik event emiter http://stackoverflow.com/a/24216547/1866147
81 | // usage:
82 | // function Example() {
83 | // CustomEmitter.call(this);
84 | // }
85 |
86 | // // run it
87 | // var e = new Example();
88 |
89 | // e.addEventListener("something", function (event) {
90 | // console.log(event)
91 | // });
92 |
93 | // e.dispatchEvent(new Event("something"));
94 | export function CustomEmitter() {
95 | var eventTarget = document.createDocumentFragment();
96 |
97 | function delegate(method) {
98 | this[method] = eventTarget[method].bind(eventTarget);
99 | }
100 |
101 | [
102 | "addEventListener",
103 | "dispatchEvent",
104 | "removeEventListener"
105 | ].forEach(delegate, this);
106 | }
107 |
108 | /** ### wrapKeyEvent
109 | *
110 | * Handle old IE event differences for key events
111 | *
112 | * @param {Function} fn callback
113 | */
114 | export function wrapKeyEvent(fn) {
115 | return function (ev) {
116 | if (!ev || !ev.keyCode) {
117 | if (!ev) {
118 | ev = window.event;
119 | }
120 |
121 | if (ev.which) {
122 | ev.keyCode = ev.which;
123 | }
124 | }
125 |
126 | return fn(ev);
127 | };
128 | }
--------------------------------------------------------------------------------
/gamee/src/core.js:
--------------------------------------------------------------------------------
1 | import * as controllers from "./game_controllers.js"
2 | import { wrapKeyEvent } from "../libs/shims.js"
3 |
4 | // unlock audio
5 | // overrides native AudioContext & webkitAudioContext
6 | (function () {
7 | // this works as a constructor
8 | var overloadedAudioContext = function (type) {
9 | var ctx = new type();
10 |
11 | // add audio resume to function on touchstart
12 | if (ctx.state === 'suspended') {
13 |
14 | var resume = function () {
15 |
16 | // Check if hack is necessary. Only occurs in iOS6+ devices
17 | // and only when you first boot the iPhone, or play a audio/video
18 | // with a different sample rate
19 | if (/(iPhone|iPad)/i.test(navigator.userAgent)) {
20 | var buffer = ctx.createBuffer(1, 1, 44100);
21 | var dummy = ctx.createBufferSource();
22 | dummy.buffer = buffer;
23 | dummy.connect(ctx.destination);
24 | dummy.start(0);
25 | dummy.disconnect();
26 | }
27 |
28 | ctx.resume();
29 | setTimeout(function () {
30 | if (ctx.state === 'running') {
31 | document.body.removeEventListener([
32 | 'touchcancel',
33 | 'touchend',
34 | 'touchenter',
35 | 'touchleave',
36 | 'touchmove',
37 | 'touchstart',
38 | 'mouseenter',
39 | 'mouseover',
40 | 'mousemove',
41 | 'mousedown',
42 | 'mouseup'
43 | ].join(" "), resume, false);
44 | }
45 | }, 0);
46 | };
47 |
48 | // only touchend will work, but hey, we tried...
49 | // https://github.com/WebAudio/web-audio-api/issues/836
50 | // https://www.chromestatus.com/feature/6406908126691328
51 | document.body.addEventListener([
52 | 'touchcancel',
53 | 'touchend',
54 | 'touchenter',
55 | 'touchleave',
56 | 'touchmove',
57 | 'touchstart',
58 | 'mouseenter',
59 | 'mouseover',
60 | 'mousemove',
61 | 'mousedown',
62 | 'mouseup'
63 | ].join(" "),
64 | resume, false);
65 | }
66 | // allowed in JS to return different type of the object in the constructor
67 | return ctx
68 | };
69 |
70 | try {
71 | if (typeof window.AudioContext !== 'undefined') {
72 | window.AudioContext = overloadedAudioContext.bind(null, window.AudioContext);
73 | } else if (typeof webkitAudioContext !== 'undefined') {
74 | window.webkitAudioContext = overloadedAudioContext.bind(null, window.webkitAudioContext);
75 | }
76 | } catch (e) { // throw error in async part
77 | setTimeout(() => {
78 | throw e;
79 | }, 0)
80 | }
81 | })();
82 |
83 |
84 | /**
85 | * @class core
86 | */
87 | export var core = (function () {
88 |
89 | // # Gamee.js
90 | //
91 | // This file defines and expose a public API for games to communicate
92 | // with Gamee*.
93 | //
94 | // Also it handles some requirements when Gamee is run in an desktop
95 | // environment.
96 | //
97 | // \* _later in the document Gamee will be referred as GameeApp to not
98 | // be mistaken for word game_
99 | //
100 | // ** _GameeWebApp will refer to Gamee which is running in a desktop
101 | // browser_
102 |
103 | /** an empty function */
104 | var noop = function () { };
105 |
106 | var cache = {};
107 |
108 | /** internal variables/constants (uppercase) coupled inside separate object for potential easy referencing */
109 | var internals = {
110 | VERSION: "2.4.0", // version of the gamee library
111 | CAPABILITIES: ["ghostMode", "saveState", "replay", "socialData","rewardedAds","coins","logEvents","playerData","share", "gems"], // supported capabilities
112 | variant: 0, // for automating communication with server
113 | soundUnlocked: false,
114 | onReady: noop, // for intercepting real onReady because of behind the scenes variant handling
115 | onGameStart: noop // for intercepting real onGameStart because of unlocking sound
116 | };
117 |
118 | /** ## gamee
119 | *
120 | * GameeApp interface for games. It is exposed as a `gamee` global
121 | * object and games should only use its public methods and
122 | * properties to communicate with the GameeApp.
123 | *
124 | * _There is also [$gameeNative](gamee_native.js.html) global object
125 | * which handles internal parts of the communication._
126 | */
127 | var core = {};
128 |
129 | //
130 | // ## Signaling game state
131 | //
132 | // The game should signal the GameeApp its status (playing/game-over)
133 | // and current score.
134 | //
135 |
136 | /** ### gamee.gameeInit
137 | *
138 | * Must be called first before any other gamee calls
139 | * returns controller object the same way requestController did previously
140 | * ctrlType/ctrlOpts - requested control type + options
141 | * capabilities -> array of strings representing supported features:
142 | * after the initialization onReady is invoked and after that game can use the api
143 | */
144 | core.gameeInit = function (ctrlType, ctrlOpts, capabilities, cb, silentMode = false) {
145 | // let's validate the array here, so that all backends can benefit from it
146 | var allOk = true, cap = {};
147 | if ((capabilities !== undefined) && (Array.isArray(capabilities))) {
148 | for (var i = 0; i < capabilities.length; i++) {
149 | if ((typeof capabilities[i] !== "string") ||
150 | (internals.CAPABILITIES.indexOf(capabilities[i]) === -1)) allOk = false;
151 | cap[capabilities[i]] = true;
152 | }
153 | } else allOk = false;
154 |
155 | if (!allOk)
156 | throw "Capabilities array passed to gameeInit is void, malformed or unsupported capabilites requested.";
157 | // TODO remove
158 | // gameeNative.gameeInit(core, internals.VERSION, ctrlType, allOk ? capabilities : []);
159 |
160 | this.native.createRequest("init", {
161 | version: internals.VERSION,
162 | controller: ctrlType,
163 | capabilities: cap
164 | }, function (responseData) {
165 | // remember capabilities of the game
166 | cache.capabilities = cap;
167 | //
168 | // // Mute gamee-js console output
169 | // cache.silentMode = silentMode;
170 |
171 | // might fail if controller of this type doesnt exist
172 | var error = null;
173 | try {
174 | if (this.native.platform === "web") {
175 | responseData.controller = core.controller.requestController(ctrlType, { enableKeyboard: true });
176 | this._bindKeyboardTriggers(responseData.controller);
177 | } else {
178 | responseData.controller = core.controller.requestController(ctrlType, {});
179 | }
180 | } catch (err) {
181 | error = err;
182 | }
183 |
184 | cb(error, responseData);
185 | }.bind(this));
186 | // TODO remove
187 | // return core.controller.requestController(ctrlType, ctrlOpts);
188 | };
189 |
190 | core._bindKeyboardTriggers = function (controller) {
191 | global.addEventListener('message', function (ev) {
192 | switch (ev.data[0]) {
193 | case 'button_button_down':
194 | controller.trigger("keydown", { button: "button" });
195 | break;
196 |
197 | case 'button_button_up':
198 | controller.trigger("keyup", { button: "button" });
199 | break;
200 |
201 | case 'button_left_up':
202 | controller.trigger("keyup", { button: "left" });
203 | break;
204 |
205 | case 'button_left_down':
206 | controller.trigger("keydown", { button: "left" });
207 | break;
208 |
209 | case 'button_right_down':
210 | controller.trigger("keydown", { button: "right" });
211 | break;
212 |
213 | case 'button_right_up':
214 | controller.trigger("keyup", { button: "right" });
215 | break;
216 |
217 | case 'button_up_down':
218 | controller.trigger("keydown", { button: "up" });
219 | break;
220 |
221 | case 'button_up_up':
222 | controller.trigger("keyup", { button: "up" });
223 | break;
224 |
225 | case 'button_down_down':
226 | controller.trigger("keydown", { button: "down" });
227 | break;
228 |
229 | case 'button_down_up':
230 | controller.trigger("keyup", { button: "down" });
231 | break;
232 |
233 | case 'button_a_down':
234 | controller.trigger("keydown", { button: "A" });
235 | break;
236 |
237 | case 'button_a_up':
238 | controller.trigger("keyup", { button: "A" });
239 | break;
240 |
241 | case 'button_b_down':
242 | controller.trigger("keydown", { button: "B" });
243 | break;
244 |
245 | case 'button_b_up':
246 | controller.trigger("keyup", { button: "B" });
247 | break;
248 | }
249 | });
250 | };
251 |
252 | /** ### gamee.gameLoadingProgress
253 | *
254 | * Indicates how much content is already loaded in %.
255 | */
256 | core.gameLoadingProgress = (function () {
257 | var percentageSoFar = 0;
258 |
259 | return function (percentage) {
260 | if ((typeof percentage !== "number") || (percentage < 0) || (percentage > 100))
261 | throw "Percentage passed to gameLoadingProgress out of bounds or not a number.";
262 | else if (percentage > percentageSoFar) {
263 | percentageSoFar = percentage;
264 | this.native.createRequest("gameLoadingProgress", { percentage: percentage });
265 | }
266 | };
267 | })();
268 |
269 |
270 | /** ### gamee.gameReady
271 | *
272 | * Notifies platform game can accept start command.
273 | */
274 | core.gameReady = function () {
275 | this.native.createRequest("gameReady");
276 | };
277 |
278 | /** ### gamee.gameStart
279 | *
280 | * Indicates that game is ready to be started (even after restart).
281 | */
282 | // core.gameStart = function () {
283 | // gameeNative.gameLoadingProgress(100); // FB requires this
284 | // gameeNative.gameStart(gamee);
285 | // };
286 |
287 | /** ### gamee.updateScore
288 | *
289 | * sends score to UI
290 | */
291 | core.updateScore = function (score, opt_ghostSign) {
292 | if (typeof score !== "number")
293 | throw "Score passed to updateScore is not a number.";
294 | var data = {
295 | score: parseInt(score, 10)
296 | };
297 | if (opt_ghostSign) {
298 | data.ghostSign = true;
299 | }
300 | this.native.createRequest("updateScore", data);
301 | // core.native.createRequest(method, requestData, callback);
302 | };
303 |
304 | /** ### gamee.gameOver
305 | *
306 | * Indicates the game has ended, the game is waiting for subsequent onGameStart.
307 | * Data has the same format as data received in onReady callback.
308 | * Data must be string = responsibility for turning data structure into string is left to the game!
309 | */
310 | core.gameOver = function (opt_replayData, opt_saveState, opt_hideOverlay) {
311 | opt_hideOverlay = opt_hideOverlay !== undefined ? opt_hideOverlay : false;
312 | // var allOk = ((data !== undefined) && (typeof data === "string")) || (data === undefined);
313 | // if (!allOk) console.error("Data provided to gameOver function must be string.");
314 | // gameeNative.gameOver(gamee, internals.variant, allOk ? data : "");
315 | var requestData = {};
316 | if (opt_replayData) {
317 | if (!opt_replayData.hasOwnProperty("variant")) {
318 | opt_replayData.variant = "";
319 | }
320 | if (!opt_replayData.hasOwnProperty("data")) {
321 | throw "Replay data must have `data` property";
322 | }
323 | requestData.replayData = opt_replayData;
324 | }
325 | requestData.hideOverlay = opt_hideOverlay;
326 |
327 | if (opt_saveState) {
328 | requestData.state = opt_saveState;
329 | }
330 |
331 | core.native.createRequest("gameOver", requestData);
332 | };
333 |
334 | /** ### gamee.gameSave
335 | *
336 | * Player has requested saving current game's state
337 | * data must be string = responsibility for turning data structure into string is left to game!
338 | * share must be expression evaluating to either true or false; it indicates, whether the game progress should be shared on feed
339 | */
340 | core.gameSave = function (data, share) {
341 |
342 | if(!cache.capabilities.saveState)
343 | throw "Save State not supported, you must add the capability on gamee.Init";
344 |
345 | core.native.createRequest("saveState", { state: data, share: share });
346 | };
347 |
348 | core.requestSocial = function (cb,numberOfPlayers) {
349 |
350 | if(!cache.capabilities.socialData)
351 | throw "Social Data not supported, you must add the capability on gamee.Init";
352 |
353 | this.native.createRequest("requestSocial", numberOfPlayers, function (responseData) {
354 | cb(null, responseData);
355 | });
356 | };
357 |
358 | core.logEvent = function (eventName, eventValue) {
359 |
360 | if(!cache.capabilities.logEvents)
361 | throw "Log Events not supported, you must add the capability on gamee.Init";
362 |
363 | //var valuesToLogString = JSON.stringify(eventValue)
364 |
365 | this.native.createRequest("logEvent", {eventName,eventValue}, function (error){
366 | if(error){
367 | throw error
368 | }
369 | });
370 |
371 | };
372 |
373 | core.requestBattleData = function (cb) {
374 | this.native.createRequest("requestBattleData", undefined, function (responseData) {
375 | cb(null, responseData);
376 | });
377 | };
378 |
379 | core.requestPlayerReplay = function (userID, cb) {
380 |
381 | if(!cache.capabilities.replay)
382 | throw "Replays not supported, you must add the capability on gamee.Init";
383 |
384 | this.native.createRequest("requestPlayerReplay", {userID}, function (responseData) {
385 | cb(null, responseData);
386 | });
387 | };
388 |
389 | core.requestPlayerSaveState = function (userID, cb) {
390 | this.native.createRequest("requestPlayerSaveState", {userID}, function (responseData) {
391 | cb(null, responseData);
392 | });
393 | };
394 |
395 | core.purchaseItemWithCoins = function (options, cb, oldMethod) {
396 |
397 | if(!cache.capabilities.coins)
398 | throw "Coins purchases not supported, you must add the capability on gamee.Init";
399 |
400 | if (options) {
401 | var propertiesList = ["coinsCost","itemName"];
402 | propertiesList.forEach(function (property){
403 | if(!options.hasOwnProperty(property))
404 | throw "Purchase Options must have `"+property+"` property"
405 | })
406 | }
407 |
408 | if (!this.isSilentModeEnabled()) {
409 | console.log(options);
410 | }
411 |
412 | var method = "purchaseItemWithCoins";
413 | if (oldMethod !== undefined && oldMethod === true) {
414 | method = "purchaseItem";
415 | }
416 | this.native.createRequest(method, options, function (responseData) {
417 | cb(null, responseData);
418 | });
419 | };
420 |
421 | core.purchaseItemWithGems = function (options, cb) {
422 |
423 | if(!cache.capabilities.gems)
424 | throw "Gems purchases not supported, you must add the capability on gamee.Init";
425 |
426 | if (options) {
427 | var propertiesList = ["gemsCost","itemName"];
428 | propertiesList.forEach(function (property){
429 | if(!options.hasOwnProperty(property))
430 | throw "Purchase options must have `"+property+"` property"
431 | })
432 | }
433 |
434 | if (!this.isSilentModeEnabled()) {
435 | console.log(options);
436 | }
437 |
438 | this.native.createRequest("purchaseItemWithGems", options, function (responseData) {
439 | cb(null, responseData);
440 | });
441 | };
442 |
443 | core.share = function (options, cb) {
444 |
445 | if(!cache.capabilities.share)
446 | throw "Share option not supported, you must add the capability on gamee.Init";
447 |
448 | if (options) {
449 | var propertiesList = ["destination"];
450 | propertiesList.forEach(function (property){
451 | if(!options.hasOwnProperty(property))
452 | throw "Share Options must have `"+property+"` property";
453 | })
454 | }
455 |
456 | if (!this.isSilentModeEnabled()) {
457 | console.log(options);
458 | }
459 |
460 | this.native.createRequest("share",options, function (responseData) {
461 | cb(null, responseData);
462 | });
463 | };
464 |
465 | core.loadRewardedVideo = function (cb) {
466 |
467 | if(!cache.capabilities.rewardedAds)
468 | throw "Rewarded Ads not supported, you must add the capability on gamee.Init";
469 |
470 | this.native.createRequest("loadRewardedVideo", function (responseData) {
471 | cb(null, responseData);
472 | });
473 | };
474 |
475 | core.showRewardedVideo = function (cb) {
476 |
477 | if(!cache.capabilities.rewardedAds)
478 | throw "Rewarded Ads not supported, you must add the capability on gamee.Init";
479 |
480 | this.native.createRequest("showRewardedVideo", function (responseData) {
481 | cb(null, responseData);
482 | });
483 | };
484 |
485 | core.requestPlayerData = function (cb, userID) {
486 |
487 | if(!cache.capabilities.playerData)
488 | throw "Player Data not supported, you must add the capability on gamee.Init";
489 |
490 | let options = undefined;
491 | if (userID) {
492 | options = {userID};
493 | }
494 |
495 | this.native.createRequest("requestPlayerData", options, function (responseData) {
496 | cb(null, responseData);
497 | });
498 | };
499 |
500 | core.startSignal = function (data) {
501 | var error;
502 |
503 | if (data.replay && !cache.capabilities.replay)
504 | error = "Game doesn't support replay. ";
505 |
506 | if (data.ghostMode && !cache.capabilities.ghostMode)
507 | error = "Game doesn't support ghost Mode. ";
508 |
509 | return error;
510 | };
511 | //
512 | // ## Private objects and methods
513 | // These are internal objects in closed scope. Good to know about them
514 | // when debugging.
515 |
516 | //
517 | // ## gamee.controller
518 | //
519 | // Namespace where the methods for controller are published.
520 | //
521 |
522 | /**
523 | * TODO transform this into instance of gamee class
524 | */
525 | core.controller = {
526 | /** ### mainController
527 | *
528 | * Current controller.
529 | */
530 | mainController: null,
531 |
532 | /** ### requestController
533 | *
534 | * Factory method to create a controller. It creates the controller
535 | * and signals to GameeApp which type the game requires
536 | *
537 | * You should called this method once before calling
538 | * `gamee.gameStart()`.
539 | *
540 | * @param {String} type type of controller (see [controllerTypes](#controllertypes))
541 | * @param {Object} [opts] optional controller options
542 | * {'enableKeyboard': .., 'buttons': ...}
543 | * @param {boolean} [opts.enableKeyboard] enable the keyboard
544 | * @param {Object} [opts.buttons] remap buttons {'oldKey': 'newKey',
545 | * 'left': 'break' ..}
546 | */
547 | requestController: function (type, opts) {
548 | if (type === "FullScreen")
549 | return null;
550 |
551 | var controller = createController(type, opts);
552 |
553 | this.mainController = controller;
554 |
555 | return controller;
556 | },
557 |
558 | /** ### additionalController
559 | *
560 | * Construct an additional controller. Sometimes games require a
561 | * different controller depending on platform (eg. touch on mobile,
562 | e but Four Buttons on desktop)
563 | *
564 | * **This is currently supported only for GameeWebApp** as a way to
565 | * have alternate keybinding. The game should request a type used
566 | * for mobile platform and then some other as *additionalController*
567 | * if alternate keybinding is needed;
568 | */
569 | // TODO remove this function
570 | additionalController: function (type, opts) {
571 | var controller = createController(type, opts);
572 | gameeNative.additionalController(type);
573 |
574 | return controller;
575 | },
576 |
577 | /** ### trigger
578 | *
579 | * Triggers and event for the controller
580 | *
581 | * This is called by GameeApp to trigger the *keydown*, *keyup*
582 | * events. For more info see [Controller](#controller)
583 | *
584 | * @param {String} eventName name of the event
585 | * @param {*} [data,...] data to pass for the event
586 | *
587 | */
588 | trigger: function () {
589 | var i;
590 |
591 | if (this.mainController) {
592 | this.mainController.trigger.apply(this.mainController, arguments);
593 | } else {
594 | throw new Error('No controller present');
595 | }
596 | }
597 | };
598 |
599 | /** ### core._keydown
600 | *
601 | * A helper function to listen for `keydown` events on window object.
602 | *
603 | * @param {Function} fn callback to handle the event
604 | */
605 | core._keydown = function (fn) {
606 | global.addEventListener('keydown', wrapKeyEvent(fn));
607 | };
608 |
609 | /** ### core._keyup
610 | *
611 | * A helper function to listen for `keyup` events on window object.
612 | *
613 | * @param {Function} fn callback to handle the event
614 | */
615 | core._keyup = function (fn) {
616 | global.addEventListener('keyup', wrapKeyEvent(fn));
617 | };
618 |
619 | /** ### createController
620 | *
621 | * Function to create a controller.
622 | *
623 | * *see [requestController](#requestcontroller)
624 | *
625 | * @param {String} type
626 | * @param {Object} [opts]
627 | * @returns {Controller} controller
628 | */
629 | function createController(type, opts) {
630 | var btn, controller;
631 |
632 | if (!controllerTypes[type]) {
633 | throw new Error('Unsupported controller type, ' + type);
634 | }
635 |
636 | opts = opts || {};
637 |
638 | controller = new controllerTypes[type]();
639 |
640 | if (opts.enableKeyboard) {
641 | controller.enableKeyboard(core);
642 | }
643 |
644 | if (opts.buttons) {
645 | for (btn in opts.buttons) {
646 | controller.remapButton(btn, opts.buttons[btn]);
647 | }
648 | }
649 |
650 | return controller;
651 | }
652 |
653 |
654 |
655 | /** ### controllerTypes
656 | *
657 | * List of controller types and their coresponding classes.
658 | *
659 | * *see [Controllers](#controllers) for more info*
660 | * @requires Controller
661 | */
662 | var controllerTypes = {
663 | 'OneButton': controllers.OneButtonController,
664 | 'TwoButtons': controllers.TwoButtonController,
665 | 'FourButtons': controllers.FourButtonController,
666 | 'FiveButtons': controllers.FiveButtonController,
667 | 'SixButtons': controllers.SixButtonController,
668 | 'FourArrows': controllers.FourArrowController,
669 | 'Touch': controllers.TouchController,
670 | 'Joystick': controllers.JoystickController,
671 | 'JoystickWithButton': controllers.JoystickButtonController,
672 | 'TwoArrowsTwoButtons': controllers.TwoArrowsTwoButtonsController,
673 | 'TwoArrowsOneButton': controllers.TwoArrowsOneButtonController,
674 | 'TwoActionButtons': controllers.TwoActionButtonsController
675 | };
676 |
677 |
678 | core.registerPlatform = function (platformAPI) {
679 | // platformAPI.addEventListener()
680 | // TODO ?
681 | };
682 |
683 | /**
684 | * Is true mute all console outputs
685 | * @return {boolean}
686 | */
687 | core.isSilentModeEnabled = function () {
688 | return cache.silentMode;
689 | };
690 |
691 | return core;
692 | })();
693 |
694 | export var DataTypeException = function (expected, present, argument, method) {
695 | this.expected = expected;
696 | this.present = present;
697 | this.method = method;
698 | this.argument = argument;
699 | this.message = `Invalid data type in method ${this.method}, argument ${this.argument} is expected to be ${this.expected}, but found ${this.present}`;
700 | };
701 |
702 | export var validateDataType = function (testedInput, expectedType, argument, originMethod) {
703 | switch (expectedType) {
704 |
705 | case "array":
706 | if (!Array.isArray(testedInput))
707 | throw new DataTypeException(expectedType, typeof testedInput, argument, originMethod);
708 | break;
709 |
710 | default:
711 | if (typeof testedInput !== expectedType)
712 | throw new DataTypeException(expectedType, typeof testedInput, argument, originMethod);
713 | }
714 | };
715 |
--------------------------------------------------------------------------------
/gamee/src/game_controllers.js:
--------------------------------------------------------------------------------
1 | import { Bullet } from "../libs/bullet.js"
2 |
3 | /**
4 | * @module game_controllers
5 | */
6 |
7 | /** ## Bullet
8 | *
9 | * [Bullet.js](https://github.com/munkychop/bullet) is used as pub/sub
10 | * library.
11 | *
12 | * The controller and its buttons are instance of Bullet.
13 | */
14 | export var BulletClass = Bullet.constructor;
15 |
16 |
17 | /** ## Button
18 | *
19 | * Represenation of a controller button. It is a child of
20 | * [Bullet](https://github.com/munkychop/bullet), so you can
21 | * subscribe for events triggered on it.
22 | *
23 | * @class Button
24 | * @param {String} key name of the button
25 | * @param {Number} keyCode keycode for the key to represent the button
26 | * on keyboard
27 | */
28 | export function Button(key, keyCode) {
29 | var self = this;
30 |
31 | BulletClass.call(this);
32 |
33 | this._pressed = true;
34 |
35 | this.key = key;
36 | this.keyCode = keyCode;
37 |
38 | this.on('keydown', function () {
39 | self._pressed = true;
40 | });
41 |
42 | this.on('keyup', function () {
43 | self._pressed = false;
44 | });
45 | }
46 |
47 | Button.prototype = Object.create(BulletClass.constructor.prototype);
48 | Button.constructor = Button;
49 |
50 | /** ### isDown
51 | *
52 | * Ask if the button is currently pressed.
53 | *
54 | * @return {Boolean} true if the button is currently pressed
55 | */
56 | Button.prototype.isDown = function () {
57 | return this._pressed;
58 | };
59 |
60 | /** ## Controller
61 | *
62 | * Controller has a collection of [buttons](#buttons).
63 | * It is a child of
64 | * [Bullet](https://github.com/munkychop/bullet), so you can
65 | * subscribe for events triggered on it.
66 | *
67 | * Controllers will get all the events for its buttons so you can
68 | * listen for them globaly from controller or individualy on every
69 | * button.
70 | *
71 | * ```javascript
72 | * controller.on('keydown', function(data) {
73 | * console.log('button ' + data.button + ' is pressed');
74 | * });
75 | *
76 | * controller.buttons.left.on('keydown', function() {
77 | * console.log('button left is pressed');
78 | * });
79 | * ```
80 | *
81 | * @class Controller
82 | */
83 | export function Controller() {
84 | var self = this;
85 |
86 | BulletClass.call(this);
87 |
88 | // ### buttons
89 | //
90 | // Map of controller's [buttons](#button) by their name.
91 | //
92 | // ```javascript
93 | // controller.buttons.left // Button('left', ..)
94 | // ```
95 | this.buttons = {};
96 |
97 | // ### buttonAlias
98 | //
99 | // Map of remapped buttons.
100 | //
101 | // *see [remapButton](#remapbutton) for more info*
102 | //
103 | this.buttonAlias = {};
104 |
105 | // Events prefixed with *$* are private, sent from GameeApp ment
106 | // to be handled before resended as *public (non-prefixed)*
107 | // event.
108 | //
109 | // They should be not used in games as they can change in the future.
110 | this.on('$keydown', function (data) {
111 | if (data.button && self.buttonAlias[data.button]) {
112 | data.button = self.buttonAlias[data.button];
113 | }
114 |
115 | self.trigger('keydown', data);
116 | });
117 |
118 | this.on('$keyup', function (data) {
119 | if (data.button && self.buttonAlias[data.button]) {
120 | data.button = self.buttonAlias[data.button];
121 | }
122 |
123 | self.trigger('keyup', data);
124 | });
125 |
126 | // By default GameeApp will trigger *keydown* and *keyup* events for
127 | // the controller for every button presses/released.
128 | //
129 | // The controller then handles the event and triggers the event for
130 | // the coresponding button.
131 | //
132 | // It expexts a `data` argument which should have a property `button`
133 | // with the name of button.
134 | this.on('keydown', function (data) {
135 | if (!data.button || !self.buttons[data.button]) {
136 | return;
137 | }
138 |
139 | self.buttons[data.button].trigger('keydown');
140 | });
141 |
142 | this.on('keyup', function (data) {
143 | if (!data.button || !self.buttons[data.button]) {
144 | return;
145 | }
146 |
147 | self.buttons[data.button].trigger('keyup');
148 | });
149 | }
150 |
151 | Controller.prototype = Object.create(BulletClass.constructor.prototype);
152 | Controller.constructor = Controller;
153 |
154 | /** ### addButton
155 | *
156 | * Add button to the controller.
157 | *
158 | * @param {Button} button a [Button](#button) instance
159 | */
160 | Controller.prototype.addButton = function (button) {
161 | this.buttons[button.key] = button;
162 | };
163 |
164 | /** ### enableKeyboard
165 | *
166 | * Enable keyboard controlls. It will attach event listeners to the
167 | * *window* object for every button and trigger their *keydown* /
168 | * *keyup* event for the controller.
169 | */
170 | Controller.prototype.enableKeyboard = function (gamee) {
171 | var key, button, keyCodes = {}, self = this;
172 |
173 | for (key in this.buttons) {
174 | button = this.buttons[key];
175 |
176 | if (button.keyCode) {
177 | keyCodes[button.keyCode] = button;
178 | }
179 | }
180 |
181 | gamee._keydown(function (ev) {
182 | var button = keyCodes[ev.keyCode];
183 |
184 | if (!button) {
185 | return;
186 | }
187 |
188 | ev.preventDefault();
189 | self.trigger('keydown', { button: button.key });
190 | });
191 |
192 | gamee._keyup(function (ev) {
193 | var button = keyCodes[ev.keyCode];
194 |
195 | if (!button) {
196 | return;
197 | }
198 |
199 | ev.preventDefault();
200 | self.trigger('keyup', { button: button.key });
201 | });
202 | };
203 |
204 | /** ### remapButton
205 | *
206 | * Remap the names of the controller's buttons. Controllers have their
207 | * button names set (left, right, A, B), but sometimes in context of
208 | * the game a different names are desired.
209 | *
210 | * ```javascript
211 | * var controller = gamee.controller.requestController('TwoButtons');
212 | * controller.remapButton('left', 'throttle');
213 | * controller.remapButton('right', 'break');
214 | *
215 | * controller.buttons.throttle.on('keydown', ..);
216 | * ```
217 | *
218 | * @param {String} oldName button name we want to change
219 | * @param {String} newName new button name
220 | */
221 | Controller.prototype.remapButton = function (oldName, newName) {
222 |
223 | // handle old code
224 | if (newName.name) {
225 | newName = newName.name;
226 | }
227 |
228 | if (this.buttons[oldName]) {
229 | this.buttonAlias[oldName] = newName.name;
230 |
231 | this.buttons[newName.name] = this.buttons[oldName];
232 |
233 | delete this.buttons[oldName];
234 | } else {
235 | throw Error('Button ' + oldName + ' was not found in controller');
236 | }
237 | };
238 |
239 | // ## Controllers
240 |
241 | /** ### OneButtonController
242 | *
243 | * Controller with only one button.
244 | * @class OneButtonController
245 | */
246 | export function OneButtonController() {
247 | Controller.call(this);
248 |
249 | // * __name__: 'button'
250 | // * __key__: spacebar
251 | this.addButton(new Button('button', 32));
252 | }
253 | OneButtonController.prototype = Object.create(Controller.prototype);
254 | OneButtonController.prototype.constructor = OneButtonController;
255 |
256 |
257 | /** ### TwoButtonController
258 | *
259 | * Controller with two buttons
260 | * @class TwoButtonController
261 | */
262 | export function TwoButtonController() {
263 | Controller.call(this);
264 |
265 | // * __name__: 'left'
266 | // * __key__: left arrow
267 | this.addButton(new Button('left', 37));
268 |
269 | // * __name__: 'right'
270 | // * __key__: righ arrow
271 | this.addButton(new Button('right', 39));
272 | }
273 | TwoButtonController.prototype = Object.create(Controller.prototype);
274 | TwoButtonController.prototype.constructor = TwoButtonController;
275 |
276 |
277 | /** ### TwoActionButtonsController
278 | *
279 | * Controller with two action buttons (A,B)
280 | * @class TwoActionButtonsController
281 | */
282 | export function TwoActionButtonsController() {
283 | Controller.call(this);
284 |
285 | // * __name__: 'left'
286 | // * __key__: left arrow
287 | this.addButton(new Button('A', 32));
288 |
289 | // * __name__: 'right'
290 | // * __key__: righ arrow
291 | this.addButton(new Button('B', 17));
292 | }
293 | TwoActionButtonsController.prototype = Object.create(Controller.prototype);
294 | TwoActionButtonsController.prototype.constructor = TwoActionButtonsController;
295 |
296 |
297 | /** ### FourButtonController
298 | *
299 | * Controller with four buttons
300 | * @class FourButtonController
301 | */
302 | export function FourButtonController() {
303 | Controller.call(this);
304 |
305 | // * __name__: 'up'
306 | // * __key__: left arrow
307 | this.addButton(new Button('up', 38));
308 |
309 | // * __name__: 'left'
310 | // * __key__: left arrow
311 | this.addButton(new Button('left', 37));
312 |
313 |
314 | // * __name__: 'right'
315 | // * __key__: righ arrow
316 | this.addButton(new Button('right', 39));
317 |
318 | // * __name__: 'A'
319 | // * __key__: spacebar
320 | this.addButton(new Button('A', 32));
321 | }
322 | FourButtonController.prototype = Object.create(Controller.prototype);
323 | FourButtonController.prototype.constructor = FourButtonController;
324 |
325 | /** ### FiveButtonController
326 | *
327 | * Controller with five buttons
328 | * @class FiveButtonController
329 | */
330 | export function FiveButtonController() {
331 | Controller.call(this);
332 |
333 | // * __name__: 'up'
334 | // * __key__: left arrow
335 | this.addButton(new Button('up', 38));
336 |
337 | // * __name__: 'left'
338 | // * __key__: left arrow
339 | this.addButton(new Button('left', 37));
340 |
341 |
342 | // * __name__: 'right'
343 | // * __key__: righ arrow
344 | this.addButton(new Button('right', 39));
345 |
346 | // * __name__: 'down'
347 | // * __key__: down arrow
348 | this.addButton(new Button('down', 40));
349 |
350 | // * __name__: 'A'
351 | // * __key__: spacebar
352 | this.addButton(new Button('A', 32));
353 | }
354 | FiveButtonController.prototype = Object.create(Controller.prototype);
355 | FiveButtonController.prototype.constructor = FiveButtonController;
356 |
357 | /** ### SixButtonController
358 | *
359 | * Controller with six buttons
360 | * @class SixButtonController
361 | */
362 | export function SixButtonController() {
363 | Controller.call(this);
364 |
365 | // * __name__: 'up'
366 | // * __key__: left arrow
367 | this.addButton(new Button('up', 38));
368 |
369 | // * __name__: 'left'
370 | // * __key__: left arrow
371 | this.addButton(new Button('left', 37));
372 |
373 |
374 | // * __name__: 'right'
375 | // * __key__: righ arrow
376 | this.addButton(new Button('right', 39));
377 |
378 | // * __name__: 'down'
379 | // * __key__: down arrow
380 | this.addButton(new Button('down', 40));
381 |
382 | // * __name__: 'A'
383 | // * __key__: spacebar
384 | this.addButton(new Button('A', 32));
385 |
386 | // * __name__: 'B'
387 | // * __key__: ctrl
388 | this.addButton(new Button('B', 17));
389 | }
390 | SixButtonController.prototype = Object.create(Controller.prototype);
391 | SixButtonController.prototype.constructor = SixButtonController;
392 |
393 | /** ### TwoArrowsOneButtonController
394 | *
395 | * Controller with two arrows and one action button
396 | * @class TwoArrowsOneButtonController
397 | */
398 | export function TwoArrowsOneButtonController() {
399 | Controller.call(this);
400 |
401 |
402 | // * __name__: 'left'
403 | // * __key__: left arrow
404 | this.addButton(new Button('left', 37));
405 |
406 |
407 | // * __name__: 'right'
408 | // * __key__: righ arrow
409 | this.addButton(new Button('right', 39));
410 |
411 |
412 | // * __name__: 'A'
413 | // * __key__: spacebar
414 | this.addButton(new Button('A', 32));
415 |
416 | }
417 | TwoArrowsOneButtonController.prototype = Object.create(Controller.prototype);
418 | TwoArrowsOneButtonController.prototype.constructor = TwoArrowsOneButtonController;
419 |
420 | /** ### TwoArrowsTwoButtonsController
421 | *
422 | * Controller with two arrows and two action buttons
423 | * @class TwoArrowsTwoButtonsController
424 | */
425 | export function TwoArrowsTwoButtonsController() {
426 | Controller.call(this);
427 |
428 |
429 | // * __name__: 'left'
430 | // * __key__: left arrow
431 | this.addButton(new Button('left', 37));
432 |
433 |
434 | // * __name__: 'right'
435 | // * __key__: righ arrow
436 | this.addButton(new Button('right', 39));
437 |
438 |
439 | // * __name__: 'A'
440 | // * __key__: spacebar
441 | this.addButton(new Button('A', 32));
442 |
443 | // * __name__: 'B'
444 | // * __key__: ctrl
445 | this.addButton(new Button('B', 17));
446 |
447 | }
448 | TwoArrowsTwoButtonsController.prototype = Object.create(Controller.prototype);
449 | TwoArrowsTwoButtonsController.prototype.constructor = TwoArrowsTwoButtonsController;
450 |
451 | /** ### FourArrowController
452 | *
453 | * Controller with four arrow buttons
454 | * @class FourArrowController
455 | */
456 | export function FourArrowController() {
457 | Controller.call(this);
458 |
459 | // * __name__: 'up'
460 | // * __key__: left arrow
461 | this.addButton(new Button('up', 38));
462 |
463 | // * __name__: 'left'
464 | // * __key__: left arrow
465 | this.addButton(new Button('left', 37));
466 |
467 |
468 | // * __name__: 'right'
469 | // * __key__: righ arrow
470 | this.addButton(new Button('right', 39));
471 |
472 | // * __name__: 'down'
473 | // * __key__: down arrow
474 | this.addButton(new Button('down', 40));
475 | }
476 | FourArrowController.prototype = Object.create(Controller.prototype);
477 | FourArrowController.prototype.constructor = FourArrowController;
478 |
479 | /** ### TouchController
480 | *
481 | * This controller has no buttons. Instead it has a touchpad which
482 | * triggers *touchstart*, *touchend*, *touchmove*, *touchcancel*,
483 | * *touchend* events (similar to
484 | * [Touch event types](https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent#Touch_event_types))
485 | *
486 | * The position of the touch is in the `data.position` argument as a
487 | * *x* and *y* with the values between [0, 0] for the left top corner
488 | * and [1, 1] for the bottom right corner ([0.5, 0.5] is the center).
489 | *
490 | * ```javascript
491 | * controller = gamee.controller.requestController('Touch');
492 | *
493 | * controller.on('touchstart', function(data) {
494 | * if (data.position.x < 0.5 && data.position.y < 0.5) {
495 | * console.log('touch in the top left quadrant');
496 | * }
497 | * })
498 | * ```
499 | * @class TouchController
500 | */
501 | export function TouchController() {
502 | var self = this;
503 |
504 | Controller.call(this);
505 |
506 | this.on("$touchstart", function (data) {
507 | self.trigger('touchstart', data);
508 | });
509 |
510 | this.on("$touchend", function (data) {
511 | self.trigger('touchend', data);
512 | });
513 |
514 | this.on("$touchmove", function (data) {
515 | self.trigger('touchmove', data);
516 | });
517 |
518 | this.on("$touchleave", function (data) {
519 | self.trigger('touchleave', data);
520 | });
521 |
522 | this.on("$touchcancel", function (data) {
523 | self.trigger('touchcancel', data);
524 | });
525 | }
526 | TouchController.prototype = Object.create(TouchController.prototype);
527 | TouchController.prototype.constructor = TouchController;
528 |
529 | /** ### JoystickController
530 | *
531 | * JoystickController emits `change` event, after the position of the
532 | * joystick is changed.
533 | *
534 | * The position of the joystick is in the property `x` and `y`. The
535 | * position on axis is between <-1, 1> (for x -1 is max left
536 | * position, 1 max right position). [0.0, 0.0] is the center.
537 | *
538 | * ```javascript
539 | * joystick = gamee.controller.requestController('Joystick');
540 | *
541 | * joystick.on('change', function() {
542 | * new_x = joystick.x;
543 | * nex_y = joystick.y;
544 | * })
545 | * ```
546 | * @class JoystickController
547 | */
548 | export function JoystickController() {
549 | var self = this;
550 |
551 | Controller.call(this);
552 |
553 | // x axis
554 | this.x = 0;
555 | // y axis
556 | this.y = 0;
557 |
558 | this.on("$change", function (data) {
559 | self.x = data.position.x;
560 | self.y = data.position.y;
561 |
562 | self.trigger("change", data);
563 | });
564 | }
565 | JoystickController.prototype = Object.create(Controller.prototype);
566 | JoystickController.prototype.constructor = JoystickController;
567 |
568 | /** ### JoystickButtonController
569 | *
570 | * JoystickButtonController is a `JoystickController` with one button.
571 | *
572 | * ```javascript
573 | * joystick = gamee.controller.requestController('JoystickWithButton');
574 | *
575 | * joystick.on('change', function() {
576 | * new_x = joystick.x;
577 | * nex_y = joystick.y;
578 | * })
579 | *
580 | * joystick.buttons.button.on('keydown', callback)
581 | * // or simply
582 | * joystick.on('keydown', callback)
583 | * ```
584 | * @class JoystickButtonController
585 | */
586 | export function JoystickButtonController() {
587 | var self = this;
588 |
589 | JoystickController.call(this);
590 |
591 | // * __name__: 'button'
592 | // * __key__: spacebar
593 | this.addButton(new Button('button', 32));
594 | }
595 | JoystickButtonController.prototype = Object.create(JoystickController.prototype);
596 | JoystickButtonController.prototype.constructor = JoystickButtonController;
597 |
--------------------------------------------------------------------------------
/gamee/src/gameeAPI.js:
--------------------------------------------------------------------------------
1 | import { core } from "./core.js"
2 | import { CustomEmitter } from "../libs/shims.js"
3 | import { validateDataType } from "./core.js"
4 |
5 | /**
6 | * gameeAPI module desc
7 | * @module gameeAPI
8 | */
9 |
10 | /**
11 | * Emit events
12 | * @class GameeEmitter
13 | * @extends CustomEmitter
14 | */
15 | export var GameeEmitter = function () {
16 | CustomEmitter.call(this);
17 | };
18 |
19 | /**
20 | * @class Gamee
21 | * @requires core
22 | *
23 | */
24 | export var Gamee = function (platform) {
25 | /**
26 | * @instance
27 | *
28 | * @fires gameeAPI:GameeEmitter~start
29 | * @fires gameeAPI:GameeEmitter~mute
30 | * @fires gameeAPI:GameeEmitter~unmute
31 | * @fires gameeAPI:GameeEmitter~pause
32 | * @fires gameeAPI:GameeEmitter~unpause
33 | * @fires gameeAPI:GameeEmitter~ghostHide
34 | * @fires gameeAPI:GameeEmitter~ghostShow
35 | */
36 | this.emitter = new GameeEmitter();
37 | this._platform = platform;
38 | };
39 |
40 | Gamee.prototype = (function () {
41 |
42 | var cbError = function (err) {
43 | if (err) {
44 | throw "Error " + err.toString();
45 | }
46 | };
47 |
48 | return {
49 | _controller: core.controller,
50 | /**
51 | * gameInit
52 | * @memberof Gamee
53 | * @param {string} controllType
54 | * @param {object} controllOpts
55 | * @param {string[]} capabilities
56 | * @param {gameInitCallback} cb
57 | * @param {boolean} silentMode
58 | */
59 | gameInit: function (controllType, controllOpts, capabilities, cb, silentMode = false) {
60 | validateDataType(controllType, "string", "controllType", "gamee.updateScore");
61 | validateDataType(controllOpts, "object", "controllOpts", "gamee.gameInit");
62 | validateDataType(capabilities, "array", "capabilities", "gamee.gameInit");
63 | validateDataType(cb, "function", "cb", "gamee.gameInit");
64 | validateDataType(silentMode, "boolean", "silentMode", "gamee.gameInit");
65 | var result = core.gameeInit(controllType, controllOpts, capabilities, cb, silentMode);
66 | // cb(null, result);
67 | },
68 |
69 | /**
70 | * gameLoadingProgress
71 | *
72 | * gamee.gameLoadingProgress()
73 | *
74 | * @memberof Gamee
75 | * @param {number} percentage current loading progress
76 | * @param {Gamee~voidCallback} [opt_cb]
77 | *
78 | */
79 | gameLoadingProgress: function (percentage, opt_cb) {
80 | validateDataType(percentage, "number", "percentage", "gamee.gameLoadingProgress");
81 | opt_cb = opt_cb || cbError;
82 | validateDataType(opt_cb, "function", "opt_cb", "gamee.gameLoadingProgress");
83 | core.gameLoadingProgress(percentage);
84 | opt_cb(null);
85 | },
86 |
87 | /**
88 | * gameReady
89 | *
90 | * @memberof Gamee
91 | * @param {Gamee~voidCallback} [opt_cb]
92 | */
93 | gameReady: function (opt_cb) {
94 | opt_cb = opt_cb || cbError;
95 | validateDataType(opt_cb, "function", "opt_cb", "gamee.gameReady");
96 | core.gameReady();
97 | opt_cb(null);
98 | },
99 |
100 | /**
101 | * gameSave
102 | *
103 | * NOTE: There are 2 signatures for this function
104 | *
105 | * gamee.gameSave(data, opt_cb)
106 | * gamee.gameSave(data, opt_share, opt_cb)
107 | *
108 | * @memberof Gamee
109 | * @param {String} data current ingame progress
110 | * @param {Boolean} [opt_share=false]
111 | * @param {Gamee~voidCallback} [opt_cb]
112 | *
113 | */
114 | gameSave: function (data, opt_share, opt_cb) {
115 | var share = false, cb;
116 | validateDataType(data, "string", "data", "gamee.gameSave");
117 | if (typeof opt_share === 'function')
118 | opt_cb = opt_share;
119 | else if (typeof opt_share !== "undefined")
120 | validateDataType(opt_share, "boolean", "opt_share", "gamee.gameSave");
121 |
122 | opt_cb = opt_cb || cbError;
123 | validateDataType(opt_cb, "function", "opt_cb", "gamee.gameSave");
124 | core.gameSave(data, share);
125 | opt_cb(null);
126 | },
127 |
128 | /**
129 | * getPlatform
130 | *
131 | * @memberof Gamee
132 | * @returns {string} platform type can be android | ios | web | fb
133 | */
134 | getPlatform: function () {
135 | return this._platform;
136 | },
137 |
138 | /**
139 | * updateScore
140 | *
141 | * @memberof Gamee
142 | * @param {number} score
143 | * @param {boolean} [opt_ghostSign=false] If true, score will be updated for ghost instead.
144 | * @param {Gamee~voidCallback} [opt_cb]
145 | */
146 | updateScore: function (score, opt_ghostSign, opt_cb) {
147 | validateDataType(score, "number", "score", "gamee.updateScore");
148 | if (typeof opt_ghostSign === "function")
149 | opt_cb = opt_ghostSign;
150 | else if (typeof opt_ghostSign !== "undefined")
151 | validateDataType(opt_ghostSign, "boolean", "opt_ghostSign", "gamee.updateScore");
152 |
153 | opt_cb = opt_cb || cbError;
154 | validateDataType(opt_cb, "function", "opt_cb", "gamee.updateScore");
155 | core.updateScore(score, opt_ghostSign);
156 | opt_cb(null);
157 | },
158 |
159 | /**
160 | * gameOver
161 | *
162 | * @memberof Gamee
163 | * @param {Gamee~ReplayData} [opt_replayData]
164 | * @param {Gamee~voidCallback} [opt_cb]
165 | * @param {Gamee~object} [opt_saveState]
166 | * @param {Gamee~boolean} [opt_hideOverlay]
167 | */
168 | gameOver: function (opt_replayData, opt_cb, opt_saveState, opt_hideOverlay) {
169 | if (typeof opt_replayData === "function")
170 | opt_cb = opt_replayData;
171 | else if (typeof opt_replayData !== "undefined")
172 | validateDataType(opt_replayData, "object", "opt_replayData", "gamee.gameOver");
173 |
174 | if (typeof opt_hideOverlay !== 'undefined') {
175 | validateDataType(opt_hideOverlay, "boolean", "opt_hideOverlay", "gamee.gameOver");
176 | }
177 |
178 | opt_cb = opt_cb || cbError;
179 | validateDataType(opt_cb, "function", "opt_cb", "gamee.gameOver");
180 | core.gameOver(opt_replayData, opt_saveState, opt_hideOverlay);
181 | opt_cb(null);
182 | },
183 |
184 | /**
185 | * requestSocialData
186 | *
187 | * @memberof Gamee
188 | * @param {Gamee~requestSocialDataCallback} cb
189 | * @param {number} numberOfPlayers
190 | */
191 | requestSocial: function (cb, numberOfPlayers) {
192 | validateDataType(cb, "function", "cb", "gamee.requestSocial");
193 |
194 | // functionality supposed to be removed once we do update for iOS
195 | var data = core.requestSocial(function (error, responseData) {
196 | var modifiedResponse = !responseData.hasOwnProperty("socialData") ? { socialData: responseData } : responseData;
197 | cb(null, modifiedResponse);
198 | }, numberOfPlayers);
199 |
200 | // var data = core.requestSocial(cb);
201 | //cb(null, data);
202 | },
203 |
204 | /**
205 | * logEvent
206 | *
207 | * @memberof Gamee
208 | * @param {string} eventName
209 | * @param {string} eventValue
210 | */
211 | logEvent: function (eventName, eventValue) {
212 |
213 | validateDataType(eventName,"string","eventName","gamee.logEvent");
214 |
215 | if(!eventName || eventName.length > 24){
216 | console.error("eventName parameter cant be null and can only contain up to 24 characters");
217 | return
218 | }
219 |
220 | validateDataType(eventValue,"string","eventValue","gamee.logEvent");
221 |
222 | if(!eventValue || eventValue.length > 160){
223 | console.error("eventValue parameter cant be null and can only contain up to 160 characters");
224 | return
225 | }
226 |
227 | core.logEvent(eventName,eventValue);
228 | },
229 |
230 | /**
231 | * requestBattleData
232 | *
233 | * @memberof Gamee
234 | * @param {Gamee~requestBattleDataDataCallback} cb
235 | */
236 | requestBattleData: function (cb) {
237 | validateDataType(cb, "function", "cb", "gamee.requestBattleData");
238 |
239 | core.requestBattleData(cb);
240 | },
241 |
242 | /**
243 | * requestPlayerReplay
244 | *
245 | * @memberof Gamee
246 | * @param {number} userID
247 | * @param {Gamee~requestPlayerReplayDataCallback} cb
248 | */
249 | requestPlayerReplay: function (userID, cb) {
250 |
251 | validateDataType(userID, "number", "userID", "gamee.requestPlayerReplay");
252 | validateDataType(cb, "function", "cb", "gamee.requestPlayerReplay");
253 |
254 | core.requestPlayerReplay(userID, cb);
255 | },
256 |
257 | /**
258 | * requestPlayerSaveState
259 | *
260 | * @memberof Gamee
261 | * @param {number} userID
262 | * @param {Gamee~requestPlayerSaveStateDataCallback} cb
263 | */
264 | requestPlayerSaveState: function (userID, cb) {
265 |
266 | validateDataType(userID, "number", "userID", "gamee.requestPlayerSaveState");
267 | validateDataType(cb, "function", "cb", "gamee.requestPlayerSaveState");
268 |
269 | core.requestPlayerSaveState(userID, cb);
270 | },
271 |
272 | /*
273 | *purchaseItem
274 | *@member of Gamee
275 | *@param {object} purchaseDetails
276 | *@param {Gamee~purchaseItemDataCallback} cb
277 | */
278 | purchaseItem: function (purchaseDetails,cb){
279 |
280 | validateDataType(purchaseDetails,"object","purchaseDetails","gamee.purchaseItem");
281 | validateDataType(cb,"function","cb","gamee.purchaseItem");
282 |
283 | core.purchaseItemWithCoins(purchaseDetails, cb, true)
284 | },
285 |
286 | /*
287 | *purchaseItemWithCoins
288 | *@member of Gamee
289 | *@param {object} purchaseDetails
290 | *@param {Gamee~purchaseItemDataCallback} cb
291 | */
292 | purchaseItemWithCoins: function (purchaseDetails, cb) {
293 | validateDataType(purchaseDetails,"object","purchaseDetails","gamee.purchaseItemWithCoins");
294 | validateDataType(cb,"function","cb","gamee.purchaseItemWithCoins");
295 |
296 | core.purchaseItemWithCoins(purchaseDetails, cb)
297 | },
298 |
299 | /*
300 | *purchaseItemWithGems
301 | *@member of Gamee
302 | *@param {object} purchaseDetails
303 | *@param {Gamee~purchaseItemWithGemsDataCallback} cb
304 | */
305 | purchaseItemWithGems: function (purchaseDetails,cb) {
306 |
307 | validateDataType(purchaseDetails,"object","purchaseDetails","gamee.purchaseItemWithGems");
308 | validateDataType(cb,"function","cb","gamee.purchaseItemWithGems");
309 |
310 | core.purchaseItemWithGems(purchaseDetails,cb)
311 | },
312 |
313 | /*share
314 | *@member of Gamee
315 | *@param {object} shareDetails
316 | *@param {Gamee~shareDataCallback} cb
317 | */
318 | share: function (shareDetails,cb){
319 | validateDataType(shareDetails,"object","shareDetails","gamee.share");
320 | validateDataType(cb,"function","cb","gamee.share");
321 |
322 | core.share(shareDetails,cb)
323 | },
324 |
325 | /*
326 | *loadRewardedVideo
327 | *@member of Gamee
328 | *@param {Gamee~loadRewardedVideo} cb
329 | */
330 | loadRewardedVideo: function (cb){
331 |
332 | validateDataType(cb,"function","cb","gamee.loadRewardedVideo");
333 | core.loadRewardedVideo(cb)
334 | },
335 |
336 | /*
337 | *showRewardedVideo
338 | *@member of Gamee
339 | *@param{Gamee~showRewardedVideo} cb
340 | */
341 | showRewardedVideo: function (cb){
342 |
343 | validateDataType(cb,"function","cb","gamee.showRewardedVideo");
344 | core.showRewardedVideo(cb)
345 | },
346 |
347 | /**
348 | *requestPlayerData
349 | *@member of Gamee
350 | *@param{Gamee~requestPlayerData} cb
351 | * @param {number} userID
352 | */
353 | requestPlayerData: function (cb, userID){
354 |
355 | validateDataType(cb,"function","cb","gamee.requestPlayerData");
356 | if (userID !== undefined) {
357 | validateDataType(userID,"number","userId","gamee.requestPlayerData");
358 | }
359 | core.requestPlayerData(cb, userID)
360 | },
361 | };
362 |
363 | /**
364 | *
365 | * @typedef ReplayData
366 | * @param {string} variant
367 | * @param {string} data
368 | */
369 |
370 | /**
371 | * This callback is displayed as part of the Requester class.
372 | * @callback Gamee~voidCallback
373 | * @param {string} responseCode
374 | */
375 |
376 | /**
377 | * This callback is displayed as part of the Requester class.
378 | * @callback Gamee~gameInitCallback
379 | * @param {object} data
380 | * @param {string} responseCode
381 | */
382 |
383 | /**
384 | * This callback is displayed as part of the Requester class.
385 | * @callback Gamee~requestSocialDataCallback
386 | * @param {object} data
387 | * @param {string} responseCode
388 | */
389 |
390 | })();
391 |
392 | /**
393 | * Signals that game should start as normal|replay|ghost game.
394 | * Signal means there is no overlay over the game.
395 | * This signal is also being used for game restart. If previous
396 | * instance of the game was running, it should be terminated without
397 | * any additional calls and current progress should be tossed.
398 | * @event gameeAPI:GameeEmitter~start
399 | * @type {object}
400 | * @property {EventDetailStart} detail - Common property of events
401 | */
402 |
403 | /**
404 | * Data carried with start event.
405 | * @typedef EventDetailStart
406 | * @property {Gamee~voidCallback} callback - called after finishing task
407 | * @property {boolean} [opt_resetState=false] - if true, game must delete current progress and saved progress
408 | * @property {boolean} [opt_replay] - if true, game must run in replay mode
409 | * @property {boolean} [opt_ghostMode] - if true, game must run in ghost mode
410 | */
411 |
412 | /**
413 | * After that signal, game must silent all sounds immediately.
414 | * Game must remain silent until unmute signal occures.
415 | * @event gameeAPI:GameeEmitter~mute
416 | * @type {object}
417 | * @property {EventDetailVoid} detail - Common property of events
418 | */
419 |
420 | /**
421 | * After unmute signal, game can play sounds again.
422 | * @event gameeAPI:GameeEmitter~unmute
423 | * @type {object}
424 | * @property {EventDetailVoid} detail - Common property of events
425 | */
426 |
427 | /**
428 | * Pause signal means there appeared overlay over the game. Player
429 | * is unable to reach the context of the game anymore. So game should
430 | * pause all its acctions immediately.
431 | * @event gameeAPI:GameeEmitter~pause
432 | * @type {object}
433 | * @property {EventDetailVoid} detail - Common property of events
434 | */
435 |
436 | /**
437 | * Unpause signal means there is no overlay over the game anymore.
438 | * Game should continue with all previous actions.
439 | * @event gameeAPI:GameeEmitter~unpause
440 | * @type {object}
441 | * @property {EventDetailVoid} detail - Common property of events
442 | */
443 |
444 | /**
445 | * Signal ghostHide can appear only if game is running in ghost mode.
446 | * Game should hide ghost behavior and look like exactly as game without
447 | * the ghost (if this is possible).
448 | * @event gameeAPI:GameeEmitter~ghostHide
449 | * @type {object}
450 | * @property {EventDetailVoid} detail - Common property of events
451 | */
452 |
453 | /**
454 | * Signal ghostShow can appear only if game is running in ghost mode.
455 | * Game should show ghost again if it was hidden. If ghost died or ended
456 | * while it was hidden, game should point that out, so the player can understand
457 | * why the ghost is not visible anymore.
458 | * @event gameeAPI:GameeEmitter~ghostShow
459 | * @type {object}
460 | * @property {EventDetailVoid} detail - Common property of events
461 | */
462 |
463 | /**
464 | * Data carried with various events. Contains only callback method.
465 | * @typedef {object} EventDetailVoid
466 | * @property {Gamee~voidCallback} callback - call after finishing task
467 | */
468 |
469 | /**
470 | * @type {function}
471 | * @param {MyEvent} e - The observable event.
472 | * @listens gameeAPI:GameeEmitter~event:snowball
473 | */
474 |
--------------------------------------------------------------------------------
/gamee/src/index.js:
--------------------------------------------------------------------------------
1 | import { } from "../libs/shims.js"
2 | import { Gamee } from "./gameeAPI.js"
3 | import { core } from "./core.js"
4 | import { PlatformAPI, PlatformBridge, PostMessageBridge, MobileBridge } from "./platform_bridge.js"
5 |
6 |
7 | /**
8 | * Instance of gamee object with API for developers.
9 | * Internal functions becomes private this way
10 | *
11 | * @requires Gamee
12 | */
13 | export var gamee;
14 |
15 | /**
16 | * Resolves what platform is being used and make instance of platform API.
17 | *
18 | * @requires PlatformBridge
19 | */
20 | var platformBridge = (function () {
21 |
22 | var platformBridge, platformType = "web";
23 |
24 | // Reslove Gamee enviroment
25 | /* current user agent */
26 | var userAgent = navigator.userAgent.toLowerCase();
27 |
28 | if (/iphone|ipod|ipad/.test(userAgent)) { // test ios device
29 | // user agent is use to determine current enviroment
30 |
31 | // Test if window with game have a parent (loading in iframe)
32 | if (window.self !== window.top) {
33 | platformType = "web";
34 | } else {
35 | platformType = "ios";
36 | }
37 | } else if (/gamee\/[0-9\.]+$/.test(userAgent)) { // test android app
38 | // TODO do you really test android like that?
39 | platformType = "android";
40 | } else if (window.parent) { // TODO doesnt make sence, parent always exists!!
41 | platformType = "web";
42 | } else if (window.parent && window.parent.gameeSimulator) { // TODO doesnt make sence, parent always exist?
43 | platformType = "web";
44 | }
45 |
46 | gamee = new Gamee(platformType);
47 |
48 | window.gamee = gamee;
49 |
50 | switch (platformType) {
51 | case "web":
52 | if (window.parent === window) {
53 | console.error("Gamee must run in iframe on web platform");
54 | }
55 | platformBridge = new PostMessageBridge(window.parent);
56 | break;
57 | case "ios":
58 | platformBridge = new MobileBridge("ios");
59 | break;
60 | case "android":
61 | platformBridge = new MobileBridge("android");
62 | break;
63 | default:
64 | throw "Can't identify the platform";
65 | }
66 | return platformBridge;
67 | })();
68 |
69 | core.PlatformAPI = PlatformAPI;
70 | core.native = platformBridge;
71 |
72 | PlatformAPI.emitter = gamee.emitter;
73 |
74 |
75 | function loadScript (url, callback) {
76 | // Adding the script tag to the head as suggested before
77 | var head = document.getElementsByTagName('head')[0];
78 | var script = document.createElement('script');
79 | script.src = url;
80 |
81 | // Then bind the event to the callback function.
82 | // There are several events for cross browser compatibility.
83 | script.onreadystatechange = callback;
84 | script.onload = callback;
85 |
86 | // Fire the loading
87 | head.appendChild(script);
88 | }
89 |
--------------------------------------------------------------------------------
/gamee/src/platform_bridge.js:
--------------------------------------------------------------------------------
1 | import { core } from "./core.js"
2 |
3 | /**
4 | *
5 | * @requires core
6 | *
7 | * @typedef PlatformAPI
8 | * @param {EventTarget} emitter
9 | * @param {function} _pause
10 | * @param {function} _resume
11 | * @param {function} _ghostShow
12 | * @param {function} _ghostHide
13 | * @param {function} _mute
14 | * @param {function} _unmute
15 | * @param {function} _start
16 | */
17 | export var PlatformAPI = {
18 | emitter: null,
19 | pause: function (cb) {
20 | var event = new CustomEvent('pause', {
21 | detail: {
22 | callback: cb
23 | }
24 | });
25 | this.emitter.dispatchEvent(event);
26 | },
27 | resume: function (cb) {
28 | var event = new CustomEvent('resume', {
29 | detail: {
30 | callback: cb
31 | }
32 | });
33 | this.emitter.dispatchEvent(event);
34 | },
35 | ghostShow: function (cb) {
36 | var event = new CustomEvent('ghostShow', {
37 | detail: {
38 | callback: cb
39 | }
40 | });
41 | this.emitter.dispatchEvent(event);
42 | },
43 | ghostHide: function (cb) {
44 | var event = new CustomEvent('ghostHide', {
45 | detail: {
46 | callback: cb
47 | }
48 | });
49 | this.emitter.dispatchEvent(event);
50 | },
51 | mute: function (cb) {
52 | var event = new CustomEvent('mute', {
53 | detail: {
54 | callback: cb
55 | }
56 | });
57 | this.emitter.dispatchEvent(event);
58 | },
59 | unmute: function (cb) {
60 | var event = new CustomEvent('unmute', {
61 | detail: {
62 | callback: cb
63 | }
64 | });
65 | this.emitter.dispatchEvent(event);
66 | },
67 | start: function (data, cb) {
68 | var event = new CustomEvent('start', {
69 | detail: {
70 | callback: cb
71 | }
72 | });
73 |
74 | var error = core.startSignal(data);
75 | if (error) {
76 | cb(error);
77 | return;
78 | }
79 |
80 | if (data.replay)
81 | event.detail.opt_replay = true;
82 | if (data.ghostMode)
83 | event.detail.opt_ghostMode = true;
84 | if (data.resetState)
85 | event.detail.opt_resetState = true;
86 | if (data.replayData){
87 | event.detail.replayData = data.replayData
88 | }
89 |
90 | this.emitter.dispatchEvent(event);
91 | }
92 | };
93 |
94 |
95 | /**
96 | * @class PlatformBridge
97 | *
98 | */
99 | export function PlatformBridge() {
100 | this.requests = {};
101 | this.platform = "";
102 | this._init();
103 | }
104 |
105 | PlatformBridge.prototype = {
106 | instCount: 0,
107 | _init: function () {
108 | },
109 | createRequest: function (method, opt_requestData, opt_callback) {
110 | if (!this.validateMethod(method))
111 | return;
112 | if (typeof opt_requestData === 'function') {
113 | opt_callback = opt_requestData;
114 | opt_requestData = undefined;
115 | }
116 |
117 | var messId = this.instCount++;
118 |
119 | if (typeof opt_callback !== 'undefined') {
120 | this.requests[messId] = opt_callback;
121 | }
122 |
123 | var preparedObject = {
124 | request: {
125 | method: method,
126 | messageId: messId,
127 | data: null
128 | }
129 | };
130 |
131 | this.doCall(preparedObject, opt_requestData);
132 | },
133 | validateMethod: function (method) {
134 | return method === "gameLoadingProgress" ? false : true;
135 | },
136 | /**
137 | * @abstract
138 | */
139 | doCall: function (preparedObject, requestData) {
140 | throw "Not implemented";
141 | },
142 | _callback: function (id, responseData) {
143 | var cb = this.requests[id];
144 | delete this.requests[id];
145 | if (cb)
146 | cb(responseData);
147 | },
148 | /**
149 | * @abstract
150 | */
151 | doResponse: function (preparedObject, responseData) {
152 | throw "Not implemented";
153 | },
154 | };
155 |
156 |
157 | /**
158 | * @class PostMessageBridge
159 | * @requires PlatformBridge
160 | */
161 | export function PostMessageBridge(endpoint) {
162 | this._gameeWin = endpoint;
163 | PlatformBridge.call(this);
164 | this.platform = "web";
165 | }
166 |
167 | PostMessageBridge.prototype = Object.create(PlatformBridge.prototype);
168 | PostMessageBridge.prototype.constructor = PostMessageBridge;
169 |
170 | PostMessageBridge.prototype._init = function () {
171 |
172 | window.addEventListener('message', function (ev) {
173 | // if(ev.origin === "source we want")
174 | // console.log("_triggerMessage detail: " + ev.detail);
175 | // console.log("_triggerMessage data: " + ev.data);
176 | var data;
177 | if (typeof ev.detail === "object" && typeof ev.detail !== null) {
178 | data = ev.detail;
179 | } else if (typeof ev.data === "object") {
180 | data = ev.data;
181 | } else {
182 | // message is not from native platform
183 | return;
184 | }
185 |
186 | if (!core.isSilentModeEnabled()) {
187 | console.log(JSON.stringify(data, null, 4) + ' data');
188 | }
189 | // this is request
190 | if (data.request && data.request.method && typeof data.request.messageId !== "undefined") {
191 | this._resolveAPICall(data.request.method, data.request.messageId, data.request.data);
192 | }
193 | // this is reponse
194 | else if (data.response && typeof data.response.messageId !== "undefined") {
195 | if (data.error)
196 | throw data.error;
197 | this._callback(data.response.messageId, data.response.data);
198 | }
199 | // else this message target is not this framework
200 | }.bind(this), false);
201 | };
202 |
203 |
204 | PostMessageBridge.prototype.doCall = function (preparedObject, requestData) {
205 | if (typeof requestData === "object") {
206 | preparedObject.request.data = requestData || {};
207 | }
208 | this._gameeWin.postMessage(preparedObject, "*");
209 | };
210 |
211 | PostMessageBridge.prototype.doResponse = function (messageId, responseData) {
212 | var preparedObject = {
213 | version: this.version,
214 | response: {
215 | messageId: messageId
216 | }
217 | };
218 |
219 | if (responseData)
220 | preparedObject.data = responseData;
221 |
222 | this._gameeWin.postMessage(preparedObject, "*");
223 | };
224 |
225 | PostMessageBridge.prototype._resolveAPICall = function (method, messageId, opt_data) {
226 | var cb = this.doResponse.bind(this, messageId);
227 |
228 | switch (method) {
229 | case "pause":
230 | PlatformAPI.pause(cb);
231 | break;
232 | case "resume":
233 | PlatformAPI.resume(cb);
234 | break;
235 | case "mute":
236 | PlatformAPI.mute(cb);
237 | break;
238 | case "unmute":
239 | PlatformAPI.unmute(cb);
240 | break;
241 | case "ghostShow":
242 | PlatformAPI.ghostShow(cb);
243 | break;
244 | case "ghostHide":
245 | PlatformAPI.ghostHide(cb);
246 | break;
247 | case "start":
248 | if (!opt_data) {
249 | throw "Method _start missing params";
250 | }
251 | PlatformAPI.start(opt_data, cb);
252 | break;
253 | default:
254 | if (!core.isSilentModeEnabled()) {
255 | console.error("Unknown method call");
256 | }
257 | }
258 | };
259 |
260 |
261 | /**
262 | * @class MobileBridge
263 | * @requires PlatformBridge
264 | *
265 | */
266 | export function MobileBridge(device) {
267 | this.device = device;
268 | PostMessageBridge.call(this);
269 | this.platform = "mobile";
270 | }
271 |
272 | MobileBridge.prototype = Object.create(PostMessageBridge.prototype);
273 | MobileBridge.prototype.constructor = MobileBridge;
274 |
275 | MobileBridge.prototype._init = function () {
276 | PostMessageBridge.prototype._init.call(this);
277 | if (this.device === "ios") {
278 | this._gameeWin = webkit.messageHandlers.callbackHandler;
279 | } else if (this.device === "android") {
280 | this._gameeWin = _toDevice;
281 | } else {
282 | throw "Unknown device used in webkit bridge";
283 | }
284 |
285 | window._triggerMessage = function (data) {
286 | try {
287 | data = JSON.parse(data); // message is custom message from IOS/android platform
288 | } catch (err) {
289 | throw "Couldn't parse message from native app: \n" + data + "\n" + err;
290 | }
291 | if (!core.isSilentModeEnabled()) {
292 | console.log(JSON.stringify(data, null, 4));
293 | }
294 | this.dispatchEvent(new CustomEvent("message", { detail: data }));
295 | }.bind(window);
296 |
297 | };
298 |
299 | MobileBridge.prototype.doCall = function (preparedObject, requestData) {
300 | if (typeof requestData === "object") {
301 | preparedObject.request.data = requestData || {};
302 | }
303 |
304 | if (this.device === "android") // stringify data for android devices, but not for ios
305 | preparedObject = JSON.stringify(preparedObject);
306 |
307 | this._gameeWin.postMessage(preparedObject, "*");
308 | };
309 |
--------------------------------------------------------------------------------
/gamee/tests/api.test.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert');
2 |
3 | import { gamee } from '../dist/gamee-js.min.js'
4 |
5 | describe('Framework API', () => {
6 |
7 | it('gamee.getPlatform returns platform', () => {
8 | assert.equal(gamee.getPlatform(), "web" || "ios" || "android" || "fb");
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/gamee/tests/dummy.test.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert');
2 |
3 | describe('Dummy test pass', () => {
4 | it('should add correctly', () => {
5 | assert.equal(2, 2);
6 | });
7 | });
8 |
9 | describe('Dummy test fail', () => {
10 | it('should add correctly', () => {
11 | assert.equal(3, 2);
12 | });
13 | });
14 |
--------------------------------------------------------------------------------
/gamee/tests/framework-integrity.test.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert');
2 |
3 | import { gamee } from '../dist/gamee-js.min.js'
4 |
5 | describe('Test of properties of the gamee object', () => {
6 | // gamee object
7 | it('gamee variable is an object', () => {
8 | assert.equal(typeof gamee, "object");
9 | });
10 |
11 | // basic properties
12 | it('gamee.gameInit is a function', () => {
13 | assert.equal(typeof gamee.gameInit, "function");
14 | });
15 | it('gamee.gameReady is a function', () => {
16 | assert.equal(typeof gamee.gameReady, "function");
17 | });
18 | it('gamee.updateScore is a function', () => {
19 | assert.equal(typeof gamee.updateScore, "function");
20 | });
21 | it('gamee.gameOver is a function', () => {
22 | assert.equal(typeof gamee.gameOver, "function");
23 | });
24 | it('gamee.emitter is an object', () => {
25 | assert.equal(typeof gamee.emitter, "object");
26 | });
27 |
28 | // advanced properties
29 | it('gamee.getPlatform is a function', () => {
30 | assert.equal(typeof gamee.getPlatform, "function");
31 | });
32 | it('gamee.gameLoadingProgress is a function', () => {
33 | assert.equal(typeof gamee.gameLoadingProgress, "function");
34 | });
35 | it('gamee.gameSave is a function', () => {
36 | assert.equal(typeof gamee.gameSave, "function");
37 | });
38 | it('gamee.requestSocial is a function', () => {
39 | assert.equal(typeof gamee.requestSocial, "function");
40 | });
41 | });
42 |
--------------------------------------------------------------------------------
/gamee/tests/index.js:
--------------------------------------------------------------------------------
1 | // Skip execution in Node
2 | if (module.hot) {
3 | const context = require.context(
4 | 'mocha-loader!./', // Process through mocha-loader
5 | false, // Skip recursive processing
6 | /\.test.js$/ // Pick only files ending with .test.js
7 | );
8 |
9 | // Execute each test suite
10 | context.keys().forEach(context);
11 | }
12 |
--------------------------------------------------------------------------------
/jsdoc.conf.json:
--------------------------------------------------------------------------------
1 | {
2 | "tags": {
3 | "allowUnknownTags": true
4 | },
5 | "plugins": [
6 | "plugins/markdown"
7 | ],
8 | "private": false,
9 | "templates": {
10 | "cleverLinks": false,
11 | "monospaceLinks": true,
12 | "dateFormat": "ddd MMM Do YYYY",
13 | "outputSourceFiles": false,
14 | "outputSourcePath": false,
15 | "systemName": "GAMEE",
16 | "footer": "",
17 | "copyright": "",
18 | "linenums": true,
19 | "collapseSymbols": false,
20 | "inverseNav": true,
21 | "highlightTutorialCode": true,
22 | "default": {
23 | "outputSourceFiles": false,
24 | "includeDate": false
25 | }
26 | },
27 | "markdown": {
28 | "parser": "gfm",
29 | "hardwrap": true
30 | },
31 | "opts": {
32 | "readme": "README.md",
33 | "encoding": "utf8"
34 | }
35 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gamee-js",
3 | "version": "2.4.0",
4 | "description": "Gamee JS SDK",
5 | "main": "gamee/src/index.js",
6 | "scripts": {
7 | "test": "mocha tests",
8 | "test:mocha": "mocha tests",
9 | "test:mocha:watch": "webpack-dev-server --hot --config config/webpack.mocha.js",
10 | "b:dist": "webpack --env=prod --config config/webpack.config.js --progress --profile --colors",
11 | "watch": "webpack --env=prod --config config/webpack.config.js --progress --profile --colors --watch",
12 | "start": "start npm run watch && start npm run test:mocha:watch"
13 | },
14 | "bugs": {
15 | "url": "https://github.com/gameeapp/gamee-js/issues"
16 | },
17 | "homepage": "https://github.com/gameeapp/gamee-js",
18 | "devDependencies": {
19 | "babel-core": "^6.25.0",
20 | "babel-loader": "^7.0.0",
21 | "babel-preset-env": "^1.5.1",
22 | "banner-webpack-plugin": "^0.2.3",
23 | "html-webpack-plugin": "^2.29.0",
24 | "mocha": "^3.4.2",
25 | "mocha-loader": "^1.1.1",
26 | "webpack": "^2.7.0",
27 | "webpack-dev-server": "^2.11.3",
28 | "webpack-merge": "^4.1.0"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------