├── .eslintignore ├── .eslintrc.yml ├── .gitignore ├── .hintrc ├── README.md ├── demo ├── .eslintrc.yml ├── demo-animation-chain.html ├── demo-animation-chain.js ├── demo-animation.html ├── demo-animation.js ├── demo-chain.html ├── demo-chain.js ├── demo-fx.html ├── demo-fx.js ├── demo-group.html ├── demo-group.js ├── demo-input.html ├── demo-input.js ├── demo-keyboard.html ├── demo-keyboard.js ├── demo-light.html ├── demo-light.js ├── demo-load.html ├── demo-load.js ├── demo-particles.html ├── demo-particles.js ├── demo-plane.html ├── demo-plane.js ├── demo-play.html ├── demo-play.js ├── demo-postfx.html ├── demo-postfx.js ├── demo-sound-markers.html ├── demo-sound-markers.js ├── demo-sound.html ├── demo-sound.js ├── demo-tilemap.html ├── demo-tilemap.js ├── demo-timeline.html ├── demo-timeline.js ├── demo-timer-event.html ├── demo-timer-event.js ├── demo-tween.html ├── demo-tween.js ├── demo-video.html ├── demo-video.js ├── demo.html └── demo.js ├── package-lock.json ├── package.json ├── rollup.config.js ├── src ├── DefaultPluginsConfig.js ├── EaseMap.js ├── FXMap.js ├── InspectorGlobalPlugin.js ├── InspectorScenePlugin.js ├── Install.js ├── const.js ├── main.js └── util.js └── test ├── .eslintrc.yml ├── test-load.html ├── test-load.js ├── test.html └── test.js /.eslintignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | vendor/ -------------------------------------------------------------------------------- /.eslintrc.yml: -------------------------------------------------------------------------------- 1 | env: 2 | browser: yes 3 | es6: yes 4 | extends: semistandard 5 | globals: 6 | Atomics: readonly 7 | SharedArrayBuffer: readonly 8 | parserOptions: 9 | ecmaVersion: 2018 10 | sourceType: module 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | dist 4 | vendor 5 | assets 6 | -------------------------------------------------------------------------------- /.hintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "development" 4 | ], 5 | "hints": { 6 | "meta-viewport": "off" 7 | } 8 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Phaser 3 Inspector Plugin 🧐 2 | ========================= 3 | 4 | View and change game properties, with [Tweakpane](https://github.com/cocopon/tweakpane). 5 | 6 | Demos 7 | ----- 8 | 9 | - [First Phaser 3 game](https://codepen.io/samme/pen/YzxbMBV?editors=0010) — simple game, helper functions 10 | - [All the demos](https://codepen.io/collection/LPeVMY) 11 | 12 | You can also paste the [Quick load](#quick-load) snippet into any of the [labs examples](https://labs.phaser.io). 13 | 14 | Install 15 | ------- 16 | 17 | The plugins add controls for the game and scene systems. If you don't need these, you can skip this step and use the [helper functions](#helper-functions) only. 18 | 19 | ### Browser / UMD 20 | 21 | [First Phaser 3 game](https://codepen.io/samme/pen/YzxbMBV?editors=0010) shows this setup. 22 | 23 | Include Phaser, [Tweakpane](https://cdn.jsdelivr.net/npm/tweakpane/), and [the plugin UMD script](https://cdn.jsdelivr.net/npm/phaser-plugin-inspector/) in this order. You can download the scripts or use the CDN links. 24 | 25 | ```html 26 | 27 | 28 | 29 | ``` 30 | 31 | If this is the only plugin you're using then you can use the "default" configuration: 32 | 33 | ```js 34 | /* global PhaserPluginInspector */ 35 | 36 | new Phaser.Game({ 37 | plugins: PhaserPluginInspector.DefaultPluginsConfig 38 | }); 39 | ``` 40 | 41 | Or you can configure the plugins individually: 42 | 43 | ```js 44 | /* global PhaserPluginInspector */ 45 | 46 | const { InspectorGlobalPlugin, InspectorScenePlugin } = PhaserPluginInspector; 47 | 48 | new Phaser.Game({ 49 | plugins: { 50 | global: [{ key: 'InspectorGlobalPlugin', plugin: InspectorGlobalPlugin, mapping: 'inspectorGame' }], 51 | scene: [{ key: 'InspectorScenePlugin', plugin: InspectorScenePlugin, mapping: 'inspectorScene' }] 52 | } 53 | }); 54 | ``` 55 | 56 | You can use any mapping, or `{ start: true }` for no mapping. If you don't want to add any controls, you don't need any mapping. 57 | 58 | The helper functions are on the same namespace: 59 | 60 | ```js 61 | /* global PhaserPluginInspector */ 62 | 63 | const { AddGameObject } = PhaserPluginInspector 64 | ``` 65 | 66 | ### Module 67 | 68 | ```sh 69 | npm install phaser-plugin-inspector tweakpane 70 | ``` 71 | 72 | This package has an ES module (`phaser-plugin-inspector.esm.js`, marked as `module`) and a CommonJS-compatible UMD module(`phaser-plugin-inspector.umd.js`, marked as `browser`). You should use the ES module, but some bundlers may pick the UMD module by default. Configure your bundler to use the `module` field, or add an alias to the ES module file, or import the ES module file directly. 73 | 74 | If this is the only plugin you're using then you can use the "default" configuration: 75 | 76 | ```js 77 | import { DefaultPluginsConfig } from 'phaser-plugin-inspector'; 78 | 79 | new Phaser.Game({ 80 | plugins: DefaultPluginsConfig 81 | }); 82 | ``` 83 | 84 | Or you can configure the plugins individually: 85 | 86 | ```js 87 | import { InspectorGlobalPlugin, InspectorScenePlugin } from 'phaser-plugin-inspector'; 88 | 89 | new Phaser.Game({ 90 | plugins: { 91 | global: [{ key: 'InspectorGlobalPlugin', plugin: InspectorGlobalPlugin, mapping: 'inspectorGame' }], 92 | scene: [{ key: 'InspectorScenePlugin', plugin: InspectorScenePlugin, mapping: 'inspectorScene' }] 93 | } 94 | }); 95 | ``` 96 | 97 | You can import the helper functions as well: 98 | 99 | ```js 100 | import { AddGameObject } from 'phaser-plugin-inspector'; 101 | ``` 102 | 103 | ### Quick load 104 | 105 | ```js 106 | function preload() { 107 | this.load.scripts('inspector', [ 108 | 'https://cdn.jsdelivr.net/npm/tweakpane@3.1.10/dist/tweakpane.js', 109 | 'https://cdn.jsdelivr.net/npm/phaser-plugin-inspector@2.6.0/dist/phaser-plugin-inspector.umd.js', 110 | ]); 111 | this.load.once('complete', () => { 112 | PhaserPluginInspector.Install(this.plugins); 113 | }); 114 | } 115 | ``` 116 | 117 | ### Load from console 118 | 119 | Given a `game` variable: 120 | 121 | ```js 122 | const scene = game.scene.getScenes(true)[0]; 123 | 124 | scene.load.scripts('inspector', [ 125 | 'https://cdn.jsdelivr.net/npm/tweakpane@3.1.10/dist/tweakpane.js', 126 | 'https://cdn.jsdelivr.net/npm/phaser-plugin-inspector@2.6.0/dist/phaser-plugin-inspector.umd.js', 127 | ]); 128 | scene.load.once('complete', () => { 129 | PhaserPluginInspector.Install(game.plugins); 130 | }).start(); 131 | ``` 132 | 133 | Use 134 | --- 135 | 136 | All of the “Print” buttons call `console.info()` or `console.table()`. 137 | 138 | Beware that Tweakpane inputs (checkboxes, sliders, etc.) do not update their values automatically; use the pane's **Refresh** button. 139 | 140 | Tweakpane monitors are updated automatically 5 times per second. For more precise work you may want to pause a scene or its systems. 141 | 142 | You can inspect game objects using the **Display List: Inspect** and **Update List: Inspect** buttons in each scene. The new folder is added to the end of the inspector pane. Look in the console to confirm. 143 | 144 | To step one frame at a time, use **Game → Loop → Sleep**, **Game → Step** (repeat), **Game → Loop → Wake**. 145 | 146 | Helper functions 147 | ---------------- 148 | 149 | These create a set of controls for common Phaser objects. 150 | 151 | You can use these functions with or without the plugins. 152 | 153 | The `pane` argument is the Tweakpane pane or a folder in it. The `options` argument is options for the folder. 154 | 155 | Each function creates a [folder](https://cocopon.github.io/tweakpane/ui-components.html#folder) and returns it. 156 | 157 | If you've installed the plugins, then within a scene context (`this`) 158 | 159 | - `this.inspectorGame.pane` or `this.inspectorScene.pane` is the main pane 160 | - `this.inspectorGame.folder` is the “Game” folder 161 | - `this.inspectorScene.folder` is the current scene's folder 162 | 163 | See the [First Phaser 3 game](https://codepen.io/samme/pen/YzxbMBV?editors=0010) demo for this setup. 164 | 165 | If you're not using the plugins, then you should create a pane yourself: 166 | 167 | ```js 168 | const pane = new Tweakpane.Pane(); 169 | ``` 170 | 171 | Some of these folders need to be disposed manually if you destroy the target object or stop the scene it belongs to. Use 172 | 173 | ```js 174 | folder.dispose(); 175 | ``` 176 | 177 | ### AddActive(items, pane, options?) → folder 178 | 179 | Adds a set of "active" toggles for any objects with an `active` property, identified by `name`. 180 | 181 | ### AddAlpha(items, pane, options?) → folder 182 | 183 | Adds a set of "alpha" sliders for any objects with an `alpha` property, identified by `name`. 184 | 185 | ### AddAnimationState(animationState, pane, options?) → folder 186 | 187 | Adds a folder for a sprite's animation state, e.g., 188 | 189 | AddAnimationState(sprite.anims, pane); 190 | 191 | ### AddArcadeBody(body, pane, options?) → folder 192 | 193 | Adds a folder for a game object's Arcade Physics body, e.g., 194 | 195 | AddArcadeBody(sprite.body, pane); 196 | 197 | ### AddCamera(camera, pane) → folder 198 | 199 | Adds a folder for a camera, e.g., 200 | 201 | AddCamera(this.cameras.main, pane); 202 | 203 | ### AddChain(chain, pane, options?) → folder 204 | 205 | Adds a folder for a [tween chain](https://docs.phaser.io/api-documentation/class/tweens-tweenchain). 206 | 207 | Dispose this folder if you remove the tween chain. 208 | 209 | ### AddFXComponent(component, pane, options?) → folder 210 | 211 | Adds a folder for a game object's [FX component](https://docs.phaser.io/api-documentation/class/gameobjects-components-fx), e.g., 212 | 213 | AddFXComponent(sprite.preFX, pane); 214 | 215 | Note that Post FX controllers are always [enabled](https://docs.phaser.io/api-documentation/class/gameobjects-components-fx#enabled). 216 | 217 | ### AddFXController(controller, pane, options?) → folder 218 | 219 | Adds a folder for a game object's [FX controller](https://docs.phaser.io/api-documentation/class/fx-controller), e.g., 220 | 221 | const barrelEffect = sprite.preFX.addBarrel(); 222 | 223 | AddFXController(barrelEffect, pane); 224 | 225 | Note that Post FX controllers are always [active](https://docs.phaser.io/api-documentation/class/fx-controller#active). 226 | 227 | ### AddGameObject(obj, pane, options?) → folder 228 | 229 | Adds a folder for a game object (except group). 230 | 231 | ### AddGroup(group, pane, options?) → folder 232 | 233 | Adds a folder for a group. 234 | 235 | ### AddInput(interactiveObject, pane, options?) → folder 236 | 237 | Adds a folder for a game object's [interactive object](https://docs.phaser.io/api-documentation/typedef/types-input#interactiveobject), e.g., 238 | 239 | AddInput(sprite.input, pane); 240 | 241 | ### AddKey(key, pane, options?) → folder 242 | 243 | Adds a folder for a [keyboard key object](https://docs.phaser.io/api-documentation/class/input-keyboard-key). 244 | 245 | Dispose this folder if you remove the key. 246 | 247 | ### AddKeys(keys, pane, options?) → folder 248 | 249 | Adds a folder for an object map of [keyboard key objects](https://docs.phaser.io/api-documentation/class/input-keyboard-key), such as that returned by [addKeys()](https://docs.phaser.io/api-documentation/class/input-keyboard-keyboardplugin#addkeys). 250 | 251 | Dispose this folder if you remove those keys. 252 | 253 | ### AddLight(light, pane, options?) → folder 254 | 255 | Adds a folder for a [light](https://docs.phaser.io/api-documentation/class/gameobjects-light) (not point light). 256 | 257 | ### AddParticleEmitter(emitter, pane, options?) → folder 258 | 259 | Adds a folder for a [particle emitter](https://docs.phaser.io/api-documentation/class/gameobjects-particles-particleemitter). 260 | 261 | ### AddScenes(scene, pane, options?) → folder 262 | 263 | Adds a set of "visible" toggles for the scenes, e.g., 264 | 265 | AddScenes(this.scene.manager.getScenes(false), pane); 266 | 267 | ### AddSound(sound, pane, options?) → folder 268 | 269 | Adds a folder for a [sound](https://docs.phaser.io/api-documentation/class/sound-basesound). 270 | 271 | ### AddTimeline(timeline, pane, options?) → folder 272 | 273 | Adds a folder for a [timeline](https://docs.phaser.io/api-documentation/class/time-timeline). 274 | 275 | ### AddTimerEvent(timerEvent, pane, options?) → folder 276 | 277 | Adds a folder for a [timer event](https://docs.phaser.io/api-documentation/class/time-timerevent). 278 | 279 | Dispose this folder if you remove the timer event. 280 | 281 | ### AddTween(tween, pane, options?) → folder 282 | 283 | Adds a folder for a [tween](https://docs.phaser.io/api-documentation/class/tweens-tween). 284 | 285 | ### AddVideo(video, pane, options?) → folder 286 | 287 | Adds a folder for a [Video game object](https://docs.phaser.io/api-documentation/class/gameobjects-video). 288 | 289 | ### AddVisible(items, pane, options?) → folder 290 | 291 | Adds a set of "visible" toggles for any objects with an `visible` property, identified by `name`. 292 | 293 | -------------------------------------------------------------------------------- /demo/.eslintrc.yml: -------------------------------------------------------------------------------- 1 | env: 2 | browser: yes 3 | es6: no 4 | extends: semistandard 5 | globals: 6 | Atomics: readonly 7 | SharedArrayBuffer: readonly 8 | Phaser: readonly 9 | __Global__: readonly 10 | -------------------------------------------------------------------------------- /demo/demo-animation-chain.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | Demo of Phaser 3 Inspector Plugin 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /demo/demo-animation-chain.js: -------------------------------------------------------------------------------- 1 | /* global Phaser, PhaserPluginInspector */ 2 | 3 | const { AddAnimationState } = PhaserPluginInspector; 4 | 5 | class Example extends Phaser.Scene { 6 | preload () { 7 | this.load.atlas('knight', 'assets/animations/knight.png', 'assets/animations/knight.json'); 8 | this.load.image('bg', 'assets/skies/clouds.png'); 9 | this.load.spritesheet('tiles', 'assets/tilemaps/tiles/fantasy-tiles.png', { frameWidth: 64, frameHeight: 64 }); 10 | } 11 | 12 | create () { 13 | // The background and floor 14 | this.add.image(400, 16, 'bg').setOrigin(0.5, 0); 15 | 16 | for (var i = 0; i < 13; i++) { 17 | this.add.image(64 * i, 536, 'tiles', 1).setOrigin(0); 18 | } 19 | 20 | var text = this.add.text(400, 8, 'Click to play animation chain', { color: '#ffffff' }).setOrigin(0.5, 0); 21 | 22 | // Our animations 23 | this.anims.create({ 24 | key: 'guardStart', 25 | frames: this.anims.generateFrameNames('knight', { prefix: 'guard_start/frame', start: 0, end: 3, zeroPad: 4 }), 26 | frameRate: 8 27 | }); 28 | 29 | this.anims.create({ 30 | key: 'guard', 31 | frames: this.anims.generateFrameNames('knight', { prefix: 'guard/frame', start: 0, end: 5, zeroPad: 4 }), 32 | frameRate: 8, 33 | repeat: 2 34 | }); 35 | 36 | this.anims.create({ 37 | key: 'guardEnd', 38 | frames: this.anims.generateFrameNames('knight', { prefix: 'guard_end/frame', start: 0, end: 3, zeroPad: 4 }), 39 | frameRate: 8 40 | }); 41 | 42 | this.anims.create({ 43 | key: 'idle', 44 | frames: this.anims.generateFrameNames('knight', { prefix: 'idle/frame', start: 0, end: 5, zeroPad: 4 }), 45 | frameRate: 8, 46 | repeat: -1 47 | }); 48 | 49 | var lancelot = this.add.sprite(500, 536).setName('lancelot'); 50 | 51 | AddAnimationState(lancelot.anims, this.inspectorScene.pane); 52 | 53 | lancelot.setOrigin(0.5, 1); 54 | lancelot.setScale(8); 55 | lancelot.play('idle'); 56 | 57 | lancelot.on(Phaser.Animations.Events.SPRITE_ANIMATION_START, function (anim) { 58 | text.setText('Playing ' + anim.key); 59 | }); 60 | 61 | this.input.on('pointerdown', function () { 62 | if (lancelot.anims.getName() === 'idle') { 63 | lancelot.playAfterRepeat('guardStart'); 64 | lancelot.chain(['guard', 'guardEnd', 'idle']); 65 | } 66 | }, this); 67 | } 68 | } 69 | 70 | // eslint-disable-next-line no-new 71 | new Phaser.Game({ 72 | width: 800, 73 | height: 600, 74 | pixelArt: true, 75 | scene: Example, 76 | plugins: PhaserPluginInspector.DefaultPluginsConfig, 77 | audio: { 78 | disableAudio: true 79 | } 80 | }); 81 | -------------------------------------------------------------------------------- /demo/demo-animation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | Demo of Phaser 3 Inspector Plugin 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /demo/demo-animation.js: -------------------------------------------------------------------------------- 1 | /* global Phaser, PhaserPluginInspector */ 2 | 3 | const { AddAnimationState } = PhaserPluginInspector; 4 | 5 | function preload () { 6 | this.load.path = 'assets/animations/aseprite/'; 7 | 8 | this.load.aseprite('paladin', 'paladin.png', 'paladin.json'); 9 | } 10 | 11 | function create () { 12 | var tags = this.anims.createFromAseprite('paladin'); 13 | 14 | var sprite = this.add.sprite(500, 300).play({ key: 'Magnum Break', repeat: -1 }).setScale(6).setName('paladin'); 15 | 16 | AddAnimationState(sprite.anims, this.inspectorScene.pane); 17 | 18 | for (var i = 0; i < tags.length; i++) { 19 | var label = this.add.text(32, 32 + (i * 16), tags[i].key, { color: '#00ff00' }); 20 | 21 | label.setInteractive(); 22 | } 23 | 24 | this.input.on('gameobjectdown', function (pointer, obj) { 25 | sprite.play({ 26 | key: obj.text, 27 | repeat: -1 28 | }); 29 | }); 30 | 31 | this.input.on('gameobjectover', function (pointer, obj) { 32 | obj.setColor('#ff00ff'); 33 | }); 34 | 35 | this.input.on('gameobjectout', function (pointer, obj) { 36 | obj.setColor('#00ff00'); 37 | }); 38 | } 39 | 40 | // eslint-disable-next-line no-new 41 | new Phaser.Game({ 42 | width: 800, 43 | height: 600, 44 | pixelArt: true, 45 | scene: { preload, create }, 46 | plugins: PhaserPluginInspector.DefaultPluginsConfig, 47 | audio: { 48 | disableAudio: true 49 | } 50 | }); 51 | -------------------------------------------------------------------------------- /demo/demo-chain.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | Demo of Phaser 3 Inspector Plugin 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /demo/demo-chain.js: -------------------------------------------------------------------------------- 1 | /* global PhaserPluginInspector, Tweakpane */ 2 | 3 | const { AddChain, AddTween } = PhaserPluginInspector; 4 | 5 | class Example extends Phaser.Scene { 6 | preload () { 7 | this.load.atlas('assets', 'assets/atlas/tweenparts.png', 'assets/atlas/tweenparts.json'); 8 | } 9 | 10 | create () { 11 | const chest = this.add.image(400, 600, 'assets', 'blue-closed').setOrigin(0.5, 1); 12 | const key = this.add.image(-200, 300, 'assets', 'simple-key-gold'); 13 | 14 | const chain1 = this.tweens.chain({ 15 | targets: chest, 16 | tweens: [ 17 | { 18 | y: 470, 19 | scaleX: 0.7, 20 | duration: 300, 21 | ease: 'quad.out' 22 | }, 23 | { 24 | y: 600, 25 | scaleX: 1, 26 | duration: 1000, 27 | ease: 'bounce.out' 28 | } 29 | ], 30 | loop: -1, 31 | loopDelay: 300 32 | }); 33 | 34 | const chain2 = this.tweens.chain({ 35 | paused: true, 36 | targets: key, 37 | tweens: [ 38 | { 39 | x: 200, 40 | duration: 300, 41 | ease: 'quad.out', 42 | delay: 500 43 | }, 44 | { 45 | angle: 360, 46 | duration: 200, 47 | ease: 'linear', 48 | repeat: 4 49 | }, 50 | { 51 | angle: 270, 52 | duration: 200, 53 | ease: 'linear' 54 | }, 55 | { 56 | scale: 0.65, 57 | y: 380, 58 | duration: 200, 59 | ease: 'power2' 60 | }, 61 | { 62 | x: 410, 63 | duration: 300, 64 | ease: 'bounce.out' 65 | }, 66 | { 67 | targets: chest, 68 | texture: ['assets', 'blue-open'], 69 | duration: 100 70 | }, 71 | { 72 | alpha: 0, 73 | duration: 400, 74 | ease: 'linear' 75 | } 76 | ] 77 | }); 78 | 79 | AddChain(chain1, pane); 80 | AddChain(chain2, pane); 81 | 82 | this.input.once('pointerdown', () => { 83 | chain1.completeAfterLoop(0); 84 | chain2.play(); 85 | this.openChest(chest, key); 86 | }); 87 | } 88 | 89 | openChest (chest, key) { 90 | const tween = this.tweens.add({ 91 | targets: chest, 92 | x: 550, 93 | ease: 'power3', 94 | duration: 500 95 | }); 96 | 97 | AddTween(tween, pane); 98 | } 99 | } 100 | 101 | const config = { 102 | width: 800, 103 | height: 600, 104 | backgroundColor: '#2d2d2d', 105 | scene: Example 106 | }; 107 | 108 | const pane = new Tweakpane.Pane({ title: 'Chains' }); 109 | 110 | // eslint-disable-next-line no-unused-vars 111 | const game = new Phaser.Game(config); 112 | -------------------------------------------------------------------------------- /demo/demo-fx.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | Demo of Phaser 3 Inspector Plugin 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /demo/demo-fx.js: -------------------------------------------------------------------------------- 1 | /* global Phaser, PhaserPluginInspector */ 2 | 3 | // eslint-disable-next-line no-unused-vars 4 | const { AddGameObject, AddFXComponent, AddFXController } = PhaserPluginInspector; 5 | 6 | class Example extends Phaser.Scene { 7 | init () { 8 | console.log('renderer', this.renderer); 9 | } 10 | 11 | preload () { 12 | this.load.image('bg', 'assets/skies/space4.png'); 13 | this.load.image('lollipop', 'assets/sprites/lollipop.png'); 14 | this.load.image('gingerbread', 'assets/sprites/gingerbread.png'); 15 | this.load.image('cake', 'assets/sprites/strawberry-cake.png'); 16 | } 17 | 18 | create () { 19 | const preMethods = [ 20 | 'addBarrel', 21 | // 'addBloom', 22 | 'addBlur', 23 | 'addBokeh', 24 | 'addCircle', 25 | // 'addColorMatrix', 26 | 'addDisplacement', 27 | // 'addGlow', 28 | 'addGradient', 29 | 'addPixelate', 30 | 'addReveal', 31 | 'addShadow', 32 | 'addShine', 33 | 'addTiltShift', 34 | 'addVignette', 35 | 'addWipe' 36 | ]; 37 | 38 | this.add.image(400, 300, 'bg'); 39 | 40 | const preFXFolder = this.inspectorGame.pane.addFolder({ title: 'Pre Effects' }); 41 | const goFolder = this.inspectorGame.pane.addFolder({ title: 'Game Objects' }); 42 | const cakes = []; 43 | 44 | for (const m of preMethods) { 45 | const cake = this.add.image(0, 0, 'cake').setName(`cake ${m}`); 46 | cake.preFX.setPadding(8); 47 | const fx = cake.preFX[m](); 48 | AddFXController(fx, preFXFolder, { title: m }); 49 | cakes.push(cake); 50 | } 51 | 52 | Phaser.Actions.GridAlign(cakes, { width: 6, cellWidth: 120, cellHeight: 150 }); 53 | 54 | const lollipop = this.add.image(400, 400, 'lollipop').setName('lollipop'); 55 | lollipop.preFX.setPadding(8); 56 | lollipop.preFX.addColorMatrix().grayscale(); 57 | lollipop.preFX.addShadow(); 58 | 59 | AddGameObject(lollipop, goFolder); 60 | } 61 | } 62 | 63 | // eslint-disable-next-line no-new 64 | new Phaser.Game({ 65 | // type: Phaser.CANVAS, 66 | width: 800, 67 | height: 600, 68 | pixelArt: true, 69 | scene: Example, 70 | plugins: PhaserPluginInspector.DefaultPluginsConfig, 71 | audio: { 72 | disableAudio: true 73 | } 74 | }); 75 | -------------------------------------------------------------------------------- /demo/demo-group.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | Demo of Phaser 3 Inspector Plugin 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /demo/demo-group.js: -------------------------------------------------------------------------------- 1 | /* global Phaser, PhaserPluginInspector, Tweakpane */ 2 | 3 | const { AddGroup } = PhaserPluginInspector; 4 | 5 | const pane = new Tweakpane.Pane(); 6 | 7 | let group; 8 | 9 | function preload () { 10 | this.load.image('space', 'assets/skies/space.jpg'); 11 | this.load.spritesheet('alien', 'assets/tests/invaders/invader1.png', { 12 | frameWidth: 32, 13 | frameHeight: 32 14 | }); 15 | } 16 | 17 | function create () { 18 | this.anims.create({ 19 | key: 'creep', 20 | frames: this.anims.generateFrameNumbers('alien', { start: 0, end: 1 }), 21 | frameRate: 2, 22 | repeat: -1 23 | }); 24 | 25 | this.add.image(512, 384, 'space'); 26 | 27 | group = this.add 28 | .group({ 29 | defaultKey: 'alien', 30 | maxSize: 50, 31 | createCallback: function (alien) { 32 | alien.setName('alien' + this.getLength()); 33 | }, 34 | removeCallback: function (alien) {} 35 | }) 36 | .setName('aliens'); 37 | 38 | AddGroup(group, pane); 39 | 40 | this.time.addEvent({ 41 | delay: 200, 42 | repeat: 199, 43 | callback: addAlien 44 | }); 45 | } 46 | 47 | function update () { 48 | group.children.iterate(function (alien) { 49 | alien.y += 1; 50 | 51 | if (alien.y > 768) { 52 | group.killAndHide(alien); 53 | } 54 | }); 55 | } 56 | 57 | function activateAlien (alien) { 58 | alien 59 | .setActive(true) 60 | .setVisible(true) 61 | .setTint(Phaser.Display.Color.RandomRGB().color) 62 | .play('creep'); 63 | } 64 | 65 | function addAlien () { 66 | // Random position above screen 67 | const x = Phaser.Math.Between(0, 1024); 68 | const y = Phaser.Math.Between(-64, 0); 69 | 70 | // Find first inactive sprite in group or add new sprite, and set position 71 | const alien = group.get(x, y); 72 | 73 | // None free or already at maximum amount of sprites in group 74 | if (!alien) return; 75 | 76 | activateAlien(alien); 77 | } 78 | 79 | // eslint-disable-next-line no-new 80 | new Phaser.Game({ 81 | width: 800, 82 | height: 600, 83 | pixelArt: true, 84 | scene: { preload, create, update }, 85 | audio: { 86 | disableAudio: true 87 | } 88 | }); 89 | -------------------------------------------------------------------------------- /demo/demo-input.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | Demo of Phaser 3 Inspector Plugin 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /demo/demo-input.js: -------------------------------------------------------------------------------- 1 | 2 | /* global Phaser, PhaserPluginInspector */ 3 | 4 | const { AddInput } = PhaserPluginInspector; 5 | 6 | function preload () { 7 | this.load.image('ayu', 'assets/pics/ayu2.png'); 8 | this.load.image('eye', 'assets/pics/lance-overdose-loader-eye.png'); 9 | } 10 | 11 | function create () { 12 | const { pane } = this.inspectorGame; 13 | const zone = this.add.image(500, 300, 'ayu').setInteractive({ dropZone: true }).setName('ayu'); 14 | const image = this.add.sprite(200, 300, 'eye').setInteractive({ draggable: true, cursor: 'grab' }).setName('eye'); 15 | 16 | AddInput(zone.input, pane); 17 | AddInput(image.input, pane); 18 | 19 | this.input.on('dragstart', function (pointer, gameObject) { 20 | gameObject.setTint(0xff00ff); 21 | }); 22 | 23 | this.input.on('drag', function (pointer, gameObject, dragX, dragY) { 24 | gameObject.x = dragX; 25 | gameObject.y = dragY; 26 | }); 27 | 28 | this.input.on('dragend', function (pointer, gameObject) { 29 | gameObject.clearTint(); 30 | }); 31 | 32 | this.input.on('dragenter', function (pointer, gameObject, dropZone) { 33 | dropZone.setTint(0x00ff00); 34 | }); 35 | 36 | this.input.on('dragleave', function (pointer, gameObject, dropZone) { 37 | dropZone.clearTint(); 38 | }); 39 | 40 | this.input.on('drop', function (pointer, gameObject, dropZone) { 41 | gameObject.x = dropZone.x; 42 | gameObject.y = dropZone.y; 43 | 44 | dropZone.clearTint(); 45 | }); 46 | } 47 | 48 | // eslint-disable-next-line no-new 49 | new Phaser.Game({ 50 | scene: { preload, create }, 51 | plugins: PhaserPluginInspector.DefaultPluginsConfig 52 | }); 53 | -------------------------------------------------------------------------------- /demo/demo-keyboard.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | Demo of Phaser 3 Inspector Plugin 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /demo/demo-keyboard.js: -------------------------------------------------------------------------------- 1 | /* global Phaser, PhaserPluginInspector */ 2 | 3 | const { AddKey, AddKeys } = PhaserPluginInspector; 4 | 5 | function create () { 6 | const { pane } = this.inspectorScene; 7 | const { keyboard } = this.input; 8 | 9 | AddKey(keyboard.addKey('SPACE'), pane); 10 | 11 | AddKeys(keyboard.addKeys('W,A,S,D'), pane); 12 | 13 | AddKeys(keyboard.createCursorKeys(), pane); 14 | } 15 | 16 | // eslint-disable-next-line no-new 17 | new Phaser.Game({ 18 | scene: { create }, 19 | plugins: PhaserPluginInspector.DefaultPluginsConfig, 20 | audio: { 21 | disableWebAudio: true 22 | } 23 | }); 24 | -------------------------------------------------------------------------------- /demo/demo-light.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | Demo of Phaser 3 Inspector Plugin 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /demo/demo-light.js: -------------------------------------------------------------------------------- 1 | /* global Phaser, PhaserPluginInspector */ 2 | 3 | const { AddLight } = PhaserPluginInspector; 4 | 5 | // eslint-disable-next-line no-new 6 | new Phaser.Game({ 7 | type: Phaser.WEBGL, 8 | plugins: PhaserPluginInspector.DefaultPluginsConfig, 9 | scene: { preload, create } 10 | }); 11 | 12 | function preload () { 13 | this.load.image('robot', ['assets/pics/equality-by-ragnarok.png', 'assets/normal-maps/equality-by-ragnarok_n.png']); 14 | this.load.image('atari', 'assets/sprites/atari400.png'); 15 | } 16 | 17 | function create () { 18 | this.lights.enable().setAmbientColor(0x333333); 19 | 20 | const robot = this.add.image(-100, 0, 'robot').setOrigin(0).setScale(0.7); 21 | 22 | robot.setPipeline('Light2D'); 23 | 24 | const light = this.lights.addLight(180, 80, 200).setColor(0xffffff).setIntensity(2); 25 | 26 | AddLight(light, this.inspectorScene.pane); 27 | } 28 | -------------------------------------------------------------------------------- /demo/demo-load.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | Demo of Phaser 3 Inspector Plugin 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /demo/demo-load.js: -------------------------------------------------------------------------------- 1 | /* global Phaser, PhaserPluginInspector */ 2 | 3 | // eslint-disable-next-line no-new 4 | new Phaser.Game({ 5 | scene: [ 6 | { 7 | map: {}, 8 | 9 | physics: { arcade: {}, matter: {} }, 10 | 11 | preload: function () { 12 | this.sys.load.scripts('inspector', ['../vendor/tweakpane.js', '../dist/phaser-plugin-inspector.umd.js']); 13 | this.sys.load.once('complete', function () { 14 | // eslint-disable-next-line no-undef 15 | PhaserPluginInspector.Install(this.sys.plugins); 16 | }, this); 17 | } 18 | } 19 | ] 20 | }); 21 | -------------------------------------------------------------------------------- /demo/demo-particles.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | Demo of Phaser 3 Inspector Plugin 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /demo/demo-particles.js: -------------------------------------------------------------------------------- 1 | 2 | /* global Phaser, PhaserPluginInspector */ 3 | 4 | const { AddGameObject, AddParticleEmitter } = PhaserPluginInspector; 5 | 6 | function preload () { 7 | this.load.atlas('flares', 'assets/particles/flares.png', 'assets/particles/flares.json'); 8 | this.load.image('bg', 'assets/skies/darkstone.png'); 9 | this.load.image('flare', 'assets/particles/white-flare.png'); 10 | this.load.image('fox', 'assets/pics/card3.png'); 11 | } 12 | 13 | function create () { 14 | createGlowEmitter.call(this); 15 | createZoneEmitter.call(this); 16 | } 17 | 18 | function createGlowEmitter () { 19 | this.add.image(400, 300, 'bg'); 20 | 21 | const card = this.add.image(400, 300, 'fox').setInteractive(); 22 | 23 | const emitZone1 = { type: 'edge', source: card.getBounds(), quantity: 42 }; 24 | 25 | const emitter = this.add.particles(0, 0, 'flare', { 26 | speed: 24, 27 | frequency: -1, 28 | lifespan: 2000, 29 | quantity: 100, 30 | maxParticles: 1000, 31 | scale: { start: 0.4, end: 0 }, 32 | color: [0xffffff, 0x00ffff, 0x0000ff], 33 | emitZone: emitZone1, 34 | duration: 1000, 35 | emitting: false 36 | }); 37 | 38 | card.on('pointerdown', () => { 39 | emitter.explode(); 40 | }); 41 | 42 | const { pane } = this.inspectorScene; 43 | 44 | AddParticleEmitter(emitter, pane); 45 | AddGameObject(emitter, pane); 46 | } 47 | 48 | function createZoneEmitter () { 49 | const shape1 = new Phaser.Geom.Circle(0, 0, 160); 50 | const shape2 = new Phaser.Geom.Ellipse(0, 0, 500, 150); 51 | const shape3 = new Phaser.Geom.Rectangle(-150, -150, 300, 300); 52 | const shape4 = new Phaser.Geom.Line(-150, -150, 150, 150); 53 | const shape5 = new Phaser.Geom.Triangle.BuildEquilateral(0, -140, 300); 54 | 55 | const emitter = this.add.particles(400, 300, 'flares', { 56 | blendMode: 'ADD', 57 | delay: 100, 58 | duration: 60000, 59 | frame: { frames: ['red', 'green', 'blue'], cycle: true }, 60 | frequency: 25, 61 | hold: 200, 62 | lifespan: 600, 63 | maxAliveParticles: 100, 64 | name: 'cycling flares', 65 | scale: { start: 0.6, end: 0.1 } 66 | }); 67 | 68 | emitter.addEmitZone({ type: 'edge', source: shape1, quantity: 32, total: 64 }); 69 | emitter.addEmitZone({ type: 'edge', source: shape2, quantity: 32, total: 64 }); 70 | emitter.addEmitZone({ type: 'edge', source: shape3, quantity: 32, total: 64 }); 71 | emitter.addEmitZone({ type: 'edge', source: shape4, quantity: 32, total: 64 }); 72 | emitter.addEmitZone({ type: 'edge', source: shape5, quantity: 32, total: 64 }); 73 | 74 | emitter.createGravityWell({ 75 | x: 0, 76 | y: 0, 77 | power: 2, 78 | epsilon: 200, 79 | gravity: 100 80 | }); 81 | 82 | console.log('emitter', emitter); 83 | 84 | const { pane } = this.inspectorScene; 85 | 86 | AddParticleEmitter(emitter, pane); 87 | AddGameObject(emitter, pane); 88 | } 89 | 90 | function update () { 91 | } 92 | 93 | // eslint-disable-next-line no-new 94 | new Phaser.Game({ 95 | scene: { preload, create, update }, 96 | plugins: PhaserPluginInspector.DefaultPluginsConfig, 97 | audio: { 98 | disableAudio: true 99 | } 100 | }); 101 | -------------------------------------------------------------------------------- /demo/demo-plane.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | Demo of Phaser 3 Inspector Plugin 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /demo/demo-plane.js: -------------------------------------------------------------------------------- 1 | /* global Phaser, PhaserPluginInspector */ 2 | 3 | const { AddGameObject } = PhaserPluginInspector; 4 | 5 | class Example extends Phaser.Scene { 6 | preload () { 7 | this.load.image('bg', 'assets/skies/space4.png'); 8 | this.load.image('pudding', 'assets/tests/pipeline/pudding.png'); 9 | } 10 | 11 | create () { 12 | this.add.image(400, 300, 'bg'); 13 | 14 | // For NPOT textures (like our pudding texture) you cannot uvScale 15 | // them, because WebGL1 doesn't support this. So instead we can 16 | // create a Plane that is 8x8 cells in size and tile the texture 17 | // across each cell (the last 3 parameters) 18 | const plane = this.add.plane(400, 300, 'pudding', null, 8, 8, true).setName('pudding'); 19 | 20 | plane.setViewHeight(512); 21 | 22 | plane.modelRotation.x = -0.59; 23 | plane.modelRotation.y = 0.707; 24 | plane.viewPosition.z = 2.209; 25 | 26 | const rotateRate = 1; 27 | const panRate = 1; 28 | const zoomRate = 4; 29 | 30 | this.input.on('pointermove', pointer => { 31 | if (!pointer.isDown) { 32 | return; 33 | } 34 | 35 | if (!pointer.event.shiftKey) { 36 | plane.modelRotation.y += pointer.velocity.x * (rotateRate / 800); 37 | plane.modelRotation.x += pointer.velocity.y * (rotateRate / 600); 38 | } else { 39 | plane.panX(pointer.velocity.x * (panRate / 800)); 40 | plane.panY(pointer.velocity.y * (panRate / 600)); 41 | } 42 | }); 43 | 44 | this.input.on('wheel', (pointer, over, deltaX, deltaY, deltaZ) => { 45 | plane.panZ(deltaY * (zoomRate / 600)); 46 | }); 47 | 48 | AddGameObject(plane, this.inspectorScene.pane); 49 | } 50 | } 51 | 52 | // eslint-disable-next-line no-new 53 | new Phaser.Game({ 54 | width: 800, 55 | height: 600, 56 | pixelArt: true, 57 | scene: Example, 58 | plugins: PhaserPluginInspector.DefaultPluginsConfig, 59 | audio: { 60 | disableAudio: true 61 | } 62 | }); 63 | -------------------------------------------------------------------------------- /demo/demo-play.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | Demo of Phaser 3 Inspector Plugin 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /demo/demo-play.js: -------------------------------------------------------------------------------- 1 | 2 | /* global Phaser, PhaserPluginInspector */ 3 | 4 | console.info(PhaserPluginInspector); 5 | // console.info('{ %s }', Object.keys(PhaserPluginInspector).sort().join(', ')); 6 | 7 | const { AddArcadeBody, AddGameObject, AddParticleEmitter } = PhaserPluginInspector; 8 | 9 | let sky; 10 | 11 | function preload () { 12 | this.load.image('sky', 'assets/skies/starfield.png'); 13 | this.load.image('logo', 'assets/sprites/phaser3-logo.png'); 14 | this.load.image('red', 'assets/particles/red.png'); 15 | } 16 | 17 | function create () { 18 | sky = this.add.tileSprite(0, 0, 1024, 768, 'sky') 19 | .setOrigin(0, 0) 20 | .setName('sky'); 21 | 22 | const emitter = this.add.particles(0, 0, 'red', { 23 | name: 'red flares', 24 | frequency: 25, 25 | speed: 100, 26 | scale: { start: 1, end: 0 }, 27 | blendMode: 'ADD' 28 | }); 29 | 30 | const ghost = this.physics.add.image(400, 150, 'logo') 31 | .setAlpha(0.2); 32 | 33 | ghost.body.setAllowGravity(false); 34 | 35 | const logo = this.physics.add.image(400, 100, 'logo') 36 | .setName('logo') 37 | .setVelocity(100, 200) 38 | .setBounce(1, 1) 39 | .setCollideWorldBounds(true); 40 | 41 | this.physics.add.overlap(ghost, logo); 42 | 43 | emitter.startFollow(logo); 44 | 45 | const { pane } = this.inspectorScene; 46 | 47 | AddGameObject(sky, pane); 48 | AddGameObject(logo, pane); 49 | AddArcadeBody(logo.body, pane); 50 | AddGameObject(emitter, pane); 51 | AddParticleEmitter(emitter, pane); 52 | } 53 | 54 | function update () { 55 | sky.tilePositionX += 1; 56 | } 57 | 58 | // eslint-disable-next-line no-new 59 | new Phaser.Game({ 60 | scene: { preload, create, update }, 61 | plugins: PhaserPluginInspector.DefaultPluginsConfig, 62 | audio: { 63 | disableWebAudio: true 64 | }, 65 | physics: { 66 | default: 'arcade', 67 | arcade: { 68 | debug: true, 69 | gravity: { y: 200 } 70 | } 71 | } 72 | }); 73 | -------------------------------------------------------------------------------- /demo/demo-postfx.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | Demo of Phaser 3 Inspector Plugin 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /demo/demo-postfx.js: -------------------------------------------------------------------------------- 1 | /* global Phaser, PhaserPluginInspector */ 2 | 3 | const { AddGameObject, AddFXComponent, AddFXController } = PhaserPluginInspector; 4 | 5 | class Example extends Phaser.Scene { 6 | create () { 7 | const graphics = this.add.graphics().setName('with glow and wipe postFX'); 8 | 9 | graphics.fillStyle(0xffff00, 1); 10 | graphics.fillRect(100, 100, 256, 256); 11 | 12 | graphics.fillStyle(0xff00ff, 1); 13 | graphics.fillRect(300, 200, 256, 256); 14 | 15 | graphics.fillStyle(0x00ff00, 1); 16 | graphics.fillTriangle(200, 200, 400, 50, 500, 300); 17 | 18 | const glow = graphics.postFX.addGlow(); 19 | const wipe = graphics.postFX.addWipe(); 20 | 21 | wipe.progress = 0.25; 22 | 23 | const { pane } = this.inspectorGame; 24 | 25 | AddFXController(glow, pane); 26 | AddFXController(wipe, pane); 27 | 28 | // Only `clear()` is useful: 29 | AddFXComponent(graphics.postFX, pane, { title: 'Post FX (always active, always enabled)' }); 30 | 31 | AddGameObject(graphics, pane); 32 | } 33 | } 34 | 35 | // eslint-disable-next-line no-new 36 | new Phaser.Game({ 37 | // type: Phaser.CANVAS, 38 | width: 800, 39 | height: 600, 40 | scene: Example, 41 | plugins: PhaserPluginInspector.DefaultPluginsConfig, 42 | audio: { 43 | disableAudio: true 44 | } 45 | }); 46 | -------------------------------------------------------------------------------- /demo/demo-sound-markers.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | Demo of Phaser 3 Inspector Plugin 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /demo/demo-sound-markers.js: -------------------------------------------------------------------------------- 1 | 2 | /* global Phaser, PhaserPluginInspector */ 3 | 4 | const { AddSound } = PhaserPluginInspector; 5 | 6 | function preload () { 7 | this.load.image('bg', 'assets/pics/cougar-dragonsun.png'); 8 | this.load.audio('sfx', [ 9 | 'assets/audio/SoundEffects/magical_horror_audiosprite.ogg', 10 | 'assets/audio/SoundEffects/magical_horror_audiosprite.mp3' 11 | ]); 12 | } 13 | 14 | function create () { 15 | this.add.image(400, 300, 'bg'); 16 | 17 | const fx = this.sound.add('sfx'); 18 | 19 | const markers = [ 20 | { name: 'charm', start: 0, duration: 2.7, config: {} }, 21 | { name: 'curse', start: 4, duration: 2.9, config: {} }, 22 | { name: 'fireball', start: 8, duration: 5.2, config: {} }, 23 | { name: 'spell', start: 14, duration: 4.7, config: {} }, 24 | { name: 'soundscape', start: 20, duration: 18.8, config: {} } 25 | ]; 26 | 27 | for (const marker of markers) { 28 | fx.addMarker(marker); 29 | } 30 | 31 | AddSound(fx, this.inspectorGame.pane); 32 | } 33 | 34 | // eslint-disable-next-line no-new 35 | new Phaser.Game({ 36 | scene: { preload, create }, 37 | plugins: PhaserPluginInspector.DefaultPluginsConfig, 38 | audio: { 39 | disableWebAudio: true 40 | } 41 | }); 42 | -------------------------------------------------------------------------------- /demo/demo-sound.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | Demo of Phaser 3 Inspector Plugin 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /demo/demo-sound.js: -------------------------------------------------------------------------------- 1 | 2 | /* global Phaser, PhaserPluginInspector */ 3 | 4 | const { AddSound } = PhaserPluginInspector; 5 | 6 | function preload () { 7 | this.load.audio('music', 'assets/audio/Ludwig van Beethoven - The Creatures of Prometheus, Op. 43/Overture.mp3'); 8 | } 9 | 10 | function create () { 11 | const music = this.sound.add('music'); 12 | music.play(); 13 | 14 | const { pane } = this.inspectorScene; 15 | 16 | AddSound(music, pane); 17 | 18 | this.scene.remove(); 19 | } 20 | 21 | // eslint-disable-next-line no-new 22 | new Phaser.Game({ 23 | scene: { preload, create }, 24 | plugins: PhaserPluginInspector.DefaultPluginsConfig, 25 | audio: { 26 | disableWebAudio: true 27 | } 28 | }); 29 | -------------------------------------------------------------------------------- /demo/demo-tilemap.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | Demo of Phaser 3 Inspector Plugin 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /demo/demo-tilemap.js: -------------------------------------------------------------------------------- 1 | /* global PhaserPluginInspector, Tweakpane */ 2 | 3 | const { AddAlpha, AddVisible, AddGameObject } = PhaserPluginInspector; 4 | 5 | const pane = new Tweakpane.Pane({ title: 'Tilemap Demo' }); 6 | 7 | class Example extends Phaser.Scene { 8 | preload () { 9 | this.load.image('kenny_platformer_64x64', 'assets/tilemaps/tiles/kenny_platformer_64x64.png'); 10 | this.load.tilemapTiledJSON('multiple-layers-map', 'assets/tilemaps/maps/multiple-layers.json'); 11 | } 12 | 13 | create () { 14 | this.map = this.make.tilemap({ key: 'multiple-layers-map' }); 15 | 16 | const tiles = this.map.addTilesetImage('kenny_platformer_64x64'); 17 | 18 | const grid = this.add.grid( 19 | 0, 0, 20 | this.map.widthInPixels, this.map.heightInPixels, 21 | this.map.tileWidth, this.map.tileHeight, 22 | 0, 1, 23 | 0xffff00, 1 24 | ).setAlpha(0.2).setOrigin(0, 0); 25 | 26 | for (const layer of this.map.layers) { 27 | this.map.createLayer(layer.name, tiles).setName(layer.name); 28 | } 29 | 30 | this.map.getLayer('Water Layer').tilemapLayer.setAlpha(0.8); 31 | 32 | const tilemapLayers = this.map.layers.map(l => l.tilemapLayer); 33 | 34 | AddAlpha([grid, ...tilemapLayers], pane); 35 | AddVisible([grid, ...tilemapLayers], pane); 36 | 37 | for (const tilemapLayer of tilemapLayers) { 38 | AddGameObject(tilemapLayer, pane, { title: tilemapLayer.name, expanded: false }); 39 | } 40 | 41 | const cursors = this.input.keyboard.createCursorKeys(); 42 | const controlConfig = { 43 | camera: this.cameras.main, 44 | left: cursors.left, 45 | right: cursors.right, 46 | up: cursors.up, 47 | down: cursors.down, 48 | speed: 1 49 | }; 50 | 51 | this.controls = new Phaser.Cameras.Controls.FixedKeyControl(controlConfig); 52 | } 53 | 54 | update (time, delta) { 55 | this.controls.update(delta); 56 | } 57 | } 58 | 59 | const config = { 60 | width: 1024, 61 | height: 1024, 62 | pixelArt: true, 63 | scene: Example 64 | }; 65 | 66 | // eslint-disable-next-line no-new 67 | new Phaser.Game(config); 68 | -------------------------------------------------------------------------------- /demo/demo-timeline.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | Demo of Phaser 3 Inspector Plugin 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /demo/demo-timeline.js: -------------------------------------------------------------------------------- 1 | /* global PhaserPluginInspector, Tweakpane */ 2 | 3 | const { AddTimeline } = PhaserPluginInspector; 4 | 5 | class Example extends Phaser.Scene { 6 | preload () { 7 | this.load.atlas('timeline', 'assets/atlas/timeline.png', 'assets/atlas/timeline.json'); 8 | this.load.image('bg', 'assets/skies/spookysky.jpg'); 9 | this.load.atlas('flares', 'assets/particles/flares.png', 'assets/particles/flares.json'); 10 | } 11 | 12 | create () { 13 | this.add.image(400, 300, 'bg'); 14 | 15 | const crystalball = this.add.sprite(400, 800, 'timeline', 'crystalball'); 16 | 17 | const glowFX = crystalball.preFX.addGlow(); 18 | 19 | const emitter = this.add.particles(400, 300, 'flares', { 20 | frame: 'white', 21 | blendMode: 'ADD', 22 | lifespan: 1200, 23 | gravityY: -100, 24 | scale: { start: 0.3, end: 0 }, 25 | emitting: false 26 | }); 27 | 28 | emitter.addEmitZone({ source: new Phaser.Geom.Circle(0, -20, 90) }); 29 | 30 | const timeline = this.add.timeline([ 31 | { 32 | at: 0, 33 | run: () => { 34 | glowFX.setActive(false); 35 | glowFX.outerStrength = 0; 36 | glowFX.innerStrength = 0; 37 | }, 38 | tween: { 39 | targets: crystalball, 40 | y: 300, 41 | ease: 'sine.in', 42 | duration: 750 43 | } 44 | }, 45 | { 46 | at: 1000, 47 | run: () => { 48 | glowFX.setActive(true); 49 | emitter.start(); 50 | }, 51 | tween: { 52 | targets: glowFX, 53 | outerStrength: 16, 54 | innerStrength: 8, 55 | ease: 'sine.in', 56 | yoyo: true, 57 | duration: 500, 58 | repeat: 3 59 | } 60 | }, 61 | { 62 | at: 4000, 63 | run: () => { 64 | emitter.stop(); 65 | }, 66 | tween: { 67 | targets: crystalball, 68 | y: 800, 69 | ease: 'sine.in', 70 | duration: 500 71 | } 72 | }, 73 | { 74 | at: 5000, 75 | stop: true 76 | } 77 | ]); 78 | 79 | AddTimeline(timeline, pane); 80 | 81 | timeline.play(); 82 | } 83 | } 84 | 85 | const config = { 86 | width: 800, 87 | height: 600, 88 | scene: Example 89 | }; 90 | 91 | const pane = new Tweakpane.Pane({ title: 'Timeline Demo' }); 92 | 93 | // eslint-disable-next-line no-unused-vars 94 | const game = new Phaser.Game(config); 95 | -------------------------------------------------------------------------------- /demo/demo-timer-event.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | Demo of Phaser 3 Inspector Plugin 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /demo/demo-timer-event.js: -------------------------------------------------------------------------------- 1 | /* global PhaserPluginInspector */ 2 | 3 | const { AddTimerEvent } = PhaserPluginInspector; 4 | 5 | class Example extends Phaser.Scene { 6 | preload () { 7 | this.load.atlas('timeline', 'assets/atlas/timeline.png', 'assets/atlas/timeline.json'); 8 | this.load.image('bg', 'assets/skies/spookysky.jpg'); 9 | } 10 | 11 | create () { 12 | // this.time.paused = true; 13 | 14 | this.add.image(400, 300, 'bg'); 15 | 16 | const bat = this.add.sprite(200, 150, 'timeline', 'bat'); 17 | 18 | const timer = this.time.addEvent({ 19 | delay: 200, 20 | startAt: 0, 21 | repeat: 9, 22 | callback: () => { 23 | bat.angle += 36; 24 | } 25 | }); 26 | 27 | AddTimerEvent(timer, this.inspectorGame.pane); 28 | } 29 | } 30 | 31 | const gameConfig = { 32 | width: 800, 33 | height: 600, 34 | scene: Example, 35 | plugins: PhaserPluginInspector.DefaultPluginsConfig 36 | }; 37 | 38 | // eslint-disable-next-line no-unused-vars 39 | const game = new Phaser.Game(gameConfig); 40 | -------------------------------------------------------------------------------- /demo/demo-tween.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | Demo of Phaser 3 Inspector Plugin 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /demo/demo-tween.js: -------------------------------------------------------------------------------- 1 | 2 | /* global Phaser, PhaserPluginInspector */ 3 | 4 | const { AddTween } = PhaserPluginInspector; 5 | 6 | function preload () { 7 | this.load.image('block', 'assets/sprites/block.png'); 8 | } 9 | 10 | function create () { 11 | const image1 = this.add.image(130, 50, 'block'); 12 | const image2 = this.add.image(190, 80, 'block'); 13 | const image3 = this.add.image(50, 150, 'block'); 14 | 15 | const tween = this.tweens.add({ 16 | targets: [image1, image2, image3], 17 | props: { 18 | x: { value: '+=600', duration: 3000, ease: 'Power2' }, 19 | y: { value: '500', duration: 1500, ease: 'Bounce.easeOut' } 20 | }, 21 | delay: 1000 22 | }); 23 | 24 | const folder = AddTween(tween, this.inspectorScene.pane); 25 | 26 | this.events.once('shutdown', () => { folder.dispose(); }); 27 | } 28 | 29 | function update () { 30 | } 31 | 32 | // eslint-disable-next-line no-new 33 | new Phaser.Game({ 34 | scene: { preload, create, update }, 35 | plugins: PhaserPluginInspector.DefaultPluginsConfig, 36 | audio: { 37 | disableWebAudio: true 38 | } 39 | }); 40 | -------------------------------------------------------------------------------- /demo/demo-video.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | Demo of Phaser 3 Inspector Plugin 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /demo/demo-video.js: -------------------------------------------------------------------------------- 1 | /* global Phaser, PhaserPluginInspector */ 2 | 3 | const { AddGameObject, AddVideo } = PhaserPluginInspector; 4 | 5 | class Example extends Phaser.Scene { 6 | preload () { 7 | this.load.video('spaceace', 'assets/video/spaceace.mp4'); 8 | this.load.video('underwater', 'assets/video/underwater.mp4'); 9 | } 10 | 11 | create () { 12 | const intro = this.add.video(360, 240, 'underwater').setName('intro'); 13 | 14 | intro.on('locked', () => { 15 | const message = this.add.text(360, 120, '👆 Click to play video', { font: '32px Courier', fill: '#00ff00' }).setShadow(1, 1).setOrigin(0.5); 16 | 17 | intro.on('unlocked', () => { 18 | message.destroy(); 19 | }); 20 | }); 21 | 22 | intro.play(); 23 | 24 | AddVideo(intro, this.inspectorScene.pane); 25 | AddGameObject(intro, this.inspectorScene.pane); 26 | } 27 | } 28 | 29 | // eslint-disable-next-line no-new 30 | new Phaser.Game({ 31 | width: 720, 32 | height: 480, 33 | scene: Example, 34 | plugins: PhaserPluginInspector.DefaultPluginsConfig 35 | }); 36 | -------------------------------------------------------------------------------- /demo/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | Demo of Phaser 3 Inspector Plugin 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /demo/demo.js: -------------------------------------------------------------------------------- 1 | 2 | /* global Phaser, PhaserPluginInspector */ 3 | 4 | // eslint-disable-next-line no-new 5 | new Phaser.Game({ 6 | type: Phaser.CANVAS, 7 | plugins: PhaserPluginInspector.DefaultPluginsConfig, 8 | scene: [ 9 | { key: 'active' }, 10 | { key: 'arcade', physics: { arcade: {} } }, 11 | { key: 'matter', physics: { matter: {} } }, 12 | { key: 'plugins', plugins: ['InspectorScenePlugin'], active: true }, 13 | { key: 'shutdown', active: true, update: function () { this.scene.stop(); } }, 14 | { key: 'remove', active: true, update: function () { this.scene.remove(); } } 15 | ] 16 | }); 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "phaser-plugin-inspector", 3 | "version": "2.6.0", 4 | "description": "View and change Phaser 3 game properties", 5 | "type": "module", 6 | "module": "dist/phaser-plugin-inspector.esm.js", 7 | "browser": "dist/phaser-plugin-inspector.umd.js", 8 | "files": [ 9 | "dist", 10 | "src" 11 | ], 12 | "directories": { 13 | "test": "test" 14 | }, 15 | "devDependencies": { 16 | "@rollup/plugin-buble": "^0.21.3", 17 | "@rollup/plugin-commonjs": "^11.1.0", 18 | "@rollup/plugin-node-resolve": "^7.1.3", 19 | "acorn": "^6.4.1", 20 | "chai": "^4.2.0", 21 | "eslint": "^8.57.1", 22 | "eslint-config-semistandard": "^15.0.1", 23 | "eslint-config-standard": "^14.1.1", 24 | "eslint-plugin-import": "^2.22.0", 25 | "eslint-plugin-node": "^10.0.0", 26 | "eslint-plugin-promise": "^4.2.1", 27 | "eslint-plugin-standard": "^4.0.1", 28 | "mocha": "^10.8.2", 29 | "phaser": "3.87.0", 30 | "rollup": "^2.23.0", 31 | "tweakpane": "3.1.10" 32 | }, 33 | "peerDependencies": { 34 | "phaser": "^3.60.0", 35 | "tweakpane": "^3.1.0" 36 | }, 37 | "scripts": { 38 | "build": "rollup -c", 39 | "clean": "rm dist/*.js", 40 | "dev": "rollup -c -w", 41 | "postbuild": "node -c dist/phaser-plugin-inspector.umd.js", 42 | "vendor": "cp -v node_modules/tweakpane/dist/tweakpane.js node_modules/mocha/mocha.{css,js} node_modules/chai/chai.js node_modules/phaser/dist/phaser.js vendor/", 43 | "preversion": "npm run build", 44 | "test": "eslint src" 45 | }, 46 | "repository": { 47 | "type": "git", 48 | "url": "git+https://github.com/samme/phaser-plugin-inspector.git" 49 | }, 50 | "keywords": [ 51 | "phaser", 52 | "phaser-plugin", 53 | "phaser3", 54 | "phaser3-plugin", 55 | "tweakpane" 56 | ], 57 | "author": "samme", 58 | "license": "ISC", 59 | "bugs": { 60 | "url": "https://github.com/samme/phaser-plugin-inspector/issues" 61 | }, 62 | "homepage": "https://github.com/samme/phaser-plugin-inspector#readme" 63 | } 64 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import resolve from '@rollup/plugin-node-resolve'; 2 | import commonjs from '@rollup/plugin-commonjs'; 3 | import pkg from './package.json'; 4 | 5 | export default [ 6 | { 7 | external: ['phaser', 'tweakpane'], 8 | input: 'src/main.js', 9 | output: [ 10 | { 11 | name: 'PhaserPluginInspector', 12 | file: pkg.browser, 13 | format: 'umd', 14 | globals: { phaser: 'Phaser', tweakpane: 'Tweakpane' } 15 | }, 16 | { 17 | file: pkg.module, 18 | format: 'es' 19 | } 20 | ], 21 | plugins: [ 22 | resolve(), 23 | commonjs() 24 | ] 25 | } 26 | ]; 27 | -------------------------------------------------------------------------------- /src/DefaultPluginsConfig.js: -------------------------------------------------------------------------------- 1 | import { InspectorGlobalPlugin } from './InspectorGlobalPlugin'; 2 | import { InspectorScenePlugin } from './InspectorScenePlugin'; 3 | import { 4 | GLOBAL_PLUGIN_KEY, 5 | GLOBAL_PLUGIN_MAPPING, 6 | SCENE_PLUGIN_KEY, 7 | SCENE_PLUGIN_SCENE_MAPPING 8 | } from './const'; 9 | 10 | export const DefaultPluginsConfig = { 11 | global: [{ key: GLOBAL_PLUGIN_KEY, plugin: InspectorGlobalPlugin, mapping: GLOBAL_PLUGIN_MAPPING }], 12 | scene: [{ key: SCENE_PLUGIN_KEY, plugin: InspectorScenePlugin, mapping: SCENE_PLUGIN_SCENE_MAPPING }] 13 | }; 14 | -------------------------------------------------------------------------------- /src/EaseMap.js: -------------------------------------------------------------------------------- 1 | import Phaser from 'phaser'; 2 | 3 | const { 4 | Back, 5 | Bounce, 6 | Circular, 7 | Cubic, 8 | Elastic, 9 | Expo, 10 | Linear, 11 | Quadratic, 12 | Quartic, 13 | Quintic, 14 | Sine, 15 | Stepped 16 | } = Phaser.Math.Easing; 17 | 18 | /** 19 | * EaseMap 20 | * 21 | * @author Richard Davey 22 | * @copyright 2013-2024 Phaser Studio Inc. 23 | * @license {@link https://opensource.org/licenses/MIT|MIT License} 24 | */ 25 | 26 | export const EaseMap = { 27 | Power0: Linear, 28 | Power1: Quadratic.Out, 29 | Power2: Cubic.Out, 30 | Power3: Quartic.Out, 31 | Power4: Quintic.Out, 32 | 33 | Linear: Linear, 34 | Quad: Quadratic.Out, 35 | Cubic: Cubic.Out, 36 | Quart: Quartic.Out, 37 | Quint: Quintic.Out, 38 | Sine: Sine.Out, 39 | Expo: Expo.Out, 40 | Circ: Circular.Out, 41 | Elastic: Elastic.Out, 42 | Back: Back.Out, 43 | Bounce: Bounce.Out, 44 | Stepped: Stepped, 45 | 46 | 'Quad.easeIn': Quadratic.In, 47 | 'Cubic.easeIn': Cubic.In, 48 | 'Quart.easeIn': Quartic.In, 49 | 'Quint.easeIn': Quintic.In, 50 | 'Sine.easeIn': Sine.In, 51 | 'Expo.easeIn': Expo.In, 52 | 'Circ.easeIn': Circular.In, 53 | 'Elastic.easeIn': Elastic.In, 54 | 'Back.easeIn': Back.In, 55 | 'Bounce.easeIn': Bounce.In, 56 | 57 | 'Quad.easeOut': Quadratic.Out, 58 | 'Cubic.easeOut': Cubic.Out, 59 | 'Quart.easeOut': Quartic.Out, 60 | 'Quint.easeOut': Quintic.Out, 61 | 'Sine.easeOut': Sine.Out, 62 | 'Expo.easeOut': Expo.Out, 63 | 'Circ.easeOut': Circular.Out, 64 | 'Elastic.easeOut': Elastic.Out, 65 | 'Back.easeOut': Back.Out, 66 | 'Bounce.easeOut': Bounce.Out, 67 | 68 | 'Quad.easeInOut': Quadratic.InOut, 69 | 'Cubic.easeInOut': Cubic.InOut, 70 | 'Quart.easeInOut': Quartic.InOut, 71 | 'Quint.easeInOut': Quintic.InOut, 72 | 'Sine.easeInOut': Sine.InOut, 73 | 'Expo.easeInOut': Expo.InOut, 74 | 'Circ.easeInOut': Circular.InOut, 75 | 'Elastic.easeInOut': Elastic.InOut, 76 | 'Back.easeInOut': Back.InOut, 77 | 'Bounce.easeInOut': Bounce.InOut 78 | }; 79 | -------------------------------------------------------------------------------- /src/FXMap.js: -------------------------------------------------------------------------------- 1 | export const FXMap = { 2 | 4: 'GLOW', 3 | 5: 'SHADOW', 4 | 6: 'PIXELATE', 5 | 7: 'VIGNETTE', 6 | 8: 'SHINE', 7 | 9: 'BLUR', 8 | 12: 'GRADIENT', 9 | 13: 'BLOOM', 10 | 14: 'COLOR_MATRIX', 11 | 15: 'CIRCLE', 12 | 16: 'BARREL', 13 | 17: 'DISPLACEMENT', 14 | 18: 'WIPE', 15 | 19: 'BOKEH' 16 | }; 17 | -------------------------------------------------------------------------------- /src/InspectorGlobalPlugin.js: -------------------------------------------------------------------------------- 1 | import Phaser from 'phaser'; 2 | import { Pane } from 'tweakpane'; 3 | import { 4 | AddPointer, 5 | AddScenes, 6 | copyToSafeObj, 7 | animToPrint, 8 | FormatLength, 9 | sceneToPrint, 10 | soundToPrint, 11 | textureToPrint, 12 | printCaches, 13 | printDevice, 14 | snapshot 15 | } from './util'; 16 | 17 | export class InspectorGlobalPlugin extends Phaser.Plugins.BasePlugin { 18 | constructor (pluginManager) { 19 | if (Phaser.VERSION.split('.')[1] < 60) { 20 | throw new Error('Phaser v3.60 or later is required'); 21 | } 22 | 23 | super(pluginManager); 24 | 25 | this.pane = null; 26 | this.style = null; 27 | } 28 | 29 | init (data) { 30 | } 31 | 32 | start () { 33 | this.pane = new Pane({ title: 'Inspector' }); 34 | 35 | this.add(); 36 | 37 | this.style = document.createElement('style'); 38 | this.style.innerText = '.tp-dfwv { top: 0; width: 320px; max-height: 100%; overflow: auto }'; 39 | document.head.appendChild(this.style); 40 | } 41 | 42 | stop () { 43 | document.head.removeChild(this.style); 44 | this.style = null; 45 | this.pane.dispose(); 46 | this.pane = null; 47 | } 48 | 49 | destroy () { 50 | this.stop(); 51 | super.destroy(); 52 | } 53 | 54 | add () { 55 | const { game, pane } = this; 56 | const { anims, cache, device, input, loop, registry, renderer, scale, scene, sound, textures } = game; 57 | const { keyboard, touch } = input; 58 | 59 | pane.addButton({ title: 'Refresh' }).on('click', () => { console.time('refresh'); pane.refresh(); console.timeEnd('refresh'); }); 60 | 61 | const folder = pane.addFolder({ title: 'Game', expanded: false }); 62 | 63 | folder.addMonitor(game, 'hasFocus'); 64 | folder.addMonitor(game, 'isPaused'); 65 | folder.addButton({ title: 'Pause' }).on('click', () => { console.info('Pause game'); game.pause(); }); 66 | folder.addButton({ title: 'Resume' }).on('click', () => { console.info('Resume game'); game.resume(); }); 67 | folder.addButton({ title: 'Step' }).on('click', () => { const t = performance.now(); const dt = loop._target; console.info('step', t, dt); game.step(t, dt); }); 68 | folder.addButton({ title: 'Destroy' }).on('click', () => { console.info('Destroy game'); game.destroy(true); }); 69 | 70 | const animsFolder = folder.addFolder({ title: 'Animations', expanded: false }); 71 | animsFolder.addButton({ title: 'Pause all' }).on('click', () => { console.info('Pause all animations'); anims.pauseAll(); }); 72 | animsFolder.addButton({ title: 'Resume all' }).on('click', () => { console.info('Resume all animations'); anims.resumeAll(); }); 73 | animsFolder.addButton({ title: 'Print animations' }).on('click', () => { console.info('Animations:'); console.table(anims.anims.getArray().map(animToPrint)); }); 74 | animsFolder.addButton({ title: 'Print JSON' }).on('click', () => { console.info(JSON.stringify(anims.toJSON())); }); 75 | 76 | const cacheFolder = folder.addFolder({ title: 'Cache', expanded: false }); 77 | cacheFolder.addButton({ title: 'Print cache contents' }).on('click', () => { printCaches(cache); }); 78 | 79 | const configFolder = folder.addFolder({ title: 'Config', expanded: false }); 80 | configFolder.addButton({ title: 'Print game config' }).on('click', () => { console.info('Game config (partial):'); console.table(copyToSafeObj(game.config)); }); 81 | 82 | const deviceFolder = folder.addFolder({ title: 'Device', expanded: false }); 83 | deviceFolder.addButton({ title: 'Print device info' }).on('click', () => { console.info('Device:'); printDevice(device); }); 84 | 85 | const inputFolder = folder.addFolder({ title: 'Input', expanded: false }); 86 | inputFolder.addMonitor(input, 'isOver'); 87 | inputFolder.addInput(input, 'enabled'); 88 | inputFolder.addInput(input, 'globalTopOnly'); 89 | 90 | for (const pointer of input.pointers) { 91 | AddPointer(pointer, inputFolder); 92 | } 93 | 94 | if (keyboard) { 95 | const keyboardFolder = folder.addFolder({ title: 'Keyboard', expanded: false }); 96 | keyboardFolder.addInput(keyboard, 'enabled'); 97 | keyboardFolder.addMonitor(keyboard, 'preventDefault'); 98 | } 99 | 100 | if (touch) { 101 | const touchFolder = folder.addFolder({ title: 'Touch', expanded: false }); 102 | touchFolder.addInput(touch, 'capture'); 103 | touchFolder.addInput(touch, 'enabled'); 104 | } 105 | 106 | const loopProxy = { 107 | get 'getDuration()' () { return loop.getDuration(); } 108 | }; 109 | const loopFolder = folder.addFolder({ title: 'Loop', expanded: false }); 110 | loopFolder.addMonitor(loop, 'actualFps', { view: 'graph', min: 0, max: 120 }); 111 | loopFolder.addMonitor(loop, 'delta', { view: 'graph', min: 0, max: 50 }); 112 | loopFolder.addMonitor(loop, 'frame', { format: Math.floor }); 113 | loopFolder.addMonitor(loopProxy, 'getDuration()'); 114 | loopFolder.addMonitor(loop, 'now'); 115 | loopFolder.addMonitor(loop, 'rawDelta', { view: 'graph', min: 0, max: 50 }); 116 | loopFolder.addMonitor(loop, 'running'); 117 | loopFolder.addMonitor(loop, 'startTime'); 118 | loopFolder.addMonitor(loop, 'time'); 119 | loopFolder.addButton({ title: 'Sleep' }).on('click', () => { console.info('Sleep game loop'); loop.sleep(); }); 120 | loopFolder.addButton({ title: 'Wake' }).on('click', () => { console.info('Wake game loop'); loop.wake(); }); 121 | loopFolder.addButton({ title: 'Step' }).on('click', () => { const t = performance.now(); console.info('step', t); loop.step(t); }); 122 | 123 | const registryFolder = folder.addFolder({ title: 'Registry', expanded: false }); 124 | registryFolder.addButton({ title: 'Print registry values' }).on('click', () => { console.info('Registry:'); console.table(registry.getAll()); }); 125 | 126 | const rendererFolder = folder.addFolder({ title: 'Renderer', expanded: false }); 127 | if (renderer.type === Phaser.CANVAS) { 128 | rendererFolder.addInput(renderer, 'antialias'); 129 | rendererFolder.addMonitor(renderer, 'drawCount', { view: 'graph', min: 0, max: 100 }); 130 | } 131 | rendererFolder.addButton({ title: 'Snapshot' }).on('click', () => { 132 | console.info('Snapshot'); 133 | renderer.snapshot(snapshot); 134 | }); 135 | rendererFolder.addButton({ title: 'Print config' }).on('click', () => { console.info('Renderer config:'); console.table(copyToSafeObj(renderer.config)); }); 136 | 137 | const scaleFolder = folder.addFolder({ title: 'Scale', expanded: false }); 138 | scaleFolder.addMonitor(scale, 'width'); 139 | scaleFolder.addMonitor(scale, 'height'); 140 | scaleFolder.addButton({ title: 'Start full screen' }).on('click', () => { console.info('Start fullscreen'); scale.startFullscreen(); }); 141 | scaleFolder.addButton({ title: 'Stop full screen' }).on('click', () => { console.info('Stop fullscreen'); scale.stopFullscreen(); }); 142 | 143 | const sceneFolder = folder.addFolder({ title: 'Scenes', expanded: false }); 144 | sceneFolder.addButton({ title: 'Print scenes' }).on('click', () => { console.info('Scenes:'); console.table(scene.scenes.map(sceneToPrint)); }); 145 | sceneFolder.addButton({ title: 'Add visible controls' }).on('click', () => { AddScenes(scene.getScenes(false), sceneFolder); }); 146 | 147 | const soundFolder = folder.addFolder({ title: 'Sound', expanded: false }); 148 | soundFolder.addInput(sound, 'mute'); 149 | soundFolder.addInput(sound, 'pauseOnBlur'); 150 | soundFolder.addMonitor(sound.sounds, 'length', { label: 'sounds.length', format: FormatLength }); 151 | soundFolder.addInput(sound, 'volume', { min: 0, max: 1, step: 0.1 }); 152 | soundFolder.addButton({ title: 'Pause all' }).on('click', () => { console.info('Pause all sounds'); sound.pauseAll(); }); 153 | soundFolder.addButton({ title: 'Remove all' }).on('click', () => { console.info('Remove all sounds'); sound.removeAll(); }); 154 | soundFolder.addButton({ title: 'Resume all' }).on('click', () => { console.info('Resume all sounds'); sound.resumeAll(); }); 155 | soundFolder.addButton({ title: 'Stop all' }).on('click', () => { console.info('Stop all sounds'); sound.stopAll(); }); 156 | soundFolder.addButton({ title: 'Print sounds' }).on('click', () => { console.info('Sounds:'); console.table(sound.sounds.map(soundToPrint)); }); 157 | 158 | const texturesFolder = folder.addFolder({ title: 'Textures', expanded: false }); 159 | texturesFolder.addButton({ title: 'Print textures' }).on('click', () => { console.info('Textures:'); console.table(Object.values(textures.list).map(textureToPrint)); }); 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/InspectorScenePlugin.js: -------------------------------------------------------------------------------- 1 | import Phaser from 'phaser'; 2 | import { GLOBAL_PLUGIN_KEY } from './const'; 3 | import { AddActive, AddArcadePhysicsWorld, AddCamera, AddMatterPhysicsWorld, AddVisible, cameraToPrint, displayListItemToPrint, FormatLength, InspectByIndex, InspectByName, InspectByType, keyToPrint, lightToPrint, timerEventToPrint, tweenToPrint, updateListItemToPrint } from './util'; 4 | 5 | const { 6 | CREATE, 7 | DESTROY, 8 | START 9 | } = Phaser.Scenes.Events; 10 | 11 | const { 12 | START: STATUS_START, 13 | SHUTDOWN: STATUS_SHUTDOWN 14 | } = Phaser.Scenes; 15 | 16 | export class InspectorScenePlugin extends Phaser.Plugins.ScenePlugin { 17 | constructor (scene, pluginManager) { 18 | super(scene, pluginManager); 19 | 20 | this.folder = null; 21 | this.pane = null; 22 | } 23 | 24 | boot () { 25 | this.pane = this.pluginManager.get(GLOBAL_PLUGIN_KEY).pane; 26 | this.folder = this.pane.addFolder({ title: `Scene “${this.systems.settings.key}”`, expanded: false }); 27 | 28 | this.systems.events 29 | .on(DESTROY, this.sceneDestroy, this); 30 | 31 | this.add(); 32 | } 33 | 34 | destroy () { 35 | this.folder.dispose(); 36 | this.folder = null; 37 | 38 | this.systems.events 39 | .off(DESTROY, this.sceneDestroy, this); 40 | 41 | super.destroy(); 42 | } 43 | 44 | sceneDestroy () { 45 | this.destroy(); 46 | } 47 | 48 | add () { 49 | const { arcadePhysics, cameras, data, displayList, events, input, load, lights, matterPhysics, scenePlugin, time, tweens, updateList } = this.systems; 50 | const sceneKey = scenePlugin.settings.key; 51 | const sceneStatus = scenePlugin.settings.status; 52 | 53 | const camerasFolder = this.folder.addFolder({ title: 'Cameras', expanded: false }); 54 | camerasFolder.addButton({ title: 'Print cameras' }).on('click', () => { console.info('Cameras:'); console.table(cameras.cameras.map(cameraToPrint)); }); 55 | 56 | if (data) { 57 | const dataFolder = this.folder.addFolder({ title: 'Data', expanded: false }); 58 | dataFolder.addButton({ title: 'Print data' }).on('click', () => { console.info('Data:'); console.table(data.getAll()); }); 59 | } 60 | 61 | const displayListFolder = this.folder.addFolder({ title: 'Display List', expanded: false }); 62 | displayListFolder.addMonitor(displayList, 'length', { format: FormatLength }); 63 | displayListFolder.addButton({ title: 'Print' }).on('click', () => { console.info('Display list:'); console.table(displayList.getChildren().map(displayListItemToPrint)); }); 64 | displayListFolder.addButton({ title: 'Save JSON' }).on('click', () => { load.saveJSON(displayList.getChildren(), `${sceneKey} displayList.json`); }); 65 | displayListFolder.addButton({ title: 'Inspect by name …' }).on('click', () => { InspectByName(prompt('Inspect first game object on display list with name:'), displayList.getChildren(), this.pane); }); 66 | displayListFolder.addButton({ title: 'Inspect by type …' }).on('click', () => { InspectByType(prompt('Inspect first game object on display list with type:'), displayList.getChildren(), this.pane); }); 67 | displayListFolder.addButton({ title: 'Inspect by index …' }).on('click', () => { InspectByIndex(prompt(`Inspect game object on display list at index (0 to ${displayList.length - 1}):`), displayList.getChildren(), this.pane); }); 68 | displayListFolder.addButton({ title: 'Add visible controls' }).on('click', () => { AddVisible(displayList.getChildren(), displayListFolder); }); 69 | 70 | if (input) { 71 | const { gamepad, keyboard } = input; 72 | const inputFolder = this.folder.addFolder({ title: 'Input', expanded: false }); 73 | inputFolder.addInput(input, 'dragDistanceThreshold', { min: 0, max: 32, step: 1 }); 74 | inputFolder.addInput(input, 'dragTimeThreshold', { min: 0, max: 100, step: 10 }); 75 | inputFolder.addInput(input, 'enabled'); 76 | inputFolder.addMonitor(input, 'pollRate'); 77 | inputFolder.addInput(input, 'topOnly'); 78 | inputFolder.addMonitor(input, 'x'); 79 | inputFolder.addMonitor(input, 'y'); 80 | inputFolder.addButton({ title: 'Set poll always' }).on('click', () => { console.info('Poll always'); input.setPollAlways(); }); 81 | inputFolder.addButton({ title: 'Set poll on move' }).on('click', () => { console.info('Poll on move'); input.setPollOnMove(); }); 82 | inputFolder.addButton({ title: 'Print game objects' }).on('click', () => { console.info('Interactive game objects: '); console.table(input._list.map(displayListItemToPrint)); }); 83 | 84 | if (gamepad) { 85 | const gamepadFolder = this.folder.addFolder({ title: 'Gamepads', expanded: false }); 86 | gamepadFolder.addInput(gamepad, 'enabled'); 87 | gamepadFolder.addMonitor(gamepad, 'total'); 88 | } 89 | 90 | if (keyboard) { 91 | const keyboardFolder = this.folder.addFolder({ title: 'Keyboard', expanded: false }); 92 | keyboardFolder.addInput(keyboard, 'enabled'); 93 | keyboardFolder.addButton({ title: 'Clear captures' }).on('click', () => { console.info('Clear key captures'); keyboard.clearCaptures(); }); 94 | keyboardFolder.addButton({ title: 'Remove all keys' }).on('click', () => { console.info('Remove all keys'); keyboard.removeAllKeys(); }); 95 | keyboardFolder.addButton({ title: 'Reset keys' }).on('click', () => { console.info('Reset keys'); keyboard.resetKeys(); }); 96 | keyboardFolder.addButton({ title: 'Print captures' }).on('click', () => { console.info('Key captures:'); console.table(keyboard.getCaptures()); }); 97 | keyboardFolder.addButton({ title: 'Print keys' }).on('click', () => { console.info('Keys:'); console.table(keyboard.keys.map(keyToPrint)); }); 98 | } 99 | } 100 | 101 | if (lights) { 102 | const lightsFolder = this.folder.addFolder({ title: 'Lights', expanded: false }); 103 | lightsFolder.addInput(lights, 'active'); 104 | lightsFolder.addInput(lights, 'ambientColor', { color: { type: 'float' } }); 105 | lightsFolder.addMonitor(lights, 'visibleLights', { format: FormatLength }); 106 | lightsFolder.addButton({ title: 'Print lights' }).on('click', () => { console.info('Lights:'); console.table(lights.lights.map(lightToPrint)); }); 107 | } 108 | 109 | if (load) { 110 | const loadFolder = this.folder.addFolder({ title: 'Load', expanded: false }); 111 | loadFolder.addMonitor(load, 'progress', { view: 'graph', min: 0, max: 1 }); 112 | loadFolder.addMonitor(load, 'totalComplete'); 113 | loadFolder.addMonitor(load, 'totalFailed'); 114 | loadFolder.addMonitor(load, 'totalToLoad'); 115 | } 116 | 117 | const scenePluginFolder = this.folder.addFolder({ title: 'Scene', expanded: false }); 118 | scenePluginFolder.addMonitor(scenePlugin.settings, 'active'); 119 | scenePluginFolder.addMonitor(scenePlugin.settings, 'visible'); 120 | scenePluginFolder.addMonitor(scenePlugin.settings, 'status'); 121 | scenePluginFolder.addButton({ title: 'Pause' }).on('click', () => { console.info('Pause scene', sceneKey); scenePlugin.pause(); }); 122 | scenePluginFolder.addButton({ title: 'Resume' }).on('click', () => { console.info('Resume scene', sceneKey); scenePlugin.resume(); }); 123 | scenePluginFolder.addButton({ title: 'Sleep' }).on('click', () => { console.info('Sleep scene', sceneKey); scenePlugin.sleep(); }); 124 | scenePluginFolder.addButton({ title: 'Wake' }).on('click', () => { console.info('Wake scene', sceneKey); scenePlugin.wake(); }); 125 | scenePluginFolder.addButton({ title: 'Stop' }).on('click', () => { console.info('Stop scene', sceneKey); scenePlugin.stop(); }); 126 | scenePluginFolder.addButton({ title: 'Restart' }).on('click', () => { console.info('Restart scene', sceneKey); scenePlugin.restart(); }); 127 | scenePluginFolder.addButton({ title: 'Remove' }).on('click', () => { console.info('Remove scene', sceneKey); scenePlugin.remove(); }); 128 | scenePluginFolder.addButton({ title: 'Print scene data' }).on('click', () => { console.info(`Scene data for ${sceneKey}:`); console.table(scenePlugin.settings.data); }); 129 | 130 | if (time) { 131 | const timeFolder = this.folder.addFolder({ title: 'Time', expanded: false }); 132 | timeFolder.addMonitor(time._active, 'length', { label: 'events (length)', format: FormatLength }); 133 | timeFolder.addMonitor(time, 'now'); 134 | timeFolder.addInput(time, 'paused'); 135 | timeFolder.addButton({ title: 'Print timer events' }).on('click', () => { console.info('Timer events:'); console.table(time._active.map(timerEventToPrint)); }); 136 | } 137 | 138 | if (tweens) { 139 | const tweensFolder = this.folder.addFolder({ title: 'Tweens', expanded: false }); 140 | tweensFolder.addInput(tweens, 'timeScale', { min: 0.1, max: 10, step: 0.1 }); 141 | tweensFolder.addButton({ title: 'Pause all' }).on('click', () => { console.info('Pause all tweens'); tweens.pauseAll(); }); 142 | tweensFolder.addButton({ title: 'Resume all' }).on('click', () => { console.info('Resume all tweens'); tweens.resumeAll(); }); 143 | tweensFolder.addButton({ title: 'Stop all' }).on('click', () => { console.info('Stop all tweens'); tweens.killAll(); }); 144 | tweensFolder.addButton({ title: 'Print tweens' }).on('click', () => { console.info('Tweens:'); console.table(tweens.getTweens().map(tweenToPrint)); }); 145 | } 146 | 147 | const updateListFolder = this.folder.addFolder({ title: 'Update List', expanded: false }); 148 | updateListFolder.addMonitor(updateList, 'length', { format: FormatLength }); 149 | updateListFolder.addButton({ title: 'Print' }).on('click', () => { console.info('Update list:'); console.table(updateList.getActive().map(updateListItemToPrint)); }); 150 | updateListFolder.addButton({ title: 'Save JSON' }).on('click', () => { load.saveJSON(updateList.getActive(), `${sceneKey} updateList.json`); }); 151 | updateListFolder.addButton({ title: 'Inspect by name …' }).on('click', () => { InspectByName(prompt('Inspect first game object on update list with name:'), updateList.getActive(), this.pane); }); 152 | updateListFolder.addButton({ title: 'Inspect by type …' }).on('click', () => { InspectByType(prompt('Inspect first game object on update list with type:'), updateList.getActive(), this.pane); }); 153 | updateListFolder.addButton({ title: 'Inspect by index …' }).on('click', () => { InspectByIndex(prompt(`Inspect game object on update list at index (0 to ${updateList.length - 1}):`), updateList.getActive(), this.pane); }); 154 | updateListFolder.addButton({ title: 'Add active controls' }).on('click', () => { AddActive(updateList.getActive(), updateListFolder); }); 155 | 156 | events.on(CREATE, () => { 157 | for (const cam of cameras.cameras) { AddCamera(cam, camerasFolder); } 158 | }); 159 | 160 | if (arcadePhysics) { 161 | if (sceneStatus < STATUS_START || sceneStatus === STATUS_SHUTDOWN) { 162 | events.on(START, () => { AddArcadePhysicsWorld(arcadePhysics.world, this.folder); }); 163 | } else { 164 | AddArcadePhysicsWorld(arcadePhysics.world, this.folder); 165 | } 166 | } 167 | 168 | if (matterPhysics) { 169 | if (sceneStatus < STATUS_START || sceneStatus === STATUS_SHUTDOWN) { 170 | events.on(START, () => { AddMatterPhysicsWorld(matterPhysics.world, this.folder); }); 171 | } else { 172 | AddMatterPhysicsWorld(matterPhysics.world, this.folder); 173 | } 174 | } 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /src/Install.js: -------------------------------------------------------------------------------- 1 | import { InspectorGlobalPlugin } from './InspectorGlobalPlugin'; 2 | import { InspectorScenePlugin } from './InspectorScenePlugin'; 3 | import { 4 | GLOBAL_PLUGIN_KEY, 5 | GLOBAL_PLUGIN_MAPPING, 6 | SCENE_PLUGIN_KEY, 7 | SCENE_PLUGIN_SCENE_MAPPING, 8 | SCENE_PLUGIN_SYS_MAPPING 9 | } from './const'; 10 | 11 | export function Install (pluginsManager) { 12 | pluginsManager.install(GLOBAL_PLUGIN_KEY, InspectorGlobalPlugin, true, GLOBAL_PLUGIN_MAPPING); 13 | pluginsManager.installScenePlugin(SCENE_PLUGIN_KEY, InspectorScenePlugin, SCENE_PLUGIN_SCENE_MAPPING); 14 | 15 | for (const scene of pluginsManager.game.scene.scenes) { 16 | const plugin = new InspectorScenePlugin(scene, pluginsManager); 17 | 18 | scene[SCENE_PLUGIN_SCENE_MAPPING] = plugin; 19 | scene.sys[SCENE_PLUGIN_SYS_MAPPING] = plugin; 20 | 21 | plugin.boot(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/const.js: -------------------------------------------------------------------------------- 1 | 2 | export const GLOBAL_PLUGIN_KEY = 'InspectorGlobalPlugin'; 3 | export const GLOBAL_PLUGIN_MAPPING = 'inspectorGame'; 4 | export const SCENE_PLUGIN_KEY = 'InspectorScenePlugin'; 5 | export const SCENE_PLUGIN_SCENE_MAPPING = 'inspectorScene'; 6 | export const SCENE_PLUGIN_SYS_MAPPING = 'inspectorScene'; 7 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | export { InspectorGlobalPlugin } from './InspectorGlobalPlugin'; 2 | export { InspectorScenePlugin } from './InspectorScenePlugin'; 3 | export { DefaultPluginsConfig } from './DefaultPluginsConfig'; 4 | export { Install } from './Install'; 5 | export { 6 | AddActive, 7 | AddAlpha, 8 | AddAnimationState, 9 | AddArcadeBody, 10 | AddArcadePhysicsWorld, 11 | AddCamera, 12 | AddChain, 13 | AddFXComponent, 14 | AddFXController, 15 | AddGameObject, 16 | AddGroup, 17 | AddInput, 18 | AddKey, 19 | AddKeys, 20 | AddLight, 21 | AddMatterPhysicsWorld, 22 | AddParticleEmitter, 23 | AddPipeline, 24 | AddPointer, 25 | AddScenes, 26 | AddSound, 27 | AddTimeline, 28 | AddTimerEvent, 29 | AddTween, 30 | AddVideo, 31 | AddVisible 32 | } from './util'; 33 | -------------------------------------------------------------------------------- /src/util.js: -------------------------------------------------------------------------------- 1 | import Phaser from 'phaser'; 2 | import { FXMap } from './FXMap'; 3 | 4 | const TAU = 2 * Math.PI; 5 | const CacheNames = ['audio', 'binary', 'bitmapFont', 'html', 'json', 'obj', 'physics', 'shader', 'text', 'tilemap', 'video', 'xml']; 6 | const CameraEvents = Phaser.Cameras.Scene2D.Events; 7 | const SceneEvents = Phaser.Scenes.Events; 8 | const GameObjectEvents = Phaser.GameObjects.Events; 9 | const { BlendModes } = Phaser; 10 | const { GetFirst } = Phaser.Utils.Array; 11 | 12 | export function animToPrint ({ key, delay, duration, frameRate, repeat, repeatDelay }) { 13 | return { key, delay, duration, frameRate, repeat, repeatDelay }; 14 | } 15 | 16 | export function sceneToPrint (scene) { 17 | const { key, status, active, visible } = scene.sys.settings; 18 | 19 | return { key, status, active, visible }; 20 | } 21 | 22 | export function soundToPrint ({ key, isPaused, isPlaying, seek, totalDuration, volume }) { 23 | return { key, isPaused, isPlaying, seek, totalDuration, volume }; 24 | } 25 | 26 | export function textureToPrint ({ key, firstFrame, frameTotal }) { 27 | return { key, firstFrame, frameTotal }; 28 | } 29 | 30 | export function copyToSafeObj (obj) { 31 | const out = {}; 32 | 33 | for (const key in obj) { 34 | const val = obj[key]; 35 | const typ = typeof val; 36 | 37 | if (!val || typ === 'boolean' || typ === 'number' || typ === 'string') { 38 | out[key] = val; 39 | } 40 | } 41 | 42 | return out; 43 | } 44 | 45 | export function copyToSafeTable (obj) { 46 | const out = {}; 47 | 48 | for (const key in obj) { 49 | const val = obj[key]; 50 | 51 | out[key] = typeof val === 'object' ? copyToSafeObj(obj[key]) : val; 52 | } 53 | 54 | return out; 55 | } 56 | 57 | export function printCaches (manager) { 58 | for (const name of CacheNames) { 59 | printCache(name, manager[name]); 60 | } 61 | 62 | for (const name in manager.custom) { 63 | printCache(name, manager.custom[name]); 64 | } 65 | } 66 | 67 | export function printCache (name, cache) { 68 | const { size } = cache.entries; 69 | 70 | if (size > 0) { 71 | console.info(`${name} cache (${size})`); 72 | 73 | console.table(copyToSafeTable(cache.entries.entries)); 74 | } else { 75 | console.info(`${name} cache is empty`); 76 | } 77 | } 78 | 79 | export function printDevice (device) { 80 | for (const key in device) { 81 | console.info(key); 82 | console.table(copyToSafeObj(device[key])); 83 | } 84 | } 85 | 86 | export function snapshot (img) { 87 | img.style.width = '256px'; 88 | img.style.height = 'auto'; 89 | document.body.appendChild(img); 90 | } 91 | 92 | export function AddPointer (pointer, pane) { 93 | const folder = pane.addFolder({ title: `Pointer ${pointer.id}`, expanded: false }); 94 | 95 | folder.addMonitor(pointer, 'active'); 96 | folder.addMonitor(pointer, 'angle'); 97 | folder.addMonitor(pointer, 'buttons'); 98 | folder.addMonitor(pointer, 'deltaX'); 99 | folder.addMonitor(pointer, 'deltaY'); 100 | folder.addMonitor(pointer, 'deltaZ'); 101 | folder.addMonitor(pointer, 'distance'); 102 | folder.addMonitor(pointer, 'downX'); 103 | folder.addMonitor(pointer, 'downY'); 104 | folder.addMonitor(pointer, 'id'); 105 | folder.addMonitor(pointer, 'isDown'); 106 | folder.addMonitor(pointer, 'locked'); 107 | folder.addMonitor(pointer, 'movementX'); 108 | folder.addMonitor(pointer, 'movementY'); 109 | folder.addMonitor(pointer, 'primaryDown'); 110 | folder.addMonitor(pointer, 'upX'); 111 | folder.addMonitor(pointer, 'upY'); 112 | folder.addMonitor(pointer.velocity, 'x', { label: 'velocity x' }); 113 | folder.addMonitor(pointer.velocity, 'y', { label: 'velocity y' }); 114 | folder.addMonitor(pointer, 'worldX'); 115 | folder.addMonitor(pointer, 'worldY'); 116 | folder.addMonitor(pointer, 'x'); 117 | folder.addMonitor(pointer, 'y'); 118 | 119 | return folder; 120 | } 121 | 122 | export function AddSound (sound, pane) { 123 | const folder = pane.addFolder({ title: `Sound “${sound.key}”`, expanded: false }); 124 | 125 | sound.once('destroy', () => { folder.dispose(); }); 126 | 127 | if (sound.currentMarker) { 128 | folder.addMonitor(sound.currentMarker, 'name'); 129 | } 130 | 131 | folder.addMonitor(sound, 'duration'); 132 | folder.addMonitor(sound, 'isPaused'); 133 | folder.addMonitor(sound, 'isPlaying'); 134 | folder.addMonitor(sound, 'seek'); 135 | folder.addMonitor(sound, 'totalDuration'); 136 | 137 | folder.addMonitor(sound, 'loop'); 138 | folder.addInput(sound, 'mute'); 139 | folder.addInput(sound, 'volume', { min: 0, max: 1 }); 140 | 141 | folder.addButton({ title: 'Play' }).on('click', () => { console.info('Play sound “%s”', sound.key); sound.play(); }); 142 | folder.addButton({ title: 'Pause' }).on('click', () => { console.info('Pause sound “%s”', sound.key); sound.pause(); }); 143 | folder.addButton({ title: 'Resume' }).on('click', () => { console.info('Resume sound “%s”', sound.key); sound.resume(); }); 144 | folder.addButton({ title: 'Stop' }).on('click', () => { console.info('Stop sound “%s”', sound.key); sound.stop(); }); 145 | folder.addButton({ title: 'Remove' }).on('click', () => { console.info('Remove sound “%s”', sound.key); sound.destroy(); }); 146 | 147 | for (const name in sound.markers) { 148 | folder.addButton({ title: `Play “${name}”` }).on('click', () => { console.info('Play sound “%s” marker “%s”', sound.key, name); sound.play(name); }); 149 | } 150 | 151 | return folder; 152 | } 153 | 154 | export function displayListItemToPrint ({ name, type, x, y, visible, depth }) { 155 | return { name, type, x, y, visible, depth }; 156 | } 157 | 158 | export function updateListItemToPrint ({ name, type, active }) { 159 | return { name, type, active }; 160 | } 161 | 162 | export function tweenToPrint ({ duration, elapsed, paused, progress, state, totalElapsed, totalProgress }) { 163 | return { duration, elapsed, paused, progress, state, totalElapsed, totalProgress }; 164 | } 165 | 166 | export function timerEventToPrint ({ delay, elapsed, loop, paused, repeat, repeatCount }) { 167 | return { delay, elapsed, loop, paused, repeat, repeatCount }; 168 | } 169 | 170 | export function keyToPrint ({ duration, emitOnRepeat, enabled, isDown, isUp, location, repeats, timeDown, timeUp }) { 171 | return { duration, emitOnRepeat, enabled, isDown, isUp, location, repeats, timeDown, timeUp }; 172 | } 173 | 174 | export function cameraToPrint ({ name, id, x, y, width, height, visible, alpha }) { 175 | return { name, id, x, y, width, height, visible, alpha }; 176 | } 177 | 178 | export function lightToPrint ({ x, y, radius, color, intensity, visible }) { 179 | return { x, y, radius, color: `rgb(${color.r.toFixed(2)}, ${color.g.toFixed(2)}, ${color.b.toFixed(2)})`, intensity, visible }; 180 | } 181 | 182 | export function AddCamera (camera, pane) { 183 | const defaultCamera = camera.cameraManager.default; 184 | const w = defaultCamera.width; 185 | const h = defaultCamera.height; 186 | const folder = pane.addFolder({ title: `Camera ${camera.id} ${camera.name || ''}`, expanded: false }); 187 | 188 | folder.addMonitor(camera, 'name'); 189 | folder.addInput(camera, 'alpha', { min: 0, max: 1, step: 0.05 }); 190 | folder.addInput(camera, 'backgroundColor'); 191 | folder.addInput(camera, 'x', { min: -w, max: w, step: 10 }); 192 | folder.addInput(camera, 'y', { min: -h, max: h, step: 10 }); 193 | folder.addInput(camera, 'width', { min: 0, max: w, step: 10 }); 194 | folder.addInput(camera, 'height', { min: 0, max: h, step: 10 }); 195 | folder.addInput(camera, 'scrollX', { min: -w, max: w, step: 10 }); 196 | folder.addInput(camera, 'scrollY', { min: -h, max: h, step: 10 }); 197 | folder.addInput(camera, 'originX', { min: 0, max: 1, step: 0.05 }); 198 | folder.addInput(camera, 'originY', { min: 0, max: 1, step: 0.05 }); 199 | folder.addInput(camera, 'rotation', { min: 0, max: TAU }); 200 | folder.addInput(camera, 'zoom', { min: 0.1, max: 10, step: 0.05 }); 201 | folder.addInput(camera, 'followOffset'); 202 | folder.addInput(camera, 'disableCull'); 203 | folder.addInput(camera, 'inputEnabled'); 204 | folder.addInput(camera, 'roundPixels'); 205 | folder.addInput(camera, 'useBounds'); 206 | folder.addInput(camera, 'visible'); 207 | folder.addMonitor(camera, 'centerX'); 208 | folder.addMonitor(camera, 'centerY'); 209 | folder.addMonitor(camera.midPoint, 'x', { label: 'midPoint x' }); 210 | folder.addMonitor(camera.midPoint, 'y', { label: 'midPoint y' }); 211 | folder.addMonitor(camera.worldView, 'x', { label: 'world x' }); 212 | folder.addMonitor(camera.worldView, 'y', { label: 'world y' }); 213 | folder.addMonitor(camera.worldView, 'width', { label: 'world width' }); 214 | folder.addMonitor(camera.worldView, 'height', { label: 'world height' }); 215 | 216 | // TODO 217 | const { deadzone } = camera; 218 | if (deadzone) { 219 | folder.addMonitor(deadzone, 'x', { label: 'deadzone x' }); 220 | folder.addMonitor(deadzone, 'y', { label: 'deadzone y' }); 221 | folder.addMonitor(deadzone, 'width', { label: 'deadzone width' }); 222 | folder.addMonitor(deadzone, 'height', { label: 'deadzone height' }); 223 | } 224 | 225 | if (camera.hasPostPipeline) { 226 | AddPipelines(camera.postPipelines, folder, { title: 'Post Pipelines' }); 227 | } 228 | 229 | folder.addButton({ title: 'Fade in' }).on('click', () => { camera.fadeIn(); }); 230 | folder.addButton({ title: 'Fade out' }).on('click', () => { camera.fadeOut(); }); 231 | folder.addButton({ title: 'Flash' }).on('click', () => { camera.flash(); }); 232 | folder.addButton({ title: 'Shake' }).on('click', () => { camera.shake(); }); 233 | folder.addButton({ title: 'Reset effects' }).on('click', () => { camera.resetFX(); }); 234 | folder.addButton({ title: 'Reset post pipeline' }).on('click', () => { camera.resetPostPipeline(); }); 235 | 236 | camera.on(CameraEvents.DESTROY, () => { 237 | folder.dispose(); 238 | }); 239 | 240 | return folder; 241 | } 242 | 243 | export function AddArcadePhysicsWorld (world, pane) { 244 | const { arcadePhysics, events } = world.scene.sys; 245 | const folder = pane.addFolder({ title: 'Arcade Physics', expanded: false }); 246 | 247 | folder.addMonitor(world.bodies, 'size', { label: 'bodies.size' }); 248 | folder.addInput(world, 'fixedStep'); 249 | folder.addInput(world, 'forceX'); 250 | folder.addInput(world, 'fps', { min: 5, max: 300, step: 5 }).on('change', ({ value }) => { world.setFPS(value); }); 251 | folder.addMonitor(world, '_frameTimeMS'); 252 | folder.addInput(world, 'gravity', { x: { min: -1000, max: 1000 }, y: { min: -1000, max: 1000 } }); 253 | folder.addInput(world, 'isPaused'); 254 | folder.addInput(world, 'OVERLAP_BIAS', { label: 'OVERLAP_BIAS', min: 0, max: 32, step: 1 }); 255 | folder.addMonitor(world.staticBodies, 'size', { label: 'staticBodies.size' }); 256 | folder.addInput(world, 'TILE_BIAS', { label: 'TILE_BIAS', min: 0, max: 32, step: 1 }); 257 | folder.addInput(world, 'timeScale', { min: 0.1, max: 10, step: 0.1 }); 258 | folder.addInput(world, 'useTree'); 259 | if (world.debugGraphic) { 260 | folder.addInput(world.debugGraphic, 'visible', { label: 'debugGraphic.visible' }); 261 | } 262 | folder.addButton({ title: 'Enable update' }).on('click', () => { arcadePhysics.enableUpdate(); }); 263 | folder.addButton({ title: 'Disable update' }).on('click', () => { arcadePhysics.disableUpdate(); }); 264 | folder.addButton({ title: 'Update' }).on('click', () => { world.update(0, world._frameTimeMS || (1000 / 60)); }); 265 | folder.addButton({ title: 'Print colliders' }).on('click', () => { console.info('Colliders', world.colliders.getActive()); }); 266 | 267 | events.once(SceneEvents.SHUTDOWN, () => { 268 | folder.dispose(); 269 | }); 270 | 271 | return folder; 272 | } 273 | 274 | export function AddMatterPhysicsWorld (world, pane) { 275 | const { events } = world.scene.sys; 276 | const folder = pane.addFolder({ title: 'Matter Physics', expanded: false }); 277 | folder.addInput(world, 'autoUpdate'); 278 | folder.addInput(world, 'enabled'); 279 | folder.addInput(world.localWorld, 'gravity'); 280 | folder.addInput(world.localWorld.gravity, 'scale', { label: 'gravity scale', min: 0, max: 0.1, step: 0.001 }); 281 | if (world.debugGraphic) { 282 | folder.addInput(world.debugGraphic, 'visible', { label: 'debugGraphic.visible' }); 283 | } 284 | folder.addButton({ title: 'Pause' }).on('click', () => { world.pause(); }); 285 | folder.addButton({ title: 'Resume' }).on('click', () => { world.resume(); }); 286 | folder.addButton({ title: 'Step' }).on('click', () => { world.step(); }); 287 | 288 | events.once(SceneEvents.SHUTDOWN, () => { 289 | folder.dispose(); 290 | }); 291 | 292 | return folder; 293 | } 294 | 295 | export function AddGameObject (obj, pane, options = { title: `${obj.type} “${obj.name}”` }) { 296 | const folder = pane.addFolder(options); 297 | 298 | folder.addInput(obj, 'active'); 299 | folder.addMonitor(obj, 'cameraFilter'); 300 | folder.addMonitor(obj, 'state'); 301 | 302 | if ('texture' in obj && obj.texture && obj.texture.key) { 303 | const proxy = { 304 | get 'texture.key' () { return obj.texture.key; }, 305 | get 'frame.name' () { return obj.frame.name; } 306 | }; 307 | 308 | folder.addMonitor(proxy, 'texture.key'); 309 | folder.addMonitor(proxy, 'frame.name', { format: String }); 310 | } 311 | 312 | if ('displayTexture' in obj) { 313 | const proxy = { 314 | get 'displayTexture.key' () { return obj.displayTexture.key; }, 315 | get 'displayFrame.name' () { return obj.displayFrame.name; } 316 | }; 317 | 318 | folder.addMonitor(proxy, 'displayTexture.key'); 319 | folder.addMonitor(proxy, 'displayFrame.name', { format: String }); 320 | } 321 | 322 | if ('alpha' in obj) { 323 | folder.addInput(obj, 'alpha', { min: 0, max: 1, step: 0.05 }); 324 | } 325 | 326 | if ('blendMode' in obj) { 327 | folder.addInput(obj, 'blendMode', { options: BlendModes }); 328 | } 329 | 330 | if ('depth' in obj) { 331 | folder.addMonitor(obj, 'depth'); 332 | } 333 | 334 | if ('width' in obj) { 335 | folder.addMonitor(obj, 'width'); 336 | folder.addMonitor(obj, 'height'); 337 | } 338 | 339 | if ('displayWidth' in obj) { 340 | folder.addMonitor(obj, 'displayWidth'); 341 | folder.addMonitor(obj, 'displayHeight'); 342 | } 343 | 344 | if ('originX' in obj) { 345 | folder.addMonitor(obj, 'originX'); 346 | folder.addMonitor(obj, 'originY'); 347 | } 348 | 349 | if ('displayOriginX' in obj) { 350 | folder.addMonitor(obj, 'displayOriginX'); 351 | folder.addMonitor(obj, 'displayOriginY'); 352 | } 353 | 354 | if ('scaleX' in obj) { 355 | folder.addMonitor(obj, 'scaleX'); 356 | folder.addMonitor(obj, 'scaleY'); 357 | folder.addInput(obj, 'scale', { min: 0.1, max: 10, step: 0.1 }); 358 | } 359 | 360 | if ('flipX' in obj) { 361 | folder.addInput(obj, 'flipX'); 362 | folder.addInput(obj, 'flipY'); 363 | } 364 | 365 | if ('angle' in obj) { 366 | folder.addMonitor(obj, 'angle'); 367 | } 368 | 369 | if ('rotation' in obj) { 370 | folder.addInput(obj, 'rotation', { min: 0, max: TAU, step: 0.01 * TAU }); 371 | } 372 | 373 | if ('visible' in obj) { 374 | folder.addInput(obj, 'visible'); 375 | } 376 | 377 | if ('x' in obj) { 378 | folder.addMonitor(obj, 'x'); 379 | folder.addMonitor(obj, 'y'); 380 | folder.addMonitor(obj, 'z'); 381 | folder.addMonitor(obj, 'w'); 382 | } 383 | 384 | if ('modelPosition' in obj) { 385 | folder.addInput(obj, 'modelPosition'); 386 | folder.addInput(obj, 'modelScale'); 387 | folder.addInput(obj, 'modelRotation'); 388 | } 389 | 390 | if ('fov' in obj) { 391 | folder.addMonitor(obj, 'fov'); 392 | } 393 | 394 | if ('faces' in obj && 'length' in obj.faces) { 395 | folder.addMonitor(obj.faces, 'length', { label: 'faces.length', format: FormatLength }); 396 | } 397 | 398 | if ('vertices' in obj && 'length' in obj.vertices) { 399 | folder.addMonitor(obj.vertices, 'length', { label: 'vertices.length', format: FormatLength }); 400 | } 401 | 402 | if ('totalRendered' in obj) { 403 | folder.addMonitor(obj, 'totalRendered', { format: FormatLength }); 404 | } 405 | 406 | if ('tilesDrawn' in obj) { 407 | folder.addMonitor(obj, 'tilesDrawn', { format: FormatLength }); 408 | } 409 | 410 | if ('tilesTotal' in obj) { 411 | folder.addMonitor(obj, 'tilesTotal', { format: FormatLength }); 412 | } 413 | 414 | if (obj.pipeline) { 415 | // WebGL only 416 | 417 | if ('getPipelineName' in obj) { 418 | const proxy = { get 'getPipelineName()' () { return obj.getPipelineName(); } }; 419 | 420 | folder.addMonitor(proxy, 'getPipelineName()', { label: 'getPipelineName()' }); 421 | } 422 | 423 | if ('hasPostPipeline' in obj) { 424 | folder.addMonitor(obj, 'hasPostPipeline'); 425 | 426 | if (obj.hasPostPipeline) { 427 | AddPipelines(obj.postPipelines, folder, { title: 'Post Pipelines' }); 428 | } 429 | } 430 | 431 | if ('resetPipeline' in obj) { 432 | folder.addButton({ title: 'Reset pipeline' }).on('click', () => { console.info('Reset pipeline', obj.type, obj.name); obj.resetPipeline(); }); 433 | } 434 | 435 | if ('resetPostPipeline' in obj) { 436 | folder.addButton({ title: 'Reset post pipeline' }).on('click', () => { console.info('Reset post pipeline', obj.type, obj.name); obj.resetPostPipeline(); }); 437 | } 438 | } 439 | 440 | if ('preFX' in obj && obj.preFX && obj.preFX.list.length > 0) { 441 | AddFXComponent(obj.preFX, folder); 442 | } 443 | 444 | // The `postFX` controller doesn't seem to show any relevant state. 445 | 446 | if ('children' in obj && 'length' in obj.children) { 447 | folder.addMonitor(obj.children, 'length', { label: 'children.length', format: FormatLength }); 448 | } 449 | 450 | if ('displayList' in obj) { 451 | const { displayList } = obj; 452 | 453 | folder.addButton({ title: 'Bring to top' }).on('click', () => { console.info('Bring to top', obj.type, obj.name); displayList.bringToTop(obj); }); 454 | folder.addButton({ title: 'Move down' }).on('click', () => { console.info('Move down', obj.type, obj.name); displayList.moveDown(obj); }); 455 | folder.addButton({ title: 'Move to …' }).on('click', () => { const idx = prompt(`Move to index (0 to ${displayList.length - 1}):`); if (!idx) { return; } console.info('Move to index', idx, obj.type, obj.name); displayList.moveTo(obj, idx); }); 456 | folder.addButton({ title: 'Move up' }).on('click', () => { console.info('Move up', obj.type, obj.name); displayList.moveUp(obj); }); 457 | folder.addButton({ title: 'Send to back' }).on('click', () => { console.info('Send to back', obj.type, obj.name); displayList.sendToBack(obj); }); 458 | } 459 | 460 | folder.addButton({ title: 'Destroy' }).on('click', () => { console.info('Destroy', obj.type, obj.name); obj.destroy(); }); 461 | 462 | obj.once(GameObjectEvents.DESTROY, () => { folder.dispose(); }); 463 | 464 | return folder; 465 | } 466 | 467 | export function AddGroup (group, pane, options = { title: `${group.type} “${group.name}”` }) { 468 | const folder = pane.addFolder(options); 469 | const graphOptions = { view: 'graph', min: 0, max: group.maxSize === -1 ? 100 : group.maxSize }; 470 | 471 | folder.addMonitor(group.getChildren(), 'length', graphOptions); 472 | 473 | const proxy = { 474 | get active () { return group.countActive(true); }, 475 | get inactive () { return group.countActive(false); }, 476 | get free () { return group.getTotalFree(); }, 477 | get full () { return group.isFull(); } 478 | }; 479 | 480 | folder.addMonitor(proxy, 'active', graphOptions); 481 | folder.addMonitor(proxy, 'inactive', graphOptions); 482 | if (group.maxSize > -1) { folder.addMonitor(proxy, 'free', graphOptions); } 483 | folder.addMonitor(group, 'maxSize'); 484 | folder.addMonitor(proxy, 'full'); 485 | 486 | folder.addButton({ title: 'Clear' }).on('click', () => { console.info('Clear group', group.name); group.clear(); }); 487 | folder.addButton({ title: 'Destroy' }).on('click', () => { console.info('Destroy group', group.name); group.destroy(); }); 488 | folder.addButton({ title: 'Destroy group members' }).on('click', () => { console.info('Destroy group members', group.name); group.clear(true, true); }); 489 | 490 | group.once(GameObjectEvents.DESTROY, () => { folder.dispose(); }); 491 | 492 | return folder; 493 | } 494 | 495 | export function AddLight (light, pane, options = { title: 'Light' }) { 496 | const folder = pane.addFolder(options); 497 | 498 | folder.addInput(light, 'color', { color: { type: 'float' } }); 499 | folder.addInput(light, 'intensity', { min: 0, max: 10, step: 0.1 }); 500 | folder.addInput(light, 'radius', { min: 0, max: 1024, step: 8 }); 501 | folder.addInput(light, 'visible'); 502 | folder.addMonitor(light, 'x'); 503 | folder.addMonitor(light, 'y'); 504 | 505 | return folder; 506 | } 507 | 508 | export function AddParticleEmitter (emitter, pane, options = { title: `Particle Emitter “${emitter.name}”` }) { 509 | const folder = pane.addFolder(options); 510 | 511 | const max = emitter.maxParticles || 100; 512 | 513 | const proxy = { 514 | get 'atLimit()' () { return emitter.atLimit(); }, 515 | get 'getParticleCount()' () { return emitter.getParticleCount(); } 516 | }; 517 | 518 | folder.addMonitor(emitter, 'active'); 519 | folder.addMonitor(emitter, 'animQuantity'); 520 | folder.addMonitor(proxy, 'atLimit()'); 521 | folder.addMonitor(emitter, 'delay'); 522 | folder.addMonitor(emitter, 'duration'); 523 | folder.addMonitor(emitter, 'emitting'); 524 | folder.addMonitor(emitter, 'frameQuantity'); 525 | folder.addMonitor(emitter, 'maxAliveParticles'); 526 | folder.addMonitor(emitter, 'maxParticles'); 527 | folder.addMonitor(emitter, 'quantity'); 528 | folder.addMonitor(emitter, 'stopAfter'); 529 | 530 | folder.addInput(emitter, 'blendMode', { options: BlendModes }); 531 | folder.addInput(emitter, 'frequency', { min: -1, max: 1000 }); 532 | folder.addInput(emitter, 'moveTo'); 533 | folder.addInput(emitter, 'particleBringToTop'); 534 | folder.addInput(emitter, 'radial'); 535 | folder.addInput(emitter, 'randomFrame'); 536 | folder.addInput(emitter, 'timeScale', { min: 0.1, max: 10, step: 0.1 }); 537 | folder.addInput(emitter, 'visible'); 538 | 539 | const opsFolder = folder.addFolder({ title: 'Ops', expanded: false }); 540 | 541 | for (const op of Object.values(emitter.ops)) { 542 | const { propertyKey, start, end, current, method } = op; 543 | const opFolder = opsFolder.addFolder({ title: propertyKey, expanded: false }); 544 | 545 | if (typeof current === 'number') { 546 | if (method === 1) { 547 | opFolder.addInput(op, 'current'); 548 | } else { 549 | opFolder.addMonitor(op, 'current'); 550 | } 551 | } 552 | 553 | if (method === 4 || method === 5 || method === 6) { 554 | opFolder.addInput(op, 'start'); 555 | opFolder.addInput(op, 'end'); 556 | } 557 | 558 | if (method === 4) { 559 | opFolder.addInput(op, 'steps', { step: 1 }); 560 | opFolder.addInput(op, 'yoyo'); 561 | opFolder.addInput(op, 'direction', { min: 0, max: 1, step: 1 }); 562 | opFolder.addMonitor(op, 'counter', { min: start, max: end, view: 'graph' }); 563 | } 564 | } 565 | 566 | const graphsFolder = folder.addFolder({ title: 'Counters', expanded: false }); 567 | 568 | graphsFolder.addMonitor(emitter.alive, 'length', { view: 'graph', min: 0, max: max, label: 'getAliveParticleCount()', format: FormatLength }); 569 | graphsFolder.addMonitor(emitter.dead, 'length', { view: 'graph', min: 0, max: max, label: 'getDeadParticleCount()', format: FormatLength }); 570 | graphsFolder.addMonitor(proxy, 'getParticleCount()', { view: 'graph', min: 0, max: max, format: FormatLength }); 571 | 572 | if (emitter.frequency > 0) { 573 | graphsFolder.addMonitor(emitter, 'flowCounter', { view: 'graph', min: 0, max: emitter.frequency }); 574 | } 575 | 576 | if (emitter.frameQuantity > 1) { 577 | graphsFolder.addMonitor(emitter, 'frameCounter', { view: 'graph', min: 0, max: emitter.frameQuantity }); 578 | } 579 | 580 | if (emitter.animQuantity > 1) { 581 | graphsFolder.addMonitor(emitter, 'animCounter', { view: 'graph', min: 0, max: emitter.animQuantity }); 582 | } 583 | 584 | if (emitter.duration > 0) { 585 | graphsFolder.addMonitor(emitter, 'elapsed', { view: 'graph', min: 0, max: emitter.duration }); 586 | } 587 | 588 | if (emitter.stopAfter > 0) { 589 | graphsFolder.addMonitor(emitter, 'stopCounter', { view: 'graph', min: 0, max: emitter.stopAfter }); 590 | } 591 | 592 | if (emitter.emitZones.length > 1) { 593 | graphsFolder.addMonitor(emitter, 'zoneIndex', { view: 'graph', min: 0, max: emitter.emitZones.length }); 594 | } 595 | 596 | if (emitter.frames.length > 1) { 597 | graphsFolder.addMonitor(emitter, 'currentFrame', { view: 'graph', min: 0, max: emitter.frames.length }); 598 | } 599 | 600 | if (emitter.anims.length > 1) { 601 | graphsFolder.addMonitor(emitter, 'currentAnim', { view: 'graph', min: 0, max: emitter.anims.length }); 602 | } 603 | 604 | const { processors } = emitter; 605 | 606 | if (processors.length > 0) { 607 | const processorsFolder = folder.addFolder({ title: 'Processors' }); 608 | 609 | for (const processor of processors.list) { 610 | processorsFolder.addInput(processor, 'active', { label: `${processor.name || 'Processor'} active` }); 611 | } 612 | } 613 | 614 | folder.addButton({ title: 'Start' }).on('click', () => { emitter.start(); }); 615 | folder.addButton({ title: 'Stop' }).on('click', () => { emitter.stop(); }); 616 | folder.addButton({ title: 'Pause' }).on('click', () => { emitter.pause(); }); 617 | folder.addButton({ title: 'Resume' }).on('click', () => { emitter.resume(); }); 618 | folder.addButton({ title: 'Kill all' }).on('click', () => { emitter.killAll(); }); 619 | folder.addButton({ title: 'Print JSON' }).on('click', () => { console.log(JSON.stringify(emitter.toJSON())); }); 620 | 621 | emitter.once(GameObjectEvents.DESTROY, () => { folder.dispose(); }); 622 | 623 | return folder; 624 | } 625 | 626 | export function AddVideo (video, pane, options = { title: `Video “${video.name}”` }) { 627 | const folder = pane.addFolder(options); 628 | 629 | const videoProxy = { 630 | get 'getCurrentTime()' () { return video.getCurrentTime(); }, 631 | get 'getDuration()' () { return video.getDuration(); }, 632 | get 'getLoop()' () { return video.getLoop(); }, 633 | get 'getPlaybackRate()' () { return video.getPlaybackRate(); }, 634 | get 'getProgress()' () { return video.getProgress(); }, 635 | get 'getVolume()' () { return video.getVolume(); }, 636 | get 'isMuted()' () { return video.isMuted(); }, 637 | get 'isPaused()' () { return video.isPaused(); }, 638 | get 'isPlaying()' () { return video.isPlaying(); }, 639 | 640 | get 'seekTo()' () { return video.getProgress(); }, 641 | set 'seekTo()' (v) { video.seekTo(v); }, 642 | get 'setPlaybackRate()' () { return video.getPlaybackRate(); }, 643 | set 'setPlaybackRate()' (v) { video.setPlaybackRate(v); }, 644 | get 'setVolume()' () { return video.getVolume(); }, 645 | set 'setVolume()' (v) { video.setVolume(v); } 646 | }; 647 | 648 | folder.addMonitor(video, 'failedPlayAttempts'); 649 | folder.addMonitor(video, 'frameReady'); 650 | folder.addMonitor(videoProxy, 'getCurrentTime()'); 651 | folder.addMonitor(videoProxy, 'getDuration()'); 652 | folder.addMonitor(videoProxy, 'getLoop()'); 653 | folder.addMonitor(videoProxy, 'getPlaybackRate()'); 654 | folder.addMonitor(videoProxy, 'getProgress()'); 655 | folder.addMonitor(videoProxy, 'getVolume()'); 656 | folder.addMonitor(videoProxy, 'isMuted()'); 657 | folder.addMonitor(videoProxy, 'isPaused()'); 658 | folder.addMonitor(videoProxy, 'isPlaying()'); 659 | folder.addMonitor(video, 'isSeeking'); 660 | folder.addMonitor(video, 'isStalled'); 661 | folder.addMonitor(video, 'retry'); 662 | folder.addInput(videoProxy, 'seekTo()', { min: 0, max: 1 }); 663 | folder.addInput(videoProxy, 'setPlaybackRate()', { min: 0.25, max: 4, step: 0.25 }); 664 | folder.addInput(videoProxy, 'setVolume()', { min: 0, max: 1 }); 665 | folder.addMonitor(video, 'touchLocked'); 666 | 667 | folder.addButton({ title: 'Play' }).on('click', () => { console.info('Play video'); video.play(); }); 668 | folder.addButton({ title: 'Stop' }).on('click', () => { console.info('Stop video'); video.stop(); }); 669 | folder.addButton({ title: 'Pause' }).on('click', () => { console.info('Pause video'); video.pause(); }); 670 | folder.addButton({ title: 'Resume' }).on('click', () => { console.info('Resume video'); video.resume(); }); 671 | 672 | folder.addButton({ title: 'Change source …' }).on('click', () => { const src = prompt(`Change source (from '${video.cacheKey}')`); if (src) video.changeSource(src); }); 673 | folder.addButton({ title: 'Set current time …' }).on('click', () => { video.setCurrentTime(prompt(`Set current time (0 to ${video.getDuration()})`)); }); 674 | folder.addButton({ title: 'Set loop true' }).on('click', () => { video.setLoop(true); }); 675 | folder.addButton({ title: 'Set loop false' }).on('click', () => { video.setLoop(false); }); 676 | folder.addButton({ title: 'Set mute true' }).on('click', () => { video.setMute(true); }); 677 | folder.addButton({ title: 'Set mute false' }).on('click', () => { video.setMute(false); }); 678 | 679 | video.once(GameObjectEvents.DESTROY, () => { folder.dispose(); }); 680 | 681 | return folder; 682 | } 683 | 684 | export function AddTween (tween, pane, options = { title: 'Tween' }) { 685 | const folder = pane.addFolder(options); 686 | 687 | // > When creating a Tween, you can no longer pass a function for the following properties: 688 | // > duration, hold, repeat and repeatDelay. 689 | // > These should be numbers only. You can, however, still provide a function for delay, to keep it compatible with the StaggerBuilder. 690 | 691 | folder.addMonitor(tween, 'countdown'); 692 | folder.addMonitor(tween, 'duration'); 693 | folder.addMonitor(tween, 'elapsed'); 694 | folder.addMonitor(tween, 'loop'); 695 | folder.addMonitor(tween, 'loopCounter'); 696 | folder.addMonitor(tween, 'state'); 697 | folder.addInput(tween, 'timeScale', { min: 0.1, max: 10, step: 0.1 }); 698 | folder.addMonitor(tween, 'totalData'); 699 | folder.addMonitor(tween, 'totalDuration'); 700 | folder.addMonitor(tween, 'totalElapsed'); 701 | folder.addMonitor(tween, 'totalProgress', { view: 'graph', min: 0, max: 1 }); 702 | 703 | for (const dat of tween.data) { 704 | folder.addMonitor(dat, 'progress', { view: 'graph', min: 0, max: 1, label: `${dat.key} progress` }); 705 | } 706 | 707 | for (const dat of tween.data) { 708 | folder.addMonitor(dat, 'current', { label: `${dat.key} current` }); 709 | } 710 | 711 | folder.addButton({ title: 'Play' }).on('click', () => { console.info('Play tween'); tween.play(); }); 712 | folder.addButton({ title: 'Pause' }).on('click', () => { console.info('Pause tween'); tween.pause(); }); 713 | folder.addButton({ title: 'Resume' }).on('click', () => { console.info('Resume tween'); tween.resume(); }); 714 | folder.addButton({ title: 'Stop' }).on('click', () => { console.info('Stop tween'); tween.stop(); }); 715 | folder.addButton({ title: 'Restart' }).on('click', () => { console.info('Restart tween'); tween.restart(); }); 716 | folder.addButton({ title: 'Remove' }).on('click', () => { console.info('Remove tween'); tween.remove(); }); 717 | 718 | return folder; 719 | } 720 | 721 | export function AddChain (chain, pane, options = { title: 'Tween Chain' }) { 722 | const folder = pane.addFolder(options); 723 | 724 | folder.addMonitor(chain, 'currentIndex', { min: 0, max: chain.totalData, view: 'graph' }); 725 | folder.addMonitor(chain, 'hasStarted'); 726 | folder.addMonitor(chain, 'loop'); 727 | folder.addMonitor(chain, 'loopCounter'); 728 | folder.addMonitor(chain, 'state'); 729 | folder.addInput(chain, 'timeScale', { min: 0.1, max: 10, step: 0.1 }); 730 | folder.addMonitor(chain, 'totalData'); 731 | 732 | folder.addButton({ title: 'Play' }).on('click', () => { console.info('Play chain'); chain.play(); }); 733 | folder.addButton({ title: 'Stop' }).on('click', () => { console.info('Stop chain'); chain.stop(); }); 734 | folder.addButton({ title: 'Restart' }).on('click', () => { console.info('Restart chain'); chain.restart(); }); 735 | folder.addButton({ title: 'Pause' }).on('click', () => { console.info('Pause chain'); chain.pause(); }); 736 | folder.addButton({ title: 'Resume' }).on('click', () => { console.info('Resume chain'); chain.resume(); }); 737 | folder.addButton({ title: 'Destroy' }).on('click', () => { console.info('Destroy chain'); chain.destroy(); }); 738 | 739 | return folder; 740 | } 741 | 742 | export function AddTimeline (timeline, pane, options = { title: 'Timeline' }) { 743 | const folder = pane.addFolder(options); 744 | const proxy = { 745 | get 'getProgress()' () { return timeline.getProgress(); }, 746 | get 'isPlaying()' () { return timeline.isPlaying(); } 747 | }; 748 | 749 | folder.addMonitor(timeline, 'complete'); 750 | folder.addMonitor(timeline, 'elapsed'); 751 | folder.addMonitor(proxy, 'getProgress()', { min: 0, max: 1, view: 'graph' }); 752 | folder.addMonitor(proxy, 'isPlaying()'); 753 | folder.addMonitor(timeline, 'paused'); 754 | folder.addMonitor(timeline, 'totalComplete'); 755 | 756 | folder.addButton({ title: 'Clear' }).on('click', () => { console.info('Clear timeline'); timeline.clear(); }); 757 | folder.addButton({ title: 'Destroy' }).on('click', () => { console.info('Destroy timeline'); timeline.destroy(); }); 758 | folder.addButton({ title: 'Pause' }).on('click', () => { console.info('Pause timeline'); timeline.pause(); }); 759 | folder.addButton({ title: 'Play' }).on('click', () => { console.info('Play timeline'); timeline.play(); }); 760 | folder.addButton({ title: 'Reset' }).on('click', () => { console.info('Reset timeline'); timeline.reset(); }); 761 | folder.addButton({ title: 'Resume' }).on('click', () => { console.info('Resume timeline'); timeline.resume(); }); 762 | folder.addButton({ title: 'Stop' }).on('click', () => { console.info('Stop timeline'); timeline.stop(); }); 763 | 764 | return folder; 765 | } 766 | 767 | export function AddTimerEvent (timer, pane, options = { title: 'Timer Event' }) { 768 | const folder = pane.addFolder(options); 769 | const proxy = { 770 | get 'getOverallProgress()' () { return timer.getOverallProgress(); }, 771 | get 'getProgress()' () { return timer.getProgress(); }, 772 | get 'getOverallRemaining()' () { return timer.getOverallRemaining(); }, 773 | get 'getRemaining()' () { return timer.getRemaining(); } 774 | }; 775 | folder.addMonitor(timer, 'elapsed'); 776 | folder.addMonitor(timer, 'hasDispatched'); 777 | folder.addMonitor(proxy, 'getOverallProgress()', { min: 0, max: 1, view: 'graph' }); 778 | folder.addMonitor(proxy, 'getProgress()', { min: 0, max: 1, view: 'graph' }); 779 | folder.addMonitor(proxy, 'getOverallRemaining()'); 780 | folder.addMonitor(proxy, 'getRemaining()'); 781 | folder.addMonitor(timer, 'loop'); 782 | folder.addMonitor(timer, 'paused'); 783 | folder.addInput(timer, 'paused'); 784 | folder.addMonitor(timer, 'repeat'); 785 | folder.addMonitor(timer, 'repeatCount'); 786 | 787 | folder.addButton({ title: 'Dispatch and remove' }).on('click', () => { console.info('Dispatch and remove timer'); timer.remove(true); }); 788 | folder.addButton({ title: 'Remove' }).on('click', () => { console.info('Remove timer'); timer.remove(); }); 789 | folder.addButton({ title: 'Reset with current config' }).on('click', () => { console.info('Reset timer with current config', timer); timer.reset(timer); }); 790 | 791 | return folder; 792 | } 793 | 794 | export function AddInput (input, pane, options = { title: `Input (${input.gameObject.type} “${input.gameObject.name}”)` }) { 795 | const folder = pane.addFolder(options); 796 | const { gameObject } = input; 797 | const inputPlugin = gameObject.scene.sys.input; 798 | 799 | folder.addMonitor(input, 'cursor'); 800 | folder.addMonitor(input, 'customHitArea'); 801 | folder.addMonitor(input, 'draggable'); 802 | folder.addMonitor(input, 'dragStartX'); 803 | folder.addMonitor(input, 'dragStartXGlobal'); 804 | folder.addMonitor(input, 'dragStartY'); 805 | folder.addMonitor(input, 'dragStartYGlobal'); 806 | folder.addMonitor(input, 'dragState'); 807 | folder.addMonitor(input, 'dragX'); 808 | folder.addMonitor(input, 'dragY'); 809 | folder.addMonitor(input, 'dropZone'); 810 | folder.addMonitor(input, 'enabled'); 811 | folder.addMonitor(input, 'localX'); 812 | folder.addMonitor(input, 'localY'); 813 | 814 | folder.addButton({ title: 'Enable debug' }).on('click', () => { inputPlugin.enableDebug(gameObject); }); 815 | folder.addButton({ title: 'Remove debug' }).on('click', () => { inputPlugin.removeDebug(gameObject); }); 816 | 817 | input.gameObject.once(GameObjectEvents.DESTROY, () => { folder.dispose(); }); 818 | 819 | return folder; 820 | } 821 | 822 | export function AddArcadeBody (body, pane, options = { title: `Body (${body.gameObject.type} “${body.gameObject.name}”)` }) { 823 | const folder = pane.addFolder(options); 824 | 825 | // body.physicsType === Phaser.Physics.Arcade.DYNAMIC_BODY 826 | 827 | folder.addMonitor(body, 'enable'); 828 | folder.addInput(body, 'enable'); 829 | folder.addInput(body, 'debugShowBody'); 830 | folder.addInput(body, 'debugShowVelocity'); 831 | folder.addInput(body, 'debugBodyColor', { view: 'color' }); 832 | folder.addMonitor(body.velocity, 'x', { label: 'velocity x' }); 833 | folder.addMonitor(body.velocity, 'y', { label: 'velocity y' }); 834 | folder.addMonitor(body, 'speed'); 835 | folder.addMonitor(body, 'angle'); 836 | folder.addMonitor(body, '_dx', { label: 'deltaX()' }); 837 | folder.addMonitor(body, '_dy', { label: 'deltaY()' }); 838 | folder.addMonitor(body, '_tx', { label: 'deltaXFinal()' }); 839 | folder.addMonitor(body, '_ty', { label: 'deltaYFinal()' }); 840 | folder.addMonitor(body, 'left'); 841 | folder.addMonitor(body, 'top'); 842 | folder.addMonitor(body, 'right'); 843 | folder.addMonitor(body, 'bottom'); 844 | folder.addMonitor(body.center, 'x', { label: 'center.x' }); 845 | folder.addMonitor(body.center, 'y', { label: 'center.y' }); 846 | 847 | body.gameObject.once(GameObjectEvents.DESTROY, () => { folder.dispose(); }); 848 | 849 | return folder; 850 | } 851 | 852 | export function AddAnimationState (state, pane, options = { title: `Animation (${state.parent.type} “${state.parent.name}”)` }) { 853 | const folder = pane.addFolder(options); 854 | 855 | const proxy = { 856 | get 'getName()' () { return state.getName(); }, 857 | get 'getFrameName()' () { return state.getFrameName(); }, 858 | get nextAnim () { return state.nextAnim ? (state.nextAnim.key || state.nextAnim) : ''; } 859 | }; 860 | 861 | folder.addMonitor(proxy, 'getName()'); 862 | folder.addMonitor(proxy, 'getFrameName()'); 863 | folder.addMonitor(state, 'delay'); 864 | folder.addMonitor(state, 'delayCounter'); 865 | folder.addMonitor(state, 'duration'); 866 | folder.addMonitor(state, 'forward'); 867 | folder.addMonitor(state, 'frameRate'); 868 | folder.addMonitor(state, 'hasStarted'); 869 | folder.addMonitor(state, 'isPaused'); 870 | folder.addMonitor(state, 'isPlaying'); 871 | folder.addMonitor(state, 'msPerFrame'); 872 | folder.addMonitor(proxy, 'nextAnim', { label: 'nextAnim (key)' }); 873 | folder.addMonitor(state.nextAnimsQueue, 'length', { label: 'nextAnimsQueue.length', format: FormatLength }); 874 | folder.addMonitor(state, 'repeat'); 875 | folder.addMonitor(state, 'repeatCounter'); 876 | folder.addMonitor(state, 'repeatDelay'); 877 | folder.addInput(state, 'skipMissedFrames'); 878 | folder.addInput(state, 'timeScale', { min: 0.1, max: 10, step: 0.1 }); 879 | folder.addMonitor(state, 'yoyo'); 880 | 881 | folder.addButton({ title: 'Stop' }).on('click', () => { console.info('Stop animation'); state.stop(); }); 882 | folder.addButton({ title: 'Pause' }).on('click', () => { console.info('Pause animation'); state.pause(); }); 883 | folder.addButton({ title: 'Resume' }).on('click', () => { console.info('Resume animation'); state.resume(); }); 884 | folder.addButton({ title: 'Restart' }).on('click', () => { console.info('Restart animation'); state.restart(); }); 885 | folder.addButton({ title: 'Reverse' }).on('click', () => { console.info('Reverse animation'); state.reverse(); }); 886 | folder.addButton({ title: 'Next frame' }).on('click', () => { console.info('Next animation frame'); state.nextFrame(); }); 887 | folder.addButton({ title: 'Previous frame' }).on('click', () => { console.info('Previous animation frame'); state.previousFrame(); }); 888 | 889 | state.parent.once(GameObjectEvents.DESTROY, () => { folder.dispose(); }); 890 | 891 | return folder; 892 | } 893 | 894 | export function AddKey (key, pane, options = { title: `Key (${key.keyCode})` }) { 895 | const folder = pane.addFolder(options); 896 | 897 | folder.addMonitor(key, 'duration'); 898 | folder.addInput(key, 'emitOnRepeat'); 899 | folder.addInput(key, 'enabled'); 900 | folder.addMonitor(key, 'isDown'); 901 | folder.addMonitor(key, 'isUp'); 902 | folder.addMonitor(key, 'location'); 903 | folder.addMonitor(key, 'repeats'); 904 | folder.addMonitor(key, 'timeDown'); 905 | folder.addMonitor(key, 'timeUp'); 906 | 907 | folder.addButton({ title: 'Destroy' }).on('click', () => { console.info('Destroy key'); key.destroy(); folder.dispose(); }); 908 | 909 | return folder; 910 | } 911 | 912 | export function AddKeys (keys, pane, options = { title: 'Keys' }) { 913 | const folder = pane.addFolder(options); 914 | 915 | for (const name in keys) { 916 | const key = keys[name]; 917 | 918 | folder.addMonitor(key, 'isDown', { label: `${name} isDown` }); 919 | } 920 | 921 | return folder; 922 | } 923 | 924 | export function AddFXComponent (comp, pane, options = { title: `${comp.isPost ? 'Post' : 'Pre'} FX` }) { 925 | const folder = pane.addFolder(options); 926 | 927 | folder.addMonitor(comp, 'enabled'); 928 | 929 | folder.addInput(comp, 'padding', { min: 0, max: 32, step: 1 }); 930 | 931 | folder.addButton({ title: 'Clear' }).on('click', () => { comp.clear(); }); 932 | folder.addButton({ title: 'Disable' }).on('click', () => { comp.disable(); }); 933 | folder.addButton({ title: 'Enable' }).on('click', () => { comp.enable(); }); 934 | 935 | for (const ctrl of comp.list) { 936 | AddFXController(ctrl, folder); 937 | } 938 | 939 | return folder; 940 | } 941 | 942 | export function AddFXController (ctrl, pane, options = { title: `FX ${FXMap[ctrl.type]}` }) { 943 | const folder = pane.addFolder(options); 944 | 945 | for (const key in ctrl) { 946 | if (key.startsWith('_')) continue; 947 | 948 | if (key === 'type') continue; 949 | 950 | const val = ctrl[key]; 951 | const typ = typeof val; 952 | 953 | if (typ !== 'number' && typ !== 'boolean') continue; 954 | 955 | if (key === 'alpha') { 956 | folder.addInput(ctrl, key, { min: 0, max: 1 }); 957 | 958 | continue; 959 | } 960 | 961 | if (key === 'axis' || key === 'direction') { 962 | folder.addInput(ctrl, key, { min: 0, max: 1, step: 1 }); 963 | 964 | continue; 965 | } 966 | 967 | if (key === 'color' || key === 'color1' || key === 'color2' || key === 'backgroundColor') { 968 | folder.addInput(ctrl, key, { view: 'color' }); 969 | 970 | continue; 971 | } 972 | 973 | if (key === 'progress') { 974 | folder.addInput(ctrl, key, { min: 0, max: 1 }); 975 | 976 | continue; 977 | } 978 | 979 | if (key === 'quality') { 980 | folder.addInput(ctrl, key, { options: { low: 0, medium: 1, high: 2 } }); 981 | 982 | continue; 983 | } 984 | 985 | if (key === 'samples') { 986 | folder.addInput(ctrl, key, { min: 1, max: 12, step: 1 }); 987 | 988 | continue; 989 | } 990 | 991 | if (key === 'steps') { 992 | folder.addInput(ctrl, key, { min: 1, max: 10, step: 1 }); 993 | 994 | continue; 995 | } 996 | 997 | folder.addInput(ctrl, key); 998 | } 999 | 1000 | return folder; 1001 | } 1002 | 1003 | export function AddPipelines (pipelines, pane, options = { title: 'Pipelines' }) { 1004 | const folder = pane.addFolder(options); 1005 | 1006 | for (const pipeline of pipelines) { 1007 | folder.addInput(pipeline, 'active', { label: `${pipeline.name} active` }); 1008 | } 1009 | 1010 | return folder; 1011 | } 1012 | 1013 | export function AddPipeline (pipeline, pane, options = { title: `${pipeline.isPost ? 'Post Pipeline' : 'Pipeline'} “${pipeline.name}”` }) { 1014 | const folder = pane.addFolder(options); 1015 | 1016 | folder.addInput(pipeline, 'active'); 1017 | // What else? 1018 | 1019 | return folder; 1020 | } 1021 | 1022 | export function AddActive (items, pane, options = { title: 'Active' }) { 1023 | const folder = pane.addFolder(options); 1024 | 1025 | for (const item of items) { 1026 | folder.addInput(item, 'active', { min: 0, max: 1, label: item.name || item.type || '(Unnamed)' }); 1027 | } 1028 | 1029 | return folder; 1030 | } 1031 | 1032 | export function AddAlpha (items, pane, options = { title: 'Alpha' }) { 1033 | const folder = pane.addFolder(options); 1034 | 1035 | for (const item of items) { 1036 | folder.addInput(item, 'alpha', { min: 0, max: 1, label: item.name || item.type || '(Unnamed)' }); 1037 | } 1038 | 1039 | return folder; 1040 | } 1041 | 1042 | export function AddVisible (items, pane, options = { title: 'Visible' }) { 1043 | const folder = pane.addFolder(options); 1044 | 1045 | for (const item of items) { 1046 | folder.addInput(item, 'visible', { label: item.name || item.type || '(Unnamed)' }); 1047 | } 1048 | 1049 | return folder; 1050 | } 1051 | 1052 | export function AddScenes (scenes, pane, options = { title: 'Scenes Visible' }) { 1053 | const folder = pane.addFolder(options); 1054 | 1055 | for (const scene of scenes) { 1056 | folder.addInput(scene.sys.settings, 'visible', { label: scene.sys.settings.key }); 1057 | } 1058 | 1059 | return folder; 1060 | } 1061 | 1062 | export function FormatLength (len) { 1063 | return len.toFixed(0); 1064 | } 1065 | 1066 | export function InspectByName (name, gameObjects, pane) { 1067 | if (name === null) return; 1068 | 1069 | const gameObject = GetFirst(gameObjects, 'name', name); 1070 | 1071 | if (!gameObject) { 1072 | console.info('No game object found with name "%s"', name); 1073 | 1074 | return; 1075 | } 1076 | 1077 | const newPane = AddGameObject(gameObject, pane); 1078 | 1079 | console.info('Added folder %s to folder %s', newPane.title, pane.title); 1080 | } 1081 | 1082 | export function InspectByType (type, gameObjects, pane) { 1083 | if (!type) return; 1084 | 1085 | const gameObject = GetFirst(gameObjects, 'type', type); 1086 | 1087 | if (!gameObject) { 1088 | console.info('No game object found with type "%s"', type); 1089 | 1090 | return; 1091 | } 1092 | 1093 | const newPane = AddGameObject(gameObject, pane); 1094 | 1095 | console.info('Added folder %s to folder %s', newPane.title, pane.title); 1096 | } 1097 | 1098 | export function InspectByIndex (index, gameObjects, pane) { 1099 | if (index === null || index < 0) return; 1100 | 1101 | index = Number(index); 1102 | 1103 | const gameObject = gameObjects[index]; 1104 | 1105 | if (!gameObject) { 1106 | console.info('No game object found at index %s', index); 1107 | 1108 | return; 1109 | } 1110 | 1111 | const newPane = AddGameObject(gameObject, pane); 1112 | 1113 | console.info('Added folder %s to folder %s', newPane.title, pane.title); 1114 | } 1115 | -------------------------------------------------------------------------------- /test/.eslintrc.yml: -------------------------------------------------------------------------------- 1 | env: 2 | browser: yes 3 | es6: no 4 | mocha: yes 5 | extends: semistandard 6 | globals: 7 | Atomics: readonly 8 | SharedArrayBuffer: readonly 9 | Phaser: readonly 10 | chai: readonly 11 | rules: 12 | no-new: off 13 | -------------------------------------------------------------------------------- /test/test-load.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 25 | Test of Phaser 3 Inspector Plugin, script loading 26 | 27 | 28 |
29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /test/test-load.js: -------------------------------------------------------------------------------- 1 | /* global Phaser */ 2 | 3 | const { assert } = chai; 4 | 5 | mocha.setup('bdd'); 6 | 7 | describe('Phaser', function () { 8 | it('is an object', function () { 9 | assert.isObject(Phaser); 10 | }); 11 | 12 | it('is the required version', function () { 13 | assert.propertyVal(Phaser, 'VERSION', '3.80.1'); 14 | }); 15 | }); 16 | 17 | describe('new Game', function () { 18 | let game; 19 | 20 | afterEach(function () { 21 | game.destroy(true); 22 | game.runDestroy(); 23 | game = null; 24 | }); 25 | 26 | describe('Load script and install', function () { 27 | it('should not error', function (done) { 28 | game = new Phaser.Game({ 29 | type: Phaser.AUTO, 30 | audio: { noAudio: true }, 31 | scene: [ 32 | { 33 | key: 'scene1', 34 | 35 | map: {}, 36 | 37 | physics: { 38 | arcade: {}, 39 | matter: {} 40 | }, 41 | 42 | init: function () { 43 | this.sys.scenePlugin.start('preload'); 44 | } 45 | }, 46 | { 47 | key: 'preload', 48 | 49 | map: {}, 50 | 51 | physics: { 52 | arcade: {}, 53 | matter: {} 54 | }, 55 | 56 | preload: function () { 57 | this.sys.load.scripts('inspector', ['../vendor/tweakpane.js', '../dist/phaser-plugin-inspector.umd.js']); 58 | this.sys.load.once('complete', function () { 59 | // eslint-disable-next-line no-undef 60 | PhaserPluginInspector.Install(this.sys.plugins); 61 | done(); 62 | }, this); 63 | }, 64 | 65 | create: function () { 66 | this.sys.scenePlugin.start('scene2'); 67 | } 68 | }, 69 | { key: 'scene2', map: {}, physics: { arcade: {}, matter: {} } }, 70 | { key: 'scene3', map: {}, physics: { arcade: {}, matter: {} } } 71 | ] 72 | }); 73 | }); 74 | }); 75 | }); 76 | 77 | // mocha.checkLeaks(); 78 | mocha.globals(['Phaser']); 79 | mocha.run(); 80 | -------------------------------------------------------------------------------- /test/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 25 | Test of Phaser 3 Inspector Plugin 26 | 27 | 28 |
29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | /* global Phaser, PhaserPluginInspector, Tweakpane */ 2 | 3 | const { assert } = chai; 4 | 5 | mocha.setup({ allowUncaught: true, ui: 'bdd' }); 6 | 7 | describe('Phaser', function () { 8 | it('is an object', function () { 9 | assert.isObject(Phaser); 10 | }); 11 | 12 | it('is the required version', function () { 13 | assert.propertyVal(Phaser, 'VERSION', '3.87'); 14 | }); 15 | }); 16 | 17 | describe('Tweakpane', function () { 18 | it('is an object', function () { 19 | assert.isObject(Tweakpane); 20 | }); 21 | }); 22 | 23 | describe('PhaserPluginInspector', function () { 24 | it('is an object', function () { 25 | assert.isObject(PhaserPluginInspector); 26 | }); 27 | 28 | describe('PhaserPluginInspector.DefaultPluginsConfig', function () { 29 | it('is an object', function () { 30 | assert.isObject(PhaserPluginInspector.DefaultPluginsConfig); 31 | }); 32 | }); 33 | 34 | describe('PhaserPluginInspector.InspectorGlobalPlugin', function () { 35 | it('is a function', function () { 36 | assert.isFunction(PhaserPluginInspector.InspectorGlobalPlugin); 37 | }); 38 | }); 39 | 40 | describe('PhaserPluginInspector.InspectorScenePlugin', function () { 41 | it('is a function', function () { 42 | assert.isFunction(PhaserPluginInspector.InspectorScenePlugin); 43 | }); 44 | }); 45 | 46 | for ( 47 | const name of [ 48 | 'AddActive', 49 | 'AddAlpha', 50 | 'AddAnimationState', 51 | 'AddArcadeBody', 52 | 'AddArcadePhysicsWorld', 53 | 'AddCamera', 54 | 'AddChain', 55 | 'AddGameObject', 56 | 'AddGroup', 57 | 'AddFXComponent', 58 | 'AddFXController', 59 | 'AddInput', 60 | 'AddKey', 61 | 'AddKeys', 62 | 'AddLight', 63 | 'AddMatterPhysicsWorld', 64 | 'AddParticleEmitter', 65 | 'AddPointer', 66 | 'AddScenes', 67 | 'AddSound', 68 | 'AddTimeline', 69 | 'AddTimerEvent', 70 | 'AddTween', 71 | 'AddVideo', 72 | 'AddVisible' 73 | ] 74 | ) { 75 | describe(`PhaserPluginInspector.${name}`, function () { 76 | it('is a function', function () { 77 | assert.isFunction(PhaserPluginInspector[name]); 78 | }); 79 | }); 80 | } 81 | }); 82 | 83 | describe('new Game', function () { 84 | let game; 85 | 86 | beforeEach(function () { 87 | }); 88 | 89 | afterEach(function () { 90 | console.log('Destroy InspectorGlobalPlugin …'); 91 | game.plugins.get('InspectorGlobalPlugin').destroy(); 92 | console.log('Remove InspectorGlobalPlugin …'); 93 | game.plugins.removeGlobalPlugin('InspectorGlobalPlugin'); 94 | console.log('Remove InspectorScenePlugin …'); 95 | game.plugins.removeScenePlugin('InspectorScenePlugin'); 96 | console.log('Destroy game …'); 97 | game.destroy(true); 98 | game.runDestroy(); 99 | game = null; 100 | }); 101 | 102 | describe('Install with DefaultPluginsConfig', function () { 103 | it('should not error', function (done) { 104 | game = new Phaser.Game({ 105 | input: { activePointers: 0 }, 106 | plugins: PhaserPluginInspector.DefaultPluginsConfig, 107 | callbacks: { 108 | postBoot: function (game) { 109 | assert.isObject(game.plugins.getEntry('InspectorGlobalPlugin')); 110 | assert.include(game.plugins.getDefaultScenePlugins(), 'InspectorScenePlugin'); 111 | done(); 112 | } 113 | }, 114 | scene: { 115 | map: {}, 116 | physics: { arcade: {}, matter: {} }, 117 | init: function () { 118 | assert.property(this, 'inspectorGame'); 119 | assert.property(this, 'inspectorScene'); 120 | assert.notProperty(this.sys, 'inspectorGame'); 121 | assert.property(this.sys, 'inspectorScene'); 122 | } 123 | } 124 | }); 125 | }); 126 | }); 127 | 128 | describe('Install with DefaultPluginsConfig, Canvas renderer', function () { 129 | it('should not error', function (done) { 130 | game = new Phaser.Game({ 131 | type: Phaser.CANVAS, 132 | input: { activePointers: 0 }, 133 | plugins: PhaserPluginInspector.DefaultPluginsConfig, 134 | callbacks: { 135 | postBoot: function (game) { 136 | assert.isObject(game.plugins.getEntry('InspectorGlobalPlugin')); 137 | assert.include(game.plugins.getDefaultScenePlugins(), 'InspectorScenePlugin'); 138 | done(); 139 | } 140 | }, 141 | scene: { 142 | map: {}, 143 | physics: { arcade: {}, matter: {} }, 144 | init: function () { 145 | console.log('init', this); 146 | assert.property(this, 'inspectorGame'); 147 | assert.property(this, 'inspectorScene'); 148 | assert.notProperty(this.sys, 'inspectorGame'); 149 | assert.property(this.sys, 'inspectorScene'); 150 | } 151 | } 152 | }); 153 | }); 154 | }); 155 | 156 | describe('Install with DefaultPluginsConfig, disable Web Audio', function () { 157 | it('should not error', function (done) { 158 | game = new Phaser.Game({ 159 | audio: { disableWebAudio: true }, 160 | input: { activePointers: 0 }, 161 | plugins: PhaserPluginInspector.DefaultPluginsConfig, 162 | callbacks: { 163 | postBoot: function (game) { 164 | assert.isObject(game.plugins.getEntry('InspectorGlobalPlugin')); 165 | assert.include(game.plugins.getDefaultScenePlugins(), 'InspectorScenePlugin'); 166 | done(); 167 | } 168 | }, 169 | scene: { 170 | map: {}, 171 | physics: { arcade: {}, matter: {} }, 172 | init: function () { 173 | assert.property(this, 'inspectorGame'); 174 | assert.property(this, 'inspectorScene'); 175 | assert.notProperty(this.sys, 'inspectorGame'); 176 | assert.property(this.sys, 'inspectorScene'); 177 | } 178 | } 179 | }); 180 | }); 181 | }); 182 | 183 | describe('Install with DefaultPluginsConfig, disable audio', function () { 184 | it('should not error', function (done) { 185 | game = new Phaser.Game({ 186 | audio: { disableAudio: true }, 187 | input: { activePointers: 0 }, 188 | plugins: PhaserPluginInspector.DefaultPluginsConfig, 189 | callbacks: { 190 | postBoot: function (game) { 191 | assert.isObject(game.plugins.getEntry('InspectorGlobalPlugin')); 192 | assert.include(game.plugins.getDefaultScenePlugins(), 'InspectorScenePlugin'); 193 | done(); 194 | } 195 | }, 196 | scene: { 197 | map: {}, 198 | physics: { arcade: {}, matter: {} }, 199 | init: function () { 200 | assert.property(this, 'inspectorGame'); 201 | assert.property(this, 'inspectorScene'); 202 | assert.notProperty(this.sys, 'inspectorGame'); 203 | assert.property(this.sys, 'inspectorScene'); 204 | } 205 | } 206 | }); 207 | }); 208 | }); 209 | 210 | describe('Install with DefaultPluginsConfig, disable input', function () { 211 | it('should not error', function (done) { 212 | game = new Phaser.Game({ 213 | audio: { disableAudio: true }, 214 | input: { gamepad: false, keyboard: false, mouse: false, touch: false, wheel: false }, 215 | plugins: PhaserPluginInspector.DefaultPluginsConfig, 216 | callbacks: { 217 | postBoot: function (game) { 218 | assert.isObject(game.plugins.getEntry('InspectorGlobalPlugin')); 219 | assert.include(game.plugins.getDefaultScenePlugins(), 'InspectorScenePlugin'); 220 | done(); 221 | } 222 | }, 223 | scene: { 224 | map: {}, 225 | physics: { arcade: {}, matter: {} }, 226 | init: function () { 227 | assert.property(this, 'inspectorGame'); 228 | assert.property(this, 'inspectorScene'); 229 | assert.notProperty(this.sys, 'inspectorGame'); 230 | assert.property(this.sys, 'inspectorScene'); 231 | } 232 | } 233 | }); 234 | }); 235 | }); 236 | 237 | describe('Install with DefaultPluginsConfig, click buttons', function () { 238 | it.skip('should not error', function (done) { 239 | game = new Phaser.Game({ 240 | input: { activePointers: 0 }, 241 | plugins: PhaserPluginInspector.DefaultPluginsConfig, 242 | callbacks: { 243 | postBoot: function (game) { 244 | assert.isObject(game.plugins.getEntry('InspectorGlobalPlugin')); 245 | assert.include(game.plugins.getDefaultScenePlugins(), 'InspectorScenePlugin'); 246 | } 247 | }, 248 | scene: { 249 | map: {}, 250 | physics: { arcade: {}, matter: {} }, 251 | create: function () { 252 | assert.property(this, 'inspectorGame'); 253 | 254 | console.warn('Will click a lot of buttons. These have side effects.'); 255 | 256 | const skipExpr = /(Destroy|Remove|…)/; 257 | 258 | for (const button of this.inspectorGame.pane.containerElem_.querySelectorAll('.tp-btnv_b')) { 259 | const { innerText } = button; 260 | 261 | if (skipExpr.test(innerText)) { 262 | console.log('Skipping button because it matches the exclude pattern', innerText); 263 | 264 | continue; 265 | } 266 | 267 | console.log('Click', button.innerText); 268 | 269 | button.click(); 270 | } 271 | 272 | console.log('Wait for 0.4s'); 273 | 274 | setTimeout(() => { 275 | console.log('Done waiting'); 276 | 277 | done(); 278 | }, 400); 279 | } 280 | } 281 | }); 282 | }); 283 | }); 284 | 285 | describe('Install with mappings', function () { 286 | it('should not error', function (done) { 287 | game = new Phaser.Game({ 288 | type: Phaser.AUTO, 289 | audio: { noAudio: true }, 290 | input: { activePointers: 0 }, 291 | plugins: { 292 | global: [{ key: 'InspectorGlobalPlugin', plugin: PhaserPluginInspector.InspectorGlobalPlugin, mapping: 'inspectorGadget' }], 293 | scene: [{ key: 'InspectorScenePlugin', plugin: PhaserPluginInspector.InspectorScenePlugin, mapping: 'inspectorClouseau' }] 294 | }, 295 | callbacks: { 296 | postBoot: function (game) { 297 | assert.isObject(game.plugins.getEntry('InspectorGlobalPlugin')); 298 | assert.include(game.plugins.getDefaultScenePlugins(), 'InspectorScenePlugin'); 299 | done(); 300 | } 301 | }, 302 | scene: { 303 | map: {}, 304 | physics: { arcade: {}, matter: {} }, 305 | init: function () { 306 | console.log('init', this); 307 | assert.property(this, 'inspectorGadget'); 308 | assert.property(this, 'inspectorClouseau'); 309 | assert.notProperty(this.sys, 'inspectorGadget'); 310 | assert.property(this.sys, 'inspectorClouseau'); 311 | } 312 | } 313 | }); 314 | }); 315 | }); 316 | 317 | describe('Install without mappings', function () { 318 | it('should not error', function (done) { 319 | game = new Phaser.Game({ 320 | type: Phaser.AUTO, 321 | audio: { noAudio: true }, 322 | plugins: { 323 | global: [{ key: 'InspectorGlobalPlugin', plugin: PhaserPluginInspector.InspectorGlobalPlugin, start: true }], 324 | scene: [{ key: 'InspectorScenePlugin', plugin: PhaserPluginInspector.InspectorScenePlugin, start: true }] 325 | }, 326 | callbacks: { 327 | postBoot: function (game) { 328 | assert.isObject(game.plugins.getEntry('InspectorGlobalPlugin')); 329 | assert.include(game.plugins.getDefaultScenePlugins(), 'InspectorScenePlugin'); 330 | done(); 331 | } 332 | }, 333 | scene: { 334 | map: {}, 335 | physics: { arcade: {}, matter: {} }, 336 | init: function () { 337 | console.log('init', this); 338 | } 339 | } 340 | }); 341 | }); 342 | }); 343 | 344 | describe('Install plugin from postBoot()', function () { 345 | it('should not error', function (done) { 346 | game = new Phaser.Game({ 347 | type: Phaser.AUTO, 348 | audio: { noAudio: true }, 349 | callbacks: { 350 | postBoot: function (game) { 351 | PhaserPluginInspector.Install(game.plugins); 352 | assert.isObject(game.plugins.getEntry('InspectorGlobalPlugin')); 353 | assert.include(game.plugins.getDefaultScenePlugins(), 'InspectorScenePlugin'); 354 | done(); 355 | } 356 | }, 357 | scene: { 358 | map: {}, 359 | physics: { arcade: {}, matter: {} }, 360 | init: function () { 361 | assert.notProperty(this, 'inspectorScene', 'Plugin not in scene!'); 362 | assert.notProperty(this.sys, 'inspectorScene', 'Plugin not in scene systems!'); 363 | } 364 | } 365 | }); 366 | }); 367 | }); 368 | }); 369 | 370 | for (const renderType of [Phaser.CANVAS, Phaser.WEBGL]) { 371 | describe(`new Game, no install, renderer ${renderType}`, function () { 372 | const { 373 | AddActive, 374 | AddAlpha, 375 | AddAnimationState, 376 | AddArcadeBody, 377 | AddCamera, 378 | AddChain, 379 | AddFXController, 380 | AddGameObject, 381 | AddGroup, 382 | AddKey, 383 | AddKeys, 384 | AddInput, 385 | AddLight, 386 | AddParticleEmitter, 387 | AddScenes, 388 | AddTimeline, 389 | AddTimerEvent, 390 | AddTween, 391 | AddVideo, 392 | AddVisible 393 | } = PhaserPluginInspector; 394 | 395 | let pane = new Tweakpane.Pane(); 396 | let game; 397 | let scene; 398 | 399 | before(function (done) { 400 | game = new Phaser.Game({ 401 | type: renderType, 402 | canvasStyle: 'display: none', 403 | scene: { 404 | physics: { arcade: { debug: true }, matter: {} }, 405 | init: function () { 406 | scene = this; 407 | this.scene.sleep(); 408 | done(); 409 | } 410 | } 411 | }); 412 | }); 413 | 414 | after(function () { 415 | pane.dispose(); 416 | game.destroy(true); 417 | game.runDestroy(); 418 | game = null; 419 | pane = null; 420 | scene = null; 421 | }); 422 | 423 | afterEach(function () { 424 | console.log('Clear display list?', scene.sys.displayList.length); 425 | scene.sys.displayList.shutdown(); 426 | }); 427 | 428 | describe('game.config.renderType', function () { 429 | it('is the specified type', function () { 430 | assert.propertyVal(game.config, 'renderType', renderType); 431 | }); 432 | }); 433 | 434 | describe('game.renderer.type', function () { 435 | it('is the specified type', function () { 436 | assert.propertyVal(game.renderer, 'type', renderType); 437 | }); 438 | }); 439 | 440 | describe('AddActive()', function () { 441 | it('does not error', function () { 442 | AddActive( 443 | [{ name: '1', active: true }, { name: '2', active: false }], 444 | pane 445 | ); 446 | }); 447 | }); 448 | 449 | describe('AddAlpha()', function () { 450 | it('does not error', function () { 451 | AddAlpha( 452 | [{ name: '1', alpha: 1 }, { name: '2', alpha: 0 }], 453 | pane 454 | ); 455 | }); 456 | }); 457 | 458 | describe('AddAnimationState(sprite.anims)', function () { 459 | it('does not error', function () { 460 | AddAnimationState(scene.add.sprite(0, 0, '__DEFAULT').anims, pane); 461 | }); 462 | }); 463 | 464 | describe('AddAnimationState() with chained key', function () { 465 | it('does not error', function () { 466 | scene.anims.create('anim1', { frames: [{ key: '__DEFAULT', frame: '__BASE' }] }); 467 | const sprite = scene.add.sprite(0, 0, '__DEFAULT'); 468 | sprite.anims.chain('anim1'); 469 | AddAnimationState(sprite.anims, pane); 470 | }); 471 | }); 472 | 473 | describe('AddAnimationState() with chained anim', function () { 474 | it('does not error', function () { 475 | const anim = scene.anims.create('anim2', { frames: [{ key: '__DEFAULT', frame: '__BASE' }] }); 476 | const sprite = scene.add.sprite(0, 0, '__DEFAULT'); 477 | sprite.anims.chain(anim); 478 | AddAnimationState(sprite.anims, pane); 479 | }); 480 | }); 481 | 482 | describe('AddAnimationState() with chained play config', function () { 483 | it('does not error', function () { 484 | scene.anims.create('anim3', { frames: [{ key: '__DEFAULT', frame: '__BASE' }] }); 485 | const sprite = scene.add.sprite(0, 0, '__DEFAULT'); 486 | sprite.anims.chain({ key: 'anim3' }); 487 | AddAnimationState(sprite.anims, pane); 488 | }); 489 | }); 490 | 491 | describe('AddArcadeBody(body)', function () { 492 | it('does not error', function () { 493 | AddArcadeBody(scene.physics.add.image(0, 0, '__DEFAULT').body, pane); 494 | }); 495 | }); 496 | 497 | describe('AddCamera()', function () { 498 | it('does not error', function () { 499 | const cam = scene.cameras.add(); 500 | 501 | AddCamera(cam, pane); 502 | 503 | scene.cameras.remove(cam); 504 | }); 505 | }); 506 | 507 | // this.cameras.main.setPostPipeline(Phaser.FX.BLUR); 508 | 509 | describe('AddCamera(), setPostPipeline()', function () { 510 | it('does not error', function () { 511 | const cam = scene.cameras.add().setPostPipeline(Phaser.FX.BLUR); 512 | 513 | AddCamera(cam, pane); 514 | 515 | scene.cameras.remove(cam); 516 | }); 517 | }); 518 | 519 | describe('AddChain()', function () { 520 | it('does not error', function () { 521 | const chain = scene.tweens.chain({ 522 | targets: { x: 0, y: 0 }, 523 | tweens: [{ x: 1 }, { y: 1 }] 524 | }); 525 | 526 | AddChain(chain, pane); 527 | 528 | chain.destroy(); 529 | }); 530 | }); 531 | 532 | describe('AddGameObject(bitmap text)', function () { 533 | it('does not error', function () { 534 | scene.cache.bitmapFont.add('bitmapFont', Phaser.GameObjects.RetroFont.Parse(scene, { 535 | image: '__DEFAULT', 536 | width: 1, 537 | height: 1, 538 | chars: Phaser.GameObjects.RetroFont.TEXT_SET6, 539 | charsPerRow: 32 540 | })); 541 | 542 | AddGameObject(scene.add.bitmapText(0, 0, 'bitmapFont', 'Hello'), pane); 543 | }); 544 | }); 545 | 546 | describe('AddGameObject(blitter)', function () { 547 | it('does not error', function () { 548 | AddGameObject(scene.add.blitter(0, 0, '__DEFAULT'), pane); 549 | }); 550 | }); 551 | 552 | describe('AddGameObject(container)', function () { 553 | it('does not error', function () { 554 | AddGameObject(scene.add.container(0, 0, [scene.add.sprite(0, 0, '__DEFAULT')]), pane); 555 | }); 556 | }); 557 | 558 | describe('AddGameObject(dom)', function () { 559 | it('does not error', function () { 560 | AddGameObject(scene.add.dom(0, 0, 'b', '', 'Hello'), pane); 561 | }); 562 | }); 563 | 564 | describe('AddGameObject(graphics)', function () { 565 | it('does not error', function () { 566 | AddGameObject(scene.add.graphics(), pane); 567 | }); 568 | }); 569 | 570 | describe('AddGameObject(image)', function () { 571 | it('does not error', function () { 572 | AddGameObject(scene.add.image(0, 0, '__DEFAULT'), pane); 573 | }); 574 | }); 575 | 576 | describe('AddGameObject(layer)', function () { 577 | it('does not error', function () { 578 | AddGameObject(scene.add.layer(scene.add.sprite(0, 0, '__DEFAULT')), pane); 579 | }); 580 | }); 581 | 582 | describe('AddGameObject(nineslice)', function () { 583 | it('does not error', function () { 584 | AddGameObject(scene.add.nineslice(0, 0, '__DEFAULT'), pane); 585 | }); 586 | }); 587 | 588 | describe('AddGameObject(point light)', function () { 589 | it('does not error', function () { 590 | AddGameObject(scene.add.pointlight(0, 0), pane); 591 | }); 592 | }); 593 | 594 | describe('AddGameObject(render texture)', function () { 595 | it('does not error', function () { 596 | AddGameObject(scene.add.renderTexture(0, 0, 128, 128), pane); 597 | }); 598 | }); 599 | 600 | describe('AddGameObject(rope)', function () { 601 | it('does not error', function () { 602 | AddGameObject(scene.add.rope(0, 0, '__DEFAULT'), pane); 603 | }); 604 | }); 605 | 606 | describe('AddGameObject(shader)', function () { 607 | it('does not error', function () { 608 | if (game.config.renderType === Phaser.WEBGL) { 609 | AddGameObject(scene.add.shader(new Phaser.Display.BaseShader('test'), 0, 0, 1, 1), pane); 610 | } else { 611 | this.skip(); 612 | } 613 | }); 614 | }); 615 | 616 | describe('AddGameObject(sprite)', function () { 617 | it('does not error', function () { 618 | AddGameObject(scene.add.sprite(0, 0, '__DEFAULT'), pane); 619 | }); 620 | }); 621 | 622 | describe('AddGameObject(star)', function () { 623 | it('does not error', function () { 624 | AddGameObject(scene.add.star(0, 0, 5, 10, 20), pane); 625 | }); 626 | }); 627 | 628 | describe('AddGameObject(text)', function () { 629 | it('does not error', function () { 630 | AddGameObject(scene.add.text(0, 0, 'Hello'), pane); 631 | }); 632 | }); 633 | 634 | describe('AddGameObject(tilemap layer)', function () { 635 | it('does not error', function () { 636 | const map = scene.make.tilemap({ width: 64, height: 64, tileWidth: 16, tileHeight: 16 }); 637 | const tileset = map.addTilesetImage('__DEFAULT'); 638 | 639 | AddGameObject(map.createBlankLayer('layer', tileset), pane); 640 | }); 641 | }); 642 | 643 | describe('AddGameObject(tilesprite)', function () { 644 | it('does not error', function () { 645 | AddGameObject(scene.add.tileSprite(0, 0, 32, 32, '__DEFAULT'), pane); 646 | }); 647 | }); 648 | 649 | describe('AddGameObject(mesh)', function () { 650 | it('does not error', function () { 651 | AddGameObject(scene.add.mesh(0, 0, '__DEFAULT').addVertices([-1, 1, 1, 1, -1, -1, 1, -1], [0, 0, 1, 0, 0, 1, 1, 1], [0, 2, 1, 2, 3, 1]), pane); 652 | }); 653 | }); 654 | 655 | describe('AddGameObject(plane)', function () { 656 | it('does not error', function () { 657 | AddGameObject(scene.add.plane(400, 300, '__DEFAULT', null, 8, 8, true), pane); 658 | }); 659 | }); 660 | 661 | describe('AddGameObject(image), preFX.addShadow()', function () { 662 | it('does not error', function () { 663 | const img = scene.add.image(0, 0, '__DEFAULT'); 664 | 665 | img.preFX.addShadow(0, 0, 0.006, 2, 0x333333, 10); 666 | 667 | AddGameObject(img, pane); 668 | }); 669 | }); 670 | 671 | describe('AddGameObject(image), postFX.addShine()', function () { 672 | it('does not error', function () { 673 | if (game.config.renderType === Phaser.WEBGL) { 674 | const img = scene.add.image(0, 0, '__DEFAULT'); 675 | 676 | img.postFX.addShine(1, 0.2, 5); 677 | 678 | AddGameObject(img, pane); 679 | } else { 680 | this.skip(); 681 | } 682 | }); 683 | }); 684 | 685 | describe('AddFXController(preFX.addBarrel())', function () { 686 | it('does not error', function () { 687 | const fx = scene.add.image(0, 0, '__DEFAULT').preFX.addBarrel(); 688 | 689 | AddFXController(fx, pane); 690 | }); 691 | }); 692 | 693 | describe('AddFXController(preFX.addBloom())', function () { 694 | it('does not error', function () { 695 | const fx = scene.add.image(0, 0, '__DEFAULT').preFX.addBloom(); 696 | AddFXController(fx, pane); 697 | }); 698 | }); 699 | 700 | describe('AddFXController(preFX.addBlur())', function () { 701 | it('does not error', function () { 702 | const fx = scene.add.image(0, 0, '__DEFAULT').preFX.addBlur(); 703 | AddFXController(fx, pane); 704 | }); 705 | }); 706 | 707 | describe('AddFXController(preFX.addBokeh())', function () { 708 | it('does not error', function () { 709 | const fx = scene.add.image(0, 0, '__DEFAULT').preFX.addBokeh(); 710 | AddFXController(fx, pane); 711 | }); 712 | }); 713 | 714 | describe('AddFXController(preFX.addCircle())', function () { 715 | it('does not error', function () { 716 | const fx = scene.add.image(0, 0, '__DEFAULT').preFX.addCircle(); 717 | AddFXController(fx, pane); 718 | }); 719 | }); 720 | 721 | describe('AddFXController(preFX.addColorMatrix())', function () { 722 | it('does not error', function () { 723 | const fx = scene.add.image(0, 0, '__DEFAULT').preFX.addColorMatrix(); 724 | AddFXController(fx, pane); 725 | }); 726 | }); 727 | 728 | describe('AddFXController(preFX.addDisplacement())', function () { 729 | it('does not error', function () { 730 | const fx = scene.add.image(0, 0, '__DEFAULT').preFX.addDisplacement(); 731 | AddFXController(fx, pane); 732 | }); 733 | }); 734 | 735 | describe('AddFXController(preFX.addGlow())', function () { 736 | it('does not error', function () { 737 | const fx = scene.add.image(0, 0, '__DEFAULT').preFX.addGlow(); 738 | AddFXController(fx, pane); 739 | }); 740 | }); 741 | 742 | describe('AddFXController(preFX.addGradient())', function () { 743 | it('does not error', function () { 744 | const fx = scene.add.image(0, 0, '__DEFAULT').preFX.addGradient(); 745 | AddFXController(fx, pane); 746 | }); 747 | }); 748 | 749 | describe('AddFXController(preFX.addPixelate())', function () { 750 | it('does not error', function () { 751 | const fx = scene.add.image(0, 0, '__DEFAULT').preFX.addPixelate(); 752 | AddFXController(fx, pane); 753 | }); 754 | }); 755 | 756 | describe('AddFXController(preFX.addReveal())', function () { 757 | it('does not error', function () { 758 | const fx = scene.add.image(0, 0, '__DEFAULT').preFX.addReveal(); 759 | AddFXController(fx, pane); 760 | }); 761 | }); 762 | 763 | describe('AddFXController(preFX.addShadow())', function () { 764 | it('does not error', function () { 765 | const fx = scene.add.image(0, 0, '__DEFAULT').preFX.addShadow(); 766 | AddFXController(fx, pane); 767 | }); 768 | }); 769 | 770 | describe('AddFXController(preFX.addShine())', function () { 771 | it('does not error', function () { 772 | const fx = scene.add.image(0, 0, '__DEFAULT').preFX.addShine(); 773 | AddFXController(fx, pane); 774 | }); 775 | }); 776 | 777 | describe('AddFXController(preFX.addTiltShift())', function () { 778 | it('does not error', function () { 779 | const fx = scene.add.image(0, 0, '__DEFAULT').preFX.addTiltShift(); 780 | AddFXController(fx, pane); 781 | }); 782 | }); 783 | 784 | describe('AddFXController(preFX.addVignette())', function () { 785 | it('does not error', function () { 786 | const fx = scene.add.image(0, 0, '__DEFAULT').preFX.addVignette(); 787 | AddFXController(fx, pane); 788 | }); 789 | }); 790 | 791 | describe('AddFXController(preFX.addWipe())', function () { 792 | it('does not error', function () { 793 | const fx = scene.add.image(0, 0, '__DEFAULT').preFX.addWipe(); 794 | AddFXController(fx, pane); 795 | }); 796 | }); 797 | 798 | describe('AddFXController(postFX.addBarrel())', function () { 799 | it('does not error', function () { 800 | if (game.config.renderType === Phaser.WEBGL) { 801 | const fx = scene.add.image(0, 0, '__DEFAULT').postFX.addBarrel(); 802 | 803 | AddFXController(fx, pane); 804 | } else { 805 | this.skip(); 806 | } 807 | }); 808 | }); 809 | 810 | describe('AddGroup(group)', function () { 811 | it('does not error', function () { 812 | AddGroup(scene.add.group(), pane); 813 | }); 814 | }); 815 | 816 | describe('AddGroup(group with maxSize)', function () { 817 | it('does not error', function () { 818 | AddGroup(scene.add.group({ maxSize: 1 }), pane); 819 | }); 820 | }); 821 | 822 | describe('AddGroup(physics group)', function () { 823 | it('does not error', function () { 824 | AddGroup(scene.physics.add.group(), pane); 825 | }); 826 | }); 827 | 828 | describe('AddGroup(static physics group)', function () { 829 | it('does not error', function () { 830 | AddGroup(scene.physics.add.staticGroup(), pane); 831 | }); 832 | }); 833 | 834 | describe('AddInput(sprite.input)', function () { 835 | it('does not error', function () { 836 | AddInput(scene.add.sprite(0, 0, '__DEFAULT').setInteractive().input, pane); 837 | }); 838 | }); 839 | 840 | describe('AddKey(key)', function () { 841 | it('does not error', function () { 842 | AddKey(scene.input.keyboard.addKey('SPACE'), pane); 843 | }); 844 | }); 845 | 846 | describe('AddKeys(key)', function () { 847 | it('does not error', function () { 848 | AddKeys(scene.input.keyboard.addKeys('W,A,S,D'), pane); 849 | }); 850 | }); 851 | 852 | describe('AddLight(light)', function () { 853 | it('does not error', function () { 854 | AddLight(scene.lights.addLight(), pane); 855 | }); 856 | }); 857 | 858 | describe('AddParticleEmitter(particle emitter)', function () { 859 | it('does not error', function () { 860 | const particles = scene.add.particles(0, 0, '__DEFAULT'); 861 | 862 | AddParticleEmitter(particles, pane); 863 | }); 864 | }); 865 | 866 | describe('AddParticleEmitter(particle emitter) ops', function () { 867 | describe('static value', function () { 868 | it('does not error', function () { 869 | AddParticleEmitter(scene.add.particles(0, 0, '__DEFAULT', { alpha: 0 }), pane); 870 | }); 871 | }); 872 | describe('random array', function () { 873 | it('does not error', function () { 874 | AddParticleEmitter(scene.add.particles(0, 0, '__DEFAULT', { alpha: [0, 1] }), pane); 875 | }); 876 | }); 877 | describe('custom emit', function () { 878 | it('does not error', function () { 879 | AddParticleEmitter(scene.add.particles(0, 0, '__DEFAULT', { alpha: { onEmit: () => 1 } }), pane); 880 | }); 881 | }); 882 | describe('stepped start-end', function () { 883 | it('does not error', function () { 884 | AddParticleEmitter(scene.add.particles(0, 0, '__DEFAULT', { alpha: { start: 0, end: 1, steps: 2 } }), pane); 885 | }); 886 | }); 887 | describe('eased start-end', function () { 888 | it('does not error', function () { 889 | AddParticleEmitter(scene.add.particles(0, 0, '__DEFAULT', { alpha: { start: 0, end: 1 } }), pane); 890 | }); 891 | }); 892 | describe('random min-max', function () { 893 | it('does not error', function () { 894 | AddParticleEmitter(scene.add.particles(0, 0, '__DEFAULT', { alpha: { min: 0, max: 1 } }), pane); 895 | }); 896 | }); 897 | describe('random integer', function () { 898 | it('does not error', function () { 899 | AddParticleEmitter(scene.add.particles(0, 0, '__DEFAULT', { alpha: { random: [0, 1] } }), pane); 900 | }); 901 | }); 902 | describe('custom emit update', function () { 903 | it('does not error', function () { 904 | AddParticleEmitter(scene.add.particles(0, 0, '__DEFAULT', { alpha: { onEmit: () => 0, onUpdate: () => 1 } }), pane); 905 | }); 906 | }); 907 | describe('interpolated', function () { 908 | it('does not error', function () { 909 | AddParticleEmitter(scene.add.particles(0, 0, '__DEFAULT', { alpha: { values: [0, 1], interpolation: 'catmull' } }), pane); 910 | }); 911 | }); 912 | describe('color', function () { 913 | it('does not error', function () { 914 | AddParticleEmitter(scene.add.particles(0, 0, '__DEFAULT', { color: [0, 1, 2] }), pane); 915 | }); 916 | }); 917 | }); 918 | 919 | describe('AddScenes()', function () { 920 | it('does not error', function () { 921 | AddScenes( 922 | [new Phaser.Scene('1'), new Phaser.Scene('2')], 923 | pane 924 | ); 925 | }); 926 | }); 927 | 928 | describe('AddTimeline()', function () { 929 | it('does not error', function () { 930 | const timeline = scene.add.timeline([ 931 | { at: 0 }, 932 | { at: 1 } 933 | ]); 934 | 935 | AddTimeline(timeline, pane); 936 | 937 | timeline.destroy(); 938 | }); 939 | }); 940 | 941 | describe('AddTimerEvent(timer event)', function () { 942 | it('does not error', function () { 943 | AddTimerEvent(scene.time.addEvent({ delay: 1000 }), pane); 944 | }); 945 | }); 946 | 947 | describe('AddTween(tween)', function () { 948 | it('does not error', function () { 949 | AddTween(scene.add.tween({ targets: {} }), pane); 950 | }); 951 | }); 952 | 953 | describe('AddTween(counter tween)', function () { 954 | it('does not error', function () { 955 | AddTween(scene.tweens.addCounter({ from: 1, to: 10 }), pane); 956 | }); 957 | }); 958 | 959 | describe('AddVideo(video)', function () { 960 | it('does not error', function () { 961 | const video = scene.add.video(0, 0).loadURL('data:video/mp4;base64,AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAAAr9tZGF0AAACoAYF//+c3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDEyNSAtIEguMjY0L01QRUctNCBBVkMgY29kZWMgLSBDb3B5bGVmdCAyMDAzLTIwMTIgLSBodHRwOi8vd3d3LnZpZGVvbGFuLm9yZy94MjY0Lmh0bWwgLSBvcHRpb25zOiBjYWJhYz0xIHJlZj0zIGRlYmxvY2s9MTowOjAgYW5hbHlzZT0weDM6MHgxMTMgbWU9aGV4IHN1Ym1lPTcgcHN5PTEgcHN5X3JkPTEuMDA6MC4wMCBtaXhlZF9yZWY9MSBtZV9yYW5nZT0xNiBjaHJvbWFfbWU9MSB0cmVsbGlzPTEgOHg4ZGN0PTEgY3FtPTAgZGVhZHpvbmU9MjEsMTEgZmFzdF9wc2tpcD0xIGNocm9tYV9xcF9vZmZzZXQ9LTIgdGhyZWFkcz02IGxvb2thaGVhZF90aHJlYWRzPTEgc2xpY2VkX3RocmVhZHM9MCBucj0wIGRlY2ltYXRlPTEgaW50ZXJsYWNlZD0wIGJsdXJheV9jb21wYXQ9MCBjb25zdHJhaW5lZF9pbnRyYT0wIGJmcmFtZXM9MyBiX3B5cmFtaWQ9MiBiX2FkYXB0PTEgYl9iaWFzPTAgZGlyZWN0PTEgd2VpZ2h0Yj0xIG9wZW5fZ29wPTAgd2VpZ2h0cD0yIGtleWludD0yNTAga2V5aW50X21pbj0yNCBzY2VuZWN1dD00MCBpbnRyYV9yZWZyZXNoPTAgcmNfbG9va2FoZWFkPTQwIHJjPWNyZiBtYnRyZWU9MSBjcmY9MjMuMCBxY29tcD0wLjYwIHFwbWluPTAgcXBtYXg9NjkgcXBzdGVwPTQgaXBfcmF0aW89MS40MCBhcT0xOjEuMDAAgAAAAA9liIQAV/0TAAYdeBTXzg8AAALvbW9vdgAAAGxtdmhkAAAAAAAAAAAAAAAAAAAD6AAAACoAAQAAAQAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAhl0cmFrAAAAXHRraGQAAAAPAAAAAAAAAAAAAAABAAAAAAAAACoAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAAAgAAAAIAAAAAAAkZWR0cwAAABxlbHN0AAAAAAAAAAEAAAAqAAAAAAABAAAAAAGRbWRpYQAAACBtZGhkAAAAAAAAAAAAAAAAAAAwAAAAAgBVxAAAAAAALWhkbHIAAAAAAAAAAHZpZGUAAAAAAAAAAAAAAABWaWRlb0hhbmRsZXIAAAABPG1pbmYAAAAUdm1oZAAAAAEAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAPxzdGJsAAAAmHN0c2QAAAAAAAAAAQAAAIhhdmMxAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAgACABIAAAASAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGP//AAAAMmF2Y0MBZAAK/+EAGWdkAAqs2V+WXAWyAAADAAIAAAMAYB4kSywBAAZo6+PLIsAAAAAYc3R0cwAAAAAAAAABAAAAAQAAAgAAAAAcc3RzYwAAAAAAAAABAAAAAQAAAAEAAAABAAAAFHN0c3oAAAAAAAACtwAAAAEAAAAUc3RjbwAAAAAAAAABAAAAMAAAAGJ1ZHRhAAAAWm1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAALWlsc3QAAAAlqXRvbwAAAB1kYXRhAAAAAQAAAABMYXZmNTQuNjMuMTA0'); 962 | 963 | AddVideo(video, pane); 964 | 965 | video.destroy(); 966 | }); 967 | }); 968 | 969 | describe('AddVisible()', function () { 970 | it('does not error', function () { 971 | AddVisible( 972 | [{ name: '1', visible: true }, { name: '2', visible: false }], 973 | pane 974 | ); 975 | }); 976 | }); 977 | }); 978 | } 979 | 980 | mocha.checkLeaks(); 981 | mocha.globals(['Phaser']); 982 | mocha.run(); 983 | --------------------------------------------------------------------------------