├── .babelrc ├── .eslintignore ├── .eslintrc.js ├── .github └── workflows │ ├── test-phaser-3.yml │ └── test-phaser-ce.yml ├── .gitignore ├── LICENSE ├── README.md ├── assets ├── diagram.png ├── diagram_column.png ├── diagram_quantitybar.png ├── diagram_row.png ├── diagram_valuebar.png └── diagram_wheel3D.png ├── docs ├── assets │ ├── anchor.js │ ├── bass-addons.css │ ├── bass.css │ ├── fonts │ │ ├── EOT │ │ │ ├── SourceCodePro-Bold.eot │ │ │ └── SourceCodePro-Regular.eot │ │ ├── LICENSE.txt │ │ ├── OTF │ │ │ ├── SourceCodePro-Bold.otf │ │ │ └── SourceCodePro-Regular.otf │ │ ├── TTF │ │ │ ├── SourceCodePro-Bold.ttf │ │ │ └── SourceCodePro-Regular.ttf │ │ ├── WOFF │ │ │ ├── OTF │ │ │ │ ├── SourceCodePro-Bold.otf.woff │ │ │ │ └── SourceCodePro-Regular.otf.woff │ │ │ └── TTF │ │ │ │ ├── SourceCodePro-Bold.ttf.woff │ │ │ │ └── SourceCodePro-Regular.ttf.woff │ │ ├── WOFF2 │ │ │ ├── OTF │ │ │ │ ├── SourceCodePro-Bold.otf.woff2 │ │ │ │ └── SourceCodePro-Regular.otf.woff2 │ │ │ └── TTF │ │ │ │ ├── SourceCodePro-Bold.ttf.woff2 │ │ │ │ └── SourceCodePro-Regular.ttf.woff2 │ │ └── source-code-pro.css │ ├── github.css │ ├── site.js │ ├── split.css │ ├── split.js │ └── style.css ├── examples │ ├── assets │ │ ├── horizontal │ │ │ ├── bar.png │ │ │ ├── sprite.png │ │ │ └── track.png │ │ ├── modal │ │ │ ├── background.png │ │ │ └── button.png │ │ ├── quantitybar │ │ │ ├── add.png │ │ │ ├── horizontal │ │ │ │ ├── bar.png │ │ │ │ └── track.png │ │ │ ├── subtract.png │ │ │ └── vertical │ │ │ │ ├── bar.png │ │ │ │ └── track.png │ │ ├── textover │ │ │ ├── button.png │ │ │ └── header.png │ │ ├── valuebar │ │ │ ├── alpha.png │ │ │ ├── background.png │ │ │ ├── bar.png │ │ │ ├── pointer.png │ │ │ ├── track.png │ │ │ └── vtrack.png │ │ ├── vertical │ │ │ ├── bar.png │ │ │ ├── sprite.png │ │ │ └── track.png │ │ └── wheel3D │ │ │ ├── icon.png │ │ │ ├── mmDown.png │ │ │ └── mmUp.png │ ├── html │ │ ├── phaser3 │ │ │ ├── hscrollbar.html │ │ │ ├── modal.html │ │ │ ├── quantitybar.html │ │ │ ├── textover.html │ │ │ ├── valuebar.html │ │ │ ├── vscrollbar.html │ │ │ └── wheel3D.html │ │ └── phaserce │ │ │ ├── hscrollbar.html │ │ │ ├── modal.html │ │ │ ├── quantitybar.html │ │ │ ├── quantitybar_column.html │ │ │ ├── textover.html │ │ │ ├── valuebar.html │ │ │ ├── valuebar_column.html │ │ │ ├── vscrollbar.html │ │ │ └── wheel3D.html │ ├── js │ │ ├── phaser3 │ │ │ ├── hscrollbar.js │ │ │ ├── modal.js │ │ │ ├── quantitybar.js │ │ │ ├── textover.js │ │ │ ├── valuebar.js │ │ │ ├── vscrollbar.js │ │ │ └── wheel3D.js │ │ └── phaserce │ │ │ ├── hscrollbar.js │ │ │ ├── modal.js │ │ │ ├── quantitybar.js │ │ │ ├── quantitybar_column.js │ │ │ ├── textover.js │ │ │ ├── valuebar.js │ │ │ ├── valuebar_column.js │ │ │ ├── vscrollbar.js │ │ │ └── wheel3D.js │ └── lib │ │ ├── phaser-ui-tools.js │ │ ├── phaser.min.js │ │ └── phaser3.min.js └── index.html ├── package-lock.json ├── package.json ├── src ├── bars │ ├── bar.js │ ├── draggable_bar.js │ ├── quantitybar.js │ ├── ranges.js │ ├── scrollbar.js │ └── valuebar.js ├── buttons.js ├── const.js ├── containers │ ├── column.js │ ├── frame.js │ ├── row.js │ └── viewport.js ├── entry.js ├── keyboard_group.js ├── phaserObjects │ ├── button.js │ ├── easing.js │ ├── graphics.js │ ├── group.js │ ├── index.js │ ├── keyboard.js │ ├── keycodes.js │ ├── rectangle.js │ ├── sprite.js │ ├── tween.js │ └── viewport_mask.js ├── utils.js └── wheel3D.js ├── tests ├── column.spec.js ├── frame.spec.js ├── row.spec.js ├── testrunner.html ├── testrunner_phaser3.html ├── viewport.spec.js └── wheel3D.spec.js └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["@babel/preset-env", { 4 | "modules": false 5 | }] 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /dist 2 | /docs 3 | /node_modules 4 | /tests 5 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "extends": "airbnb-base", 3 | "rules": { 4 | "indent": ["error", 4], 5 | "linebreak-style": 0, 6 | "no-plusplus": ["error", {"allowForLoopAfterthoughts": true}], 7 | "import/prefer-default-export": "off", 8 | "max-len": ["error", {"ignoreComments": true}], 9 | "object-curly-newline": ["error", {"ObjectPattern": {"multiline": true}}], 10 | "no-lonely-if": "off", 11 | "max-len": "off", 12 | "max-classes-per-file": "off", 13 | }, 14 | "parserOptions": { 15 | "sourceType": "module", 16 | }, 17 | "globals": { 18 | "Phaser": true, 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /.github/workflows/test-phaser-3.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | name: test-phaser-3 4 | 5 | on: 6 | push: 7 | branches: 8 | - master 9 | pull_request: 10 | branches: 11 | - master 12 | 13 | jobs: 14 | build: 15 | runs-on: ubuntu-latest 16 | name: unit-tests 17 | 18 | strategy: 19 | matrix: 20 | node-version: [14.x] 21 | 22 | steps: 23 | - name: Checkout Repository 24 | uses: actions/checkout@v2 25 | with: 26 | fetch-depth: 1 27 | 28 | - name: Setup Node ${{ matrix.node-version }} 29 | uses: actions/setup-node@v2 30 | with: 31 | always-auth: false 32 | node-version: ${{ matrix.node-version }} 33 | 34 | - name: Run npm install 35 | run: npm install 36 | 37 | - name: Build js 38 | run: npm run build:js 39 | 40 | - name: Run tests 41 | run: npm run test3 42 | env: 43 | CI: true 44 | -------------------------------------------------------------------------------- /.github/workflows/test-phaser-ce.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | name: test-phaser-ce 4 | 5 | on: 6 | push: 7 | branches: 8 | - master 9 | pull_request: 10 | branches: 11 | - master 12 | 13 | jobs: 14 | build: 15 | runs-on: ubuntu-latest 16 | name: unit-tests 17 | 18 | strategy: 19 | matrix: 20 | node-version: [14.x] 21 | 22 | steps: 23 | - name: Checkout Repository 24 | uses: actions/checkout@v2 25 | with: 26 | fetch-depth: 1 27 | 28 | - name: Setup Node ${{ matrix.node-version }} 29 | uses: actions/setup-node@v2 30 | with: 31 | always-auth: false 32 | node-version: ${{ matrix.node-version }} 33 | 34 | - name: Run npm install 35 | run: npm install 36 | 37 | - name: Build js 38 | run: npm run build:js 39 | 40 | - name: Run tests 41 | run: npm run test 42 | env: 43 | CI: true 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist/* 2 | node_modules/ 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Joshua Fehler 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Phaser UI Tools 2 | 3 | [![Build Status](https://github.com/jsfehler/phaser-ui-tools/workflows/test-phaser-3/badge.svg)](https://github.com/jsfehler/phaser-ui-tools/actions/workflows/test-phaser-3.yml) 4 | 5 | [![Build Status](https://github.com/jsfehler/phaser-ui-tools/workflows/test-phaser-ce/badge.svg)](https://github.com/jsfehler/phaser-ui-tools/actions/workflows/test-phaser-ce.yml) 6 | 7 | 8 | I really wanted a viewport with a scrollbar. Things escalated. 9 | 10 | ![scrollbar](https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/master/assets/diagram.png) 11 | 12 | ### Documentation 13 | https://jsfehler.github.io/phaser-ui-tools/ 14 | 15 | ### References 16 | Scrollbar math: 17 | http://csdgn.org/article/scrollbar 18 | 19 | 20 | ### Getting Started 21 | 22 | #### Using NPM 23 | On the command line, type: 24 | ``` 25 | npm i phaser-ui-tools 26 | ``` 27 | 28 | The objects are now available via import: 29 | ``` 30 | import { Column } from 'phaser-ui-tools'; 31 | 32 | var column = new Column(...) 33 | 34 | ``` 35 | 36 | #### Adding the file directly to your project 37 | Get phaser-ui-tools.js from the releases and add it to your project's index.html. 38 | It should look something like: 39 | ``` 40 | 41 | ``` 42 | 43 | The objects can now be used directly: 44 | 45 | ``` 46 | var column = new uiWidgets.Column(...) 47 | ``` 48 | 49 | 50 | ### The Tools 51 | 52 | #### Text Overlays 53 | 54 | ##### TextSprite 55 | A sprite that can have text on top. 56 | 57 | Text is added with the setText() method. 58 | 59 | ```javascript 60 | var textSprite = new uiWidgets.TextSprite( 61 | game, x, y, key, 62 | ); 63 | textSprite.setText(label, style); 64 | ``` 65 | 66 | ##### TextButton 67 | A button that can have text on top. 68 | 69 | Text is added with the setText() method. 70 | 71 | ```javascript 72 | var textButton = new uiWidgets.TextButton( 73 | game, x, y, key, callback, callbackContext, overKey, outKey, downKey, upKey, 74 | ); 75 | textButton.setText(label, style); 76 | ``` 77 | 78 | ##### Examples 79 | 80 | ###### Phaser CE 81 | [Header & Buttons](https://jsfehler.github.io/phaser-ui-tools/examples/html/phaserce/textover.html) | [Code](https://jsfehler.github.io/phaser-ui-tools/examples/js/phaserce/textover.js) 82 | 83 | ###### Phaser 3 84 | [Header & Buttons](https://jsfehler.github.io/phaser-ui-tools/examples/html/phaser3/textover.html) | [Code](https://jsfehler.github.io/phaser-ui-tools/examples/js/phaser3/textover.js) 85 | 86 | #### Containers 87 | 88 | ##### Column 89 | 90 | Columns are Phaser Groups where each child added to the group is placed directly under the previous child. If an object can be a child of a Group, it can likewise be in a Column. 91 | 92 | ![column](https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/master/assets/diagram_column.png) 93 | ```javascript 94 | var column = new uiWidgets.Column(game, 8, 8); 95 | column.addNode(sprite_a, 8, 8); 96 | column.addNode(sprite_b, 8, 8); 97 | column.addNode(sprite_c, 8, 8); 98 | ``` 99 | 100 | ##### Row 101 | 102 | Rows are Phaser Groups where each child added to the group is placed directly next to the previous child. If an object can be a child of a Group, it can likewise be in a Row. 103 | 104 | ![row](https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/master/assets/diagram_row.png) 105 | ```javascript 106 | var row = new uiWidgets.Row(game, 8, 8); 107 | row.addNode(sprite_a, 8, 8); 108 | row.addNode(sprite_b, 8, 8); 109 | row.addNode(sprite_c, 8, 8); 110 | ``` 111 | 112 | ##### Viewport 113 | Viewports are Phaser Groups where the children in the group are only visible if they're within the viewport's area. 114 | If an object can be a child of a Group, it can likewise be in a Viewport. 115 | 116 | Viewports can be combined with a Scrollbar to create a scrollable display. 117 | 118 | Placing a Column or Row inside a Viewport is a simple way to align content. 119 | 120 | ```javascript 121 | var viewport = new uiWidgets.Viewport(game, 75, 75, 600, 260); 122 | viewport.addNode(column); 123 | ``` 124 | 125 | #### Bars 126 | 127 | ##### Scrollbar 128 | Scrollbars are used to move the objects in a Viewport. They must be used with a Viewport. 129 | A tweening duration and easing can be specified. This will be triggered when moving the bar. 130 | 131 | ```javascript 132 | var scrollbar = new uiWidgets.Scrollbar( 133 | game, 134 | viewport, 135 | true, 136 | true, 137 | true, 138 | trackImage, 139 | barImage, 140 | {'duration': 300, 'ease': Phaser.Easing.Quadratic.Out} 141 | ); 142 | ``` 143 | 144 | ##### Examples 145 | 146 | ###### Phaser CE 147 | 148 | [Vertical](https://jsfehler.github.io/phaser-ui-tools/examples/html/phaserce/vscrollbar.html) | [Code](https://jsfehler.github.io/phaser-ui-tools/examples/js/phaserce/vscrollbar.js) 149 | 150 | [Horizontal](https://jsfehler.github.io/phaser-ui-tools/examples/html/phaserce/hscrollbar.html) | [Code](https://jsfehler.github.io/phaser-ui-tools/examples/js/phaserce/hscrollbar.js) 151 | 152 | ###### Phaser 3 153 | 154 | [Vertical](https://jsfehler.github.io/phaser-ui-tools/examples/html/phaser3/vscrollbar.html) | [Code](https://jsfehler.github.io/phaser-ui-tools/examples/js/phaser3/vscrollbar.js) 155 | 156 | [Horizontal](https://jsfehler.github.io/phaser-ui-tools/examples/html/phaser3/hscrollbar.html) | [Code](https://jsfehler.github.io/phaser-ui-tools/examples/js/phaser3/hscrollbar.js) 157 | 158 | 159 | ##### ValueBar 160 | Valuebars are like Scrollbars, but instead of moving content, they increase/decrease a number. 161 | Valuebars always have a minimum number of 0, but the starting and maximum number can be set. 162 | A tweening duration and easing can be specified. This will be triggered when moving the bar. 163 | 164 | ![valuebar](https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/master/assets/diagram_valuebar.png) 165 | 166 | ```javascript 167 | var valuebar = new uiWidgets.ValueBar( 168 | game, 169 | {'x': 50, 'y': 10}, 170 | {'step': 1, 'startValue': 0, 'maxValue': 100}, 171 | true, 172 | false, 173 | true, 174 | trackImage, 175 | barImage, 176 | {'duration': 100, 'ease': Phaser.Easing.Quadratic.Out} 177 | ); 178 | ``` 179 | 180 | ##### Examples 181 | 182 | ###### Phaser CE 183 | 184 | [ValueBar](https://jsfehler.github.io/phaser-ui-tools/examples/html/phaserce/valuebar.html) | [Code](https://jsfehler.github.io/phaser-ui-tools/examples/js/phaserce/valuebar.js) 185 | 186 | [Multiple ValueBar inside a Column, with background image and keyboard events](https://jsfehler.github.io/phaser-ui-tools/examples/html/phaserce/valuebar_column.html) | [Code](https://jsfehler.github.io/phaser-ui-tools/examples/js/phaserce/valuebar_column.js) 187 | 188 | ###### Phaser 3 189 | 190 | [ValueBar](https://jsfehler.github.io/phaser-ui-tools/examples/html/phaser3/valuebar.html) | [Code](https://jsfehler.github.io/phaser-ui-tools/examples/js/phaser3/valuebar.js) 191 | 192 | 193 | ##### QuantityBar 194 | QuantityBars do not adjust a value, they get adjusted by a value. The bar grows and shrinks based on a value. 195 | They can be used for health bars, stamina bars, etc. 196 | A tweening duration and easing can be specified. This will be triggered when moving the bar. 197 | 198 | ![quantitybar](https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/master/assets/diagram_quantitybar.png) 199 | 200 | ```javascript 201 | var quantitybar = new uiWidgets.QuantityBar( 202 | game, 203 | {'x': 50, 'y': 10}, 204 | {'startValue': 50, 'maxValue': 100}, 205 | false, 206 | false, 207 | trackImage, 208 | barImage, 209 | {'duration': 400, 'ease': Phaser.Easing.Quadratic.Out} 210 | ); 211 | ``` 212 | 213 | ##### Examples 214 | 215 | ###### Phaser CE 216 | 217 | [QuantityBar](https://jsfehler.github.io/phaser-ui-tools/examples/html/phaserce/quantitybar.html) | [Code](https://jsfehler.github.io/phaser-ui-tools/examples/js/phaserce/quantitybar.js) 218 | 219 | ###### Phaser 3 220 | 221 | [QuantityBar](https://jsfehler.github.io/phaser-ui-tools/examples/html/phaser3/quantitybar.html) | [Code](https://jsfehler.github.io/phaser-ui-tools/examples/js/phaser3/quantitybar.js) 222 | 223 | 224 | #### Wheel3D 225 | A collection of sprites that are arranged around a three dimensional wheel. 226 | The wheel can be adjusted and rotated along the x, y, or z axis. 227 | 228 | ![wheel3D](https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/master/assets/diagram_wheel3D.png) 229 | 230 | ```javascript 231 | var wheel = new uiWidgets.Wheel3D( 232 | game, 233 | {"x": game.world.centerX - 100, "y": game.world.centerY}, 234 | [sprite1, sprite2, sprite3, sprite4], 235 | 0, 236 | 90, 237 | "y", 238 | {"x":0, "y": 0, "z": 0} 239 | ); 240 | ``` 241 | 242 | ##### Examples 243 | 244 | ###### Phaser CE 245 | 246 | [Wheel3D](https://jsfehler.github.io/phaser-ui-tools/examples/html/phaserce/wheel3D.html) | [Code](https://jsfehler.github.io/phaser-ui-tools/examples/js/phaserce/wheel3D.js) 247 | 248 | ###### Phaser 3 249 | 250 | [Wheel3D](https://jsfehler.github.io/phaser-ui-tools/examples/html/phaser3/wheel3D.html) | [Code](https://jsfehler.github.io/phaser-ui-tools/examples/js/phaser3/wheel3D.js) 251 | -------------------------------------------------------------------------------- /assets/diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/assets/diagram.png -------------------------------------------------------------------------------- /assets/diagram_column.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/assets/diagram_column.png -------------------------------------------------------------------------------- /assets/diagram_quantitybar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/assets/diagram_quantitybar.png -------------------------------------------------------------------------------- /assets/diagram_row.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/assets/diagram_row.png -------------------------------------------------------------------------------- /assets/diagram_valuebar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/assets/diagram_valuebar.png -------------------------------------------------------------------------------- /assets/diagram_wheel3D.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/assets/diagram_wheel3D.png -------------------------------------------------------------------------------- /docs/assets/bass-addons.css: -------------------------------------------------------------------------------- 1 | .input { 2 | font-family: inherit; 3 | display: block; 4 | width: 100%; 5 | height: 2rem; 6 | padding: .5rem; 7 | margin-bottom: 1rem; 8 | border: 1px solid #ccc; 9 | font-size: .875rem; 10 | border-radius: 3px; 11 | box-sizing: border-box; 12 | } 13 | -------------------------------------------------------------------------------- /docs/assets/fonts/EOT/SourceCodePro-Bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/assets/fonts/EOT/SourceCodePro-Bold.eot -------------------------------------------------------------------------------- /docs/assets/fonts/EOT/SourceCodePro-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/assets/fonts/EOT/SourceCodePro-Regular.eot -------------------------------------------------------------------------------- /docs/assets/fonts/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. 2 | 3 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 4 | 5 | This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL 6 | 7 | 8 | ----------------------------------------------------------- 9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 10 | ----------------------------------------------------------- 11 | 12 | PREAMBLE 13 | The goals of the Open Font License (OFL) are to stimulate worldwide 14 | development of collaborative font projects, to support the font creation 15 | efforts of academic and linguistic communities, and to provide a free and 16 | open framework in which fonts may be shared and improved in partnership 17 | with others. 18 | 19 | The OFL allows the licensed fonts to be used, studied, modified and 20 | redistributed freely as long as they are not sold by themselves. The 21 | fonts, including any derivative works, can be bundled, embedded, 22 | redistributed and/or sold with any software provided that any reserved 23 | names are not used by derivative works. The fonts and derivatives, 24 | however, cannot be released under any other type of license. The 25 | requirement for fonts to remain under this license does not apply 26 | to any document created using the fonts or their derivatives. 27 | 28 | DEFINITIONS 29 | "Font Software" refers to the set of files released by the Copyright 30 | Holder(s) under this license and clearly marked as such. This may 31 | include source files, build scripts and documentation. 32 | 33 | "Reserved Font Name" refers to any names specified as such after the 34 | copyright statement(s). 35 | 36 | "Original Version" refers to the collection of Font Software components as 37 | distributed by the Copyright Holder(s). 38 | 39 | "Modified Version" refers to any derivative made by adding to, deleting, 40 | or substituting -- in part or in whole -- any of the components of the 41 | Original Version, by changing formats or by porting the Font Software to a 42 | new environment. 43 | 44 | "Author" refers to any designer, engineer, programmer, technical 45 | writer or other person who contributed to the Font Software. 46 | 47 | PERMISSION & CONDITIONS 48 | Permission is hereby granted, free of charge, to any person obtaining 49 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 50 | redistribute, and sell modified and unmodified copies of the Font 51 | Software, subject to the following conditions: 52 | 53 | 1) Neither the Font Software nor any of its individual components, 54 | in Original or Modified Versions, may be sold by itself. 55 | 56 | 2) Original or Modified Versions of the Font Software may be bundled, 57 | redistributed and/or sold with any software, provided that each copy 58 | contains the above copyright notice and this license. These can be 59 | included either as stand-alone text files, human-readable headers or 60 | in the appropriate machine-readable metadata fields within text or 61 | binary files as long as those fields can be easily viewed by the user. 62 | 63 | 3) No Modified Version of the Font Software may use the Reserved Font 64 | Name(s) unless explicit written permission is granted by the corresponding 65 | Copyright Holder. This restriction only applies to the primary font name as 66 | presented to the users. 67 | 68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 69 | Software shall not be used to promote, endorse or advertise any 70 | Modified Version, except to acknowledge the contribution(s) of the 71 | Copyright Holder(s) and the Author(s) or with their explicit written 72 | permission. 73 | 74 | 5) The Font Software, modified or unmodified, in part or in whole, 75 | must be distributed entirely under this license, and must not be 76 | distributed under any other license. The requirement for fonts to 77 | remain under this license does not apply to any document created 78 | using the Font Software. 79 | 80 | TERMINATION 81 | This license becomes null and void if any of the above conditions are 82 | not met. 83 | 84 | DISCLAIMER 85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 93 | OTHER DEALINGS IN THE FONT SOFTWARE. 94 | -------------------------------------------------------------------------------- /docs/assets/fonts/OTF/SourceCodePro-Bold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/assets/fonts/OTF/SourceCodePro-Bold.otf -------------------------------------------------------------------------------- /docs/assets/fonts/OTF/SourceCodePro-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/assets/fonts/OTF/SourceCodePro-Regular.otf -------------------------------------------------------------------------------- /docs/assets/fonts/TTF/SourceCodePro-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/assets/fonts/TTF/SourceCodePro-Bold.ttf -------------------------------------------------------------------------------- /docs/assets/fonts/TTF/SourceCodePro-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/assets/fonts/TTF/SourceCodePro-Regular.ttf -------------------------------------------------------------------------------- /docs/assets/fonts/WOFF/OTF/SourceCodePro-Bold.otf.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/assets/fonts/WOFF/OTF/SourceCodePro-Bold.otf.woff -------------------------------------------------------------------------------- /docs/assets/fonts/WOFF/OTF/SourceCodePro-Regular.otf.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/assets/fonts/WOFF/OTF/SourceCodePro-Regular.otf.woff -------------------------------------------------------------------------------- /docs/assets/fonts/WOFF/TTF/SourceCodePro-Bold.ttf.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/assets/fonts/WOFF/TTF/SourceCodePro-Bold.ttf.woff -------------------------------------------------------------------------------- /docs/assets/fonts/WOFF/TTF/SourceCodePro-Regular.ttf.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/assets/fonts/WOFF/TTF/SourceCodePro-Regular.ttf.woff -------------------------------------------------------------------------------- /docs/assets/fonts/WOFF2/OTF/SourceCodePro-Bold.otf.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/assets/fonts/WOFF2/OTF/SourceCodePro-Bold.otf.woff2 -------------------------------------------------------------------------------- /docs/assets/fonts/WOFF2/OTF/SourceCodePro-Regular.otf.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/assets/fonts/WOFF2/OTF/SourceCodePro-Regular.otf.woff2 -------------------------------------------------------------------------------- /docs/assets/fonts/WOFF2/TTF/SourceCodePro-Bold.ttf.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/assets/fonts/WOFF2/TTF/SourceCodePro-Bold.ttf.woff2 -------------------------------------------------------------------------------- /docs/assets/fonts/WOFF2/TTF/SourceCodePro-Regular.ttf.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/assets/fonts/WOFF2/TTF/SourceCodePro-Regular.ttf.woff2 -------------------------------------------------------------------------------- /docs/assets/fonts/source-code-pro.css: -------------------------------------------------------------------------------- 1 | @font-face{ 2 | font-family: 'Source Code Pro'; 3 | font-weight: 400; 4 | font-style: normal; 5 | font-stretch: normal; 6 | src: url('EOT/SourceCodePro-Regular.eot') format('embedded-opentype'), 7 | url('WOFF2/TTF/SourceCodePro-Regular.ttf.woff2') format('woff2'), 8 | url('WOFF/OTF/SourceCodePro-Regular.otf.woff') format('woff'), 9 | url('OTF/SourceCodePro-Regular.otf') format('opentype'), 10 | url('TTF/SourceCodePro-Regular.ttf') format('truetype'); 11 | } 12 | 13 | @font-face{ 14 | font-family: 'Source Code Pro'; 15 | font-weight: 700; 16 | font-style: normal; 17 | font-stretch: normal; 18 | src: url('EOT/SourceCodePro-Bold.eot') format('embedded-opentype'), 19 | url('WOFF2/TTF/SourceCodePro-Bold.ttf.woff2') format('woff2'), 20 | url('WOFF/OTF/SourceCodePro-Bold.otf.woff') format('woff'), 21 | url('OTF/SourceCodePro-Bold.otf') format('opentype'), 22 | url('TTF/SourceCodePro-Bold.ttf') format('truetype'); 23 | } 24 | -------------------------------------------------------------------------------- /docs/assets/github.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | github.com style (c) Vasily Polovnyov 4 | 5 | */ 6 | 7 | .hljs { 8 | display: block; 9 | overflow-x: auto; 10 | padding: 0.5em; 11 | color: #333; 12 | background: #f8f8f8; 13 | -webkit-text-size-adjust: none; 14 | } 15 | 16 | .hljs-comment, 17 | .diff .hljs-header, 18 | .hljs-javadoc { 19 | color: #998; 20 | font-style: italic; 21 | } 22 | 23 | .hljs-keyword, 24 | .css .rule .hljs-keyword, 25 | .hljs-winutils, 26 | .nginx .hljs-title, 27 | .hljs-subst, 28 | .hljs-request, 29 | .hljs-status { 30 | color: #1184CE; 31 | } 32 | 33 | .hljs-number, 34 | .hljs-hexcolor, 35 | .ruby .hljs-constant { 36 | color: #ed225d; 37 | } 38 | 39 | .hljs-string, 40 | .hljs-tag .hljs-value, 41 | .hljs-phpdoc, 42 | .hljs-dartdoc, 43 | .tex .hljs-formula { 44 | color: #ed225d; 45 | } 46 | 47 | .hljs-title, 48 | .hljs-id, 49 | .scss .hljs-preprocessor { 50 | color: #900; 51 | font-weight: bold; 52 | } 53 | 54 | .hljs-list .hljs-keyword, 55 | .hljs-subst { 56 | font-weight: normal; 57 | } 58 | 59 | .hljs-class .hljs-title, 60 | .hljs-type, 61 | .vhdl .hljs-literal, 62 | .tex .hljs-command { 63 | color: #458; 64 | font-weight: bold; 65 | } 66 | 67 | .hljs-tag, 68 | .hljs-tag .hljs-title, 69 | .hljs-rules .hljs-property, 70 | .django .hljs-tag .hljs-keyword { 71 | color: #000080; 72 | font-weight: normal; 73 | } 74 | 75 | .hljs-attribute, 76 | .hljs-variable, 77 | .lisp .hljs-body { 78 | color: #008080; 79 | } 80 | 81 | .hljs-regexp { 82 | color: #009926; 83 | } 84 | 85 | .hljs-symbol, 86 | .ruby .hljs-symbol .hljs-string, 87 | .lisp .hljs-keyword, 88 | .clojure .hljs-keyword, 89 | .scheme .hljs-keyword, 90 | .tex .hljs-special, 91 | .hljs-prompt { 92 | color: #990073; 93 | } 94 | 95 | .hljs-built_in { 96 | color: #0086b3; 97 | } 98 | 99 | .hljs-preprocessor, 100 | .hljs-pragma, 101 | .hljs-pi, 102 | .hljs-doctype, 103 | .hljs-shebang, 104 | .hljs-cdata { 105 | color: #999; 106 | font-weight: bold; 107 | } 108 | 109 | .hljs-deletion { 110 | background: #fdd; 111 | } 112 | 113 | .hljs-addition { 114 | background: #dfd; 115 | } 116 | 117 | .diff .hljs-change { 118 | background: #0086b3; 119 | } 120 | 121 | .hljs-chunk { 122 | color: #aaa; 123 | } 124 | -------------------------------------------------------------------------------- /docs/assets/site.js: -------------------------------------------------------------------------------- 1 | /* global anchors */ 2 | 3 | // add anchor links to headers 4 | anchors.options.placement = 'left'; 5 | anchors.add('h3'); 6 | 7 | // Filter UI 8 | var tocElements = document.getElementById('toc').getElementsByTagName('li'); 9 | 10 | document.getElementById('filter-input').addEventListener('keyup', function(e) { 11 | var i, element, children; 12 | 13 | // enter key 14 | if (e.keyCode === 13) { 15 | // go to the first displayed item in the toc 16 | for (i = 0; i < tocElements.length; i++) { 17 | element = tocElements[i]; 18 | if (!element.classList.contains('display-none')) { 19 | location.replace(element.firstChild.href); 20 | return e.preventDefault(); 21 | } 22 | } 23 | } 24 | 25 | var match = function() { 26 | return true; 27 | }; 28 | 29 | var value = this.value.toLowerCase(); 30 | 31 | if (!value.match(/^\s*$/)) { 32 | match = function(element) { 33 | var html = element.firstChild.innerHTML; 34 | return html && html.toLowerCase().indexOf(value) !== -1; 35 | }; 36 | } 37 | 38 | for (i = 0; i < tocElements.length; i++) { 39 | element = tocElements[i]; 40 | children = Array.from(element.getElementsByTagName('li')); 41 | if (match(element) || children.some(match)) { 42 | element.classList.remove('display-none'); 43 | } else { 44 | element.classList.add('display-none'); 45 | } 46 | } 47 | }); 48 | 49 | var items = document.getElementsByClassName('toggle-sibling'); 50 | for (var j = 0; j < items.length; j++) { 51 | items[j].addEventListener('click', toggleSibling); 52 | } 53 | 54 | function toggleSibling() { 55 | var stepSibling = this.parentNode.getElementsByClassName('toggle-target')[0]; 56 | var icon = this.getElementsByClassName('icon')[0]; 57 | var klass = 'display-none'; 58 | if (stepSibling.classList.contains(klass)) { 59 | stepSibling.classList.remove(klass); 60 | icon.innerHTML = '▾'; 61 | } else { 62 | stepSibling.classList.add(klass); 63 | icon.innerHTML = '▸'; 64 | } 65 | } 66 | 67 | function showHashTarget(targetId) { 68 | if (targetId) { 69 | var hashTarget = document.getElementById(targetId); 70 | // new target is hidden 71 | if ( 72 | hashTarget && 73 | hashTarget.offsetHeight === 0 && 74 | hashTarget.parentNode.parentNode.classList.contains('display-none') 75 | ) { 76 | hashTarget.parentNode.parentNode.classList.remove('display-none'); 77 | } 78 | } 79 | } 80 | 81 | function scrollIntoView(targetId) { 82 | // Only scroll to element if we don't have a stored scroll position. 83 | if (targetId && !history.state) { 84 | var hashTarget = document.getElementById(targetId); 85 | if (hashTarget) { 86 | hashTarget.scrollIntoView(); 87 | } 88 | } 89 | } 90 | 91 | function gotoCurrentTarget() { 92 | showHashTarget(location.hash.substring(1)); 93 | scrollIntoView(location.hash.substring(1)); 94 | } 95 | 96 | window.addEventListener('hashchange', gotoCurrentTarget); 97 | gotoCurrentTarget(); 98 | 99 | var toclinks = document.getElementsByClassName('pre-open'); 100 | for (var k = 0; k < toclinks.length; k++) { 101 | toclinks[k].addEventListener('mousedown', preOpen, false); 102 | } 103 | 104 | function preOpen() { 105 | showHashTarget(this.hash.substring(1)); 106 | } 107 | 108 | var split_left = document.querySelector('#split-left'); 109 | var split_right = document.querySelector('#split-right'); 110 | var split_parent = split_left.parentNode; 111 | var cw_with_sb = split_left.clientWidth; 112 | split_left.style.overflow = 'hidden'; 113 | var cw_without_sb = split_left.clientWidth; 114 | split_left.style.overflow = ''; 115 | 116 | Split(['#split-left', '#split-right'], { 117 | elementStyle: function(dimension, size, gutterSize) { 118 | return { 119 | 'flex-basis': 'calc(' + size + '% - ' + gutterSize + 'px)' 120 | }; 121 | }, 122 | gutterStyle: function(dimension, gutterSize) { 123 | return { 124 | 'flex-basis': gutterSize + 'px' 125 | }; 126 | }, 127 | gutterSize: 20, 128 | sizes: [33, 67] 129 | }); 130 | 131 | // Chrome doesn't remember scroll position properly so do it ourselves. 132 | // Also works on Firefox and Edge. 133 | 134 | function updateState() { 135 | history.replaceState( 136 | { 137 | left_top: split_left.scrollTop, 138 | right_top: split_right.scrollTop 139 | }, 140 | document.title 141 | ); 142 | } 143 | 144 | function loadState(ev) { 145 | if (ev) { 146 | // Edge doesn't replace change history.state on popstate. 147 | history.replaceState(ev.state, document.title); 148 | } 149 | if (history.state) { 150 | split_left.scrollTop = history.state.left_top; 151 | split_right.scrollTop = history.state.right_top; 152 | } 153 | } 154 | 155 | window.addEventListener('load', function() { 156 | // Restore after Firefox scrolls to hash. 157 | setTimeout(function() { 158 | loadState(); 159 | // Update with initial scroll position. 160 | updateState(); 161 | // Update scroll positions only after we've loaded because Firefox 162 | // emits an initial scroll event with 0. 163 | split_left.addEventListener('scroll', updateState); 164 | split_right.addEventListener('scroll', updateState); 165 | }, 1); 166 | }); 167 | 168 | window.addEventListener('popstate', loadState); 169 | -------------------------------------------------------------------------------- /docs/assets/split.css: -------------------------------------------------------------------------------- 1 | .gutter { 2 | background-color: #f5f5f5; 3 | background-repeat: no-repeat; 4 | background-position: 50%; 5 | } 6 | 7 | .gutter.gutter-vertical { 8 | background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAFAQMAAABo7865AAAABlBMVEVHcEzMzMzyAv2sAAAAAXRSTlMAQObYZgAAABBJREFUeF5jOAMEEAIEEFwAn3kMwcB6I2AAAAAASUVORK5CYII='); 9 | cursor: ns-resize; 10 | } 11 | 12 | .gutter.gutter-horizontal { 13 | background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg=='); 14 | cursor: ew-resize; 15 | } 16 | -------------------------------------------------------------------------------- /docs/assets/style.css: -------------------------------------------------------------------------------- 1 | .documentation { 2 | font-family: Helvetica, sans-serif; 3 | color: #666; 4 | line-height: 1.5; 5 | background: #f5f5f5; 6 | } 7 | 8 | .black { 9 | color: #666; 10 | } 11 | 12 | .bg-white { 13 | background-color: #fff; 14 | } 15 | 16 | h4 { 17 | margin: 20px 0 10px 0; 18 | } 19 | 20 | .documentation h3 { 21 | color: #000; 22 | } 23 | 24 | .border-bottom { 25 | border-color: #ddd; 26 | } 27 | 28 | a { 29 | color: #1184ce; 30 | text-decoration: none; 31 | } 32 | 33 | .documentation a[href]:hover { 34 | text-decoration: underline; 35 | } 36 | 37 | a:hover { 38 | cursor: pointer; 39 | } 40 | 41 | .py1-ul li { 42 | padding: 5px 0; 43 | } 44 | 45 | .max-height-100 { 46 | max-height: 100%; 47 | } 48 | 49 | .height-viewport-100 { 50 | height: 100vh; 51 | } 52 | 53 | section:target h3 { 54 | font-weight: 700; 55 | } 56 | 57 | .documentation td, 58 | .documentation th { 59 | padding: 0.25rem 0.25rem; 60 | } 61 | 62 | h1:hover .anchorjs-link, 63 | h2:hover .anchorjs-link, 64 | h3:hover .anchorjs-link, 65 | h4:hover .anchorjs-link { 66 | opacity: 1; 67 | } 68 | 69 | .fix-3 { 70 | width: 25%; 71 | max-width: 244px; 72 | } 73 | 74 | .fix-3 { 75 | width: 25%; 76 | max-width: 244px; 77 | } 78 | 79 | @media (min-width: 52em) { 80 | .fix-margin-3 { 81 | margin-left: 25%; 82 | } 83 | } 84 | 85 | .pre, 86 | pre, 87 | code, 88 | .code { 89 | font-family: Source Code Pro, Menlo, Consolas, Liberation Mono, monospace; 90 | font-size: 14px; 91 | } 92 | 93 | .fill-light { 94 | background: #f9f9f9; 95 | } 96 | 97 | .width2 { 98 | width: 1rem; 99 | } 100 | 101 | .input { 102 | font-family: inherit; 103 | display: block; 104 | width: 100%; 105 | height: 2rem; 106 | padding: 0.5rem; 107 | margin-bottom: 1rem; 108 | border: 1px solid #ccc; 109 | font-size: 0.875rem; 110 | border-radius: 3px; 111 | box-sizing: border-box; 112 | } 113 | 114 | table { 115 | border-collapse: collapse; 116 | } 117 | 118 | .prose table th, 119 | .prose table td { 120 | text-align: left; 121 | padding: 8px; 122 | border: 1px solid #ddd; 123 | } 124 | 125 | .prose table th:nth-child(1) { 126 | border-right: none; 127 | } 128 | .prose table th:nth-child(2) { 129 | border-left: none; 130 | } 131 | 132 | .prose table { 133 | border: 1px solid #ddd; 134 | } 135 | 136 | .prose-big { 137 | font-size: 18px; 138 | line-height: 30px; 139 | } 140 | 141 | .quiet { 142 | opacity: 0.7; 143 | } 144 | 145 | .minishadow { 146 | box-shadow: 2px 2px 10px #f3f3f3; 147 | } 148 | -------------------------------------------------------------------------------- /docs/examples/assets/horizontal/bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/examples/assets/horizontal/bar.png -------------------------------------------------------------------------------- /docs/examples/assets/horizontal/sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/examples/assets/horizontal/sprite.png -------------------------------------------------------------------------------- /docs/examples/assets/horizontal/track.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/examples/assets/horizontal/track.png -------------------------------------------------------------------------------- /docs/examples/assets/modal/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/examples/assets/modal/background.png -------------------------------------------------------------------------------- /docs/examples/assets/modal/button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/examples/assets/modal/button.png -------------------------------------------------------------------------------- /docs/examples/assets/quantitybar/add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/examples/assets/quantitybar/add.png -------------------------------------------------------------------------------- /docs/examples/assets/quantitybar/horizontal/bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/examples/assets/quantitybar/horizontal/bar.png -------------------------------------------------------------------------------- /docs/examples/assets/quantitybar/horizontal/track.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/examples/assets/quantitybar/horizontal/track.png -------------------------------------------------------------------------------- /docs/examples/assets/quantitybar/subtract.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/examples/assets/quantitybar/subtract.png -------------------------------------------------------------------------------- /docs/examples/assets/quantitybar/vertical/bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/examples/assets/quantitybar/vertical/bar.png -------------------------------------------------------------------------------- /docs/examples/assets/quantitybar/vertical/track.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/examples/assets/quantitybar/vertical/track.png -------------------------------------------------------------------------------- /docs/examples/assets/textover/button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/examples/assets/textover/button.png -------------------------------------------------------------------------------- /docs/examples/assets/textover/header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/examples/assets/textover/header.png -------------------------------------------------------------------------------- /docs/examples/assets/valuebar/alpha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/examples/assets/valuebar/alpha.png -------------------------------------------------------------------------------- /docs/examples/assets/valuebar/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/examples/assets/valuebar/background.png -------------------------------------------------------------------------------- /docs/examples/assets/valuebar/bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/examples/assets/valuebar/bar.png -------------------------------------------------------------------------------- /docs/examples/assets/valuebar/pointer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/examples/assets/valuebar/pointer.png -------------------------------------------------------------------------------- /docs/examples/assets/valuebar/track.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/examples/assets/valuebar/track.png -------------------------------------------------------------------------------- /docs/examples/assets/valuebar/vtrack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/examples/assets/valuebar/vtrack.png -------------------------------------------------------------------------------- /docs/examples/assets/vertical/bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/examples/assets/vertical/bar.png -------------------------------------------------------------------------------- /docs/examples/assets/vertical/sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/examples/assets/vertical/sprite.png -------------------------------------------------------------------------------- /docs/examples/assets/vertical/track.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/examples/assets/vertical/track.png -------------------------------------------------------------------------------- /docs/examples/assets/wheel3D/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/examples/assets/wheel3D/icon.png -------------------------------------------------------------------------------- /docs/examples/assets/wheel3D/mmDown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/examples/assets/wheel3D/mmDown.png -------------------------------------------------------------------------------- /docs/examples/assets/wheel3D/mmUp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsfehler/phaser-ui-tools/f3306cf9aa5e95ea746001e8c48448d24c9c4af4/docs/examples/assets/wheel3D/mmUp.png -------------------------------------------------------------------------------- /docs/examples/html/phaser3/hscrollbar.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/examples/html/phaser3/modal.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/examples/html/phaser3/quantitybar.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/examples/html/phaser3/textover.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/examples/html/phaser3/valuebar.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/examples/html/phaser3/vscrollbar.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/examples/html/phaser3/wheel3D.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/examples/html/phaserce/hscrollbar.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/examples/html/phaserce/modal.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/examples/html/phaserce/quantitybar.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/examples/html/phaserce/quantitybar_column.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/examples/html/phaserce/textover.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/examples/html/phaserce/valuebar.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/examples/html/phaserce/valuebar_column.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/examples/html/phaserce/vscrollbar.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/examples/html/phaserce/wheel3D.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/examples/js/phaser3/hscrollbar.js: -------------------------------------------------------------------------------- 1 | var config = { 2 | type: Phaser.AUTO, 3 | width: 400, 4 | height: 300, 5 | scene: { 6 | preload: preload, 7 | create: create, 8 | update: update 9 | } 10 | }; 11 | 12 | var game = new Phaser.Game(config); 13 | 14 | function preload() { 15 | var assetRoot = '../../assets/horizontal/'; 16 | this.load.image('dummyButton', `${assetRoot}sprite.png`); 17 | this.load.image('track', `${assetRoot}track.png`); 18 | this.load.spritesheet('bar', `${assetRoot}bar.png`, { frameWidth: 44, frameHeight: 22 }); 19 | } 20 | 21 | function create() { 22 | var viewport = new uiWidgets.Viewport(this, 75, 75, 260, 128); 23 | var row = new uiWidgets.Row(this, 0, 0); 24 | 25 | viewport.addNode(row); 26 | 27 | // Add things to the row. 28 | var dummy_sprite_a = this.add.image(0, 0, 'dummyButton'); 29 | var dummy_sprite_b = this.add.image(0, 0, 'dummyButton'); 30 | var dummy_sprite_c = this.add.image(0, 0, 'dummyButton'); 31 | var dummy_sprite_d = this.add.image(0, 0, 'dummyButton'); 32 | var dummy_sprite_e = this.add.image(0, 0, 'dummyButton'); 33 | var dummy_sprite_f = this.add.image(0, 0, 'dummyButton'); 34 | var dummy_sprite_g = this.add.image(0, 0, 'dummyButton'); 35 | var dummy_sprite_h = this.add.image(0, 0, 'dummyButton'); 36 | var dummy_sprite_i = this.add.image(0, 0, 'dummyButton'); 37 | 38 | row.addNode(dummy_sprite_a); 39 | row.addNode(dummy_sprite_b); 40 | row.addNode(dummy_sprite_c); 41 | row.addNode(dummy_sprite_d); 42 | row.addNode(dummy_sprite_e); 43 | row.addNode(dummy_sprite_f); 44 | row.addNode(dummy_sprite_g); 45 | row.addNode(dummy_sprite_h); 46 | row.addNode(dummy_sprite_i); 47 | 48 | var scrollbar = new uiWidgets.Scrollbar( 49 | this, 50 | viewport, 51 | true, 52 | false, 53 | "track", 54 | "bar", 55 | {'duration': 300, 'ease': Phaser.Math.Easing.Quadratic.Out} 56 | ); 57 | 58 | Phaser.Display.Align.To.BottomCenter(scrollbar, viewport, 0, 128 + 10); 59 | 60 | } 61 | 62 | function update() {} 63 | -------------------------------------------------------------------------------- /docs/examples/js/phaser3/modal.js: -------------------------------------------------------------------------------- 1 | var config = { 2 | type: Phaser.AUTO, 3 | width: 400, 4 | height: 300, 5 | scene: { 6 | preload: preload, 7 | create: create, 8 | } 9 | }; 10 | 11 | var game = new Phaser.Game(config); 12 | 13 | var textStyle = {'fill': '#FFF', 'font': '16px Courier New'}; 14 | 15 | function preload() { 16 | var assetRoot = '../../assets/modal/'; 17 | this.load.image("modalBg", assetRoot + "background.png"); 18 | this.load.spritesheet('button', assetRoot + 'button.png', { frameWidth: 128, frameHeight: 48 }); 19 | } 20 | 21 | function create() { 22 | var openButton = new uiWidgets.TextButton(this, 100, 50, "button", createModal, this, 1, 0, 2, 1) 23 | .setText("Open", textStyle) 24 | .eventTextYAdjustment(3); 25 | } 26 | 27 | function createModal() { 28 | var closeButton = new uiWidgets.TextButton(this, 0, 0, "button", closeCallback, this, 1, 0, 2, 1) 29 | .setText("Close", textStyle) 30 | .eventTextYAdjustment(3); 31 | 32 | this.modal = new uiWidgets.Column(this, 100, 100, bg="modalBg", modal=true); 33 | this.modal.addNode(closeButton, paddingX=0, paddingY=10); 34 | } 35 | 36 | function closeCallback() { 37 | this.modal.dismiss(); 38 | } 39 | -------------------------------------------------------------------------------- /docs/examples/js/phaser3/quantitybar.js: -------------------------------------------------------------------------------- 1 | var config = { 2 | type: Phaser.AUTO, 3 | width: 600, 4 | height: 400, 5 | scene: { 6 | preload: preload, 7 | create: create, 8 | } 9 | }; 10 | 11 | var game = new Phaser.Game(config); 12 | 13 | function preload() { 14 | var assetRoot = '../../assets/quantitybar/'; 15 | this.load.image("track", assetRoot + "horizontal/track.png"); 16 | this.load.spritesheet('bar', assetRoot + 'horizontal/bar.png', { frameWidth: 260, frameHeight: 32 }); 17 | 18 | this.load.image("vtrack", assetRoot + "vertical/track.png"); 19 | this.load.spritesheet('vbar', assetRoot + 'vertical/bar.png', { frameWidth: 32, frameHeight: 260 }); 20 | 21 | this.load.image("add", assetRoot + "add.png"); 22 | this.load.image("subtract", assetRoot + "subtract.png"); 23 | } 24 | 25 | var healthbar, 26 | healthbarText, 27 | vhealthbar, 28 | vhealthbarText, 29 | rhealthbar, 30 | rhealthbarText, 31 | rvhealthbar, 32 | rvhealthbarText, 33 | decreaseHealth, 34 | increaseHealth, 35 | vdecreaseHealth, 36 | vincreaseHealth, 37 | rdecreaseHealth, 38 | rincreaseHealth, 39 | rvdecreaseHealth, 40 | rvincreaseHealth, 41 | textStyle; 42 | 43 | function create() { 44 | 45 | textStyle = { 46 | font: "65px Arial", 47 | fill: "#ff0044", 48 | align: "center" 49 | }; 50 | 51 | // Create a quantitybar starting at 50. 52 | healthbar = new uiWidgets.QuantityBar( 53 | this, 54 | {"x": 50, "y": 10}, 55 | {"startValue": 50, maxValue: 100}, 56 | false, 57 | false, 58 | "track", 59 | "bar", 60 | {'duration': 400, 'ease': Phaser.Math.Easing.Quadratic.Out} 61 | ); 62 | 63 | // Display the quantitybar's value. 64 | healthbarText = this.add.text(50, 50, healthbar.valueRange.startValue, textStyle); 65 | 66 | // Add buttons to modify the value. 67 | var lessHealth = new uiWidgets.Button(this, 150, 10, 'subtract', decreaseHealth, this); 68 | var moreHealth = new uiWidgets.Button(this, 200, 10, 'add', increaseHealth, this); 69 | 70 | // Create a reverse quantitybar starting at 30. 71 | rhealthbar = new uiWidgets.QuantityBar( 72 | this, 73 | {"x": 350, "y": 10}, 74 | {"startValue": 30, maxValue: 100}, 75 | false, 76 | true, 77 | "track", 78 | "bar", 79 | {'duration': 400, 'ease': Phaser.Math.Easing.Quadratic.Out} 80 | ); 81 | 82 | rhealthbarText = this.add.text(350, 50, rhealthbar.valueRange.startValue, textStyle); 83 | 84 | var rlessHealth = new uiWidgets.Button(this, 450, 10, 'subtract', rdecreaseHealth, this); 85 | var rmoreHealth = new uiWidgets.Button(this, 500, 10, 'add', rincreaseHealth, this); 86 | 87 | // Create a vertical quantitybar starting at 50. 88 | vhealthbar = new uiWidgets.QuantityBar( 89 | this, 90 | {"x": 30, "y": 130}, 91 | {"startValue": 32, maxValue: 100}, 92 | true, 93 | false, 94 | "vtrack", 95 | "vbar", 96 | {'duration': 400, 'ease': Phaser.Math.Easing.Quadratic.Out} 97 | ); 98 | 99 | vhealthbarText = this.add.text(100, 150, vhealthbar.valueRange.startValue, textStyle); 100 | 101 | var vlessHealth = new uiWidgets.Button(this, 100, 250, 'subtract', vdecreaseHealth, this); 102 | var vmoreHealth = new uiWidgets.Button(this, 150, 250, 'add', vincreaseHealth, this); 103 | 104 | // Create a reverse vertical quantitybar starting at 50. 105 | rvhealthbar = new uiWidgets.QuantityBar( 106 | this, 107 | {"x": 250, "y": 130}, 108 | {"startValue": 30, maxValue: 100}, 109 | true, 110 | true, 111 | "vtrack", 112 | "vbar", 113 | {'duration': 400, 'ease': Phaser.Math.Easing.Quadratic.Out} 114 | ); 115 | 116 | rvhealthbarText = this.add.text(300, 150, rvhealthbar.valueRange.startValue, textStyle); 117 | 118 | var vlessHealth = new uiWidgets.Button(this, 300, 250, 'subtract', rvdecreaseHealth, this); 119 | var vmoreHealth = new uiWidgets.Button(this, 350, 250, 'add', rvincreaseHealth, this); 120 | 121 | } 122 | 123 | function increaseHealth() { 124 | healthbar.adjustBar(10); 125 | healthbarText.setText(healthbar.valueRange.getCurrentValue()); 126 | } 127 | 128 | function decreaseHealth() { 129 | healthbar.adjustBar(-10); 130 | healthbarText.setText(healthbar.valueRange.getCurrentValue()); 131 | } 132 | 133 | function vincreaseHealth() { 134 | vhealthbar.adjustBar(1); 135 | vhealthbarText.setText(vhealthbar.valueRange.getCurrentValue()); 136 | } 137 | 138 | function vdecreaseHealth() { 139 | vhealthbar.adjustBar(-1); 140 | vhealthbarText.setText(vhealthbar.valueRange.getCurrentValue()); 141 | } 142 | 143 | function rincreaseHealth() { 144 | rhealthbar.adjustBar(10); 145 | rhealthbarText.setText(rhealthbar.valueRange.getCurrentValue()); 146 | } 147 | 148 | function rdecreaseHealth() { 149 | rhealthbar.adjustBar(-10); 150 | rhealthbarText.setText(rhealthbar.valueRange.getCurrentValue()); 151 | } 152 | 153 | function rvincreaseHealth() { 154 | rvhealthbar.adjustBar(10); 155 | rvhealthbarText.setText(rvhealthbar.valueRange.getCurrentValue()); 156 | } 157 | 158 | function rvdecreaseHealth() { 159 | rvhealthbar.adjustBar(-10); 160 | rvhealthbarText.setText(rvhealthbar.valueRange.getCurrentValue()); 161 | } 162 | -------------------------------------------------------------------------------- /docs/examples/js/phaser3/textover.js: -------------------------------------------------------------------------------- 1 | var config = { 2 | type: Phaser.AUTO, 3 | width: 400, 4 | height: 300, 5 | scene: { 6 | preload: preload, 7 | create: create, 8 | } 9 | }; 10 | 11 | var game = new Phaser.Game(config); 12 | 13 | var textStyle = {'fill': '#FFF', 'font': '16px Courier New'}; 14 | 15 | function preload() { 16 | var assetRoot = '../../assets/textover/'; 17 | this.load.image("header", assetRoot + "header.png"); 18 | this.load.spritesheet('button', assetRoot + 'button.png', { frameWidth: 128, frameHeight: 48 }); 19 | } 20 | 21 | function create() { 22 | this.header = new uiWidgets.TextSprite(this, 0, 0, "header").setText('Header', textStyle).setOrigin(0.0, 0.0); 23 | 24 | var buttonOne = new uiWidgets.TextButton(this, 0, 0, "button", newGameCallback, this, 1, 0, 2, 1) 25 | .setText("New Game", textStyle) 26 | .eventTextYAdjustment(3); 27 | var buttonTwo = new uiWidgets.TextButton(this, 0, 0, "button", continueCallback, this, 1, 0, 2, 1) 28 | .setText("Continue", textStyle) 29 | .eventTextYAdjustment(3); 30 | var buttonThree = new uiWidgets.TextButton(this, 0, 0, "button", optionsCallback, this, 1, 0, 2, 1) 31 | .setText("Options", textStyle) 32 | .eventTextYAdjustment(3); 33 | 34 | var column = new uiWidgets.Column(this, 200, 100); 35 | column.addNode(buttonOne, paddingX=0, paddingY=10); 36 | column.addNode(buttonTwo, paddingX=0, paddingY=10); 37 | column.addNode(buttonThree, paddingX=0, paddingY=10); 38 | 39 | } 40 | 41 | function newGameCallback() { 42 | this.header.text.setText('You clicked the New Game button'); 43 | } 44 | 45 | 46 | function continueCallback() { 47 | this.header.text.setText('You clicked the Continue button'); 48 | } 49 | 50 | 51 | function optionsCallback() { 52 | this.header.text.setText('You clicked the Options button'); 53 | } 54 | -------------------------------------------------------------------------------- /docs/examples/js/phaser3/valuebar.js: -------------------------------------------------------------------------------- 1 | var config = { 2 | type: Phaser.AUTO, 3 | width: 600, 4 | height: 400, 5 | scene: { 6 | preload: preload, 7 | create: create, 8 | } 9 | }; 10 | 11 | var game = new Phaser.Game(config); 12 | 13 | function preload() { 14 | var assetRoot = '../../assets/valuebar/'; 15 | this.load.image("track", assetRoot + "track.png"); 16 | this.load.spritesheet('bar', assetRoot + 'bar.png', { frameWidth: 32, frameHeight: 32 }); 17 | this.load.image("vtrack", assetRoot + "vtrack.png"); 18 | this.load.image("alphaImage", assetRoot + "alpha.png"); 19 | } 20 | 21 | var valuebar0; 22 | var valuebar50; 23 | var vvaluebar50; 24 | var valuebar0_text; 25 | var valuebar50_text; 26 | var vvaluebar50_text; 27 | var alphaImage; 28 | 29 | function create() { 30 | 31 | // Create a valuebar starting at 0. 32 | valuebar0 = new uiWidgets.ValueBar( 33 | this, 34 | {"x": 50, "y": 10}, 35 | {"step": 1, "startValue": 0, maxValue: 100}, 36 | true, 37 | false, 38 | "track", 39 | "bar", 40 | {'duration': 100, 'ease': Phaser.Math.Easing.Quadratic.Out} 41 | ); 42 | 43 | valuebar0_text = this.add.text(50, 50, valuebar0.valueRange.startValue, { 44 | font: "65px Arial", 45 | fill: "#ff0044", 46 | align: "center" 47 | }); 48 | 49 | valuebar0.valueDisplay = valuebar0_text; 50 | 51 | // Use the onMovement signal to update the display of text when the bar is moved. 52 | valuebar0.emitter.on('movement', updateValueDisplay); 53 | 54 | // Create a valuebar starting at 50. 55 | valuebar50 = new uiWidgets.ValueBar( 56 | this, 57 | {"x": 50, "y": 150}, 58 | {"step": 25, "startValue": 50, maxValue: 100}, 59 | true, 60 | false, 61 | "track", 62 | "bar", 63 | {'duration': 100, 'ease': Phaser.Math.Easing.Quadratic.Out} 64 | ); 65 | 66 | valuebar50_text = this.add.text(50, 200, valuebar50.valueRange.startValue, { 67 | font: "65px Arial", 68 | fill: "#ff0044", 69 | align: "center" 70 | }); 71 | 72 | valuebar50.valueDisplay = valuebar50_text; 73 | valuebar50.emitter.on('movement', updateValueDisplay); 74 | 75 | // Create a vertical valuebar starting at 50. 76 | vvaluebar50 = new uiWidgets.ValueBar( 77 | this, 78 | {"x": 350, "y": 50}, 79 | {"step": 25, "startValue": 50, maxValue: 100}, 80 | true, 81 | true, 82 | "vtrack", 83 | "bar", 84 | {'duration': 100, 'ease': Phaser.Math.Easing.Quadratic.Out} 85 | ); 86 | 87 | vvaluebar50_text = this.add.text(400, 200, valuebar50.valueRange.startValue, { 88 | font: "65px Arial", 89 | fill: "#ff0044", 90 | align: "center" 91 | }); 92 | 93 | vvaluebar50.valueDisplay = vvaluebar50_text; 94 | vvaluebar50.emitter.on('movement', updateValueDisplay); 95 | 96 | alphaImage = this.add.sprite(500, 100, "alphaImage"); 97 | alphaImage.alpha = vvaluebar50.valueRange.getCurrentValue() / 100; 98 | 99 | // Use the onMovement signal to updte the sprite's opacity whenever the bar is moved. 100 | vvaluebar50.emitter.on('movement', updateAlpha); 101 | } 102 | 103 | function updateValueDisplay(bar) { 104 | bar.valueDisplay.setText(bar.valueRange.getCurrentValue()); 105 | } 106 | 107 | function updateAlpha(bar) { 108 | alphaImage.alpha = bar.valueRange.getCurrentValue() / 100; 109 | } 110 | -------------------------------------------------------------------------------- /docs/examples/js/phaser3/vscrollbar.js: -------------------------------------------------------------------------------- 1 | var config = { 2 | type: Phaser.AUTO, 3 | width: 600, 4 | height: 400, 5 | scene: { 6 | preload: preload, 7 | create: create, 8 | } 9 | }; 10 | 11 | var game = new Phaser.Game(config); 12 | 13 | function preload() { 14 | var assetRoot = '../../assets/vertical/'; 15 | this.load.image("dummyButton", assetRoot + "sprite.png"); 16 | this.load.image("track", assetRoot + "track.png"); 17 | this.load.spritesheet('bar', assetRoot + 'bar.png', { frameWidth: 22, frameHeight: 44 }); 18 | 19 | } 20 | 21 | function create() { 22 | 23 | // Create a viewport. A "window" with a limited area of view. 24 | var viewport = new uiWidgets.Viewport(this, 75, 75, 600, 260); 25 | 26 | // Create a column. Anything added to a column is placed under the previous thing added. 27 | var column = new uiWidgets.Column(this); 28 | 29 | // Put the column inside the viewport. 30 | viewport.addNode(column); 31 | 32 | // Add things to the column. 33 | var dummy_sprite_a = this.add.image(0, 0, "dummyButton"); 34 | var dummy_sprite_b = this.add.image(0, 0, "dummyButton"); 35 | var dummy_sprite_c = this.add.image(0, 0, "dummyButton"); 36 | var dummy_sprite_d = this.add.image(0, 0, "dummyButton"); 37 | var dummy_sprite_e = this.add.image(0, 0, "dummyButton"); 38 | var dummy_sprite_f = this.add.image(0, 0, "dummyButton"); 39 | 40 | column.addNode(dummy_sprite_a); 41 | column.addNode(dummy_sprite_b); 42 | column.addNode(dummy_sprite_c); 43 | column.addNode(dummy_sprite_d); 44 | column.addNode(dummy_sprite_e); 45 | column.addNode(dummy_sprite_f); 46 | 47 | // Create a scrollbar for the viewport. 48 | var scrollbar = new uiWidgets.Scrollbar( 49 | this, 50 | viewport, 51 | true, 52 | true, 53 | "track", 54 | "bar", 55 | {'duration': 300, 'ease': Phaser.Math.Easing.Quadratic.Out} 56 | ); 57 | 58 | // Place scrollbar next to viewport. 59 | Phaser.Display.Align.To.RightCenter(scrollbar, viewport, 300 + 10, 0); 60 | 61 | } 62 | -------------------------------------------------------------------------------- /docs/examples/js/phaser3/wheel3D.js: -------------------------------------------------------------------------------- 1 | var config = { 2 | type: Phaser.AUTO, 3 | width: 600, 4 | height: 400, 5 | scene: { 6 | preload: preload, 7 | create: create, 8 | } 9 | }; 10 | 11 | var game = new Phaser.Game(config); 12 | 13 | function preload() { 14 | var assetRoot = '../../assets/wheel3D/'; 15 | this.load.image("icon", assetRoot + "icon.png"); 16 | this.load.image("mmUp", assetRoot + "mmUp.png"); 17 | this.load.image("mmDown", assetRoot + "mmDown.png"); 18 | } 19 | 20 | function create() { 21 | 22 | var centerX = this.cameras.main.centerX; 23 | var centerY = this.cameras.main.centerY; 24 | 25 | // Example 1: Rotate around the Y axis 26 | 27 | // Build a list of sprites for the wheel. 28 | var menuListY = []; 29 | 30 | for (var i = 0; i < 12; i++) { 31 | var icon = this.add.sprite(0, 0, 'icon'); 32 | menuListY.push(icon); 33 | } 34 | 35 | // Create the wheel. 36 | menuWheelY = new uiWidgets.Wheel3D( 37 | this, 38 | {"x": centerX - 100, "y": centerY}, 39 | menuListY, 40 | 0, 41 | 90, 42 | "y", 43 | {"x":0, "y": -90, "z": 0} 44 | ); 45 | 46 | // Tint the active item after each movement. 47 | menuWheelY.emitter.on('complete', 48 | function(wheel) { 49 | for (var i = 0; i < 12; i++) { 50 | wheel.sprites[i].tint = 0xFFFFFF; 51 | } 52 | wheel.active.tint = 0xdc21ff; 53 | } 54 | ); 55 | 56 | menuWheelY.activate(); 57 | 58 | // Scroll Buttons 59 | var scrollLeftButtonY = new uiWidgets.Button( 60 | this, 61 | 0, 62 | centerY, 63 | "mmUp", 64 | scrollTheWheel, 65 | null, 66 | ); 67 | scrollLeftButtonY.wheel = menuWheelY; 68 | scrollLeftButtonY.dir = 0; 69 | 70 | var scrollRightButtonY = new uiWidgets.Button( 71 | this, 72 | 0, 73 | centerY + 48, 74 | "mmDown", 75 | scrollTheWheel, 76 | null, 77 | ); 78 | scrollRightButtonY.wheel = menuWheelY; 79 | scrollRightButtonY.dir = 1; 80 | 81 | // Example 2: Rotate around the X axis 82 | var menuListX = []; 83 | 84 | for (var i = 0; i < 12; i++) { 85 | var icon = this.add.sprite(0, 0, 'icon'); 86 | menuListX.push(icon); 87 | } 88 | 89 | // Create the wheel. 90 | menuWheelX = new uiWidgets.Wheel3D( 91 | this, 92 | {"x": centerX - 100, "y": 100}, 93 | menuListX, 94 | 0, 95 | 90, 96 | "x", 97 | {"x": 90, "y": 0, "z": 0} 98 | ); 99 | 100 | // Tint the active item after each movement. 101 | menuWheelX.emitter.on('complete', 102 | function(wheel) { 103 | for (var i = 0; i < 12; i++) { 104 | wheel.sprites[i].tint = 0xFFFFFF; 105 | } 106 | wheel.active.tint = 0xdc21ff; 107 | } 108 | ); 109 | 110 | menuWheelX.activate(); 111 | 112 | // Scroll Buttons 113 | var scrollLeftButtonX = new uiWidgets.Button( 114 | this, 115 | 0, 116 | 0, 117 | "mmUp", 118 | scrollTheWheel, 119 | null, 120 | ); 121 | scrollLeftButtonX.wheel = menuWheelX; 122 | scrollLeftButtonX.dir = 0; 123 | 124 | var scrollRightButtonX = new uiWidgets.Button( 125 | this, 126 | 0, 127 | 48, 128 | "mmDown", 129 | scrollTheWheel, 130 | null, 131 | ); 132 | scrollRightButtonX.wheel = menuWheelX; 133 | scrollRightButtonX.dir = 1; 134 | 135 | // Example 3: Rotate around the Z axis 136 | var menuListZ = []; 137 | 138 | for (var i = 0; i < 12; i++) { 139 | var icon = this.add.sprite(0, 0, 'icon'); 140 | menuListZ.push(icon); 141 | } 142 | 143 | // Create the wheel. 144 | menuWheelZ = new uiWidgets.Wheel3D( 145 | this, 146 | {"x": centerX, "y": 100}, 147 | menuListZ, 148 | 0, 149 | 90, 150 | "z", 151 | {"x": 0, "y": 0, "z": 90} 152 | ); 153 | 154 | menuWheelZ.emitter.on('start', 155 | function(wheel) { 156 | for (var i = 0; i < 12; i++) { 157 | wheel.sprites[i].tint = 0xFFFFFF; 158 | } 159 | wheel.active.tint = 0xdc21ff; 160 | } 161 | ); 162 | 163 | menuWheelZ.activate(); 164 | 165 | // Scroll Buttons 166 | var scrollLeftButtonZ = new uiWidgets.Button( 167 | this, 168 | this.cameras.main.width - 100, 169 | 0, 170 | "mmUp", 171 | scrollTheWheel, 172 | null, 173 | ); 174 | scrollLeftButtonZ.wheel = menuWheelZ; 175 | scrollLeftButtonZ.dir = 0; 176 | 177 | var scrollRightButtonZ = new uiWidgets.Button( 178 | this, 179 | this.cameras.main.width - 100, 180 | 48, 181 | "mmDown", 182 | scrollTheWheel, 183 | null, 184 | ); 185 | scrollRightButtonZ.wheel = menuWheelZ; 186 | scrollRightButtonZ.dir = 1; 187 | } 188 | 189 | var scrollTheWheel = function () { 190 | if (this.dir === 0){ 191 | this.wheel.moveBack(); 192 | } 193 | if (this.dir === 1){ 194 | this.wheel.moveForward(); 195 | } 196 | }; 197 | -------------------------------------------------------------------------------- /docs/examples/js/phaserce/hscrollbar.js: -------------------------------------------------------------------------------- 1 | var game = new Phaser.Game(400, 300, Phaser.AUTO, 'hscrollbar', { preload: preload, create: create }); 2 | 3 | function preload() { 4 | var assetRoot = '../../assets/horizontal/'; 5 | game.load.image("dummyButton", assetRoot + "sprite.png"); 6 | game.load.image("track", assetRoot + "track.png"); 7 | game.load.spritesheet('bar', assetRoot + 'bar.png', 44, 22); 8 | } 9 | 10 | function create() { 11 | // Create a viewport. A "window" with a limited area of view. 12 | var viewport = new uiWidgets.Viewport(game, 75, 75, 260, 128); 13 | 14 | // Create a row. Anything added to a row is placed next to the previous thing added. 15 | var row = new uiWidgets.Row(game); 16 | 17 | // Put the row inside the viewport. 18 | viewport.addNode(row); 19 | 20 | // Add things to the row. 21 | var dummy_sprite_a = this.game.add.sprite(0, 0, "dummyButton"); 22 | var dummy_sprite_b = this.game.add.sprite(0, 0, "dummyButton"); 23 | var dummy_sprite_c = this.game.add.sprite(0, 0, "dummyButton"); 24 | var dummy_sprite_d = this.game.add.sprite(0, 0, "dummyButton"); 25 | var dummy_sprite_e = this.game.add.sprite(0, 0, "dummyButton"); 26 | var dummy_sprite_f = this.game.add.sprite(0, 0, "dummyButton"); 27 | var dummy_sprite_g = this.game.add.sprite(0, 0, "dummyButton"); 28 | var dummy_sprite_h = this.game.add.sprite(0, 0, "dummyButton"); 29 | var dummy_sprite_i = this.game.add.sprite(0, 0, "dummyButton"); 30 | 31 | row.addNode(dummy_sprite_a); 32 | row.addNode(dummy_sprite_b); 33 | row.addNode(dummy_sprite_c); 34 | row.addNode(dummy_sprite_d); 35 | row.addNode(dummy_sprite_e); 36 | row.addNode(dummy_sprite_f); 37 | row.addNode(dummy_sprite_g); 38 | row.addNode(dummy_sprite_h); 39 | row.addNode(dummy_sprite_i); 40 | 41 | // Create a scrollbar for the viewport. 42 | var scrollbar = new uiWidgets.Scrollbar( 43 | game, 44 | viewport, 45 | true, 46 | false, 47 | "track", 48 | "bar", 49 | {'duration': 300, 'ease': Phaser.Easing.Quadratic.Out} 50 | ); 51 | 52 | // Place scrollbar below viewport. 53 | scrollbar.alignTo(viewport, Phaser.BOTTOM_LEFT, 0, 10); 54 | } 55 | -------------------------------------------------------------------------------- /docs/examples/js/phaserce/modal.js: -------------------------------------------------------------------------------- 1 | var game = new Phaser.Game( 2 | 400, 3 | 300, 4 | Phaser.AUTO, 5 | 'textover', 6 | {preload: preload, create: create}, 7 | false, 8 | false, 9 | ); 10 | 11 | var textStyle = {'fill': '#FFF', 'font': '16px Courier New'}; 12 | 13 | function preload() { 14 | var assetRoot = '../../assets/modal/'; 15 | game.load.image("modalBg", assetRoot + "background.png"); 16 | game.load.spritesheet('button', assetRoot + 'button.png', 128, 48); 17 | } 18 | 19 | function create() { 20 | var openButton = new uiWidgets.TextButton(this.game, 100, 50, "button", createModal, this, 1, 0, 2, 1) 21 | .setText("Open", textStyle) 22 | .eventTextYAdjustment(3); 23 | 24 | console.log(openButton.x, openButton.button.x, openButton.text.x) 25 | 26 | } 27 | 28 | function createModal() { 29 | var closeButton = new uiWidgets.TextButton(this.game, 0, 0, "button", closeCallback, this, 1, 0, 2, 1) 30 | .setText("Close", textStyle) 31 | .eventTextYAdjustment(3); 32 | 33 | this.modal = new uiWidgets.Column(this.game, 100, 100, bg="modalBg", modal=true); 34 | this.modal.addNode(closeButton, paddingX=0, paddingY=10); 35 | } 36 | 37 | function closeCallback() { 38 | this.modal.dismiss(); 39 | } 40 | -------------------------------------------------------------------------------- /docs/examples/js/phaserce/quantitybar.js: -------------------------------------------------------------------------------- 1 | var game = new Phaser.Game(600, 400, Phaser.AUTO, 'quantitybar', { preload: preload, create: create}); 2 | 3 | function preload() { 4 | var assetRoot = '../../assets/quantitybar/'; 5 | game.load.image("track", assetRoot + "horizontal/track.png"); 6 | game.load.spritesheet('bar', assetRoot + 'horizontal/bar.png', 260, 32); 7 | 8 | game.load.image("vtrack", assetRoot + "vertical/track.png"); 9 | game.load.spritesheet('vbar', assetRoot + 'vertical/bar.png', 32, 260); 10 | 11 | game.load.image("add", assetRoot + "add.png"); 12 | game.load.image("subtract", assetRoot + "subtract.png"); 13 | } 14 | 15 | var healthbar, 16 | healthbarText, 17 | vhealthbar, 18 | vhealthbarText, 19 | rhealthbar, 20 | rhealthbarText, 21 | rvhealthbar, 22 | rvhealthbarText, 23 | decreaseHealth, 24 | increaseHealth, 25 | vdecreaseHealth, 26 | vincreaseHealth, 27 | rdecreaseHealth, 28 | rincreaseHealth, 29 | rvdecreaseHealth, 30 | rvincreaseHealth, 31 | textStyle; 32 | 33 | function create() { 34 | 35 | textStyle = { 36 | font: "65px Arial", 37 | fill: "#ff0044", 38 | align: "center" 39 | }; 40 | 41 | // Create a quantitybar starting at 50. 42 | healthbar = new uiWidgets.QuantityBar( 43 | game, 44 | {"x": 50, "y": 10}, 45 | {"startValue": 50, maxValue: 100}, 46 | false, 47 | false, 48 | "track", 49 | "bar", 50 | {'duration': 400, 'ease': Phaser.Easing.Quadratic.Out} 51 | ); 52 | 53 | // Display the quantitybar's value. 54 | healthbarText = game.add.text(50, 50, healthbar.valueRange.startValue, textStyle); 55 | 56 | // Add buttons to modify the value. 57 | var lessHealth = game.add.button(150, 10, 'subtract', decreaseHealth, this); 58 | var moreHealth = game.add.button(200, 10, 'add', increaseHealth, this); 59 | 60 | // Create a reverse quantitybar starting at 30. 61 | rhealthbar = new uiWidgets.QuantityBar( 62 | game, 63 | {"x": 350, "y": 10}, 64 | {"startValue": 30, maxValue: 100}, 65 | false, 66 | true, 67 | "track", 68 | "bar", 69 | {'duration': 400, 'ease': Phaser.Easing.Quadratic.Out} 70 | ); 71 | 72 | rhealthbarText = game.add.text(350, 50, rhealthbar.valueRange.startValue, textStyle); 73 | 74 | var rlessHealth = game.add.button(450, 10, 'subtract', rdecreaseHealth, this); 75 | var rmoreHealth = game.add.button(500, 10, 'add', rincreaseHealth, this); 76 | 77 | // Create a vertical quantitybar starting at 50. 78 | vhealthbar = new uiWidgets.QuantityBar( 79 | game, 80 | {"x": 30, "y": 130}, 81 | {"startValue": 32, maxValue: 100}, 82 | true, 83 | false, 84 | "vtrack", 85 | "vbar", 86 | {'duration': 400, 'ease': Phaser.Easing.Quadratic.Out} 87 | ); 88 | 89 | vhealthbarText = game.add.text(100, 150, vhealthbar.valueRange.startValue, textStyle); 90 | 91 | var vlessHealth = game.add.button(100, 250, 'subtract', vdecreaseHealth, this); 92 | var vmoreHealth = game.add.button(150, 250, 'add', vincreaseHealth, this); 93 | 94 | // Create a reverse vertical quantitybar starting at 50. 95 | rvhealthbar = new uiWidgets.QuantityBar( 96 | game, 97 | {"x": 250, "y": 130}, 98 | {"startValue": 30, maxValue: 100}, 99 | true, 100 | true, 101 | "vtrack", 102 | "vbar", 103 | {'duration': 400, 'ease': Phaser.Easing.Quadratic.Out} 104 | ); 105 | 106 | rvhealthbarText = game.add.text(300, 150, rvhealthbar.valueRange.startValue, textStyle); 107 | 108 | var vlessHealth = game.add.button(300, 250, 'subtract', rvdecreaseHealth, this); 109 | var vmoreHealth = game.add.button(350, 250, 'add', rvincreaseHealth, this); 110 | 111 | } 112 | 113 | function increaseHealth() { 114 | healthbar.adjustBar(10); 115 | healthbarText.setText(healthbar.valueRange.getCurrentValue()); 116 | } 117 | 118 | function decreaseHealth() { 119 | healthbar.adjustBar(-10); 120 | healthbarText.setText(healthbar.valueRange.getCurrentValue()); 121 | } 122 | 123 | function vincreaseHealth() { 124 | vhealthbar.adjustBar(1); 125 | vhealthbarText.setText(vhealthbar.valueRange.getCurrentValue()); 126 | } 127 | 128 | function vdecreaseHealth() { 129 | vhealthbar.adjustBar(-1); 130 | vhealthbarText.setText(vhealthbar.valueRange.getCurrentValue()); 131 | } 132 | 133 | function rincreaseHealth() { 134 | rhealthbar.adjustBar(10); 135 | rhealthbarText.setText(rhealthbar.valueRange.getCurrentValue()); 136 | } 137 | 138 | function rdecreaseHealth() { 139 | rhealthbar.adjustBar(-10); 140 | rhealthbarText.setText(rhealthbar.valueRange.getCurrentValue()); 141 | } 142 | 143 | function rvincreaseHealth() { 144 | rvhealthbar.adjustBar(10); 145 | rvhealthbarText.setText(rvhealthbar.valueRange.getCurrentValue()); 146 | } 147 | 148 | function rvdecreaseHealth() { 149 | rvhealthbar.adjustBar(-10); 150 | rvhealthbarText.setText(rvhealthbar.valueRange.getCurrentValue()); 151 | } 152 | -------------------------------------------------------------------------------- /docs/examples/js/phaserce/quantitybar_column.js: -------------------------------------------------------------------------------- 1 | var game = new Phaser.Game(600, 400, Phaser.AUTO, 'quantitybar_column', { preload: preload, create: create, update: update }); 2 | 3 | function preload() { 4 | var assetRoot = '../../assets/quantitybar/horizontal/'; 5 | game.load.image("track", assetRoot + "track.png"); 6 | game.load.image('bar', assetRoot + 'bar.png'); 7 | 8 | game.load.image("add", assetRoot + "add.png"); 9 | game.load.image("subtract", assetRoot + "subtract.png"); 10 | } 11 | 12 | var healthbar; 13 | var healthbarText; 14 | var lessHealth; 15 | var moreHealth; 16 | var column; 17 | 18 | function create() { 19 | 20 | // Create a quantitybar starting at 50. 21 | healthbar = new uiWidgets.QuantityBar( 22 | game, 23 | {"x": 0, "y": 0}, 24 | {"startValue": 50, maxValue: 100}, 25 | false, 26 | false, 27 | "track", 28 | "bar", 29 | {'duration': 400, 'ease': Phaser.Easing.Quadratic.Out} 30 | ); 31 | 32 | healthbarText = game.add.text(50, 50, healthbar.valueRange.minValue, { 33 | font: "65px Arial", 34 | fill: "#ff0044", 35 | align: "center" 36 | }); 37 | 38 | lessHealth = game.add.button(150, 10, 'subtract', decreaseHealth, this); 39 | moreHealth = game.add.button(200, 10, 'add', increaseHealth, this); 40 | 41 | column = new uiWidgets.Column(game, 30, 0); 42 | column.addNode(healthbar); 43 | column.addNode(healthbarText); 44 | console.log("a", healthbar.track.x, healthbar.track.worldPosition.x) 45 | console.log("b", healthbar.bar.x, healthbar.bar.worldPosition.x) 46 | console.log("c", healthbar.x, healthbar.worldPosition.x) 47 | //console.log(healthbar.bar.mask.x, healthbar.bar.mask.worldPosition.x) 48 | //healthbar.bar.mask.x = 30 49 | //healthbar.bar.mask.y = 30 50 | 51 | } 52 | 53 | function update() { 54 | healthbarText.setText(healthbar.valueRange.getCurrentValue()); 55 | } 56 | 57 | function increaseHealth() { 58 | healthbar.adjustBar(10); 59 | 60 | } 61 | 62 | function decreaseHealth() { 63 | healthbar.adjustBar(-10); 64 | } 65 | -------------------------------------------------------------------------------- /docs/examples/js/phaserce/textover.js: -------------------------------------------------------------------------------- 1 | var game = new Phaser.Game( 2 | 400, 3 | 300, 4 | Phaser.AUTO, 5 | 'textover', 6 | {preload: preload, create: create}, 7 | false, 8 | false, 9 | ); 10 | 11 | var textStyle = {'fill': '#FFF', 'font': '16px Courier New'}; 12 | 13 | function preload() { 14 | var assetRoot = '../../assets/textover/'; 15 | game.load.image("header", assetRoot + "header.png"); 16 | game.load.spritesheet('button', assetRoot + 'button.png', 128, 48); 17 | } 18 | 19 | function create() { 20 | this.header = new uiWidgets.TextSprite(game, 0, 0, "header").setText('Header', textStyle); 21 | 22 | var buttonOne = new uiWidgets.TextButton(game, 0, 0, "button", newGameCallback, this, 1, 0, 2, 1) 23 | .setText("New Game", textStyle) 24 | .eventTextYAdjustment(3); 25 | var buttonTwo = new uiWidgets.TextButton(game, 0, 0, "button", continueCallback, this, 1, 0, 2, 1) 26 | .setText("Continue", textStyle) 27 | .eventTextYAdjustment(3); 28 | var buttonThree = new uiWidgets.TextButton(game, 0, 0, "button", optionsCallback, this, 1, 0, 2, 1) 29 | .setText("Options", textStyle) 30 | .eventTextYAdjustment(3); 31 | 32 | var column = new uiWidgets.Column(this, 200, 100); 33 | column.addNode(buttonOne, paddingX=0, paddingY=10); 34 | column.addNode(buttonTwo, paddingX=0, paddingY=10); 35 | column.addNode(buttonThree, paddingX=0, paddingY=10); 36 | 37 | } 38 | 39 | function newGameCallback() { 40 | this.header.text.setText('You clicked the New Game button'); 41 | } 42 | 43 | 44 | function continueCallback() { 45 | this.header.text.setText('You clicked the Continue button'); 46 | } 47 | 48 | 49 | function optionsCallback() { 50 | this.header.text.setText('You clicked the Options button'); 51 | } 52 | -------------------------------------------------------------------------------- /docs/examples/js/phaserce/valuebar.js: -------------------------------------------------------------------------------- 1 | var game = new Phaser.Game(600, 400, Phaser.AUTO, 'valuebar', { preload: preload, create: create }); 2 | 3 | function preload() { 4 | var assetRoot = '../../assets/valuebar/'; 5 | game.load.image("track", assetRoot + "track.png"); 6 | game.load.spritesheet('bar', assetRoot + 'bar.png', 32, 32); 7 | game.load.image("vtrack", assetRoot + "vtrack.png"); 8 | game.load.image("alphaImage", assetRoot + "alpha.png"); 9 | } 10 | 11 | var valuebar0; 12 | var valuebar50; 13 | var vvaluebar50; 14 | var valuebar0_text; 15 | var valuebar50_text; 16 | var vvaluebar50_text; 17 | var alphaImage; 18 | 19 | function create() { 20 | 21 | // Create a valuebar starting at 0. 22 | valuebar0 = new uiWidgets.ValueBar( 23 | game, 24 | {"x": 50, "y": 10}, 25 | {"step": 1, "startValue": 0, maxValue: 100}, 26 | true, 27 | false, 28 | "track", 29 | "bar", 30 | {'duration': 100, 'ease': Phaser.Easing.Quadratic.Out} 31 | ); 32 | 33 | valuebar0_text = game.add.text(50, 50, valuebar0.valueRange.startValue, { 34 | font: "65px Arial", 35 | fill: "#ff0044", 36 | align: "center" 37 | }); 38 | 39 | valuebar0.valueDisplay = valuebar0_text; 40 | 41 | // Use the onMovement signal to update the display of text when the bar is moved. 42 | valuebar0.emitter.on('movement', updateValueDisplay); 43 | 44 | // Create a valuebar starting at 50. 45 | valuebar50 = new uiWidgets.ValueBar( 46 | game, 47 | {"x": 50, "y": 150}, 48 | {"step": 25, "startValue": 50, maxValue: 100}, 49 | true, 50 | false, 51 | "track", 52 | "bar", 53 | {'duration': 100, 'ease': Phaser.Easing.Quadratic.Out} 54 | ); 55 | 56 | valuebar50_text = game.add.text(50, 200, valuebar50.valueRange.startValue, { 57 | font: "65px Arial", 58 | fill: "#ff0044", 59 | align: "center" 60 | }); 61 | 62 | valuebar50.valueDisplay = valuebar50_text; 63 | valuebar50.emitter.on('movement', updateValueDisplay); 64 | 65 | // Create a vertical valuebar starting at 50. 66 | vvaluebar50 = new uiWidgets.ValueBar( 67 | game, 68 | {"x": 350, "y": 50}, 69 | {"step": 25, "startValue": 50, maxValue: 100}, 70 | true, 71 | true, 72 | "vtrack", 73 | "bar", 74 | {'duration': 100, 'ease': Phaser.Easing.Quadratic.Out} 75 | ); 76 | 77 | vvaluebar50_text = game.add.text(400, 200, valuebar50.valueRange.startValue, { 78 | font: "65px Arial", 79 | fill: "#ff0044", 80 | align: "center" 81 | }); 82 | 83 | vvaluebar50.valueDisplay = vvaluebar50_text; 84 | vvaluebar50.emitter.on('movement', updateValueDisplay); 85 | 86 | alphaImage = game.add.sprite(500, 100, "alphaImage"); 87 | alphaImage.alpha = vvaluebar50.valueRange.getCurrentValue() / 100; 88 | 89 | // Use the onMovement signal to updte the sprite's opacity whenever the bar is moved. 90 | vvaluebar50.emitter.on('movement', updateAlpha); 91 | } 92 | 93 | function updateValueDisplay(bar) { 94 | bar.valueDisplay.setText(bar.valueRange.getCurrentValue()); 95 | } 96 | 97 | function updateAlpha(bar) { 98 | alphaImage.alpha = bar.valueRange.getCurrentValue() / 100; 99 | } 100 | -------------------------------------------------------------------------------- /docs/examples/js/phaserce/valuebar_column.js: -------------------------------------------------------------------------------- 1 | var game = new Phaser.Game(600, 400, Phaser.AUTO, 'valuebar_column', { preload: preload, create: create }); 2 | 3 | function preload() { 4 | var assetRoot = '../../assets/valuebar/'; 5 | game.load.image("bg", assetRoot + "background.png"); 6 | game.load.image("track", assetRoot + "track.png"); 7 | game.load.spritesheet('bar', assetRoot + 'bar.png', 32, 32); 8 | game.load.image("pointer", assetRoot + "pointer.png"); 9 | 10 | game.load.image("vtrack", "assets/valuebar/vtrack.png"); 11 | } 12 | 13 | var bar; 14 | var bar2; 15 | var barText; 16 | var barText2; 17 | var lessHealth; 18 | var moreHealth; 19 | var column; 20 | var keyboardGroup; 21 | var cursor; 22 | 23 | function create() { 24 | // Create a quantitybar starting at 50. 25 | bar = new uiWidgets.ValueBar( 26 | game, 27 | {"x": 0, "y": 0}, 28 | {"step": 25, "startValue": 50, maxValue: 100}, 29 | true, 30 | false, 31 | "track", 32 | "bar", 33 | {'duration': 100, 'ease': Phaser.Easing.Quadratic.Out} 34 | ); 35 | 36 | barText = game.add.text(50, 50, bar.valueRange.startValue, { 37 | font: "24px Arial", 38 | fill: "#ff0044", 39 | align: "center" 40 | }); 41 | 42 | bar.valueDisplay = barText; 43 | bar.emitter.on('movement', updateValueDisplay); 44 | 45 | // Create a quantitybar starting at 50. 46 | bar2 = new uiWidgets.ValueBar( 47 | game, 48 | {"x": 0, "y": 0}, 49 | {"step": 25, "startValue": 50, maxValue: 100}, 50 | true, 51 | false, 52 | "track", 53 | "bar", 54 | {'duration': 100, 'ease': Phaser.Easing.Quadratic.Out} 55 | ); 56 | 57 | barText2 = game.add.text(50, 50, bar2.valueRange.startValue, { 58 | font: "24px Arial", 59 | fill: "#ff0044", 60 | align: "center" 61 | }); 62 | 63 | bar2.valueDisplay = barText2; 64 | bar2.emitter.on('movement', updateValueDisplay); 65 | 66 | var prevItemCallback = function (group, context) { 67 | cursor.y = group.selected.worldPosition.y - (group.selected.height/4); 68 | }; 69 | 70 | var nextItemCallback = function (group, context) { 71 | cursor.y = group.selected.worldPosition.y - (group.selected.height/4); 72 | }; 73 | 74 | column = new uiWidgets.Column(game, 150, 50, "bg"); 75 | column.addNode(bar); 76 | column.addNode(barText); 77 | column.addNode(bar2); 78 | column.addNode(barText2); 79 | 80 | // Example of using prev/nextItem callback. 81 | // Create a cursor and move to the selected child's position. 82 | cursor = game.add.sprite(100, 42, 'pointer'); 83 | 84 | // Create a KeyboardGroup and add the Bars to it. 85 | keyboardGroup = new uiWidgets.KeyboardGroup(game, true, this); 86 | keyboardGroup.addNode(bar); 87 | keyboardGroup.addNode(bar2); 88 | 89 | keyboardGroup.emitter.on('previous', prevItemCallback); 90 | keyboardGroup.emitter.on('next', nextItemCallback); 91 | } 92 | 93 | function updateValueDisplay(bar) { 94 | bar.valueDisplay.setText(bar.valueRange.getCurrentValue()); 95 | } 96 | -------------------------------------------------------------------------------- /docs/examples/js/phaserce/vscrollbar.js: -------------------------------------------------------------------------------- 1 | var game = new Phaser.Game(600, 400, Phaser.AUTO, 'vscrollbar', { preload: preload, create: create }); 2 | 3 | function preload() { 4 | var assetRoot = '../../assets/vertical/'; 5 | game.load.image("dummyButton", assetRoot + "sprite.png"); 6 | game.load.image("track", assetRoot + "track.png"); 7 | game.load.spritesheet('bar', assetRoot + 'bar.png', 22, 44); 8 | } 9 | 10 | function create() { 11 | 12 | // Create a viewport. A "window" with a limited area of view. 13 | var viewport = new uiWidgets.Viewport(game, 75, 75, 600, 260); 14 | 15 | // Create a column. Anything added to a column is placed under the previous thing added. 16 | var column = new uiWidgets.Column(game); 17 | 18 | // Put the column inside the viewport. 19 | viewport.addNode(column); 20 | 21 | // Add things to the column. 22 | var dummy_sprite_a = this.game.add.sprite(0, 0, "dummyButton"); 23 | var dummy_sprite_b = this.game.add.sprite(0, 0, "dummyButton"); 24 | var dummy_sprite_c = this.game.add.sprite(0, 0, "dummyButton"); 25 | var dummy_sprite_d = this.game.add.sprite(0, 0, "dummyButton"); 26 | var dummy_sprite_e = this.game.add.sprite(0, 0, "dummyButton"); 27 | var dummy_sprite_f = this.game.add.sprite(0, 0, "dummyButton"); 28 | 29 | column.addNode(dummy_sprite_a); 30 | column.addNode(dummy_sprite_b); 31 | column.addNode(dummy_sprite_c); 32 | column.addNode(dummy_sprite_d); 33 | column.addNode(dummy_sprite_e); 34 | column.addNode(dummy_sprite_f); 35 | 36 | // Create a scrollbar for the viewport. 37 | var scrollbar = new uiWidgets.Scrollbar( 38 | game, 39 | viewport, 40 | true, 41 | true, 42 | "track", 43 | "bar", 44 | {'duration': 300, 'ease': Phaser.Easing.Quadratic.Out} 45 | ); 46 | 47 | // Place scrollbar next to viewport. 48 | scrollbar.alignTo(viewport, Phaser.RIGHT_TOP, 10); 49 | } 50 | -------------------------------------------------------------------------------- /docs/examples/js/phaserce/wheel3D.js: -------------------------------------------------------------------------------- 1 | var game = new Phaser.Game( 2 | 600, 3 | 400, 4 | Phaser.AUTO, 5 | 'wheel3D', 6 | { preload: preload, create: create }, 7 | ); 8 | 9 | function preload() { 10 | var assetRoot = '../../assets/wheel3D/'; 11 | game.load.image("icon", assetRoot + "icon.png"); 12 | game.load.image("mmUp", assetRoot + "mmUp.png"); 13 | game.load.image("mmDown", assetRoot + "mmDown.png"); 14 | } 15 | 16 | function create() { 17 | 18 | // Example 1: Rotate around the Y axis 19 | 20 | // Build a list of sprites for the wheel. 21 | var menuListY = []; 22 | 23 | for (var i = 0; i < 12; i++) { 24 | var icon = game.add.sprite(0, 0, 'icon'); 25 | menuListY.push(icon); 26 | } 27 | 28 | // Create the wheel. 29 | menuWheelY = new uiWidgets.Wheel3D( 30 | game, 31 | {"x": game.world.centerX - 100, "y": game.world.centerY}, 32 | menuListY, 33 | 0, 34 | 90, 35 | "y", 36 | {"x":0, "y": -90, "z": 0} 37 | ); 38 | 39 | // Tint the active item after each movement. 40 | menuWheelY.emitter.on('complete', 41 | function(wheel) { 42 | for (var i = 0; i < 12; i++) { 43 | wheel.sprites[i].tint = 0xFFFFFF; 44 | } 45 | wheel.active.tint = 0xdc21ff; 46 | } 47 | ); 48 | 49 | menuWheelY.activate(); 50 | 51 | // Scroll Buttons 52 | var scrollLeftButtonY = this.game.add.button( 53 | 0, 54 | game.world.centerY, 55 | "mmUp", 56 | scrollTheWheel, 57 | this, 58 | ); 59 | scrollLeftButtonY.wheel = menuWheelY; 60 | scrollLeftButtonY.dir = 0; 61 | 62 | var scrollRightButtonY = this.game.add.button( 63 | 0, 64 | game.world.centerY + 48, 65 | "mmDown", 66 | scrollTheWheel, 67 | this, 68 | ); 69 | scrollRightButtonY.wheel = menuWheelY; 70 | scrollRightButtonY.dir = 1; 71 | 72 | // Example 2: Rotate around the X axis 73 | var menuListX = []; 74 | 75 | for (var i = 0; i < 12; i++) { 76 | var icon = game.add.sprite(0, 0, 'icon'); 77 | menuListX.push(icon); 78 | } 79 | 80 | // Create the wheel. 81 | menuWheelX = new uiWidgets.Wheel3D( 82 | game, 83 | {"x": game.world.centerX - 100, "y": 100}, 84 | menuListX, 85 | 0, 86 | 90, 87 | "x", 88 | {"x": 90, "y": 0, "z": 0} 89 | ); 90 | 91 | // Tint the active item after each movement. 92 | menuWheelX.emitter.on('complete', 93 | function(wheel) { 94 | for (var i = 0; i < 12; i++) { 95 | wheel.sprites[i].tint = 0xFFFFFF; 96 | } 97 | wheel.active.tint = 0xdc21ff; 98 | } 99 | ); 100 | 101 | menuWheelX.activate(); 102 | 103 | // Scroll Buttons 104 | var scrollLeftButtonX = this.game.add.button( 105 | 0, 106 | 0, 107 | "mmUp", 108 | scrollTheWheel, 109 | this, 110 | ); 111 | scrollLeftButtonX.wheel = menuWheelX; 112 | scrollLeftButtonX.dir = 0; 113 | 114 | var scrollRightButtonX = this.game.add.button( 115 | 0, 116 | 48, 117 | "mmDown", 118 | scrollTheWheel, 119 | this, 120 | ); 121 | scrollRightButtonX.wheel = menuWheelX; 122 | scrollRightButtonX.dir = 1; 123 | 124 | // Example 3: Rotate around the Z axis 125 | var menuListZ = []; 126 | 127 | for (var i = 0; i < 12; i++) { 128 | var icon = game.add.sprite(0, 0, 'icon'); 129 | menuListZ.push(icon); 130 | } 131 | 132 | // Create the wheel. 133 | menuWheelZ = new uiWidgets.Wheel3D( 134 | game, 135 | {"x": game.world.centerX, "y": 100}, 136 | menuListZ, 137 | 0, 138 | 90, 139 | "z", 140 | {"x": 0, "y": 0, "z": 90} 141 | ); 142 | 143 | menuWheelZ.emitter.on('start', 144 | function(wheel) { 145 | for (var i = 0; i < 12; i++) { 146 | wheel.sprites[i].tint = 0xFFFFFF; 147 | } 148 | wheel.active.tint = 0xdc21ff; 149 | } 150 | ); 151 | 152 | menuWheelZ.activate(); 153 | 154 | // Scroll Buttons 155 | var scrollLeftButtonZ = this.game.add.button( 156 | game.world.width - 100, 157 | 0, 158 | "mmUp", 159 | scrollTheWheel, 160 | this, 161 | ); 162 | scrollLeftButtonZ.wheel = menuWheelZ; 163 | scrollLeftButtonZ.dir = 0; 164 | 165 | var scrollRightButtonZ = this.game.add.button( 166 | game.world.width - 100, 167 | 48, 168 | "mmDown", 169 | scrollTheWheel, 170 | this, 171 | ); 172 | scrollRightButtonZ.wheel = menuWheelZ; 173 | scrollRightButtonZ.dir = 1; 174 | } 175 | 176 | var scrollTheWheel = function (item) { 177 | if (item.dir === 0){ 178 | item.wheel.moveBack(); 179 | } 180 | if (item.dir === 1){ 181 | item.wheel.moveForward(); 182 | } 183 | }; 184 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "phaser-ui-tools", 3 | "version": "2.0.0-beta", 4 | "description": "User Interface objects for the phaser game engine.", 5 | "author": "Joshua Fehler ", 6 | "repository": "github:jsfehler/phaser-ui-tools", 7 | "license": "MIT", 8 | "main": "dist/phaser-ui-tools.js", 9 | "unpkg": "dist/phaser-ui-tools.min.js", 10 | "files": [ 11 | "dist/phaser-ui-tools.js", 12 | "dist/phaser-ui-tools.min.js" 13 | ], 14 | "scripts": { 15 | "build:js": "webpack", 16 | "test": "mocha-headless-chrome -f tests/testrunner.html", 17 | "test3": "mocha-headless-chrome -f tests/testrunner_phaser3.html", 18 | "copyToExamplesLib": "copyfiles -f dist/phaser-ui-tools.js docs/examples/lib/", 19 | "build:docs": "documentation build src/** -f html -o docs" 20 | }, 21 | "devDependencies": { 22 | "@babel/core": "^7.23.9", 23 | "@babel/preset-env": "^7.23.9", 24 | "babel-loader": "^9.1.3", 25 | "chai": "^4.3.4", 26 | "copyfiles": "^2.4.1", 27 | "documentation": "^14.0.2", 28 | "eslint": "^8.56.0", 29 | "eslint-config-airbnb-base": "^15.0.0", 30 | "eslint-plugin-import": "^2.29.1", 31 | "eslint-webpack-plugin": "^4.0.1", 32 | "mocha": "^10.2.0", 33 | "mocha-headless-chrome": "^4.0.0", 34 | "webpack": "^5.90.0", 35 | "webpack-cli": "^5.1.4" 36 | }, 37 | "peerDependencies": { 38 | "phaser": "^3.60.0", 39 | "phaser-ce": "2.20.0" 40 | }, 41 | "peerDependenciesMeta": { 42 | "phaser-ce": { 43 | "optional": true 44 | }, 45 | "phaser": { 46 | "optional": true 47 | } 48 | }, 49 | "dependencies": { 50 | "eventemitter3": "^5.0.1" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/bars/bar.js: -------------------------------------------------------------------------------- 1 | import * as PhaserObjects from '../phaserObjects'; 2 | 3 | /** Base object for all Bar-like Widgets. 4 | * @private 5 | * @extends PhaserObjects.Group 6 | */ 7 | export class Bar extends PhaserObjects.Group { 8 | /** 9 | * @param {Object} game - Current game instance. 10 | * @param {number} x - The Bar's x position. 11 | * @param {number} y - The Bar's y position. 12 | * @param {boolean} vertical - Sets the Bar's alignment as vertical. 13 | * @param {string} trackKey - The key to use for the track. 14 | * @param {string} barKey - The key to use for the bar. 15 | */ 16 | constructor(game, x = 0, y = 0, vertical = false, trackKey = '', barKey = '') { 17 | super(game); 18 | game.add.existing(this); 19 | 20 | this.game = game; 21 | this.x = x; 22 | this.y = y; 23 | 24 | this.vertical = vertical; 25 | 26 | this.trackKey = trackKey; 27 | this.barKey = barKey; 28 | } 29 | 30 | /** 31 | * @private 32 | * Determine the distance the bar can scroll over. 33 | */ 34 | setTrackScrollAreaSize() { 35 | if (this.vertical) { 36 | this.trackScrollAreaSize = this.track.height - this.vslice; 37 | } else { 38 | this.trackScrollAreaSize = this.track.width - this.hslice; 39 | } 40 | } 41 | 42 | /** 43 | * @private 44 | * Sets position for the bar's non-moving axis. Centers it inside the track. 45 | */ 46 | centerStaticAxis() { 47 | if (this.vertical) { 48 | this.bar.x = ( 49 | this.track.x + (this.track.width / 2)) - (this.bar.displayWidth / 2); 50 | } else { 51 | this.bar.y = ( 52 | this.track.y + (this.track.height / 2)) - (this.bar.displayHeight / 2); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/bars/draggable_bar.js: -------------------------------------------------------------------------------- 1 | import { EventEmitter } from 'eventemitter3'; 2 | import * as PhaserObjects from '../phaserObjects'; 3 | import { Bar } from './bar'; 4 | 5 | /** 6 | * Base object for Bars that can be manipulated with a mouse. 7 | * @private 8 | * @extends Bar 9 | */ 10 | export class DraggableBar extends Bar { 11 | constructor(game, x = 0, y = 0, vertical = false, trackKey = '', barKey = '') { 12 | super(game, x, y, vertical, trackKey, barKey); 13 | this.emitter = new EventEmitter(); 14 | } 15 | 16 | /** 17 | * @private 18 | * If the vertical scrollbar is draggable, 19 | * this function is called when the track is clicked. 20 | */ 21 | verticalTrackClick() { 22 | // Don't register mouse clicks on the bar itself. 23 | const mouseY = this.game.input.mousePointer.y; 24 | 25 | let barY = this.bar.y + this.worldPosition.y; 26 | 27 | if (this.parentContainer) { 28 | barY += this.parentContainer.y; 29 | } 30 | 31 | if (mouseY > barY + this.bar.displayHeight) { 32 | this.scrollDown(); 33 | } else if (mouseY < barY) { 34 | this.scrollUp(); 35 | } 36 | } 37 | 38 | /** 39 | * @private 40 | * If the horizontal scrollbar is draggable, 41 | * this function is called when the track is clicked. 42 | */ 43 | horizontalTrackClick() { 44 | // Don't register mouse clicks on the bar itself. 45 | const mouseX = this.game.input.mousePointer.x; 46 | 47 | let barX = this.bar.x + this.worldPosition.x; 48 | 49 | if (this.parentContainer) { 50 | barX += this.parentContainer.x; 51 | } 52 | 53 | if (mouseX > barX + this.bar.displayWidth) { 54 | this.scrollRight(); 55 | } else if (mouseX < barX) { 56 | this.scrollLeft(); 57 | } 58 | } 59 | 60 | /** 61 | * @private 62 | * Allows the bar to scroll when the track is clicked directly. 63 | */ 64 | enableTrackClick() { 65 | let event; 66 | 67 | this.track.setInteractive(); 68 | 69 | if (this.vertical) { 70 | event = this.verticalTrackClick; 71 | } else { 72 | event = this.horizontalTrackClick; 73 | } 74 | 75 | this.track.addDownEvent(event, this); 76 | } 77 | 78 | /** 79 | * @private 80 | * When called, ensures the bar can be moved. 81 | * Must be called once the bar has finished scrolling. 82 | */ 83 | enableBarInput() { 84 | this.trackClicked = false; 85 | this.barMoving = false; 86 | this.bar.enableDragging(this.vertical); 87 | } 88 | 89 | /** 90 | * @private 91 | * Enables clicking and dragging on the bar. 92 | */ 93 | enableBarDrag() { 94 | this.setDraggableArea(); 95 | 96 | this.bar.enableDragging(this.vertical); 97 | 98 | let draggableArea; 99 | 100 | if (this.vertical) { 101 | draggableArea = this.verticalDraggableArea; 102 | } else { 103 | draggableArea = this.horizontalDraggableArea; 104 | } 105 | 106 | this.bar.setDragBounds(draggableArea); 107 | 108 | if (this.snapping) { 109 | this.bar.addUpEvent(this.snapToClosestPosition, this); 110 | } 111 | this.bar.addDownEvent(this.saveMousePosition, this); 112 | this.bar.addDragEvent(this.moveContent, this); 113 | } 114 | 115 | saveMousePosition(pointer) { 116 | // When the bar is dragged, record where the mouse clicked down. 117 | this.mousePointer = { 118 | x: pointer.x - (pointer.x - this.bar.x), 119 | y: pointer.y - (pointer.y - this.bar.y), 120 | }; 121 | } 122 | 123 | getBarPosition() { 124 | const currentValue = this.valueRange.getCurrentValue(); 125 | const windowPositionRatio = currentValue / this.windowScrollAreaSize; 126 | return this.trackScrollAreaSize * windowPositionRatio; 127 | } 128 | 129 | getMouseDelta() { 130 | // Only difference between clicking the track/using the keyboard vs mouse drag. 131 | let newMousePointer; 132 | if (this.trackClicked) { 133 | newMousePointer = { x: this.bar.x, y: this.bar.y }; 134 | } else { 135 | const { mousePointer } = this.game.input; 136 | newMousePointer = { 137 | x: mousePointer.x - (mousePointer.x - this.bar.x), 138 | y: mousePointer.y - (mousePointer.y - this.bar.y), 139 | }; 140 | } 141 | 142 | let oldMousePosition; 143 | let newMousePosition; 144 | if (this.vertical) { 145 | oldMousePosition = this.mousePointer.y; 146 | newMousePosition = newMousePointer.y; 147 | } else { 148 | oldMousePosition = this.mousePointer.x; 149 | newMousePosition = newMousePointer.x; 150 | } 151 | 152 | this.mousePointer = newMousePointer; 153 | 154 | // Only update when the new position is inside the track. 155 | let mousePositionDelta; 156 | if (newMousePosition < this.maxValue) { 157 | mousePositionDelta = oldMousePosition - newMousePosition; 158 | } else { 159 | mousePositionDelta = 0; 160 | } 161 | 162 | return mousePositionDelta; 163 | } 164 | 165 | /** 166 | * @private 167 | * Creates the tween for moving the bar to a new position. 168 | */ 169 | addScrollTween(properties) { 170 | this.mousePointer = { x: this.bar.x, y: this.bar.y }; 171 | this.trackClicked = true; 172 | 173 | new PhaserObjects.Tween(this.game).add( 174 | this.bar, 175 | properties, 176 | this.tweenParams.duration, 177 | this.tweenParams.ease, 178 | this.enableBarInput, 179 | this.moveContent, 180 | null, 181 | this, 182 | ); 183 | } 184 | 185 | /** For Vertical Scrollbars. Scrolls up by one step. */ 186 | scrollUp() { 187 | // Prevents users from moving the bar while it's moving. 188 | if (this.bar.y !== this.track.y && !this.barMoving) { 189 | const testPosition = this.bar.y - this.vslice; 190 | let moveToY = null; 191 | this.barMoving = true; 192 | 193 | // Ensure the bar can't move above the track. 194 | if (testPosition <= this.track.y) { 195 | moveToY = this.minY; 196 | } else { 197 | moveToY = this.bar.y - this.vslice; 198 | } 199 | 200 | this.addScrollTween({ y: moveToY }); 201 | } 202 | } 203 | 204 | /** For Vertical Scrollbars. Scrolls down by one step. */ 205 | scrollDown() { 206 | if (this.bar.y + this.bar.displayHeight !== this.track.y + this.track.height && !this.barMoving) { 207 | const testPosition = this.bar.y + (this.vslice * 2); 208 | let moveToY = null; 209 | this.barMoving = true; 210 | this.bar.disableInteractive(); 211 | 212 | // Ensure the bar can't move below the track. 213 | if (testPosition >= this.track.y + this.track.height) { 214 | moveToY = this.maxY; 215 | } else { 216 | moveToY = this.bar.y + this.vslice; 217 | } 218 | 219 | this.addScrollTween({ y: moveToY }); 220 | } 221 | } 222 | 223 | /** For Horizontal Scrollbars. Scrolls left by one step. */ 224 | scrollLeft() { 225 | if (this.bar.x !== this.track.x && !this.barMoving) { 226 | const testPosition = this.bar.x - this.hslice; 227 | let moveToX = null; 228 | this.barMoving = true; 229 | this.bar.disableInteractive(); 230 | 231 | // Ensure the bar can't move above the track. 232 | if (testPosition <= this.track.x) { 233 | moveToX = this.minX; 234 | } else { 235 | moveToX = this.bar.x - this.hslice; 236 | } 237 | 238 | this.addScrollTween({ x: moveToX }); 239 | } 240 | } 241 | 242 | /** For Horizontal Scrollbars. Scrolls right by one step. */ 243 | scrollRight() { 244 | if (this.bar.x + this.bar.displayWidth !== this.track.x + this.track.width && !this.barMoving) { 245 | const testPosition = this.bar.x + (this.hslice * 2); 246 | let moveToX = null; 247 | this.barMoving = true; 248 | this.bar.disableInteractive(); 249 | 250 | // Ensure the bar can't move below the track. 251 | if (testPosition >= this.track.x + this.track.width) { 252 | moveToX = this.maxX; 253 | } else { 254 | moveToX = this.bar.x + this.hslice; 255 | } 256 | 257 | this.addScrollTween({ x: moveToX }); 258 | } 259 | } 260 | 261 | /** Called when the scrollbar needs to move the viewport. 262 | * Causes the content to move relative to the bar's position on the track. 263 | */ 264 | moveContent() { 265 | const newGripPositionRatio = this.getGripPositionRatio(); 266 | 267 | const newContentPosition = newGripPositionRatio * this.windowScrollAreaSize; 268 | 269 | this.valueRange.adjustValue(newContentPosition); 270 | 271 | this.emitter.emit('movement', this); 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /src/bars/quantitybar.js: -------------------------------------------------------------------------------- 1 | import { Bar } from './bar'; 2 | 3 | import { QuantityRange } from './ranges'; 4 | 5 | import * as PhaserObjects from '../phaserObjects'; 6 | 7 | /** 8 | * Bar that adjusts the size of a static sprite based on a value. 9 | * This is done by masking the sprite and then resizing the mask. 10 | * @extends Bar 11 | */ 12 | export class QuantityBar extends Bar { 13 | /** 14 | * @param {Object} game - Current game instance. 15 | * @param {Object} xy - Dictionary with the values for the bar's x and y position. 16 | * @param {Object} values - The numerical values for the bar. 17 | * @param {boolean} vertical - Determines if the bar should be vertical or horizontal. 18 | * @param {boolean} reverse - Determines the direction the bar moves when adjusted. 19 | * @param {string} trackKey - The key to use for the track. 20 | * @param {string} barKey - The key to use for the bar. 21 | * @param {Object} tweenParams - Object with duration and easing function for the scrolling tween. 22 | */ 23 | constructor( 24 | game, 25 | xy, 26 | values, 27 | vertical = false, 28 | reverse = false, 29 | trackKey = '', 30 | barKey = '', 31 | tweenParams = null, 32 | ) { 33 | super(game, xy.x, xy.y, vertical, trackKey, barKey); 34 | 35 | this.uiWidgetsObjectRole = 'quantitybar'; 36 | 37 | this.valueRange = new QuantityRange( 38 | this, 39 | values.startValue, 40 | values.maxValue, 41 | ); 42 | 43 | this.reverse = reverse || false; 44 | 45 | this.tweenParams = tweenParams || { duration: 300, ease: PhaserObjects.Easing.Quadratic.Out }; 46 | 47 | // The track is the static area the bar will move along. 48 | this.track = new PhaserObjects.Sprite(game, 0, 0, this.trackKey); 49 | 50 | // Phaser 3: 51 | // Anchor the track to 0 instead of 0.5 52 | this.track.displayOriginX = 0; 53 | this.track.displayOriginY = 0; 54 | 55 | this.add(this.track); 56 | 57 | this.width = this.track.width; 58 | this.height = this.track.height; 59 | 60 | // The bar is a static image taking up the width of the track. 61 | this.bar = new PhaserObjects.Sprite( 62 | game, 63 | 0, 64 | 0, 65 | this.barKey, 66 | ); 67 | 68 | // Phaser 3: 69 | // Anchor the track to 0 instead of 0.5 70 | this.bar.displayOriginX = 0; 71 | this.bar.displayOriginY = 0; 72 | 73 | this.add(this.bar); 74 | 75 | this.create(); 76 | } 77 | 78 | /** 79 | * @private 80 | * Sets the bar's mask. 81 | */ 82 | setMask() { 83 | if (this.bar.mask !== null) { 84 | this.bar.mask.destroy(); 85 | this.bar.mask = null; 86 | } 87 | 88 | const mask = new PhaserObjects.ViewportMask(this.game, this.maskX, this.maskY); 89 | this.bar.mask = mask.create(this.bar.maskX, this.bar.maskY, this.maskW, this.maskH); 90 | 91 | // Phaser CE: Mask must be added to Group 92 | if (this.version === undefined) { 93 | this.add(mask); 94 | } 95 | } 96 | 97 | getMaskXY(x = 0, y = 0) { 98 | // Phaser CE: Mask starts at bar xy, Phaser 3: Mask starts at group xy 99 | let maskX; 100 | let maskY; 101 | 102 | maskX = x; 103 | maskY = y; 104 | 105 | if (this.version === undefined) { 106 | maskX += this.bar.x; 107 | maskY += this.bar.y; 108 | } else { 109 | maskX += this.x; 110 | maskY += this.y; 111 | } 112 | 113 | // Resizes the bar. 114 | if (this.reverse) { 115 | if (this.vertical) { 116 | maskY += this.getBarFraction(); 117 | } else { 118 | maskX += this.getBarFraction(); 119 | } 120 | } 121 | 122 | return [maskX, maskY]; 123 | } 124 | 125 | getBarPosition() { 126 | const windowPositionRatio = this.valueRange.getRatio() / this.windowScrollAreaSize; 127 | return this.trackScrollAreaSize * windowPositionRatio; 128 | } 129 | 130 | create(maskX = 0, maskY = 0) { 131 | this.centerStaticAxis(); 132 | 133 | // Values for the bar's mask. 134 | this.maskW = this.bar.width; 135 | this.maskH = this.bar.height; 136 | 137 | const [mx, my] = this.getMaskXY(maskX, maskY); 138 | this.maskX = mx; 139 | this.maskY = my; 140 | 141 | this.setMask(); 142 | 143 | const barSize = this.getBarSize(); 144 | 145 | if (this.reverse) { 146 | if (this.vertical) { 147 | this.bar.mask.geometryMask.scaleY = barSize; 148 | } else { 149 | this.bar.mask.geometryMask.scaleX = barSize; 150 | } 151 | } else { 152 | if (this.vertical) { 153 | this.bar.mask.geometryMask.scaleY = barSize; 154 | } else { 155 | this.bar.mask.geometryMask.scaleX = barSize; 156 | } 157 | } 158 | 159 | // Determine the distance the window can scroll over 160 | this.windowScrollAreaSize = this.valueRange.maxValue; 161 | 162 | // Represents one fraction of the track. 163 | this.vslice = (this.track.height * this.valueRange.getRatio()); 164 | this.hslice = (this.track.width * this.valueRange.getRatio()); 165 | 166 | this.setTrackScrollAreaSize(); 167 | } 168 | 169 | /** 170 | * @private 171 | * Creates the tween for adjusting the size of the mask. 172 | * @param {Object} properties - Values for the tween's movement. 173 | */ 174 | addScrollTweenMask(properties, duration, ease) { 175 | new PhaserObjects.Tween(this.game).add( 176 | this.bar.mask.geometryMask, 177 | properties, 178 | duration, 179 | ease, 180 | ); 181 | } 182 | 183 | /** 184 | * Adjusts the bar by a given value. 185 | * @param {number} newValue - The value to adjust the bar by. 186 | */ 187 | adjustBar(newValue) { 188 | this.valueRange.currentValue += newValue; 189 | 190 | let tween; 191 | const barSize = this.getBarSize(); 192 | 193 | let moveToX; 194 | let moveToY; 195 | 196 | // Phaser 3 requires an offset 197 | if (this.version === undefined) { 198 | moveToX = 0; 199 | moveToY = 0; 200 | } else { 201 | moveToX = this.x; 202 | moveToY = this.y; 203 | } 204 | 205 | if (this.reverse) { 206 | if (this.vertical) { 207 | tween = { scaleY: barSize, y: moveToY + this.getBarFraction() }; 208 | } else { 209 | tween = { scaleX: barSize, x: moveToX + this.getBarFraction() }; 210 | } 211 | } else { 212 | if (this.vertical) { 213 | tween = { scaleY: barSize }; 214 | } else { 215 | tween = { scaleX: barSize }; 216 | } 217 | } 218 | 219 | this.addScrollTweenMask(tween, this.tweenParams.duration, this.tweenParams.ease); 220 | } 221 | 222 | getBarFraction() { 223 | let fraction; 224 | if (this.vertical) { 225 | fraction = this.track.height * this.valueRange.getRatio(); 226 | } else { 227 | fraction = this.track.width * this.valueRange.getRatio(); 228 | } 229 | 230 | return fraction; 231 | } 232 | 233 | /** 234 | * @private 235 | * Given a ratio between total content size and viewport size, 236 | * return an appropriate percentage of the track. 237 | */ 238 | getBarSize() { 239 | let barSize; 240 | 241 | if (this.reverse) { 242 | barSize = 1 - this.valueRange.getRatio(); 243 | } else { 244 | barSize = this.valueRange.getRatio(); 245 | } 246 | 247 | return barSize; 248 | } 249 | } 250 | -------------------------------------------------------------------------------- /src/bars/ranges.js: -------------------------------------------------------------------------------- 1 | /** Used by a QuantityBar to hold the bar's values. */ 2 | export class QuantityRange { 3 | /** 4 | * @param {number} bar - The QuantityBar object that uses the range. 5 | * @param {number} startValue - The initial value for the bar. 6 | * @param {number} maxValue - The maximum value the bar can have. 7 | */ 8 | constructor(bar, startValue, maxValue) { 9 | this.bar = bar; 10 | this.startValue = startValue; 11 | this.maxValue = maxValue; 12 | 13 | this.currentValue = startValue; 14 | } 15 | 16 | /** Returns the current ratio for how large the bar is compared to the track. */ 17 | getRatio() { 18 | const ratio = this.currentValue / this.maxValue; 19 | return ratio; 20 | } 21 | 22 | /** Returns the bar's current value. */ 23 | getCurrentValue() { 24 | return this.currentValue; 25 | } 26 | } 27 | 28 | /** Used by a ValueBar to hold the bar's values. */ 29 | export class ValueRange { 30 | /** 31 | * @param {number} step - The amount the bar is changed by. 32 | * @param {number} startValue - The initial value for the bar. 33 | * @param {number} maxValue - The maximum value the bar can have. 34 | */ 35 | constructor(step, startValue, maxValue) { 36 | this.step = step; 37 | this.startValue = startValue; 38 | this.maxValue = maxValue + step; 39 | 40 | this.ratio = step / maxValue; 41 | 42 | // The ratio between the step and max can't be greater than 1. 43 | // ie: There can't be more steps than the max value. 44 | if (this.ratio > 1) { 45 | this.ratio = 1; 46 | } 47 | 48 | this.currentValue = startValue; 49 | 50 | // List of every possible step. Used for snapping into position by the ValueBar. 51 | this.steps = []; 52 | for (let i = 0; i < this.maxValue; i += step) { 53 | this.steps.push(i); 54 | } 55 | } 56 | 57 | /** Adjusts the current value for the bar. 58 | * @param {number} newValue - The new current value. 59 | */ 60 | adjustValue(newValue) { 61 | this.currentValue = newValue; 62 | } 63 | 64 | /** Returns the bar's current value. */ 65 | getCurrentValue() { 66 | return this.currentValue; 67 | } 68 | } 69 | 70 | /** Used by a Scrollbar to hold the values and adjust a viewport's position. */ 71 | export class ViewportRange { 72 | /** 73 | * @param {Object} viewport - The viewport to adjust. 74 | * @param {boolean} vertical - If the viewport is vertical or horizontal. 75 | */ 76 | constructor(viewport, vertical) { 77 | this.viewport = viewport; 78 | this.vertical = vertical; 79 | 80 | if (vertical) { 81 | this.step = viewport.area.height; 82 | this.maxValue = viewport.realHeight; 83 | } else { 84 | this.step = viewport.area.width; 85 | this.maxValue = viewport.realWidth; 86 | } 87 | 88 | this.ratio = this.step / this.maxValue; 89 | 90 | // The ratio between the step and max can't be greater than 1. 91 | // ie: There can't be more steps than the max value. 92 | if (this.ratio > 1) { 93 | this.ratio = 1; 94 | } 95 | } 96 | 97 | /** Adjusts the viewport's position. */ 98 | adjustValue(newValue) { 99 | // Set the content's new position. Uses an offset for where the viewport is on screen. 100 | if (this.vertical) { 101 | this.viewport.y = newValue + this.viewport.area.y; 102 | } else { 103 | this.viewport.x = newValue + this.viewport.area.x; 104 | } 105 | 106 | this.viewport.disableOutOfBounds( 107 | this.viewport.children, 108 | this, 109 | this.vertical, 110 | ); 111 | } 112 | 113 | getCurrentValue() { 114 | let currentValue; 115 | if (this.vertical) { 116 | // y - an offset for where the viewport is on screen. 117 | currentValue = this.viewport.y - this.viewport.area.y; 118 | } else { 119 | currentValue = this.viewport.x - this.viewport.area.x; 120 | } 121 | 122 | return currentValue; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/bars/scrollbar.js: -------------------------------------------------------------------------------- 1 | import { DraggableBar } from './draggable_bar'; 2 | 3 | import { ViewportRange } from './ranges'; 4 | 5 | import * as PhaserObjects from '../phaserObjects'; 6 | 7 | /** 8 | * A bar that moves along a track. 9 | * The bar is resized relative to the size of the track and size of the content to be scrolled. 10 | * @extends DraggableBar 11 | */ 12 | export class Scrollbar extends DraggableBar { 13 | /** 14 | * @param {Object} game - Current game instance. 15 | * @param {Object} content - An object to adjust via the scrollbar. 16 | * @param {boolean} draggable - Determines if the scrollbar responds to mouse clicks. 17 | * @param {boolean} vertical - Determines if the scrollbar should be vertical or horizontal. 18 | * @param {string} trackKey - The key to use for the track. 19 | * @param {string} barKey - The key to use for the bar. 20 | * @param {Object} tweenParams - Object with duration and easing function for the scrolling tween. 21 | */ 22 | constructor(game, content, draggable, vertical = false, trackKey = '', barKey = '', tweenParams = null) { 23 | super(game, 0, 0, vertical, trackKey, barKey); 24 | 25 | this.game = game; 26 | 27 | this.content = content; 28 | 29 | this.valueRange = new ViewportRange(content, vertical); 30 | 31 | this.draggable = draggable || false; 32 | 33 | // The smallest pixel size allowed for the bar. 34 | this.minBarSize = 1; 35 | 36 | this.tweenParams = tweenParams || { duration: 300, ease: PhaserObjects.Easing.Quadratic.Out }; 37 | 38 | // Flag switched on when the track is clicked, switched off after the bar movement is finished. 39 | this.trackClicked = false; 40 | this.barMoving = false; 41 | 42 | // Records mouse pointer when clicking the bar. 43 | this.mousePointer = null; 44 | 45 | // The track is the static area the bar will move along. 46 | this.track = new PhaserObjects.Sprite( 47 | game, 48 | this.x, 49 | this.y, 50 | this.trackKey, 51 | ); 52 | 53 | // Phaser 3: 54 | // Anchor the track to 0 instead of 0.5 55 | this.track.displayOriginX = 0; 56 | this.track.displayOriginY = 0; 57 | 58 | this.add(this.track); 59 | 60 | if (this.draggable) { 61 | // If the bar is draggable, clicking the track will move the bar up or down. 62 | this.enableTrackClick(); 63 | } 64 | 65 | this.createBar(); 66 | this.add(this.bar); 67 | 68 | this.minY = this.track.y; 69 | this.maxY = (this.track.y + this.track.height) - this.bar.displayHeight; 70 | this.minX = this.track.x; 71 | this.maxX = (this.track.x + this.track.width) - this.bar.displayWidth; 72 | 73 | this.create(); 74 | 75 | // Maximum value for the mouse position. 76 | if (this.vertical) { 77 | this.maxValue = this.track.displayHeight + this.worldPosition.y; 78 | 79 | if (this.version === undefined) { 80 | this.maxValue += this.bar.displayHeight; 81 | } 82 | } else { 83 | this.maxValue = this.track.displayWidth + this.worldPosition.x; 84 | 85 | if (this.version === undefined) { 86 | this.maxValue += this.bar.displayWidth; 87 | } 88 | } 89 | } 90 | 91 | /** 92 | * @private 93 | * The bar is the part that moves, controlling the value of the scrollbar. 94 | */ 95 | createBar() { 96 | const bar = new PhaserObjects.Button( 97 | this.game, 98 | this.x, 99 | this.y, 100 | this.barKey, 101 | this.moveContent, 102 | this, 103 | 1, 104 | 0, 105 | ); 106 | 107 | // Phaser 3: 108 | // Anchor the bar to 0 instead of 0.5 109 | bar.displayOriginX = 0; 110 | bar.displayOriginY = 0; 111 | 112 | this.bar = bar; 113 | 114 | this.resizeBar(); 115 | 116 | return bar; 117 | } 118 | 119 | /** 120 | * @private 121 | * Given a ratio between total content size and viewport size, 122 | * resize the bar sprite to the appropriate percentage of the track. 123 | */ 124 | resizeBar() { 125 | let barSize; 126 | if (this.vertical) { 127 | barSize = this.track.height * this.valueRange.ratio; 128 | } else { 129 | barSize = this.track.width * this.valueRange.ratio; 130 | } 131 | 132 | // Prevents bar from becoming zero pixels. 133 | if (barSize < this.minBarSize) { 134 | barSize = this.minBarSize; 135 | } 136 | 137 | // Resizes the bar. 138 | if (this.vertical) { 139 | this.bar.displayHeight = barSize; 140 | } else { 141 | this.bar.displayWidth = barSize; 142 | } 143 | } 144 | 145 | create() { 146 | this.centerStaticAxis(); 147 | 148 | if (this.draggable) { 149 | this.enableBarDrag(); 150 | } 151 | 152 | // Determine the distance the window can scroll over 153 | this.windowScrollAreaSize = this.valueRange.maxValue - this.valueRange.step; 154 | 155 | // Represents one fraction of the track. 156 | this.vslice = (this.track.displayHeight * this.valueRange.ratio); 157 | this.hslice = (this.track.displayWidth * this.valueRange.ratio); 158 | 159 | this.setTrackScrollAreaSize(); 160 | 161 | // Initial position for the bar. 162 | this.mousePointer = { x: this.bar.x, y: this.bar.y }; 163 | 164 | this.setInitialBarPosition(); 165 | } 166 | 167 | /** 168 | * @private 169 | * Sets the draggable area of the bar. 170 | */ 171 | setDraggableArea() { 172 | let vh = this.track.displayHeight; 173 | 174 | if (this.version === 3) { 175 | vh -= this.bar.displayHeight; 176 | } 177 | 178 | this.verticalDraggableArea = { 179 | x: this.track.x - ((this.bar.displayWidth - this.track.width) / 2), 180 | y: this.track.y, 181 | w: this.bar.displayWidth, 182 | h: vh, 183 | }; 184 | 185 | this.horizontalDraggableArea = { 186 | x: this.track.x, 187 | y: this.track.y - ((this.bar.displayHeight - this.track.height) / 2), 188 | w: this.track.width, 189 | h: this.bar.displayHeight, 190 | }; 191 | } 192 | 193 | /** 194 | * @private 195 | * Ensure the bar starts off where it should be, according to the bar's logical position. 196 | */ 197 | setInitialBarPosition() { 198 | const gripPositionOnTrack = this.getBarPosition(); 199 | 200 | // Make sure the bar is physically where it should be. 201 | if (this.vertical) { 202 | this.bar.y = gripPositionOnTrack + this.track.y; 203 | } else { 204 | this.bar.x = gripPositionOnTrack + this.track.x; 205 | } 206 | } 207 | 208 | getGripPositionRatio() { 209 | const gripPositionOnTrack = this.getBarPosition(); 210 | const mousePositionDelta = this.getMouseDelta(); 211 | 212 | let newGripPosition = gripPositionOnTrack + mousePositionDelta; 213 | 214 | // Don't let the content scroll above or below the track's size 215 | if (newGripPosition > 0) { 216 | newGripPosition = 0; 217 | } else if (newGripPosition <= -this.trackScrollAreaSize) { 218 | newGripPosition = -this.trackScrollAreaSize; 219 | } 220 | 221 | // When the scrollbar is at the top or bottom, prevent a mouse movement that 222 | // doesn't move the scrollbar from moving the content. 223 | if (this.vertical) { 224 | if (this.bar.y <= this.track.y) { 225 | newGripPosition = 0; 226 | } else if (this.bar.y + this.bar.displayHeight >= this.track.y + this.track.displayHeight) { 227 | newGripPosition = -this.trackScrollAreaSize; 228 | } 229 | } else { 230 | if (this.bar.x <= this.track.x) { 231 | newGripPosition = 0; 232 | } else if (this.bar.x + this.bar.displayWidth >= this.track.x + this.track.displayWidth) { 233 | newGripPosition = -this.trackScrollAreaSize; 234 | } 235 | } 236 | 237 | let newGripPositionRatio = newGripPosition / this.trackScrollAreaSize; 238 | 239 | // If the scrollable area is less than the size of the scrollbar, 240 | // the bar and track will be the same size. 241 | // In this scenario, a divide by zero occurs. Capture that and turn it into zero. 242 | if (Number.isNaN(newGripPositionRatio)) { 243 | newGripPositionRatio = 0; 244 | } 245 | 246 | return newGripPositionRatio; 247 | } 248 | } 249 | -------------------------------------------------------------------------------- /src/bars/valuebar.js: -------------------------------------------------------------------------------- 1 | import { DraggableBar } from './draggable_bar'; 2 | 3 | import { ValueRange } from './ranges'; 4 | 5 | import * as PhaserObjects from '../phaserObjects'; 6 | 7 | /** 8 | * Bar that adjusts a number. 9 | * This is done by masking the sprite and then resizing the mask. 10 | * @extends DraggableBar 11 | */ 12 | export class ValueBar extends DraggableBar { 13 | /** 14 | * @param {Object} game - Current game instance. 15 | * @param {Object} xy - Dictionary with the values for the bar's x and y position. 16 | * @param {Object} values - The numerical values for the bar. 17 | * @param {boolean} draggable - Determines if the scrollbar responds to mouse clicks. 18 | * @param {boolean} vertical - Determines if the bar should be vertical or horizontal. 19 | * @param {string} trackKey - The key to use for the track. 20 | * @param {string} barKey - The key to use for the bar. 21 | * @param {Object} tweenParams - Object with duration and easing function for the scrolling tween. 22 | */ 23 | constructor(game, xy, values, draggable, vertical = false, trackKey = '', barKey = '', tweenParams = null) { 24 | super(game, xy.x, xy.y, vertical, trackKey, barKey); 25 | 26 | this.valueRange = new ValueRange(values.step, values.startValue, values.maxValue); 27 | 28 | this.draggable = draggable || false; 29 | 30 | this.tweenParams = tweenParams || { duration: 300, ease: PhaserObjects.Easing.Quadratic.Out }; 31 | 32 | // Flag flipped when the track is clicked, switched off after the bar movement is finished. 33 | this.trackClicked = false; 34 | this.barMoving = false; 35 | 36 | // Records mouse pointer when clicking the bar. 37 | this.mousePointer = null; 38 | 39 | // The track is the static area the bar will move along. 40 | this.track = new PhaserObjects.Sprite(game, 0, 0, this.trackKey); 41 | 42 | // Phaser 3: 43 | // Anchor the track to 0 instead of 0.5 44 | this.track.displayOriginX = 0; 45 | this.track.displayOriginY = 0; 46 | 47 | this.add(this.track); 48 | 49 | this.width = this.track.width; 50 | this.height = this.track.height; 51 | 52 | // If the bar is draggable, clicking the track will move the bar up or down. 53 | if (this.draggable) { 54 | this.enableTrackClick(); 55 | } 56 | 57 | // The bar is the part that moves, controlling the value of the scrollbar. 58 | this.bar = new PhaserObjects.Button( 59 | game, 60 | this.x, 61 | this.y, 62 | this.barKey, 63 | this.moveContent, 64 | this, 65 | 1, 66 | 0, 67 | ); 68 | 69 | // Phaser 3: 70 | // Anchor the track to 0 instead of 0.5 71 | this.bar.displayOriginX = 0; 72 | this.bar.displayOriginY = 0; 73 | 74 | // Add an invisible background. 75 | // This ensures the bar can always be entered correctly, no matter where the grip is. 76 | this.bg = new PhaserObjects.Graphics(game, { x: 0, y: 0 }); 77 | this.add(this.bg); 78 | this.sendToBack(this.bg); 79 | this.bg.fillStyle(0xff0000, 0); 80 | 81 | if (this.vertical) { 82 | this.bg.fillRect(0, 0 - (this.bar.height / 2), 1, this.track.height + this.bar.height); 83 | } else { 84 | this.bg.fillRect(0 - (this.bar.width / 2), 0, this.track.width + this.bar.width, 1); 85 | } 86 | 87 | this.snapping = true; 88 | 89 | this.add(this.bar); 90 | this.minY = this.track.y - (this.bar.height / 2); 91 | this.maxY = (this.track.y + this.track.height) - (this.bar.height / 2); 92 | this.minX = this.track.x - (this.bar.width / 2); 93 | this.maxX = (this.track.x + this.track.width) - (this.bar.width / 2); 94 | 95 | this.create(); 96 | 97 | if (this.vertical) { 98 | this.upEvent = this.scrollUp; 99 | this.downEvent = this.scrollDown; 100 | } else { 101 | this.upEvent = this.scrollLeft; 102 | this.downEvent = this.scrollRight; 103 | } 104 | 105 | // Maximum value for the mouse position. 106 | if (this.vertical) { 107 | this.maxValue = this.track.displayHeight + this.worldPosition.y; 108 | 109 | if (this.version === undefined) { 110 | this.maxValue += this.bar.displayHeight; 111 | } 112 | } else { 113 | this.maxValue = this.track.displayWidth + this.worldPosition.x; 114 | 115 | if (this.version === undefined) { 116 | this.maxValue += this.bar.displayWidth; 117 | } 118 | } 119 | } 120 | 121 | create() { 122 | this.centerStaticAxis(); 123 | 124 | if (this.draggable) { 125 | this.enableBarDrag(); 126 | } 127 | 128 | // Determine the distance the window can scroll over 129 | this.windowScrollAreaSize = this.valueRange.maxValue - this.valueRange.step; 130 | 131 | // Represents one fraction of the track. 132 | this.vslice = (this.track.displayHeight * this.valueRange.ratio); 133 | this.hslice = (this.track.displayWidth * this.valueRange.ratio); 134 | 135 | this.setTrackScrollAreaSize(); 136 | 137 | this.setInitialBarPosition(); 138 | 139 | // Initial position for the bar. 140 | this.mousePointer = { x: this.bar.x, y: this.bar.y }; 141 | } 142 | 143 | /** Sets the draggable area of the bar. */ 144 | setDraggableArea() { 145 | let vh = this.track.displayHeight; 146 | 147 | if (this.version === undefined) { 148 | vh += this.bar.displayHeight; 149 | } 150 | 151 | this.verticalDraggableArea = { 152 | x: this.track.x - ((this.bar.displayWidth - this.track.displayWidth) / 2), 153 | y: this.track.y - (this.bar.displayHeight / 2), 154 | w: this.bar.displayWidth, 155 | h: vh, 156 | }; 157 | 158 | this.horizontalDraggableArea = { 159 | x: this.track.x - (this.bar.displayWidth / 2), 160 | y: this.track.y - ((this.bar.displayHeight - this.track.displayHeight) / 2), 161 | w: this.track.displayWidth + this.bar.displayWidth, 162 | h: this.bar.displayHeight, 163 | }; 164 | } 165 | 166 | /** Determine the distance the bar can scroll over */ 167 | setTrackScrollAreaSize() { 168 | if (this.vertical) { 169 | this.trackScrollAreaSize = this.track.displayHeight; 170 | } else { 171 | this.trackScrollAreaSize = this.track.displayWidth; 172 | } 173 | } 174 | 175 | /** Ensure the bar starts off where it should be, according to the bar's logical position. */ 176 | setInitialBarPosition() { 177 | const gripPositionOnTrack = this.getBarPosition(); 178 | 179 | // The bar should always be in centered on it's current position. 180 | if (this.vertical) { 181 | this.bar.y = (gripPositionOnTrack + this.track.y) - (this.bar.displayHeight / 2); 182 | } else { 183 | this.bar.x = (gripPositionOnTrack + this.track.x) - (this.bar.displayWidth / 2); 184 | } 185 | } 186 | 187 | /** @returns {number} the closest valid value. */ 188 | getClosestPosition() { 189 | const currentValue = this.valueRange.getCurrentValue(); 190 | 191 | let diff = Math.abs(currentValue - this.valueRange.steps[0]); 192 | let closestPosition = this.valueRange.steps[0]; 193 | 194 | for (let i = 0; i < this.valueRange.steps.length; i++) { 195 | const newdiff = Math.abs(currentValue - this.valueRange.steps[i]); 196 | if (newdiff < diff) { 197 | diff = newdiff; 198 | closestPosition = this.valueRange.steps[i]; 199 | } 200 | } 201 | 202 | return closestPosition; 203 | } 204 | 205 | /** On mouse up, forces the value to equal the closest step. */ 206 | snapToClosestPosition() { 207 | const closestPosition = this.getClosestPosition(); 208 | 209 | this.valueRange.adjustValue(closestPosition); 210 | this.moveContent(); 211 | this.setInitialBarPosition(); 212 | } 213 | 214 | /** 215 | * @private 216 | * Creates the tween for moving the bar to a new position. 217 | */ 218 | addScrollTween(properties) { 219 | this.mousePointer = { x: this.bar.x, y: this.bar.y }; 220 | this.trackClicked = true; 221 | 222 | new PhaserObjects.Tween(this.game).add( 223 | this.bar, 224 | properties, 225 | this.tweenParams.duration, 226 | this.tweenParams.ease, 227 | () => { this.moveContent(); this.enableBarInput(); }, 228 | null, 229 | null, 230 | this, 231 | null, 232 | null, 233 | ); 234 | } 235 | 236 | getGripPositionRatio() { 237 | const gripPositionOnTrack = this.getBarPosition(); 238 | const mousePositionDelta = this.getMouseDelta(); 239 | 240 | let newGripPosition = gripPositionOnTrack - mousePositionDelta; 241 | // Don't let the content scroll above or below the track's size 242 | if (newGripPosition < 0) { 243 | newGripPosition = 0; 244 | } else if (newGripPosition >= this.trackScrollAreaSize) { 245 | newGripPosition = this.trackScrollAreaSize; 246 | } 247 | 248 | // When the scrollbar is at the top or bottom, prevent a mouse movement that 249 | // doesn't move the scrollbar from moving the content. 250 | if (this.vertical) { 251 | if (this.bar.y <= this.track.y) { 252 | newGripPosition = 0; 253 | } else if (this.bar.y + this.bar.displayHeight >= this.track.y + this.track.displayHeight) { 254 | newGripPosition = this.trackScrollAreaSize; 255 | } 256 | } else { 257 | if (this.bar.x <= this.track.x) { 258 | newGripPosition = 0; 259 | } else if (this.bar.x + this.bar.displayWidth >= this.track.x + this.track.displayWidth) { 260 | newGripPosition = this.trackScrollAreaSize; 261 | } 262 | } 263 | 264 | let newGripPositionRatio = newGripPosition / this.trackScrollAreaSize; 265 | 266 | // If the scrollable area is less than the size of the scrollbar, 267 | // the bar and track will be the same size. 268 | // In this scenario, a divide by zero occurs. Capture that and turn it into zero. 269 | if (Number.isNaN(newGripPositionRatio)) { 270 | newGripPositionRatio = 0; 271 | } 272 | 273 | return newGripPositionRatio; 274 | } 275 | } 276 | -------------------------------------------------------------------------------- /src/buttons.js: -------------------------------------------------------------------------------- 1 | import * as PhaserObjects from './phaserObjects'; 2 | 3 | /** Group with some added functionality for text overlays. 4 | * @private 5 | * @extends Phaser.Group 6 | */ 7 | class TextGroup extends PhaserObjects.Group { 8 | /** 9 | * @param {Object} game - Current game instance. 10 | * @param {number} x - The x coordinate on screen where the sprite will be placed. 11 | * @param {number} y - The y coordinate on screen where the sprite will be placed. 12 | */ 13 | constructor(game, x, y) { 14 | super(game, x, y); 15 | 16 | this.game = game; 17 | this.x = x; 18 | this.y = y; 19 | 20 | game.add.existing(this); 21 | } 22 | 23 | /** 24 | * @param {string} label - The text to place on top of the sprite. 25 | * @param {Object} style - The style properties to be set on the Text. 26 | */ 27 | setText(label, style) { 28 | if (this.text) { 29 | this.text.destroy(); 30 | } 31 | 32 | if (this.version === 3) { 33 | this.text = this.game.add.text(0, 0, label, style); 34 | this.text.setOrigin(0.5, 0.5); 35 | } else { 36 | this.text = this.game.add.text(this.width / 2, this.height / 2, label, style); 37 | this.text.anchor.set(0.5, 0.5); 38 | } 39 | 40 | this.add(this.text); 41 | 42 | this.text.wordWrap = true; 43 | this.text.wordWrapWidth = this.width; 44 | 45 | return this; 46 | } 47 | 48 | /** When setOrigin is called, align the text as well. */ 49 | setOrigin(x, y) { 50 | if (this.version === 3) { 51 | this.sprite.setOrigin(x, y); 52 | } else { 53 | this.sprite.anchor.set(x, y); 54 | } 55 | 56 | this.text.x = this.sprite.width / 2; 57 | this.text.y = this.sprite.height / 2; 58 | this.currentTextY = this.sprite.height / 2; 59 | 60 | return this; 61 | } 62 | } 63 | 64 | /** Sprite with text added as a child. 65 | * @extends Phaser.Group 66 | */ 67 | export class TextSprite extends TextGroup { 68 | /** 69 | * @param {Object} game - Current game instance. 70 | * @param {number} x - The x coordinate on screen where the textSprite will be placed. 71 | * @param {number} y - The y coordinate on screen where the textSprite will be placed. 72 | * @param {string} key - The image to create a sprite with. 73 | */ 74 | constructor(game, x, y, key) { 75 | super(game, x, y); 76 | 77 | this.sprite = new PhaserObjects.Sprite(game, 0, 0, key); 78 | this.add(this.sprite); 79 | 80 | this.width = this.sprite.width; 81 | this.height = this.sprite.height; 82 | } 83 | } 84 | 85 | /** Phaser Group containing a button with text anchored in the button's center. 86 | * @extends Phaser.Group 87 | */ 88 | export class TextButton extends TextGroup { 89 | /** 90 | * @param {Object} game - Current game instance. 91 | * @param {number} x - The x coordinate on screen where the textSprite will be placed. 92 | * @param {number} y - The y coordinate on screen where the textSprite will be placed. 93 | * @param {string} key - The image to create a sprite with. 94 | * @param {Object} callback - Callback to use when the button is clicked. 95 | * @param {Object} callbackContext - The context the callback is called in. 96 | * @param {number} overKey - The frame to switch to when an over event is triggered. 97 | * @param {number} outKey - The frame to switch to when an out event is triggered. 98 | * @param {number} downKey - The frame to switch to when a down event is triggered. 99 | * @param {number} upKey - The frame to switch to when an up event is triggered. 100 | */ 101 | constructor(game, x, y, key, callback, callbackContext, overKey, outKey, downKey, upKey) { 102 | super(game, x, y); 103 | 104 | this.sprite = new PhaserObjects.Button( 105 | game, 106 | 0, 107 | 0, 108 | key, 109 | callback, 110 | callbackContext, 111 | overKey, 112 | outKey, 113 | downKey, 114 | upKey, 115 | ); 116 | this.add(this.sprite); 117 | 118 | this.width = this.sprite.width; 119 | this.height = this.sprite.height; 120 | 121 | this.currentTextY = 0; 122 | } 123 | 124 | /** Adds an adjustment to the text on down/up events. */ 125 | eventTextYAdjustment(number) { 126 | this.sprite.addDownEvent(() => { this.text.y += number; }); 127 | this.sprite.addUpEvent(() => { this.text.y = this.currentTextY; }); 128 | 129 | // A pointerout event should reset the text position too. 130 | this.sprite.addOutEvent(() => { this.text.y = this.currentTextY; }); 131 | 132 | return this; 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/const.js: -------------------------------------------------------------------------------- 1 | // Matches the alignment consts from Phaser 2 | export const alignments = { 3 | TOP_LEFT: 0, 4 | TOP_CENTER: 1, 5 | TOP_RIGHT: 2, 6 | LEFT_TOP: 3, 7 | LEFT_CENTER: 4, 8 | LEFT_BOTTOM: 5, 9 | CENTER: 6, 10 | RIGHT_TOP: 7, 11 | RIGHT_CENTER: 8, 12 | RIGHT_BOTTOM: 9, 13 | BOTTOM_LEFT: 10, 14 | BOTTOM_CENTER: 11, 15 | BOTTOM_RIGHT: 12, 16 | }; 17 | -------------------------------------------------------------------------------- /src/containers/column.js: -------------------------------------------------------------------------------- 1 | import { alignments } from '../const'; 2 | import { Frame } from './frame'; 3 | 4 | /** Frame that places new child nodes directly under the previous child. 5 | * @extends Frame 6 | */ 7 | export class Column extends Frame { 8 | /** 9 | * @param {Object} game - Current game instance. 10 | * @param {Number} x - The x position of the Column. 11 | * @param {Number} y - The y position of the Column. 12 | * @param {string} bg - The background image to use. 13 | * @param {boolean} modal - If the Column should block external interaction until killed. 14 | */ 15 | constructor(game, x = 0, y = 0, bg = null, modal = false) { 16 | super(game, x, y, bg, modal); 17 | this.alignment = alignments.BOTTOM_CENTER; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/containers/frame.js: -------------------------------------------------------------------------------- 1 | import { alignments } from '../const'; 2 | import * as PhaserObjects from '../phaserObjects'; 3 | 4 | /** Group with a dedicated background image. 5 | * @extends Phaser.Group 6 | */ 7 | export class Frame extends PhaserObjects.Group { 8 | /** 9 | * @param {Object} game - Current game instance. 10 | * @param {number} x - The x position of the Frame. 11 | * @param {number} y - The y position of the Frame. 12 | * @param {string} bg - The background image to use. 13 | * @param {boolean} modal - If the Frame should block external interaction until killed. 14 | */ 15 | constructor(game, x = 0, y = 0, bg = null, modal = false) { 16 | super(game); 17 | game.add.existing(this); 18 | 19 | this.x = x; 20 | this.y = y; 21 | 22 | this.uiWidgetsObjectRole = 'layout'; 23 | 24 | this.modal = modal; 25 | 26 | this.background = null; 27 | this.back = null; 28 | 29 | if (modal) { 30 | // Create a sprite to use as the modal back. 31 | const texture = new PhaserObjects.Graphics(game, { x: 0, y: 0 }); 32 | texture.fillStyle(0xffffff, 1); 33 | texture.fillRect(0, 0, game.scale.width, game.scale.height); 34 | 35 | let modalBack; 36 | if (this.version === 3) { 37 | texture.generateTexture('modalBack'); 38 | modalBack = 'modalBack'; 39 | } else { 40 | modalBack = texture.generateTexture(); 41 | } 42 | 43 | this.back = new PhaserObjects.Sprite(game, 0, 0, modalBack); 44 | this.back.setInteractive(); 45 | this.back.setOrigin(0, 0); 46 | // CE requirement 47 | this.back.moveDown(); 48 | 49 | // Mask the back, causing it to be invisible. 50 | const backMask = new PhaserObjects.ViewportMask(game, 0, 0); 51 | this.back.mask = backMask.create(0, 0, 0, 0); 52 | 53 | game.add.existing(this.back); 54 | 55 | // Ensure the modal doesn't hide the Frame's content. 56 | this.depth = 9999; 57 | this.back.depth = 9998; 58 | } 59 | 60 | if (bg !== null) { 61 | this.background = new PhaserObjects.Sprite(game, 0, 0, bg); 62 | game.add.existing(this.background); 63 | this.background.sendToBack(); 64 | this.background.alignIn(this, alignments.TOP_LEFT); 65 | } 66 | } 67 | 68 | /** Destroy the Frame, along with any background or modal effect. */ 69 | dismiss() { 70 | if (this.modal) { 71 | this.back.destroy(); 72 | } 73 | 74 | if (this.background !== null) { 75 | this.background.destroy(); 76 | } 77 | 78 | this.destroy(); 79 | } 80 | 81 | /** Adds a new object into the Frame, then aligns it with the previous object. 82 | * @param {Object} node - The object to add to the Frame. 83 | * @param {number} paddingX - The amount of horizontal space between objects. 84 | * @param {number} paddingY - The amount of vertical space between objects. 85 | * @param {number} alignment - The alignment relative to the previous child. 86 | */ 87 | addNode(node, paddingX = 0, paddingY = 0, alignment = null) { 88 | const align = alignment || this.alignment; 89 | 90 | if (!(node instanceof PhaserObjects.Group)) { 91 | node.displayOriginX = 0; // eslint-disable-line 92 | node.displayOriginY = 0; // eslint-disable-line 93 | } else if (node instanceof PhaserObjects.Group) { 94 | node.setOrigin(0, 0); 95 | } 96 | 97 | this.add(node); 98 | this.alignNodeToPrevious(node, align, paddingX, paddingY); 99 | node.parentContainer = this; // eslint-disable-line 100 | 101 | // Phaser 3: QuantityBar's mask needs a personal touch. 102 | if (node.uiWidgetsObjectRole === 'quantitybar') { 103 | if (node.version === 3) { 104 | node.create(this.x, this.y); 105 | } 106 | } 107 | 108 | // Reset the positions for the bar's draggable area. 109 | if ('enableBarDrag' in node) { 110 | node.enableBarDrag(); 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/containers/row.js: -------------------------------------------------------------------------------- 1 | import { alignments } from '../const'; 2 | import { Frame } from './frame'; 3 | 4 | /** Frame that places new child nodes directly next to the previous child. 5 | * @extends Frame 6 | */ 7 | export class Row extends Frame { 8 | /** 9 | * @param {Object} game - Current game instance. 10 | * @param {Number} x - The x position of the Row. 11 | * @param {Number} y - The y position of the Row. 12 | * @param {string} bg - The background image to use. 13 | * @param {boolean} modal - If the Row should block external interaction until killed. 14 | */ 15 | constructor(game, x = 0, y = 0, bg = null, modal = false) { 16 | super(game, x, y, bg, modal); 17 | this.alignment = alignments.RIGHT_CENTER; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/containers/viewport.js: -------------------------------------------------------------------------------- 1 | import * as PhaserObjects from '../phaserObjects'; 2 | 3 | /** 4 | * A container with a limited viewable area. Uses a mask to hide children outside of the specified x/y/width/height area. 5 | * Content outside the viewport has their input disabled. 6 | * @extends PhaserObjects.Group 7 | */ 8 | export class Viewport extends PhaserObjects.Group { 9 | /** 10 | * @param {Object} game - Current game instance. 11 | * @param {number} x - The x coordinate on screen where the viewport will be placed. 12 | * @param {number} y - The y coordinate on screen where the viewport will be placed. 13 | * @param {number} width - The width of the viewport. 14 | * @param {number} height - The height of the viewport. 15 | */ 16 | constructor(game, x, y, width, height) { 17 | super(game); 18 | game.add.existing(this); 19 | 20 | this.x = x; 21 | this.y = y; 22 | 23 | this.uiWidgetsObjectRole = 'layout'; 24 | 25 | // Viewport size and position, distinct from the total window size. 26 | this.area = { 27 | x, 28 | y, 29 | width, 30 | height, 31 | }; 32 | 33 | // Adding the mask attribute to a group hides objects outside the mask. 34 | const mask = new PhaserObjects.ViewportMask(game, x, y); 35 | 36 | if (this.version === undefined) { 37 | this.mask = mask.create(x, y, width, height); 38 | } else { 39 | this.mask = mask.create(0, 0, width, height); 40 | } 41 | } 42 | 43 | /** Adds a new object into the Viewport. 44 | * @param {Object} node - The object to add to the Viewport. 45 | */ 46 | addNode(node) { 47 | this.add(node); 48 | node.parentContainer = this; // eslint-disable-line 49 | } 50 | 51 | /** Disable input for all objets outside the viewport's visible area. 52 | * Recursively checks all the object's children. 53 | * @param {Object} children - The objects to disable, if they're outside the viewport. 54 | * @param {Object} context - The context the function is run in. 55 | * @param {boolean} vertical - If the bounds should be checked horizontally or vertically. 56 | */ 57 | disableOutOfBounds(children, context, vertical) { 58 | let child; 59 | let location; 60 | let contentLocation; 61 | let trueCoords; 62 | 63 | // Makes sure the recursive function stops when there's no children. 64 | if (children !== undefined) { 65 | for (let i = 0; i < children.length; i++) { 66 | child = children[i]; 67 | child.inputEnabled = true; 68 | 69 | // An object's x/y is relative to it's parent. 70 | // The world gives an x/y relative to the whole game. 71 | trueCoords = child.world || child; 72 | 73 | if (vertical) { 74 | location = trueCoords.y; 75 | contentLocation = context.viewport.area.y; 76 | } else { 77 | location = trueCoords.x; 78 | contentLocation = context.viewport.area.x; 79 | } 80 | 81 | if (location < contentLocation) { 82 | child.inputEnabled = false; 83 | } 84 | 85 | this.disableOutOfBounds(child.children, context, vertical); 86 | } 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/entry.js: -------------------------------------------------------------------------------- 1 | import { TextSprite, TextButton } from './buttons'; 2 | import { KeyboardGroup } from './keyboard_group'; 3 | import { Wheel3D } from './wheel3D'; 4 | 5 | import { QuantityBar } from './bars/quantitybar'; 6 | import { Scrollbar } from './bars/scrollbar'; 7 | import { ValueBar } from './bars/valuebar'; 8 | 9 | import { Frame } from './containers/frame'; 10 | import { Column } from './containers/column'; 11 | import { Row } from './containers/row'; 12 | import { Viewport } from './containers/viewport'; 13 | 14 | import { Button } from './phaserObjects/button'; 15 | 16 | export { 17 | TextSprite, 18 | TextButton, 19 | KeyboardGroup, 20 | Wheel3D, 21 | QuantityBar, 22 | Scrollbar, 23 | ValueBar, 24 | Frame, 25 | Column, 26 | Row, 27 | Viewport, 28 | Button, 29 | }; 30 | -------------------------------------------------------------------------------- /src/keyboard_group.js: -------------------------------------------------------------------------------- 1 | import { EventEmitter } from 'eventemitter3'; 2 | import * as PhaserObjects from './phaserObjects'; 3 | 4 | import { utils } from './utils'; 5 | 6 | /** Collection of sprites that can be selected with the keyboard. 7 | * When the select key is hit, the sprite that was selected is now connected to the keyboard. 8 | */ 9 | export class KeyboardGroup { 10 | /** 11 | * @param {Object} game - Current game instance. 12 | * @param {Boolean} vertical - If the selection should be controlled with up/down or left/right arrow keys. 13 | * @param {Object} callbackContext - The context for the previous and next Events. 14 | */ 15 | constructor(game, vertical, callbackContext) { 16 | this.game = game; 17 | this.vertical = vertical || false; 18 | this.callbackContext = callbackContext; 19 | 20 | this.children = []; 21 | 22 | this.selected = null; 23 | this.idx = 0; 24 | 25 | this.upKey = this.game.input.keyboard.addKey(PhaserObjects.KeyCodes.UP); 26 | this.downKey = this.game.input.keyboard.addKey(PhaserObjects.KeyCodes.DOWN); 27 | this.leftKey = this.game.input.keyboard.addKey(PhaserObjects.KeyCodes.LEFT); 28 | this.rightKey = this.game.input.keyboard.addKey(PhaserObjects.KeyCodes.RIGHT); 29 | 30 | this.upEvent = this.prevItem; 31 | this.downEvent = this.nextItem; 32 | 33 | this.emitter = new EventEmitter(); 34 | 35 | this.activateGroup(); 36 | } 37 | 38 | /** Add a new child to the group 39 | * @param {Object} newNode - The sprite to add to the group. 40 | */ 41 | addNode(newNode) { 42 | this.children.push(newNode); 43 | 44 | // Ensure the first child is already selected when the game loads. 45 | this.selected = this.children[0]; // eslint-disable-line prefer-destructuring 46 | this.useBar(); 47 | } 48 | 49 | /** Selects the previous child. */ 50 | prevItem() { 51 | this.idx = utils.modulo(this.idx - 1, this.children.length); 52 | 53 | this.selected = this.children[this.idx]; 54 | 55 | this.useBar(); 56 | 57 | this.emitter.emit('previous', this, this.callbackContext); 58 | } 59 | 60 | /** Selects the next child. */ 61 | nextItem() { 62 | this.idx = utils.modulo(this.idx + 1, this.children.length); 63 | 64 | this.selected = this.children[this.idx]; 65 | 66 | this.useBar(); 67 | 68 | this.emitter.emit('next', this, this.callbackContext); 69 | } 70 | 71 | /** 72 | * Enables keyboard input for the group. 73 | * @private 74 | */ 75 | activateGroup() { 76 | const keyboard = new PhaserObjects.Keyboard(); 77 | 78 | if (this.vertical) { 79 | keyboard.addDownEvent(this.upKey, this.upEvent, this); 80 | keyboard.addDownEvent(this.downKey, this.downEvent, this); 81 | } else { 82 | keyboard.addDownEvent(this.leftKey, this.upEvent, this); 83 | keyboard.addDownEvent(this.rightKey, this.downEvent, this); 84 | } 85 | } 86 | 87 | /** 88 | * Enables keyboard input on a child. 89 | * @private 90 | */ 91 | useBar() { 92 | const keyboard = new PhaserObjects.Keyboard(); 93 | 94 | if (this.vertical) { 95 | keyboard.removeDownEvent(this.leftKey); 96 | keyboard.removeDownEvent(this.rightKey); 97 | 98 | keyboard.addDownEvent(this.leftKey, this.selected.upEvent, this.selected); 99 | keyboard.addDownEvent(this.rightKey, this.selected.downEvent, this.selected); 100 | } else { 101 | keyboard.removeDownEvent(this.upKey); 102 | keyboard.removeDownEvent(this.downKey); 103 | 104 | keyboard.addDownEvent(this.upKey, this.selected.upEvent, this.selected); 105 | keyboard.addDownEvent(this.downKey, this.selected.downEvent, this.selected); 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/phaserObjects/button.js: -------------------------------------------------------------------------------- 1 | import { Sprite } from './sprite'; 2 | 3 | let exportObject; 4 | 5 | if (Phaser.Button === undefined) { 6 | /** Build a button object that immitates Phaser CE's Button 7 | * @private 8 | */ 9 | class Phaser3Button extends Sprite { 10 | constructor(game, x, y, key, callback, callbackContext, overKey, outKey, downKey, upKey) { 11 | super(game, x, y, key); 12 | 13 | game.add.existing(this); 14 | 15 | this.game = game; 16 | 17 | this.overKey = overKey; 18 | this.outKey = outKey; 19 | this.downKey = downKey; 20 | this.upKey = upKey; 21 | 22 | this.setInteractive({ useHandCursor: true }); 23 | 24 | let cbContext = callbackContext; 25 | 26 | if (cbContext === null || (cbContext === undefined)) { 27 | cbContext = this; 28 | } 29 | 30 | this.on('pointerdown', (pointer) => { 31 | callback.call(cbContext, pointer); 32 | }); 33 | this.on('pointerover', this.onOver, this); 34 | this.on('pointerout', this.onOut, this); 35 | this.on('pointerdown', this.onDown, this); 36 | this.on('pointerup', this.onUp, this); 37 | } 38 | 39 | onOver() { 40 | this.setFrame(this.overKey); 41 | } 42 | 43 | onOut() { 44 | this.setFrame(this.outKey); 45 | } 46 | 47 | onDown() { 48 | this.setFrame(this.downKey); 49 | } 50 | 51 | onUp() { 52 | this.setFrame(this.upKey); 53 | } 54 | 55 | updateDrag(pointer, gameObject, x, y) { //eslint-disable-line 56 | if (gameObject.vertical) { 57 | if ((gameObject.draggableArea.y + gameObject.draggableArea.h) >= y) { 58 | if (gameObject.draggableArea.y <= y) { 59 | gameObject.y = y; //eslint-disable-line 60 | } 61 | } 62 | } else { 63 | const fx = (x + gameObject.displayWidth); 64 | if ((gameObject.draggableArea.x + gameObject.draggableArea.w) >= fx) { 65 | if (gameObject.draggableArea.x <= x) { 66 | gameObject.x = x; //eslint-disable-line 67 | } 68 | } 69 | } 70 | } 71 | 72 | setDragBounds(draggableArea) { 73 | this.draggableArea = draggableArea; 74 | } 75 | 76 | enableDragging(vertical = false) { 77 | this.setInteractive({ useHandCursor: true }); 78 | this.vertical = vertical; 79 | this.game.input.setDraggable(this); 80 | this.game.input.on('drag', this.updateDrag); 81 | } 82 | } 83 | 84 | exportObject = Phaser3Button; 85 | } else { 86 | class PhaserCEButton extends Phaser.Button { 87 | constructor(game, x, y, key, callback, callbackContext, overKey, outKey, downKey, upKey) { 88 | super(game, x, y, key, callback, callbackContext, overKey, outKey, downKey, upKey); 89 | 90 | game.add.existing(this); 91 | } 92 | 93 | setInteractive() { 94 | this.inputEnabled = true; 95 | this.input.useHandCursor = true; 96 | } 97 | 98 | disableInteractive() { 99 | this.inputEnabled = false; 100 | } 101 | 102 | setDragBounds(draggableArea) { 103 | this.input.boundsRect = new Phaser.Rectangle( 104 | draggableArea.x, 105 | draggableArea.y, 106 | draggableArea.w, 107 | draggableArea.h, 108 | ); 109 | } 110 | 111 | enableDragging(vertical = false) { 112 | this.inputEnabled = true; 113 | this.input.enableDrag(); 114 | 115 | if (vertical) { 116 | this.input.allowHorizontalDrag = false; 117 | } else { 118 | this.input.allowVerticalDrag = false; 119 | } 120 | } 121 | 122 | /** 123 | * @private 124 | * Add a callback that is triggered when the pointer moves out of the object. 125 | */ 126 | addOutEvent(callback, callbackContext) { 127 | this.events.onInputOut.add(callback, callbackContext); 128 | } 129 | 130 | /** 131 | * @private 132 | * Add a callback that is triggered when the object is unclicked. 133 | */ 134 | addUpEvent(callback, callbackContext) { 135 | this.events.onInputUp.add(callback, callbackContext); 136 | } 137 | 138 | /** 139 | * @private 140 | * Add a callback that is triggered when the object is clicked. 141 | */ 142 | addDownEvent(callback, callbackContext) { 143 | this.events.onInputDown.add(callback, callbackContext); 144 | } 145 | 146 | /** 147 | * @private 148 | * Add a callback that is triggered when the object is dragged. 149 | */ 150 | addDragEvent(callback, callbackContext) { 151 | this.events.onDragUpdate.add(callback, callbackContext); 152 | } 153 | 154 | /** Immitate the API of Phaser3. 155 | * The current displayed height of the Object. 156 | * @type {number} 157 | * @private 158 | */ 159 | get displayHeight() { 160 | return this.height; 161 | } 162 | 163 | set displayHeight(newValue) { 164 | this.height = newValue; 165 | } 166 | 167 | /** Immitate the API of Phaser3. 168 | * The current displayed width of the Object. 169 | * @type {number} 170 | * @private 171 | */ 172 | get displayWidth() { 173 | return this.width; 174 | } 175 | 176 | set displayWidth(newValue) { 177 | this.width = newValue; 178 | } 179 | } 180 | 181 | exportObject = PhaserCEButton; 182 | } 183 | 184 | export const Button = exportObject; 185 | -------------------------------------------------------------------------------- /src/phaserObjects/easing.js: -------------------------------------------------------------------------------- 1 | let exportObject; 2 | 3 | if (Phaser.Easing === undefined) { 4 | exportObject = Phaser.Math.Easing; 5 | } else { 6 | exportObject = Phaser.Easing; 7 | } 8 | 9 | export const Easing = exportObject; 10 | -------------------------------------------------------------------------------- /src/phaserObjects/graphics.js: -------------------------------------------------------------------------------- 1 | let exportObject; 2 | 3 | if (Phaser.Graphics === undefined) { 4 | exportObject = Phaser.GameObjects.Graphics; 5 | } else { 6 | class PhaserCEGraphics extends Phaser.Graphics { 7 | constructor(game, options) { 8 | super(game, options.x, options.y); 9 | } 10 | 11 | fillStyle(colour, alpha) { 12 | this.beginFill(colour, alpha); 13 | } 14 | 15 | fillRect(x, y, width, height) { 16 | this.drawRect(x, y, width, height); 17 | this.endFill(); 18 | } 19 | } 20 | 21 | exportObject = PhaserCEGraphics; 22 | } 23 | 24 | export const Graphics = exportObject; 25 | -------------------------------------------------------------------------------- /src/phaserObjects/group.js: -------------------------------------------------------------------------------- 1 | let exportObject; 2 | 3 | if (Phaser.Group === undefined) { 4 | // Emulate Phaser CE's worldPosition object 5 | class WorldPosition { 6 | constructor(parent) { 7 | this.parent = parent; 8 | } 9 | 10 | get x() { 11 | return this.parent.x; 12 | } 13 | 14 | get y() { 15 | return this.parent.y; 16 | } 17 | } 18 | 19 | class Phaser3Group extends Phaser.GameObjects.Container { 20 | constructor(game, x = 0, y = 0) { 21 | super(game, x, y); 22 | 23 | game.add.existing(this); 24 | 25 | this.parentContainer = null; 26 | 27 | this.SORT_ASCENDING = -1; 28 | this.SORT_DESCENDING = 1; 29 | 30 | this.version = 3; 31 | 32 | // Emulate Phaser CE's GameObject.alignTo 33 | this.alignToMapping = { 34 | 0: Phaser.Display.Align.To.TopLeft, 35 | 1: Phaser.Display.Align.To.TopCenter, 36 | 8: Phaser.Display.Align.To.RightCenter, 37 | 11: Phaser.Display.Align.To.BottomCenter, 38 | }; 39 | 40 | this.worldPosition = new WorldPosition(this); 41 | } 42 | 43 | /** @private Alias to match Phaser CE */ 44 | get children() { 45 | return this.list; 46 | } 47 | 48 | get realHeight() { 49 | return this.getBounds().height - this.y; 50 | } 51 | 52 | get realWidth() { 53 | return this.getBounds().width - this.x; 54 | } 55 | 56 | /** Set the origin points of every member of the group. */ 57 | setOrigin(x = 0, y = 0) { 58 | let node; 59 | 60 | for (let i = 0; i < this.children.length; i++) { 61 | node = this.children[i]; 62 | 63 | if (!(node instanceof Phaser3Group)) { 64 | node.displayOriginX = x; // eslint-disable-line 65 | node.displayOriginY = y; // eslint-disable-line 66 | } else if (node instanceof Phaser3Group) { 67 | node.setOrigin(x, y); 68 | } 69 | } 70 | } 71 | 72 | getNodes() { 73 | return this.getAll(); 74 | } 75 | 76 | // Can't align to Containers automatically 77 | alignToContainerBottom(previousNode, child) { 78 | // realWidth changes inside a Container 79 | 80 | let previousNodeWidth; 81 | let previousNodeHeight; 82 | if (child.uiWidgetsObjectRole === 'layout') { 83 | const bounds = previousNode.getBounds(); 84 | previousNodeWidth = bounds.width - this.worldPosition.x; 85 | previousNodeHeight = bounds.height - this.worldPosition.y; 86 | } else { 87 | previousNodeWidth = previousNode.width; 88 | previousNodeHeight = previousNode.height; 89 | } 90 | 91 | const centerX = (previousNodeWidth * 0.5); 92 | const bottomY = previousNodeHeight; 93 | 94 | let w = child.width; 95 | if (child.uiWidgetsObjectRole === 'layout') { 96 | w = child.getBounds().width; 97 | } 98 | 99 | child.x = centerX - (w * 0.5); // eslint-disable-line 100 | child.y = previousNode.getBounds().y + bottomY; // eslint-disable-line 101 | } 102 | 103 | /** Containers can't be aligned automatically */ 104 | alignContainerToBottom(previousNode, child) { // eslint-disable-line 105 | const bounds = previousNode.getBounds(); 106 | const centerX = previousNode.x + (bounds.width * 0.5); 107 | 108 | child.x = centerX - (child.width * 0.5); // eslint-disable-line 109 | child.y = bounds.y; // eslint-disable-line 110 | } 111 | 112 | alignContainerToRight(previousNode, child) { // eslint-disable-line 113 | const rightX = previousNode.x + previousNode.width; 114 | 115 | child.x = rightX; // eslint-disable-line 116 | } 117 | 118 | /** Aligns child to the last object in the group. 119 | * @private 120 | */ 121 | alignNodeToPrevious(child, align, paddingX, paddingY) { 122 | const nodes = this.getNodes(); 123 | const previousNode = nodes[nodes.length - 2]; 124 | 125 | const toGroupAlignFuncs = { 126 | 11: this.alignContainerToBottom, // Column 127 | 8: this.alignContainerToRight, // Row 128 | }; 129 | 130 | const toGroupAlignFunc = toGroupAlignFuncs[align]; 131 | 132 | if (previousNode instanceof Phaser3Group) { 133 | this.alignToContainerBottom(previousNode, child); 134 | } else if (child instanceof Phaser3Group && (previousNode !== undefined)) { 135 | toGroupAlignFunc(previousNode, child); 136 | } else if (previousNode !== undefined) { 137 | this.alignToMapping[align](child, previousNode, paddingX, paddingY); 138 | } 139 | } 140 | } 141 | 142 | exportObject = Phaser3Group; 143 | } else { 144 | class PhaserCEGroup extends Phaser.Group { 145 | constructor(game) { 146 | super(game); 147 | 148 | this.parentContainer = null; 149 | 150 | this.SORT_ASCENDING = -1; 151 | this.SORT_DESCENDING = 1; 152 | } 153 | 154 | get realHeight() { 155 | return this.height; 156 | } 157 | 158 | get realWidth() { 159 | return this.width; 160 | } 161 | 162 | getNodes() { 163 | return this.children; 164 | } 165 | 166 | /** Aligns child to the last object in the group. 167 | * @private 168 | */ 169 | alignNodeToPrevious(child, align, paddingX, paddingY) { 170 | const nodes = this.getNodes(); 171 | const previousNode = nodes[nodes.length - 2]; 172 | 173 | if (previousNode !== undefined) { 174 | child.alignTo(previousNode, align, paddingX, paddingY); 175 | } 176 | } 177 | } 178 | 179 | exportObject = PhaserCEGroup; 180 | } 181 | 182 | export const Group = exportObject; 183 | -------------------------------------------------------------------------------- /src/phaserObjects/index.js: -------------------------------------------------------------------------------- 1 | /** Collection of shims that provide different objects based on the Phaser 2 | * version used. 3 | * @module phaserObjects 4 | * @private 5 | */ 6 | import { Button } from './button'; 7 | import { Easing } from './easing'; 8 | import { Graphics } from './graphics'; 9 | import { Group } from './group'; 10 | import { Keyboard } from './keyboard'; 11 | import { KeyCodes } from './keycodes'; 12 | import { Rectangle } from './rectangle'; 13 | import { Sprite } from './sprite'; 14 | import { Tween } from './tween'; 15 | import { ViewportMask } from './viewport_mask'; 16 | 17 | export { 18 | Button, 19 | Easing, 20 | Graphics, 21 | Group, 22 | Keyboard, 23 | KeyCodes, 24 | Rectangle, 25 | Sprite, 26 | Tween, 27 | ViewportMask, 28 | }; 29 | -------------------------------------------------------------------------------- /src/phaserObjects/keyboard.js: -------------------------------------------------------------------------------- 1 | let exportObject; 2 | 3 | if (Phaser.Keyboard === undefined) { 4 | class Phaser3Keyboard { 5 | addDownEvent(key, event, context) { // eslint-disable-line 6 | key.on('down', event, context); 7 | } 8 | 9 | removeDownEvent(key) { // eslint-disable-line 10 | key.removeListener('down'); 11 | } 12 | } 13 | 14 | exportObject = Phaser3Keyboard; 15 | } else { 16 | class PhaserCEKeyboard { 17 | addDownEvent(key, event, context) { // eslint-disable-line 18 | key.onDown.add(event, context); 19 | } 20 | 21 | removeDownEvent(key) { // eslint-disable-line 22 | key.onDown.removeAll(); 23 | } 24 | } 25 | 26 | exportObject = PhaserCEKeyboard; 27 | } 28 | 29 | export const Keyboard = exportObject; 30 | -------------------------------------------------------------------------------- /src/phaserObjects/keycodes.js: -------------------------------------------------------------------------------- 1 | let exportKeyCodes; 2 | 3 | if (Phaser.Keyboard === undefined) { 4 | exportKeyCodes = Phaser.Input.Keyboard.KeyCodes; 5 | } else { 6 | exportKeyCodes = Phaser.Keyboard; 7 | } 8 | 9 | export const KeyCodes = exportKeyCodes; 10 | -------------------------------------------------------------------------------- /src/phaserObjects/rectangle.js: -------------------------------------------------------------------------------- 1 | let exportObject; 2 | 3 | if (Phaser.Rectangle === undefined) { 4 | exportObject = Phaser.Geom.Rectangle; 5 | } else { 6 | exportObject = Phaser.Rectangle; 7 | } 8 | 9 | export const Rectangle = exportObject; 10 | -------------------------------------------------------------------------------- /src/phaserObjects/sprite.js: -------------------------------------------------------------------------------- 1 | let exportObject; 2 | 3 | if (Phaser.Sprite === undefined) { 4 | class Phaser3Sprite extends Phaser.GameObjects.Sprite { 5 | constructor(game, x, y, image) { 6 | super(game, x, y, image); 7 | 8 | game.add.existing(this); 9 | 10 | // Map alignment constants to Phaser 3 Align functions 11 | const alignIn = Phaser.Display.Align.In; 12 | this.alignInMapping = { 13 | 0: alignIn.TopLeft, 14 | 1: alignIn.TopCenter, 15 | 2: alignIn.TopRight, 16 | 3: alignIn.LeftTop, 17 | 4: alignIn.LeftCenter, 18 | 5: alignIn.LeftBottom, 19 | 6: alignIn.Center, 20 | 7: alignIn.RightTop, 21 | 8: alignIn.RightCenter, 22 | 9: alignIn.RightBottom, 23 | 10: alignIn.BottomLeft, 24 | 11: alignIn.BottomCenter, 25 | 12: alignIn.BottomRight, 26 | }; 27 | } 28 | 29 | get maskX() { 30 | return this.x; 31 | } 32 | 33 | get maskY() { 34 | return this.y; 35 | } 36 | 37 | /** Immitate the API of PhaserCE. 38 | * Move this object behind all others. 39 | * @private 40 | */ 41 | sendToBack() { 42 | this.depth = -9999; 43 | } 44 | 45 | /** Immitate the API of PhaserCE. 46 | * Move this object down the depth order by 1. 47 | * @private 48 | */ 49 | moveDown() { 50 | this.depth -= 1; 51 | } 52 | 53 | /** Immitate the API of PhaserCE. 54 | * Align this object in another. 55 | * @private 56 | */ 57 | alignIn(other, align) { 58 | this.alignInMapping[align](this, other, other.width); 59 | } 60 | 61 | /** 62 | * @private 63 | * Add a callback that is triggered when the pointer moves out of the object. 64 | */ 65 | addOutEvent(callback, callbackContext) { 66 | this.on('pointerout', (pointer) => { 67 | callback.call(callbackContext, pointer); 68 | }); 69 | } 70 | 71 | /** 72 | * @private 73 | * Add a callback that is triggered when the object is unclicked. 74 | */ 75 | addUpEvent(callback, callbackContext) { 76 | this.on('pointerup', (pointer) => { 77 | callback.call(callbackContext, pointer); 78 | }); 79 | } 80 | 81 | /** 82 | * @private 83 | * Add a callback that is triggered when the object is clicked. 84 | */ 85 | addDownEvent(callback, callbackContext) { 86 | this.on('pointerdown', (pointer) => { 87 | callback.call(callbackContext, pointer); 88 | }); 89 | } 90 | 91 | /** 92 | * @private 93 | * Add a callback that is triggered when the object is dragged. 94 | */ 95 | addDragEvent(callback, callbackContext) { 96 | this.on('drag', () => { callback.call(callbackContext); }); 97 | } 98 | } 99 | 100 | exportObject = Phaser3Sprite; 101 | } else { 102 | class PhaserCESprite extends Phaser.Sprite { 103 | constructor(game, x, y, key) { 104 | super(game, x, y, key); 105 | 106 | game.add.existing(this); 107 | } 108 | 109 | setOrigin(x, y) { 110 | this.anchor = new Phaser.Point(x, y); 111 | } 112 | 113 | get maskX() { //eslint-disable-line 114 | return 0; 115 | } 116 | 117 | get maskY() { //eslint-disable-line 118 | return 0; 119 | } 120 | 121 | setInteractive() { 122 | this.inputEnabled = true; 123 | } 124 | 125 | disableInteractive() { 126 | this.inputEnabled = false; 127 | } 128 | 129 | /** 130 | * @private 131 | * Add a callback that is triggered when the pointer moves out of the object. 132 | */ 133 | addOutEvent(callback, callbackContext) { 134 | this.events.onInputOut.add(callback, callbackContext); 135 | } 136 | 137 | /** 138 | * @private 139 | * Add a callback that is triggered when the object is unclicked. 140 | */ 141 | addUpEvent(callback, callbackContext) { 142 | this.events.onInputUp.add(callback, callbackContext); 143 | } 144 | 145 | /** 146 | * @private 147 | * Add a callback that is triggered when the object is clicked. 148 | */ 149 | addDownEvent(callback, callbackContext) { 150 | this.events.onInputDown.add(callback, callbackContext); 151 | } 152 | 153 | /** Immitate the API of Phaser3. 154 | * The current displayed height of the Object. 155 | * @type {number} 156 | * @private 157 | */ 158 | get displayHeight() { 159 | return this.height; 160 | } 161 | 162 | set displayHeight(newValue) { 163 | this.height = newValue; 164 | } 165 | 166 | /** Immitate the API of Phaser3. 167 | * The current displayed width of the Object. 168 | * @type {number} 169 | * @private 170 | */ 171 | get displayWidth() { 172 | return this.width; 173 | } 174 | 175 | set displayWidth(newValue) { 176 | this.width = newValue; 177 | } 178 | } 179 | 180 | exportObject = PhaserCESprite; 181 | } 182 | 183 | export const Sprite = exportObject; 184 | -------------------------------------------------------------------------------- /src/phaserObjects/tween.js: -------------------------------------------------------------------------------- 1 | let exportObject; 2 | 3 | if (Phaser.Tween === undefined) { 4 | class Phaser3Tween { 5 | constructor(game) { 6 | this.game = game; 7 | } 8 | 9 | add(target, properties, duration, ease, onComplete, onUpdate, onStart, callbackScope) { 10 | const config = { 11 | targets: target, 12 | duration, 13 | ease, 14 | onComplete, 15 | onUpdate, 16 | onStart, 17 | callbackScope, 18 | }; 19 | const params = Object.assign(config, properties); 20 | this.game.tweens.add(params); 21 | } 22 | } 23 | 24 | exportObject = Phaser3Tween; 25 | } else { 26 | class PhaserCETween { 27 | constructor(game) { 28 | this.game = game; 29 | } 30 | 31 | add(target, properties, duration, ease, onComplete, onUpdate, onStart, onCompleteScope, onUpdateScope, onStartScope) { 32 | const tween = this.game.add.tween(target).to( 33 | properties, 34 | duration, 35 | ease, 36 | true, 37 | ); 38 | 39 | // Add the necessary events to the tween. 40 | if (onUpdate) { 41 | tween.onUpdateCallback(onUpdate, onUpdateScope); 42 | } 43 | 44 | if (onComplete) { 45 | tween.onComplete.add(onComplete, onCompleteScope); 46 | } 47 | 48 | if (onStart) { 49 | tween.onStart.add(onStart, onStartScope); 50 | } 51 | } 52 | } 53 | 54 | exportObject = PhaserCETween; 55 | } 56 | 57 | export const Tween = exportObject; 58 | -------------------------------------------------------------------------------- /src/phaserObjects/viewport_mask.js: -------------------------------------------------------------------------------- 1 | let exportObject; 2 | 3 | if (Phaser.Graphics === undefined) { 4 | class ViewportMask3 extends Phaser.GameObjects.Graphics { 5 | constructor(game, x, y) { 6 | super(game, { x, y }); 7 | 8 | this.game = game; 9 | this.x = x; 10 | this.y = y; 11 | } 12 | 13 | create(x, y, width, height) { 14 | this.fillStyle(0xffffff); 15 | this.beginPath(); 16 | this.fillRect(x, y, width, height); 17 | 18 | const m = this.createGeometryMask(); 19 | m.x = m.geometryMask.x; 20 | m.y = m.geometryMask.y; 21 | m.width = width; 22 | m.height = height; 23 | 24 | return m; 25 | } 26 | } 27 | exportObject = ViewportMask3; 28 | } else { 29 | class ViewportMaskCE extends Phaser.Graphics { 30 | get scaleX() { 31 | return this.scale.x; 32 | } 33 | 34 | set scaleX(value) { 35 | this.scale.x = value; 36 | } 37 | 38 | get scaleY() { 39 | return this.scale.y; 40 | } 41 | 42 | set scaleY(value) { 43 | this.scale.y = value; 44 | } 45 | 46 | create(x, y, width, height) { 47 | this.beginFill(0x0000ff); 48 | this.drawRect(x, y, width, height); 49 | this.endFill(); 50 | 51 | // Match the internals of Phaser3 52 | this.geometryMask = this; 53 | 54 | return this; 55 | } 56 | } 57 | 58 | exportObject = ViewportMaskCE; 59 | } 60 | 61 | export const ViewportMask = exportObject; 62 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | const utils = {}; 2 | 3 | /** 4 | * @private 5 | * A modulo operator that doesn't allow negative numbers. 6 | * @param {number} dividend 7 | * @param {number} divisor 8 | * @returns {number} 9 | */ 10 | utils.modulo = function modulo(dividend, divisor) { 11 | return ((((dividend) % divisor) + divisor) % divisor); 12 | }; 13 | 14 | /** 15 | * @private 16 | * Select an operator action using a string value. 17 | */ 18 | utils.operators = { 19 | '+': function add(a, b) { return a + b; }, 20 | '-': function sub(a, b) { return a - b; }, 21 | }; 22 | 23 | export { utils }; 24 | -------------------------------------------------------------------------------- /src/wheel3D.js: -------------------------------------------------------------------------------- 1 | import { EventEmitter } from 'eventemitter3'; 2 | 3 | import { utils } from './utils'; 4 | 5 | import * as PhaserObjects from './phaserObjects'; 6 | 7 | /** 8 | * Represents a single point in a Wheel3D. 9 | * @ignore 10 | */ 11 | class VectorPoint { 12 | /** 13 | * @ignore 14 | * @param {number} x - The point's virtual x location. 15 | * @param {number} y - The point's virtual y location. 16 | * @param {number} z - The point's virtual z location. 17 | * @param {Object} sprite - The sprite associated with this point. 18 | * @param {number} position - The point's position on the Wheel3D. 19 | */ 20 | constructor(x = 0, y = 0, z = 0, sprite = null, position = 0) { 21 | this.x = x; 22 | this.y = y; 23 | this.z = z; 24 | this.sprite = sprite; 25 | this.position = position; 26 | } 27 | 28 | getSinCosOfAngle(angle) { // eslint-disable-line class-methods-use-this 29 | const rad = (angle * Math.PI) / 180; 30 | const cosAngle = Math.cos(rad); 31 | const sinAngle = Math.sin(rad); 32 | 33 | return { cosine: cosAngle, sine: sinAngle }; 34 | } 35 | 36 | rotateY(angle) { 37 | const angles = this.getSinCosOfAngle(angle); 38 | const z = (this.z * angles.cosine) - (this.x * angles.sine); 39 | const x = (this.z * angles.sine) + (this.x * angles.cosine); 40 | 41 | return new VectorPoint(x, this.y, z); 42 | } 43 | 44 | rotateX(angle) { 45 | const angles = this.getSinCosOfAngle(angle); 46 | const y = (this.y * angles.cosine) - (this.z * angles.sine); 47 | const z = (this.y * angles.sine) + (this.z * angles.cosine); 48 | 49 | return new VectorPoint(this.x, y, z); 50 | } 51 | 52 | rotateZ(angle) { 53 | const angles = this.getSinCosOfAngle(angle); 54 | const x = (this.x * angles.cosine) - (this.y * angles.sine); 55 | const y = (this.x * angles.sine) + (this.y * angles.cosine); 56 | 57 | return new VectorPoint(x, y, this.z); 58 | } 59 | 60 | /** Rotate the point along the given axis by the given angle. 61 | * @param {string} axis - The axis to rotate. 62 | * @param {number} angle - The angle to rotate by. 63 | */ 64 | rotate(axis, angle) { 65 | let newVector = null; 66 | 67 | if (axis === 'x') { 68 | newVector = this.rotateX(angle); 69 | } else if (axis === 'y') { 70 | newVector = this.rotateY(angle); 71 | } else if (axis === 'z') { 72 | newVector = this.rotateZ(angle); 73 | } 74 | 75 | return newVector; 76 | } 77 | 78 | /** Project the point to the correct physical location on screen. 79 | * z axis is not projected, because screens are 2D. 80 | */ 81 | project(width, height, factor) { 82 | const x = (this.x * factor) + width; 83 | const y = (-this.y * factor) + height; 84 | 85 | return new VectorPoint(x, y, this.z); 86 | } 87 | } 88 | 89 | /** 90 | * A Wheel of sprites where each item's position is projected in 3D space. 91 | * The number of points is automatically determined by the number of items. 92 | */ 93 | export class Wheel3D { 94 | /** 95 | * @param {Object} game - Reference to current game instance. 96 | * @param {array} sprites - List of sprites to use in the wheel. 97 | * @param {Number} firstPlace - Determines which position on the wheel is the active one. 98 | * @param {Number} zoom - Determines how far to project the points. 99 | * @param {String} axis - The axis the wheel3D places items around. 100 | * @param {Object} rotations - Axis and angle to rotate the entire wheel after the initial projection. 101 | * @param {Object} visibleRange - Determines which items on the wheel should be visible. If none provided, assumes all items should be visible. 102 | * @param {Object} tweenParams - Array with the duration and easing function for the movement tween. 103 | */ 104 | constructor(game, xy, sprites, firstPlace, zoom, axis, rotations, visibleRange, tweenParams) { 105 | this.game = game; 106 | this.xy = xy; 107 | this.sprites = sprites; 108 | this.firstPlace = firstPlace; 109 | this.zoom = zoom; 110 | this.axis = axis; 111 | this.rotationAxis = rotations; 112 | this.visibleRange = visibleRange || null; 113 | this.tweenParams = tweenParams || { duration: 300, ease: PhaserObjects.Easing.Quadratic.Out }; 114 | 115 | this.emitter = new EventEmitter(); 116 | 117 | // Group to store wheel sprites in, used for zindex sorting. 118 | this.group = new PhaserObjects.Group(game); 119 | } 120 | 121 | activate() { 122 | let angle; 123 | let radCos; 124 | let radSin; 125 | let nx; 126 | let ny; 127 | let nz; 128 | 129 | this.pointsAmount = this.sprites.length; 130 | this.totalPositions = this.pointsAmount - 1; 131 | this.rotationAmount = 360 / this.pointsAmount; 132 | 133 | // Determines which items in the wheel should be visible. 134 | if (this.visibleRange !== null) { 135 | const allPositions = []; 136 | for (let i = 0; i <= this.totalPositions; i++) { 137 | allPositions.push(i); 138 | } 139 | 140 | const maxV = allPositions.slice(0, this.visibleRange.max); 141 | const minV = allPositions.slice(this.visibleRange.min); 142 | 143 | this.visiblePositions = maxV.concat(minV); 144 | } 145 | 146 | // Prevents slamming down the move keys. 147 | this.moving = false; 148 | 149 | // Stores the direction the wheel is moving in. 150 | this.direction = null; 151 | 152 | // Set point positions on logical circle. 153 | this.wheelItems = []; 154 | const radius = 1; 155 | const slice = (2 * Math.PI) / this.pointsAmount; 156 | 157 | // For a vertical wheel, the X axis is -1. Points are laid out on the Y axis (height) and Z axis (depth). The wheel rotates around the X axis. 158 | // For a horizontal wheel, the Y Axis is -1. Points are laid out on the X axis (width) and Z axis (depth). The wheel rotates around the Y axis. 159 | // For flat circular wheel, the Z Axis is -1. Points are laid out on the X axis (width) and Y axis (height). The wheel rotates around the Z axis. 160 | for (let i = 0; i < this.pointsAmount; i++) { 161 | // Add sprite to group. 162 | this.sprites[i].wheelPosition = i; 163 | this.group.add(this.sprites[i]); 164 | 165 | angle = slice * i; 166 | radCos = radius * Math.cos(angle); 167 | radSin = radius * Math.sin(angle); 168 | 169 | if (this.axis === 'x') { 170 | nx = -1; 171 | ny = radCos; 172 | nz = radSin; 173 | } else if (this.axis === 'y') { 174 | nx = radCos; 175 | ny = -1; 176 | nz = radSin; 177 | } else if (this.axis === 'z') { 178 | nx = radCos; 179 | ny = radSin; 180 | nz = -1; 181 | } 182 | 183 | this.wheelItems.push(new VectorPoint(nx, ny, nz, this.sprites[i], i)); 184 | } 185 | 186 | // Active Point 187 | this.active = this.wheelItems[this.firstPlace].sprite; 188 | 189 | this.project(); 190 | } 191 | 192 | /** Move the wheel backwards. */ 193 | moveBack() { 194 | if (this.moving === false) { 195 | this.moving = true; 196 | this.direction = 0; 197 | 198 | if (this.axis === 'x' || this.axis === 'z') { 199 | this.rotationAxis[this.axis] += this.rotationAmount; 200 | } else { // y axis needs to go in the opposite direction. 201 | this.rotationAxis[this.axis] -= this.rotationAmount; 202 | } 203 | 204 | this.updatePosition('+'); 205 | 206 | this.project(); 207 | this.resetAngle(); 208 | } 209 | } 210 | 211 | /** Move the wheel forward. */ 212 | moveForward() { 213 | if (this.moving === false) { 214 | this.moving = true; 215 | this.direction = 1; 216 | 217 | if (this.axis === 'x' || this.axis === 'z') { 218 | this.rotationAxis[this.axis] -= this.rotationAmount; 219 | } else { // y axis needs to go in the opposite direction. 220 | this.rotationAxis[this.axis] += this.rotationAmount; 221 | } 222 | 223 | this.updatePosition('-'); 224 | 225 | this.project(); 226 | this.resetAngle(); 227 | } 228 | } 229 | 230 | /** Project every item in the wheel to it's physical location. */ 231 | project() { 232 | // Create a list with the axes, then remove the projected axis. 233 | const arr = ['x', 'y', 'z']; 234 | const idx = arr.indexOf(this.axis); 235 | arr.splice(idx, 1); 236 | 237 | // We only need to call all this when moving. It doesn't need to be done 238 | // every update 239 | for (let i = 0; i < this.wheelItems.length; i++) { 240 | // Rotate along the projected axis 241 | const rotationOne = this.wheelItems[i].rotate( 242 | this.axis, 243 | this.rotationAxis[this.axis], 244 | ); 245 | 246 | // Rotate the other 2 axes 247 | const rotationTwo = rotationOne.rotate(arr[0], this.rotationAxis[arr[0]]); 248 | const rotationThree = rotationTwo.rotate(arr[1], this.rotationAxis[arr[1]]); 249 | 250 | const p = rotationThree.project( 251 | this.xy.x, 252 | this.xy.y, 253 | this.zoom, 254 | ); 255 | 256 | const transformed = this.wheelItems[i].sprite; 257 | transformed.lz = p.z; 258 | 259 | // Ensure active sprite has no scale/alpha changes. 260 | if (this.wheelItems[i].position === this.firstPlace) { 261 | transformed.alpha = 1.0; 262 | this.active = this.wheelItems[i].sprite; 263 | } else { 264 | if (this.visibleRange !== null) { 265 | const includes = this.visiblePositions.includes(this.wheelItems[i].position); 266 | // const includes = _.includes( 267 | // this.visiblePositions, 268 | // this.wheelItems[i].position, 269 | // ); 270 | 271 | if (includes) { 272 | transformed.alpha = 1.0; 273 | } else { 274 | transformed.alpha = 0.0; 275 | } 276 | } 277 | } 278 | 279 | const newTween = new PhaserObjects.Tween(this.game); 280 | 281 | if (i !== this.wheelItems.length - 1) { 282 | newTween.add( 283 | transformed, 284 | { x: p.x, y: p.y }, 285 | this.tweenParams.duration, 286 | this.tweenParams.ease, 287 | ); 288 | } else { 289 | // Wheel's signals are dispatched by the last tween. 290 | newTween.add( 291 | transformed, 292 | { x: p.x, y: p.y }, 293 | this.tweenParams.duration, 294 | this.tweenParams.ease, 295 | () => { this.enableMoving(); this.dispatchOnComplete(); }, 296 | null, 297 | () => { this.dispatchOnStart(); }, 298 | this, 299 | ); 300 | } 301 | } 302 | 303 | // Sort wheelItems by the projection's z axis for correct z-order when drawing. 304 | this.group.sort('lz', PhaserObjects.Group.SORT_ASCENDING); 305 | } 306 | 307 | /** Called after movement starts. */ 308 | dispatchOnStart() { 309 | this.emitter.emit('start', this); 310 | } 311 | 312 | /** Called after movement is finished. */ 313 | dispatchOnComplete() { 314 | if (this.direction === 0) { 315 | this.emitter.emit('backComplete', this); 316 | } else if (this.direction === 1) { 317 | this.emitter.emit('forwardComplete', this); 318 | } 319 | 320 | this.emitter.emit('complete', this); 321 | } 322 | 323 | /** Once the buttons have finished their move animation, allow them to move again. */ 324 | enableMoving() { 325 | this.moving = false; 326 | } 327 | 328 | /** Move all the WheelItem's position by 1. */ 329 | updatePosition(operator) { 330 | for (let i = 0; i < this.wheelItems.length; i++) { 331 | const { position } = this.wheelItems[i]; 332 | this.wheelItems[i].position = utils.operators[operator](position, 1); 333 | 334 | const m = utils.modulo(this.wheelItems[i].position, this.pointsAmount); 335 | this.wheelItems[i].position = m; 336 | this.wheelItems[i].sprite.wheelPosition = m; 337 | } 338 | } 339 | 340 | /** Make sure rotation can't go past 360 in either direction. */ 341 | resetAngle() { 342 | const angle = this.rotationAxis[this.axis]; 343 | 344 | if (angle === 360 || angle === -360) { 345 | this.rotationAxis[this.axis] = 0; 346 | } 347 | } 348 | } 349 | -------------------------------------------------------------------------------- /tests/column.spec.js: -------------------------------------------------------------------------------- 1 | describe("Column", function(){ 2 | var column; 3 | 4 | describe("When I add a second node to a Column", function(){ 5 | it("Then should be placed under the first node", function(){ 6 | var dummySprite = game.add.sprite(0, 0, "dummySprite"); 7 | var dummySprite2 = game.add.sprite(0, 0, "dummySprite"); 8 | column = new uiWidgets.Column(game); 9 | column.addNode(dummySprite); 10 | column.addNode(dummySprite2); 11 | 12 | chai.expect(column.children[1].y).to.equal(78); 13 | }); 14 | }); 15 | 16 | describe("When I add a second node to a Column with padding", function(){ 17 | it("Then should be placed under to the first node, offset by the padding", function(){ 18 | var dummySprite = game.add.sprite(0, 0, "dummySprite"); 19 | var dummySprite2 = game.add.sprite(0, 0, "dummySprite"); 20 | column = new uiWidgets.Column(game); 21 | column.addNode(dummySprite); 22 | column.addNode(dummySprite2, 0, 23); 23 | 24 | chai.expect(column.children[1].y).to.equal(101); 25 | }); 26 | }); 27 | 28 | afterEach(function() { 29 | column.destroy(); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /tests/frame.spec.js: -------------------------------------------------------------------------------- 1 | describe("Frame", function(){ 2 | describe("When I create a new Frame", function(){ 3 | it("Then the x, y attributes should be set correctly", function(){ 4 | var frame = new uiWidgets.Frame(game, 12, 37); 5 | 6 | chai.expect(frame.x).to.equal(12); 7 | chai.expect(frame.y).to.equal(37); 8 | 9 | }); 10 | }); 11 | describe("When I create a new Frame with no x, y attributes", function(){ 12 | it("Then the x, y attributes should be 0", function(){ 13 | var frame = new uiWidgets.Frame(game); 14 | 15 | chai.expect(frame.x).to.equal(0); 16 | chai.expect(frame.y).to.equal(0); 17 | 18 | }); 19 | }); 20 | describe("When I add a new node to a Frame", function(){ 21 | it("Then it should be added as a child of the Frame", function(){ 22 | var frame = new uiWidgets.Frame(game); 23 | var dummySprite = game.add.sprite(0, 0); 24 | frame.addNode(dummySprite); 25 | 26 | chai.expect(frame.children[0]).to.equal(dummySprite); 27 | }); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /tests/row.spec.js: -------------------------------------------------------------------------------- 1 | describe("Row", function(){ 2 | var row; 3 | 4 | describe("When I add a second node to a Row", function(){ 5 | it("Then should be placed next to the first node", function(){ 6 | var dummySprite = game.add.sprite(0, 0, "dummySprite"); 7 | var dummySprite2 = game.add.sprite(0, 0, "dummySprite"); 8 | row = new uiWidgets.Row(game); 9 | row.addNode(dummySprite); 10 | row.addNode(dummySprite2); 11 | 12 | chai.expect(row.children[1].x).to.equal(300); 13 | }); 14 | }); 15 | 16 | describe("When I add a second node to a Row with padding", function(){ 17 | it("Then should be placed next to the first node, offset by the padding", function(){ 18 | var dummySprite = game.add.sprite(0, 0, "dummySprite"); 19 | var dummySprite2 = game.add.sprite(0, 0, "dummySprite"); 20 | row = new uiWidgets.Row(game); 21 | row.addNode(dummySprite); 22 | row.addNode(dummySprite2, 17, 0); 23 | 24 | chai.expect(row.children[1].x).to.equal(317); 25 | }); 26 | }); 27 | 28 | afterEach(function() { 29 | row.destroy(); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /tests/testrunner.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mocha Tests 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
45 | 46 | 47 | -------------------------------------------------------------------------------- /tests/testrunner_phaser3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mocha Tests 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 |
58 | 59 | 60 | -------------------------------------------------------------------------------- /tests/viewport.spec.js: -------------------------------------------------------------------------------- 1 | describe("Viewport", function(){ 2 | var viewport; 3 | 4 | describe("When I create a new Viewport", function(){ 5 | it("Then the x, y attributes should be set correctly", function(){ 6 | viewport = new uiWidgets.Viewport(game, 17, 102, 103, 104); 7 | chai.expect(viewport.x).to.equal(17); 8 | chai.expect(viewport.y).to.equal(102); 9 | }); 10 | 11 | it("Then the area attribute should be set correctly", function(){ 12 | viewport = new uiWidgets.Viewport(game, 17, 102, 103, 104); 13 | chai.expect(viewport.area.x).to.equal(17); 14 | chai.expect(viewport.area.y).to.equal(102); 15 | chai.expect(viewport.area.width).to.equal(103); 16 | chai.expect(viewport.area.height).to.equal(104); 17 | }); 18 | 19 | it("Then the viewport mask attributes should be set correctly", function(){ 20 | viewport = new uiWidgets.Viewport(game, 17, 102, 103, 104); 21 | chai.expect(viewport.mask.x).to.equal(17); 22 | chai.expect(viewport.mask.y).to.equal(102); 23 | }); 24 | }); 25 | 26 | afterEach(function() { 27 | viewport.destroy(); 28 | }); 29 | 30 | }); 31 | -------------------------------------------------------------------------------- /tests/wheel3D.spec.js: -------------------------------------------------------------------------------- 1 | describe("Wheel3D", function(){ 2 | describe("When I create a new Wheel3D", function(){ 3 | describe("And I move the wheel backwards", function(){ 4 | it("Then the active sprite should be the previous one", function(done){ 5 | var menuList = []; 6 | for (var i = 0; i < 4; i++) { 7 | var dummySprite = game.add.sprite(0, 0, "dummySprite"); 8 | menuList.push(dummySprite); 9 | } 10 | 11 | var wheel = new uiWidgets.Wheel3D( 12 | game, 13 | {"x": 0, "y": 0}, 14 | menuList, 15 | 0, 16 | 90, 17 | "x", 18 | {"x":0, "y": -90, "z": 0} 19 | ); 20 | 21 | var isDone = false; 22 | 23 | wheel.emitter.on('complete', 24 | function (wheel) { 25 | isDone = true; 26 | }); 27 | wheel.activate(); 28 | wheel.moveBack(); 29 | 30 | setTimeout( function () { 31 | try { 32 | chai.expect(isDone).to.equal(true); 33 | done(); 34 | } catch(err) { 35 | done(err); 36 | } 37 | }, 500 ); 38 | }); 39 | }); 40 | describe("And I move the wheel forward", function(){ 41 | it("Then the active sprite should be the next one", function(done){ 42 | var menuList = []; 43 | for (var i = 0; i < 4; i++) { 44 | var dummySprite = game.add.sprite(0, 0, "dummySprite"); 45 | menuList.push(dummySprite); 46 | } 47 | 48 | var wheel = new uiWidgets.Wheel3D( 49 | game, 50 | {"x": 0, "y": 0}, 51 | menuList, 52 | 0, 53 | 90, 54 | "x", 55 | {"x":0, "y": -90, "z": 0} 56 | ); 57 | 58 | var isDone = false; 59 | 60 | wheel.emitter.on('complete', 61 | function (wheel) { 62 | isDone = true; 63 | }); 64 | wheel.activate(); 65 | wheel.moveForward(); 66 | 67 | setTimeout( function () { 68 | try { 69 | chai.expect(isDone).to.equal(true); 70 | done(); 71 | } catch(err) { 72 | done(err); 73 | } 74 | }, 500 ); 75 | 76 | }); 77 | }); 78 | }); 79 | }); 80 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | const ESLintPlugin = require('eslint-webpack-plugin'); 4 | 5 | module.exports = { 6 | mode: 'production', 7 | plugins: [new ESLintPlugin()], 8 | module: { 9 | rules: [ 10 | { 11 | test: /\.(js)$/, 12 | exclude: /node_modules/, 13 | use: { 14 | loader: 'babel-loader', 15 | options: { 16 | presets: ['@babel/preset-env'], 17 | }, 18 | }, 19 | }, 20 | ], 21 | }, 22 | entry: './src/entry.js', 23 | output: { 24 | library: 'uiWidgets', 25 | libraryTarget: 'umd', 26 | umdNamedDefine: true, 27 | filename: 'phaser-ui-tools.js', 28 | path: path.resolve(__dirname, 'dist'), 29 | }, 30 | }; 31 | --------------------------------------------------------------------------------