├── bin
├── .DS_Store
├── spriteUtilities.js
└── spriteUtilities.js.map
├── README.md
└── src
└── spriteUtilities.js
/bin/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kittykatattack/spriteUtilities/HEAD/bin/.DS_Store
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Sprite Utilities for Pixi (v3.0.11)
2 | =====================
3 |
4 | This repository contains a bunch of useful functions for creating
5 | [Pixi](https://github.com/GoodBoyDigital/pixi.js/) sprites and making them easier to work with.
6 |
7 | (Important! Sprite Utilities targets Pixi v3.0.11, which is the most stable version of Pixi, and is the only version I can recommend using. This library will eventually be upgraded for Pixi v4 when the v4 branch matures.)
8 |
9 | [Setting up](#settingup)
10 | [sprite: Quickly make any Sprite or MovieClip](#sprite)
11 | [tilingSprite: Make a tiling sprite](#tilingSprite)
12 | [filmstrip: Turn any tileset PNG into a texture array](#filmstrip)
13 | [frames: Capture a subset of frames from a PNG tileset](#frames)
14 | [frame: Capture a single rectangular area inside PNG image or tileset](#frame)
15 | [frameSeries: Captures a sequence of numbered frame ids from a textureatlas](#frameSeries)
16 | [text: Make a text sprite](#text)
17 | [bitmaptext: Make a BitmapText sprite](#bitmaptext)
18 | [rectangle: Draw a rectangle](#rectangle)
19 | [circle: Draw a circle](#circle)
20 | [line: Draw a line](#line)
21 | [grid: Create a grid of sprites](#grid)
22 | [group: Group sprites](#group)
23 | [batch: Create a particle container](#batch)
24 | [shoot: A method for easily shooting bullet sprites](#shoot)
25 | [shake: Make a sprite shake](#shake)
26 | [remove: Remove a sprite or array of sprites from its parent](#batch)
27 | [color: Convert a HTML or RGBA color to a Hex color code](#color)
28 |
29 |
30 | Setting up and initializing `SpriteUtilities`
31 | -------------------------------------------
32 |
33 | Create a new instance of `SpriteUtilities` like this:
34 | ```js
35 | let u = new SpriteUtilities(PIXI);
36 | ```
37 | Supply a reference to `PIXI` as the optional argument in the
38 | constructor. (If you don't supply it, `SpriteUtilites` will look for a
39 | global `PIXI` object and alert you with an error if it can't find it.)
40 |
41 | You can now access the `SpriteUtilites` instance and all its
42 | methods using the variable reference `u`.
43 |
44 |
45 | The `sprite` function
46 | -------------------
47 |
48 | Use the universal `sprite` function to make any kind of Pixi sprite.
49 | ```js
50 | let anySprite = u.sprite(frameTextures, xPosition, yPosition);
51 | ```
52 | The first argument, `frameTextures` can be any of the following:
53 |
54 | - A single PNG image string.
55 | - A Pixi `Texture` object.
56 | - An array of texture atlas frame ids.
57 | - An array of single PNG image strings.
58 | - An array of Pixi `Texture` objects.
59 |
60 | You can essentially throw anything at it, and it will give you back a sprite that works as it should,
61 | depending on the kind of texture information you've supplied. That
62 | means you can use the `sprite` function
63 | as your one-stop-shop for creating any kind of sprite. Forget about
64 | using Pixi's `Sprite` and `MovieClip`
65 | classes to make sprites and just use the `sprite` function for everything!
66 |
67 | If you supply the `sprite` function with an array, it will return a
68 | `MovieClip` sprite but with a bonus
69 | **state player** built into it. The state player is just a collection of 4 properties and methods
70 | that make it easy to control sprite animation states. Here they are:
71 |
72 | 1. `fps`: A property to set the precise animation speed, as
73 | frames-per-second. Its default value is 12. The `fps` is not linked to
74 | the renderer's fps, and that means you can have sprite animations
75 | playing at speeds that are independent of the game or application
76 | speed. `anySprite.fps = 6`.
77 |
78 | 2. `playAnimation`: A method to play the sprite's
79 | animation.`anySprite.playAnimation()`. You can supply it with start and end frame values if you want to play a sub-set of frames. Here's how: `anySprite.playAnimation([startFrame, endFrame])` The animation will play in a loop, by default, unless you set the sprite's `loop` property value to `false`.
80 |
81 | 3. `stopAnimation`: A method that stops the sprite's animation at the
82 | current frame. `anySprite.stopAnimation()`.
83 |
84 | 4. `show`: A method that displays a specific frame number.
85 | `anySprite.show(frameNumber)`.
86 |
87 | 5. `animating`: A Boolean property that will be `true` if the
88 | animation is playing and `false` if it isn't.
89 |
90 |
91 | `tilingSprite`
92 | -------------
93 |
94 | Create a sprite with an image that you can tile across its surface. The first argument is
95 | the source for the tile image. You can use ordinary images,
96 | texture atlas frames, or an array of image sources if you want to
97 | tiling sprite with multiple frames. The second and third arguments
98 | are the sprite's width and height, which determine the entire area that
99 | the tile pattern should fill. You can optionally supply the x and y
100 | position as the fourth and fifth arguments.
101 | ```js
102 | let anySprite = u.tilingSprite("images/tile.png", 128, 128);
103 | ```
104 |
105 |
106 | `filmstrip`
107 | ----------
108 |
109 | Use the`filmstrip` function to automatically turn a tileset PNG image
110 | into an array of textures that you can use to make a sprite.
111 | ```js
112 | u.filmstrip("anyTilesetImage.png", frameWidth, frameHeight, optionalPadding);
113 | ```
114 | Supply `filmstrip` with the tileset image name and the width and
115 | height of each frame. If there's padding around each frame, supply the
116 | padding amount, in pixels. `filmstrip` returns an array of frames that
117 | you can use to make an animated `MovieClip` sprite.
118 | Here's how you could use `filmstrip` with the universal `sprite`
119 | function to quickly make a sprite with multiple frames:
120 | ```js
121 | let textures = u.filmstrip("tileset.png", 32, 32);
122 | let anySprite = u.sprite(textures);
123 | ```
124 | The `filmstrip` function automatically loads every frame from a tileset image into the sprite.
125 |
126 |
127 | `frames`
128 | -------
129 |
130 | But what if you only want to use a sub-set of frames from the tileset,
131 | not all of them? Use another utility function called `frames`. The
132 | `frames` function takes 4 arguments: the texture, a 2D array of x/y
133 | frame position coordinates, and the width and height of each frame.
134 | Here's how you could use the frames function to create a sprite.
135 | ```js
136 | let textures = u.frames(
137 | "tileset.png", //The tileset image
138 | [[0,0],[32,0],[64,0]], //A 2D array of x/y frame coordianates
139 | 32, 32 //The width and height of each frame
140 | );
141 | let anySprite = u.sprite(textures);
142 | ```
143 | Use the `frames` function whenever you need to create a sprite using
144 | selected frames from a larger tileset PNG image.
145 |
146 |
147 | `frame`
148 | -------
149 |
150 | Use the `frame` function if you just want to create a texture using a smaller
151 | rectangular section of a larger image. The `frame` function takes
152 | four arguments: the image, the sub-image x position, the sub-image y
153 | position, and the sub-image's width and height.
154 | ```
155 | u.frame("image.png", x, y, width, height)
156 | ```
157 | Here's how you could make a sprite using a sub-image of a larger
158 | image.
159 | ```js
160 | let texture = u.frame("tileset.png", 64, 128, 32, 32);
161 | let anySprite = u.sprite(texture);
162 | ```
163 | Use the `frame` function to
164 | [blit](https://en.wikipedia.org/wiki/Bit_blit) a smaller image from bigger image.
165 |
166 |
167 | `frameSeries`
168 | ------------
169 |
170 | If you've loaded a texture atlas and want a sequence of numbered frame
171 | ids to create an animated sprite, use the `frameSeries` function.
172 | Imagine that you have frames in a texture atlas with the following id
173 | names:
174 | ```js
175 | frame0.png
176 | frame1.png
177 | frame2.png
178 | ```
179 | To create a sprite in Pixi using these frames, you would ordinarily
180 | write some code using Pixi's `MovieClip` class
181 | (`PIXI.extras.MovieClip`) that looks something like this:
182 | ```js
183 | let frameTextures = ["frame0.png", "frame1.png", "frame2.png"];
184 | let anySprite = MovieClip.fromFrames(frameTextures);
185 | ```
186 | You now have a sprite with 3 frames that you can control. That's not too painful, but what if you
187 | had 100 animation frames? You definitely don't want to manually type in
188 | 100 frame id's into an array. Instead, use the `frameSeries` function.
189 |
190 | `frameSeries` takes four arguments: the start frame sequence number,
191 | the end frame sequence number, the optional base file name, and the optional file extension.
192 | You could use the `frameSeries` function to create the sprite from the
193 | texture atlas frame ids like this:
194 | ```
195 | let frameTextures = u.frameSeries(0, 2, "frame", ".png");
196 | let anySprite = u.sprite(frameTextures);
197 | ```
198 | If you had 100 animation frames, your code might look like this:
199 | ```
200 | let frameTextures = u.frameSeries(0, 99, "frame", ".png");
201 | let anySprite = u.sprite(frameTextures);
202 | ```
203 | That's much better!
204 |
205 |
206 | `text`
207 | ------
208 |
209 | Use the `text` method to quickly create a text sprite.
210 | ```js
211 | let messgae = u.text("Hello!", "32px Futura", "black", xPosition, yPosition);
212 | ```
213 | Only the first argument, the text you want to display, is required.
214 | The second argument is the font size and family. You can use any
215 | system font, or a font from a loaded font file. The thrid argument is the
216 | fill color. Text colors can provided as RGBA, HLSA, hexadecimal,
217 | or HTML color string values, such as “blue” or “green.” The last
218 | arguments are the text's x and y position.
219 |
220 | You can add any additional Pixi text properties by setting the text sprite's
221 | `style` property.
222 | ```js
223 | message.style = {fill: "black", font: "16px Helvetica"};
224 | ```
225 | Check out the [full list of Pixi Text properties](http://pixijs.github.io/docs/PIXI.Text.html) to find out
226 | which styles you can apply.
227 |
228 | To change the text display at any time, use the text's `content` property.
229 | ```js
230 | message.content = "Updated text!";
231 | ```
232 |
233 |
234 | `bitmapText`
235 | -----------
236 |
237 | Bitmap text is text that is rendered using images for the letter
238 | shapes. (Ordinary font files just contain instructions about how
239 | your computer should draw the font shapes.) Bitmap fonts need to load the
240 | image and data files containing the letter shapes, but they tend to
241 | display more reliably across different platforms.
242 |
243 | The `bitmapText` method lets you quickly create a bitmap text sprite,
244 | like this:
245 | ```js
246 | let message = u.bitmapText("Hello!", "42px disko", align, tint, xPosition, yPosition);
247 | ```
248 | Only the first argument, the text to display, is required. The second
249 | argument is the font size and family.
250 |
251 | The third argument is the alignment, which determines how the text
252 | should be displayed if it appears on more than one line. Alignment
253 | values can be any of these three strings: "left", "right" or "center".
254 |
255 | The fourth argument, tint, is the color that the font should be
256 | tinted. This can be any RGBA, HLASA, Hex, or HTML string color value.
257 |
258 | Finally, the last two values are the text's x and y position values.
259 |
260 |
261 | `rectangle`
262 | ----------
263 |
264 | The `rectangle` method lets you quickly draw a rectangle.
265 | ```js
266 | u.rectangle(
267 | width, height, fillStyle, strokeStyle, lineWidth, xPosition, yPosition
268 | );
269 | ```
270 | `width` and `height` are the size, in pixels, of the rectangle.
271 | They're the only two arguments that are required.
272 | `fillStyle` is color for the inside fill color of the
273 | rectangle, and `strokeStyle` is the color code for the outline. (You
274 | can use hex colors, RGBA colors, or even any [HTML color names](http://www.w3schools.com/html/html_colornames.asp), like "blue" or "pink".)
275 | `lineWidth` determines how thick, in pixels, the rectangle's outline
276 | should be. (The default value is 0, which means the rectangle will have
277 | no outline.) The last two values are the rectangle's x and y
278 | position.
279 |
280 | Here's how to use the `rectangle` method to create a green square
281 | with a 2 pixel wide pink outline:
282 | ```js
283 | let square = u.rectangle(64, 64, "seaGreen", "hotPink", 2);
284 | ```
285 | (Because the last two arguments, x and y, haven't been provided, the
286 | rectangle will have default x and y values of 0.)
287 |
288 | Rectangles also have `strokeStyle`, `lineStyle` and `lineWidth` properties
289 | that you can change at any time.
290 |
291 |
292 | `circle`
293 | -------
294 |
295 | Use the `circle` method to draw a circle.
296 | ```js
297 | u.circle(diameter, fillStyle, strokeStyle, lineWidth, xPosition, yPosition)
298 | ```
299 | The arguments are similar to the `rectangle` method's arguments,
300 | except that the fist one is the diameter, in pixels, of the circle you
301 | want to draw. Here's how to draw a blue circle with a diameter of 64
302 | pixels and a purple outline 3 pixels wide.
303 | ```js
304 | let ball = u.circle(64, "powderBlue", "plum", 3);
305 | ```
306 | A circle's x and y position is anchored to the top left corner of an
307 | invisible rectangular bounding box that is surrounding the circle. To
308 | set the x and y position to the center of the circle, use the
309 | `anchor.set` method:
310 | ```js
311 | ball.anchor.set(0.5, 0.5);
312 | ```
313 | This sets the `x` and `y` positions to `0.5`, which means "the
314 | positions that are at half the circle's width and height". In other
315 | words, its center.
316 |
317 | Circles have `fillStyle`, `strokeStyle`, `diameter` and `radius` properties that
318 | you can access and change later if you need to.
319 |
320 |
321 | `line`
322 | -----
323 | The `line` method lets you quickly draw a straight line.
324 | ```js
325 | u.line(color, width, ax, ay, bx, by)
326 | ```
327 | The `color` should be a hexadecimal color value. (Just as with
328 | rectangles or cirlces, you
329 | can use hex colors, RGBA colors, or HTML color name strings.) The last four arguments define the line's start and end points. `ax`
330 | and `ay` are it's start point; `bx` and `by` are it's end points.
331 | Here's how to create red line, 3 pixels wide, with a start x/y point
332 | of 64 and and an end x/y point of 128.
333 |
334 | ```js
335 | let diagonal = u.line(0xff0000, 3, 64, 64, 128, 128);
336 | ```
337 | (Yes, as you can see above, you can use a hex color code with
338 | rectangles, circles or lines if you want to!)
339 |
340 | You can change the start and end points at any time. Here's how you
341 | set the line's end point to an x position of 100 and a y position of
342 | 90.
343 | ```js
344 | diagonal.bx = 100;
345 | diagonal.by = 90;
346 | ```
347 | The line will be re-drawn to these coordinates as soon as you set
348 | them.
349 |
350 | Lines have `ax`, `ay`, `bx`, `by`, `strokeStyle` and `width`
351 | properties that you can acess and change.
352 |
353 |
354 | `grid`
355 | -----
356 |
357 | `grid` is a very useful method that plots a grid of sprites for you. It
358 | returns a Pixi container object and fills it with a grid of sprites -
359 | any kind of sprite you need. Here's an example of how to use it to
360 | plot a 5 by 4 grid of black circles.
361 |
362 | ```js
363 | let circles = u.grid(
364 | 5, //The number of columns
365 | 4, //The number of rows
366 | 48, //The width of each cell
367 | 48, //The height of each cell
368 | true, //Should the sprite be centered in the cell?
369 | 0, //The sprite's xOffset from the left of the cell
370 | 0, //The sprite's yOffset from the top of the cell
371 |
372 | //A function that describes how to make each peg in the grid.
373 | //A random diameter and color are selected for each one
374 | () => {
375 | let ball = u.circle(24, 0x000000);
376 | return ball;
377 | },
378 |
379 | //Run any optional extra code after each ball is made
380 | () => console.log("extra!")
381 | );
382 |
383 | ```
384 | The `grid` method returns a Pixi `Container` object called `circles`. All the sprites
385 | inside each cell of the grid are children of that `circles` Container.
386 | Because it’s a Container, you can manipulate the entire grid just like any
387 | other sprite. That means you can set its `x` and `y` position
388 | values to move the grid around the canvas. (The default x/y position
389 | is 0.)
390 |
391 | You can access the individual sprites in the grid through the
392 | Container's `children` array property.
393 | ```js
394 | circles.children
395 | ```
396 | Just loop through the `children` array to set or access any properties
397 | of sprites in the grid.
398 |
399 |
400 | `group`
401 | ------
402 |
403 | A quick way to make a Pixi `Container` and add sprites to it. Just supply
404 | the `group` method with a single spirte, or a list of sprites, and it
405 | will return a container with those sprites as its children.
406 | ```
407 | let container = u.group(spriteOne, spriteTwo, spriteThree);
408 | ```
409 | You can alternatively create an empty group, and add sprites to it as you
410 | need to using `addChild`, like this:
411 | ```
412 | let container = u.group();
413 | container.addChild(anySprite);
414 | ```
415 |
416 |
417 | `batch`
418 | -------
419 |
420 | A quick way to create a Pixi `ParticleContainer`.
421 | ```
422 | let particleContainer = u.batch();
423 | particleContainer.addChild(anySprite);
424 | ```
425 | You can optionally create the batch with two arguments: the maximum
426 | number of sprites the container can inclue and the `ParticleContainer`
427 | object's `options`. Here's how to create a particle container with a
428 | maximum number of 20,000 sprites, and all the options set to `true`
429 | ```js
430 | let particleContainer = u.batch(20000, {rotation: true, alpha: true, scale: true, uvs: true});
431 | ```
432 | The default size is 15,000. So, if you have to contain more sprites,
433 | set it to a higher number. The `options` argument is an object with
434 | five Boolean properties that you can set: `scale`, `position`,
435 | `rotation`, `alpha`, and `uvs`. The default value for position is `true`, but all
436 | the others are set to `false`.
437 |
438 |
439 | `shoot`
440 | -------
441 |
442 | The `shoot` methods let you create bullet sprites at any position on
443 | another sprite.
444 |
445 | The first step to making bullets is to create an array to store the
446 | new bullet sprites that you’re going to make:
447 | ```js
448 | let bullets = [];
449 | ```
450 | You also need a sprite that's going to do the shooting.
451 | ```js
452 | let tank = u.sprite("tank.png");
453 | ```
454 | If you want your tank sprite to rotate around its center, then
455 | you'll want to center its x/y anchor point, like this:
456 | ```js
457 | tank.anchor.set(0.5, 0,5);
458 | ```
459 | Next, use the `shoot` method to create bullet sprites.
460 | ```js
461 | u.shoot(
462 | tank, //The sprite that will be shooting
463 | tank.rotation, //The angle at which to shoot
464 | 32, //The x point on the tank where the bullet should start
465 | 0, //The y point on the tank where the bullet should start
466 | stage, //The container you want to add the bullet to
467 | 7, //The bullet's speed (pixels per frame)
468 | bullets, //The array used to store the bullets
469 |
470 | //A function that returns the sprite that should
471 | //be used to make each bullet
472 | () => g.circle(8, "red")
473 | );
474 |
475 | ```
476 | The 3rd and 4th arguments are the local x and y points on the tank
477 | where you want the bullets to start from. The 5th argument is the Pixi
478 | container that you want to add the bullets to. The 7th argument is the
479 | array that you want to add each bullet to.
480 |
481 | The most important argument is the last one:
482 | ```js
483 | () => u.circle(8, "red")
484 | ```
485 | That’s a function that creates and returns the kind of sprite you want
486 | to use as a bullet. In this case, it’s a red circle 8 pixels in diameter.
487 | You can use any of the sprite-creation methods from this Sprite Utilities library,
488 | any standard Pixi sprite creation methods, or use your own custom function that
489 | creates and returns a sprite.
490 |
491 | All the bullet sprites that the `shoot` method creates are added to
492 | the `bullets` array, so just loop though the sprites in that array to
493 | check for collisions with other sprites.
494 |
495 |
496 | `shake`
497 | -------
498 |
499 | Use the `shake` method to make a sprite shake or create a screen-shake
500 | effect. Here's how to use it:
501 | ```js
502 | u.shake(spriteToShake, magnitude, angular?);
503 | ```
504 | The `shake` method’s first argument is the sprite, and the second is the shake
505 | magnitude in radians. The third argument is a Boolean that when `true` means
506 | the shaking should be angular around the sprite’s center point.
507 |
508 | Here's how you could make a sprite called `screen` shake around its center with a
509 | magnitude of 0.05.
510 | ```js
511 | u.shake(gameScene, 0.05, true);
512 | ```
513 | You can alternatively make the shaking happen up and down on the x/y plane.
514 | Just set the second argument to a number, in pixels, that determines the
515 | maximum amount by which the sprite should shake. Then set the third
516 | argument to `false`, to disable angular shaking.
517 | ```js
518 | shake(gameScene, 16, false);
519 | ```
520 | Which shaking style you prefer is entirely up to you.
521 |
522 | `shake` is an animation effect, and you won't see it unless run the
523 | SpriteUtilities `update` method inside a game loop. Here's how:
524 | ```js
525 | function gameLoop() {
526 | requestAnimationFrame(gameLoop);
527 |
528 | //Update the SpriteUtilities library each frame
529 | u.update();
530 | }
531 | ```
532 | The `update` method takes care animating the shake effect for you.
533 |
534 |
535 | `remove`
536 | -------
537 | `remove` is a global convenience method that will remove any sprite, or an
538 | argument list of sprites, from its parent.
539 | ```
540 | u.remove(spriteOne, spriteTwo, spriteThree);
541 | ```
542 | This is really useful because you never need to know what the sprite's
543 | parent is.
544 |
545 | You can also remove a whole array of sprites from their parents, like
546 | this:
547 | ```js
548 | u.remove(arrayOfSprites);
549 | ```
550 | Easy!
551 |
552 |
553 | `color`: Convert HTML and RGBA colors to Hexadecimal
554 | ------------------------------------------------------------
555 |
556 | Do you like Pixi, but don't like Hexadecimal color codes? Use
557 | `color` to convert any ordinary HTML color string name (like
558 | "blue" or "green",) or any RGBA value to its equivalent Hex code.
559 | ```js
560 | let hexColor = u.color("darkSeaGreen");
561 | ```
562 | Now just use `hexColor` wherever Pixi asks for a color code. Yes, all
563 | of the [HTML color string names](http://www.w3schools.com/html/html_colornames.asp) are supported.
564 |
565 |
566 |
567 |
568 |
569 |
--------------------------------------------------------------------------------
/src/spriteUtilities.js:
--------------------------------------------------------------------------------
1 | class SpriteUtilities{
2 | constructor(renderingEngine = PIXI) {
3 | if (renderingEngine === undefined) throw new Error("Please supply a reference to PIXI in the SpriteUtilities constructor before using spriteUtilities.js");
4 |
5 | //Find out which rendering engine is being used (the default is Pixi)
6 | this.renderer = "";
7 |
8 | //If the `renderingEngine` is Pixi, set up Pixi object aliases
9 | if (renderingEngine.ParticleContainer && renderingEngine.Sprite) {
10 | this.renderer = "pixi";
11 | this.Container = renderingEngine.Container;
12 | this.ParticleContainer = renderingEngine.ParticleContainer;
13 | this.TextureCache = renderingEngine.utils.TextureCache;
14 | this.Texture = renderingEngine.Texture;
15 | this.Rectangle = renderingEngine.Rectangle;
16 | this.MovieClip = renderingEngine.extras.MovieClip;
17 | this.BitmapText = renderingEngine.extras.BitmapText;
18 | this.Sprite = renderingEngine.Sprite;
19 | this.TilingSprite = renderingEngine.extras.TilingSprite;
20 | this.Graphics = renderingEngine.Graphics;
21 | this.Text = renderingEngine.Text;
22 |
23 | //An array to store all the shaking sprites
24 | this.shakingSprites = [];
25 | }
26 | }
27 |
28 | update() {
29 | if (this.shakingSprites.length > 0) {
30 | for(let i = this.shakingSprites.length - 1; i >= 0; i--) {
31 | let shakingSprite = this.shakingSprites[i];
32 | if (shakingSprite.updateShake) shakingSprite.updateShake();
33 | }
34 | }
35 | }
36 |
37 | sprite(source, x = 0, y = 0, tiling = false, width, height) {
38 |
39 | let o, texture;
40 |
41 | //Create a sprite if the `source` is a string
42 | if (typeof source === "string") {
43 |
44 | //Access the texture in the cache if it's there
45 | if (this.TextureCache[source]) {
46 | texture = this.TextureCache[source];
47 | }
48 |
49 | //If it's not is the cache, load it from the source file
50 | else {
51 | texture = this.Texture.fromImage(source);
52 | }
53 |
54 | //If the texture was created, make the o
55 | if (texture) {
56 |
57 | //If `tiling` is `false`, make a regular `Sprite`
58 | if (!tiling) {
59 | o = new this.Sprite(texture);
60 | }
61 |
62 | //If `tiling` is `true` make a `TilingSprite`
63 | else {
64 | o = new this.TilingSprite(texture, width, height);
65 | }
66 | }
67 | //But if the source still can't be found, alert the user
68 | else {
69 | throw new Error(`${source} cannot be found`);
70 | }
71 | }
72 |
73 | //Create a o if the `source` is a texture
74 | else if (source instanceof this.Texture) {
75 | if (!tiling) {
76 | o = new this.Sprite(source);
77 | } else {
78 | o = new this.TilingSprite(source, width, height);
79 | }
80 | }
81 |
82 | //Create a `MovieClip` o if the `source` is an array
83 | else if (source instanceof Array) {
84 |
85 | //Is it an array of frame ids or textures?
86 | if (typeof source[0] === "string") {
87 |
88 | //They're strings, but are they pre-existing texture or
89 | //paths to image files?
90 | //Check to see if the first element matches a texture in the
91 | //cache
92 | if (this.TextureCache[source[0]]) {
93 |
94 | //It does, so it's an array of frame ids
95 | o = this.MovieClip.fromFrames(source);
96 | } else {
97 |
98 | //It's not already in the cache, so let's load it
99 | o = this.MovieClip.fromImages(source);
100 | }
101 | }
102 |
103 | //If the `source` isn't an array of strings, check whether
104 | //it's an array of textures
105 | else if (source[0] instanceof this.Texture) {
106 |
107 | //Yes, it's an array of textures.
108 | //Use them to make a MovieClip o
109 | o = new this.MovieClip(source);
110 | }
111 | }
112 |
113 | //If the sprite was successfully created, intialize it
114 | if (o) {
115 |
116 | //Position the sprite
117 | o.x = x;
118 | o.y = y;
119 |
120 | //Set optional width and height
121 | if (width) o.width = width;
122 | if (height) o.height = height;
123 |
124 | //If the sprite is a MovieClip, add a state player so that
125 | //it's easier to control
126 | if (o instanceof this.MovieClip) this.addStatePlayer(o);
127 |
128 | //Assign the sprite
129 | return o;
130 | }
131 | }
132 |
133 | addStatePlayer(sprite) {
134 |
135 | let frameCounter = 0,
136 | numberOfFrames = 0,
137 | startFrame = 0,
138 | endFrame = 0,
139 | timerInterval = undefined;
140 |
141 | //The `show` function (to display static states)
142 | function show(frameNumber) {
143 |
144 | //Reset any possible previous animations
145 | reset();
146 |
147 | //Find the new state on the sprite
148 | sprite.gotoAndStop(frameNumber);
149 | }
150 |
151 | //The `stop` function stops the animation at the current frame
152 | function stopAnimation() {
153 | reset();
154 | sprite.gotoAndStop(sprite.currentFrame);
155 | }
156 |
157 | //The `playSequence` function, to play a sequence of frames
158 | function playAnimation(sequenceArray) {
159 |
160 | //Reset any possible previous animations
161 | reset();
162 |
163 | //Figure out how many frames there are in the range
164 | if (!sequenceArray) {
165 | startFrame = 0;
166 | endFrame = sprite.totalFrames - 1;
167 | } else {
168 | startFrame = sequenceArray[0];
169 | endFrame = sequenceArray[1];
170 | }
171 |
172 | //Calculate the number of frames
173 | numberOfFrames = endFrame - startFrame;
174 |
175 | //Compensate for two edge cases:
176 | //1. If the `startFrame` happens to be `0`
177 | /*
178 | if (startFrame === 0) {
179 | numberOfFrames += 1;
180 | frameCounter += 1;
181 | }
182 | */
183 |
184 | //2. If only a two-frame sequence was provided
185 | /*
186 | if(numberOfFrames === 1) {
187 | numberOfFrames = 2;
188 | frameCounter += 1;
189 | }
190 | */
191 |
192 | //Calculate the frame rate. Set the default fps to 12
193 | if (!sprite.fps) sprite.fps = 12;
194 | let frameRate = 1000 / sprite.fps;
195 |
196 | //Set the sprite to the starting frame
197 | sprite.gotoAndStop(startFrame);
198 |
199 | //Set the `frameCounter` to the first frame
200 | frameCounter = 1;
201 |
202 | //If the state isn't already `playing`, start it
203 | if (!sprite.animating) {
204 | timerInterval = setInterval(advanceFrame.bind(this), frameRate);
205 | sprite.animating = true;
206 | }
207 | }
208 |
209 | //`advanceFrame` is called by `setInterval` to display the next frame
210 | //in the sequence based on the `frameRate`. When the frame sequence
211 | //reaches the end, it will either stop or loop
212 | function advanceFrame() {
213 |
214 | //Advance the frame if `frameCounter` is less than
215 | //the state's total frames
216 | if (frameCounter < numberOfFrames + 1) {
217 |
218 | //Advance the frame
219 | sprite.gotoAndStop(sprite.currentFrame + 1);
220 |
221 | //Update the frame counter
222 | frameCounter += 1;
223 |
224 | //If we've reached the last frame and `loop`
225 | //is `true`, then start from the first frame again
226 | } else {
227 | if (sprite.loop) {
228 | sprite.gotoAndStop(startFrame);
229 | frameCounter = 1;
230 | }
231 | }
232 | }
233 |
234 | function reset() {
235 |
236 | //Reset `sprite.playing` to `false`, set the `frameCounter` to 0, //and clear the `timerInterval`
237 | if (timerInterval !== undefined && sprite.animating === true) {
238 | sprite.animating = false;
239 | frameCounter = 0;
240 | startFrame = 0;
241 | endFrame = 0;
242 | numberOfFrames = 0;
243 | clearInterval(timerInterval);
244 | }
245 | }
246 |
247 | //Add the `show`, `play`, `stop`, and `playSequence` methods to the sprite
248 | sprite.show = show;
249 | sprite.stopAnimation = stopAnimation;
250 | sprite.playAnimation = playAnimation;
251 | }
252 |
253 | //`tilingSpirte` lets you quickly create Pixi tiling sprites
254 | tilingSprite(source, width, height, x, y) {
255 | if (width === undefined) {
256 | throw new Error("Please define a width as your second argument for the tiling sprite");
257 | }
258 | if (height === undefined) {
259 | throw new Error("Please define a height as your third argument for the tiling sprite");
260 | }
261 | let o = this.sprite(source, x, y, true, width, height);
262 |
263 | //Add `tileX`, `tileY`, `tileScaleX` and `tileScaleY` properties
264 | Object.defineProperties(o, {
265 | "tileX": {
266 | get() {
267 | return o.tilePosition.x;
268 | },
269 | set(value) {
270 | o.tilePosition.x = value;
271 | },
272 | enumerable: true, configurable: true
273 | },
274 | "tileY": {
275 | get() {
276 | return o.tilePosition.y;
277 | },
278 | set(value) {
279 | o.tilePosition.y = value;
280 | },
281 | enumerable: true, configurable: true
282 | },
283 | "tileScaleX": {
284 | get() {
285 | return o.tileScale.x;
286 | },
287 | set(value) {
288 | o.tileScale.x = value;
289 | },
290 | enumerable: true, configurable: true
291 | },
292 | "tileScaleY": {
293 | get() {
294 | return o.tileScale.y;
295 | },
296 | set(value) {
297 | o.tileScale.y = value;
298 | },
299 | enumerable: true, configurable: true
300 | },
301 | });
302 |
303 | return o
304 | }
305 |
306 | filmstrip(
307 | texture,
308 | frameWidth,
309 | frameHeight,
310 | spacing = 0
311 | ) {
312 |
313 | //An array to store the x/y positions of the frames
314 | let positions = [];
315 |
316 | //Find the width and height of the texture
317 | let textureWidth = this.TextureCache[texture].width,
318 | textureHeight = this.TextureCache[texture].height;
319 |
320 | //Find out how many columns and rows there are
321 | let columns = textureWidth / frameWidth,
322 | rows = textureHeight / frameHeight;
323 |
324 | //Find the total number of frames
325 | let numberOfFrames = columns * rows;
326 |
327 | for (let i = 0; i < numberOfFrames; i++) {
328 |
329 | //Find the correct row and column for each frame
330 | //and figure out its x and y position
331 | let x = (i % columns) * frameWidth,
332 | y = Math.floor(i / columns) * frameHeight;
333 |
334 | //Compensate for any optional spacing (padding) around the tiles if
335 | //there is any. This bit of code accumlates the spacing offsets from the
336 | //left side of the tileset and adds them to the current tile's position
337 | if (spacing > 0) {
338 | x += spacing + (spacing * i % columns);
339 | y += spacing + (spacing * Math.floor(i / columns));
340 | }
341 |
342 | //Add the x and y value of each frame to the `positions` array
343 | positions.push([x, y]);
344 | }
345 |
346 | //Return the frames
347 | return this.frames(texture, positions, frameWidth, frameHeight);
348 | }
349 |
350 | //Make a texture from a frame in another texture or image
351 | frame(source, x, y, width, height) {
352 |
353 | let texture, imageFrame;
354 |
355 | //If the source is a string, it's either a texture in the
356 | //cache or an image file
357 | if (typeof source === "string") {
358 | if (this.TextureCache[source]) {
359 | texture = new this.Texture(this.TextureCache[source]);
360 | }
361 | }
362 |
363 | //If the `source` is a texture, use it
364 | else if (source instanceof this.Texture) {
365 | texture = new this.Texture(source);
366 | }
367 | if (!texture) {
368 | throw new Error(`Please load the ${source} texture into the cache.`);
369 | } else {
370 |
371 | //Make a rectangle the size of the sub-image
372 | imageFrame = new this.Rectangle(x, y, width, height);
373 | texture.frame = imageFrame;
374 | return texture;
375 | }
376 | }
377 |
378 | //Make an array of textures from a 2D array of frame x and y coordinates in
379 | //texture
380 | frames(source, coordinates, frameWidth, frameHeight) {
381 |
382 | let baseTexture, textures;
383 |
384 | //If the source is a string, it's either a texture in the
385 | //cache or an image file
386 | if (typeof source === "string") {
387 | if (this.TextureCache[source]) {
388 | baseTexture = new this.Texture(this.TextureCache[source]);
389 | }
390 | }
391 | //If the `source` is a texture, use it
392 | else if (source instanceof this.Texture) {
393 | baseTexture = new this.Texture(source);
394 | }
395 | if (!baseTexture) {
396 | throw new Error(`Please load the ${source} texture into the cache.`);
397 | } else {
398 | let textures = coordinates.map((position) => {
399 | let x = position[0],
400 | y = position[1];
401 | let imageFrame = new this.Rectangle(x, y, frameWidth, frameHeight);
402 | let frameTexture = new this.Texture(baseTexture);
403 | frameTexture.frame = imageFrame;
404 | return frameTexture
405 | });
406 | return textures;
407 | }
408 | }
409 |
410 | frameSeries(startNumber = 0, endNumber = 1, baseName = "", extension = "") {
411 |
412 | //Create an array to store the frame names
413 | let frames = [];
414 |
415 | for (let i = startNumber; i < endNumber + 1; i++) {
416 | let frame = this.TextureCache[`${baseName + i + extension}`];
417 | frames.push(frame);
418 | }
419 | return frames;
420 | }
421 |
422 | /* Text creation */
423 |
424 | //The`text` method is a quick way to create a Pixi Text sprite
425 | text(content = "message", font = "16px sans", fillStyle = "red", x = 0, y = 0) {
426 |
427 | //Create a Pixi Sprite object
428 | let message = new this.Text(content, {font: font, fill: fillStyle});
429 | message.x = x;
430 | message.y = y;
431 |
432 | //Add a `_text` property with a getter/setter
433 | message._content = content;
434 | Object.defineProperty(message, "content", {
435 | get() {
436 | return this._content;
437 | },
438 | set(value) {
439 | this._content = value;
440 | this.text = value;
441 | },
442 | enumerable: true, configurable: true
443 | });
444 |
445 | //Return the text object
446 | return message;
447 | }
448 |
449 | //The`bitmapText` method lets you create bitmap text
450 | bitmapText(content = "message", font, align, tint, x = 0, y = 0) {
451 |
452 | //Create a Pixi Sprite object
453 | let message = new this.BitmapText(content, {font: font, align: align, tint: tint});
454 | message.x = x;
455 | message.y = y;
456 |
457 | //Add a `_text` property with a getter/setter
458 | message._content = content;
459 | Object.defineProperty(message, "content", {
460 | get() {
461 | return this._content;
462 | },
463 | set(value) {
464 | this._content = value;
465 | this.text = value;
466 | },
467 | enumerable: true, configurable: true
468 | });
469 |
470 | //Return the text object
471 | return message;
472 | }
473 |
474 | /* Shapes and lines */
475 |
476 | //Rectangle
477 | rectangle(
478 | width = 32,
479 | height = 32,
480 | fillStyle = 0xFF3300,
481 | strokeStyle = 0x0033CC,
482 | lineWidth = 0,
483 | x = 0,
484 | y = 0
485 | ){
486 |
487 | let o = new this.Graphics();
488 | o._sprite = undefined;
489 | o._width = width;
490 | o._height = height;
491 | o._fillStyle = this.color(fillStyle);
492 | o._strokeStyle = this.color(strokeStyle);
493 | o._lineWidth = lineWidth;
494 |
495 | //Draw the rectangle
496 | let draw = (width, height, fillStyle, strokeStyle, lineWidth) => {
497 | o.clear();
498 | o.beginFill(fillStyle);
499 | if (lineWidth > 0) {
500 | o.lineStyle(lineWidth, strokeStyle, 1);
501 | }
502 | o.drawRect(0, 0, width, height);
503 | o.endFill();
504 | };
505 |
506 | //Draw the line and capture the sprite that the `draw` function
507 | //returns
508 | draw(o._width, o._height, o._fillStyle, o._strokeStyle, o._lineWidth);
509 |
510 | //Generate a texture from the rectangle
511 | let texture = o.generateTexture();
512 |
513 | //Use the texture to create a sprite
514 | let sprite = new this.Sprite(texture);
515 |
516 | //Position the sprite
517 | sprite.x = x;
518 | sprite.y = y;
519 |
520 | //Add getters and setters to the sprite
521 | let self = this;
522 | Object.defineProperties(sprite, {
523 | "fillStyle": {
524 | get() {
525 | return o._fillStyle;
526 | },
527 | set(value) {
528 | o._fillStyle = self.color(value);
529 |
530 | //Draw the new rectangle
531 | draw(o._width, o._height, o._fillStyle, o._strokeStyle, o._lineWidth, o._x, o._y);
532 |
533 | //Generate a new texture and set it as the sprite's texture
534 | let texture = o.generateTexture();
535 | o._sprite.texture = texture;
536 | },
537 | enumerable: true, configurable: true
538 | },
539 | "strokeStyle": {
540 | get() {
541 | return o._strokeStyle;
542 | },
543 | set(value) {
544 | o._strokeStyle = self.color(value);
545 |
546 | //Draw the new rectangle
547 | draw(o._width, o._height, o._fillStyle, o._strokeStyle, o._lineWidth, o._x, o._y);
548 |
549 | //Generate a new texture and set it as the sprite's texture
550 | let texture = o.generateTexture();
551 | o._sprite.texture = texture;
552 | },
553 | enumerable: true, configurable: true
554 | },
555 | "lineWidth": {
556 | get() {
557 | return o._lineWidth;
558 | },
559 | set(value) {
560 | o._lineWidth = value;
561 |
562 | //Draw the new rectangle
563 | draw(o._width, o._height, o._fillStyle, o._strokeStyle, o._lineWidth, o._x, o._y);
564 |
565 | //Generate a new texture and set it as the sprite's texture
566 | let texture = o.generateTexture();
567 | o._sprite.texture = texture;
568 | },
569 | enumerable: true, configurable: true
570 | }
571 | });
572 |
573 | //Get a local reference to the sprite so that we can
574 | //change the rectangle properties later using the getters/setters
575 | o._sprite = sprite;
576 |
577 | //Return the sprite
578 | return sprite;
579 | }
580 |
581 | //Circle
582 | circle(
583 | diameter = 32,
584 | fillStyle = 0xFF3300,
585 | strokeStyle = 0x0033CC,
586 | lineWidth = 0,
587 | x = 0,
588 | y = 0
589 | ){
590 |
591 | let o = new this.Graphics();
592 | o._diameter = diameter;
593 | o._fillStyle = this.color(fillStyle);
594 | o._strokeStyle = this.color(strokeStyle);
595 | o._lineWidth = lineWidth;
596 |
597 | //Draw the circle
598 | let draw = (diameter, fillStyle, strokeStyle, lineWidth) => {
599 | o.clear();
600 | o.beginFill(fillStyle);
601 | if (lineWidth > 0) {
602 | o.lineStyle(lineWidth, strokeStyle, 1);
603 | }
604 | o.drawCircle(0, 0, diameter / 2);
605 | o.endFill();
606 | };
607 |
608 | //Draw the cirlce
609 | draw(o._diameter, o._fillStyle, o._strokeStyle, o._lineWidth);
610 |
611 | //Generate a texture from the rectangle
612 | let texture = o.generateTexture();
613 |
614 | //Use the texture to create a sprite
615 | let sprite = new this.Sprite(texture);
616 |
617 | //Position the sprite
618 | sprite.x = x;
619 | sprite.y = y;
620 |
621 | //Add getters and setters to the sprite
622 | let self = this;
623 | Object.defineProperties(sprite, {
624 | "fillStyle": {
625 | get() {
626 | return o._fillStyle;
627 | },
628 | set(value) {
629 | o._fillStyle = self.color(value);
630 |
631 | //Draw the cirlce
632 | draw(o._diameter, o._fillStyle, o._strokeStyle, o._lineWidth);
633 |
634 | //Generate a new texture and set it as the sprite's texture
635 | let texture = o.generateTexture();
636 | o._sprite.texture = texture;
637 | },
638 | enumerable: true, configurable: true
639 | },
640 | "strokeStyle": {
641 | get() {
642 | return o._strokeStyle;
643 | },
644 | set(value) {
645 | o._strokeStyle = self.color(value);
646 |
647 | //Draw the cirlce
648 | draw(o._diameter, o._fillStyle, o._strokeStyle, o._lineWidth);
649 |
650 | //Generate a new texture and set it as the sprite's texture
651 | let texture = o.generateTexture();
652 | o._sprite.texture = texture;
653 | },
654 | enumerable: true, configurable: true
655 | },
656 | "diameter": {
657 | get() {
658 | return o._diameter;
659 | },
660 | set(value) {
661 | o._lineWidth = 10;
662 |
663 | //Draw the cirlce
664 | draw(o._diameter, o._fillStyle, o._strokeStyle, o._lineWidth);
665 |
666 | //Generate a new texture and set it as the sprite's texture
667 | let texture = o.generateTexture();
668 | o._sprite.texture = texture;
669 | },
670 | enumerable: true, configurable: true
671 | },
672 | "radius": {
673 | get() {
674 | return o._diameter / 2;
675 | },
676 | set(value) {
677 |
678 | //Draw the cirlce
679 | draw(value * 2, o._fillStyle, o._strokeStyle, o._lineWidth);
680 |
681 | //Generate a new texture and set it as the sprite's texture
682 | let texture = o.generateTexture();
683 | o._sprite.texture = texture;
684 | },
685 | enumerable: true, configurable: true
686 | },
687 | });
688 | //Get a local reference to the sprite so that we can
689 | //change the circle properties later using the getters/setters
690 | o._sprite = sprite;
691 |
692 | //Return the sprite
693 | return sprite;
694 | }
695 |
696 | //Line
697 | line(
698 | strokeStyle = 0x000000,
699 | lineWidth = 1,
700 | ax = 0,
701 | ay = 0,
702 | bx = 32,
703 | by = 32
704 | ){
705 |
706 | //Create the line object
707 | let o = new this.Graphics();
708 |
709 | //Private properties
710 | o._strokeStyle = this.color(strokeStyle);
711 | o._width = lineWidth;
712 | o._ax = ax;
713 | o._ay = ay;
714 | o._bx = bx;
715 | o._by = by;
716 |
717 | //A helper function that draws the line
718 | let draw = (strokeStyle, lineWidth, ax, ay, bx, by) => {
719 | o.clear();
720 | o.lineStyle(lineWidth, strokeStyle, 1);
721 | o.moveTo(ax, ay);
722 | o.lineTo(bx, by);
723 | };
724 |
725 | //Draw the line
726 | draw(o._strokeStyle, o._width, o._ax, o._ay, o._bx, o._by);
727 |
728 | //Define getters and setters that redefine the line's start and
729 | //end points and re-draws it if they change
730 | let self = this;
731 | Object.defineProperties(o, {
732 | "ax": {
733 | get() {
734 | return o._ax;
735 | },
736 | set(value) {
737 | o._ax = value;
738 | draw(o._strokeStyle, o._width, o._ax, o._ay, o._bx, o._by);
739 | },
740 | enumerable: true, configurable: true
741 | },
742 | "ay": {
743 | get() {
744 | return o._ay;
745 | },
746 | set(value) {
747 | o._ay = value;
748 | draw(o._strokeStyle, o._width, o._ax, o._ay, o._bx, o._by);
749 | },
750 | enumerable: true, configurable: true
751 | },
752 | "bx": {
753 | get() {
754 | return o._bx;
755 | },
756 | set(value) {
757 | o._bx = value;
758 | draw(o._strokeStyle, o._width, o._ax, o._ay, o._bx, o._by);
759 | },
760 | enumerable: true, configurable: true
761 | },
762 | "by": {
763 | get() {
764 | return o._by;
765 | },
766 | set(value) {
767 | o._by = value;
768 | draw(o._strokeStyle, o._width, o._ax, o._ay, o._bx, o._by);
769 | },
770 | enumerable: true, configurable: true
771 | },
772 | "strokeStyle": {
773 | get() {
774 | return o._strokeStyle;
775 | },
776 | set(value) {
777 | o._strokeStyle = self.color(value);
778 |
779 | //Draw the line
780 | draw(o._strokeStyle, o._width, o._ax, o._ay, o._bx, o._by);
781 | },
782 | enumerable: true, configurable: true
783 | },
784 | "width": {
785 | get() {
786 | return o._width;
787 | },
788 | set(value) {
789 | o._width = value;
790 |
791 | //Draw the line
792 | draw(o._strokeStyle, o._width, o._ax, o._ay, o._bx, o._by);
793 | },
794 | enumerable: true, configurable: true
795 | }
796 | });
797 |
798 | //Return the line
799 | return o;
800 | }
801 |
802 | /* Compound sprites */
803 |
804 | //Use `grid` to create a grid of sprites
805 | grid(
806 | columns = 0, rows = 0, cellWidth = 32, cellHeight = 32,
807 | centerCell = false, xOffset = 0, yOffset = 0,
808 | makeSprite = undefined,
809 | extra = undefined
810 | ){
811 |
812 | //Create an empty group called `container`. This `container`
813 | //group is what the function returns back to the main program.
814 | //All the sprites in the grid cells will be added
815 | //as children to this container
816 | let container = new this.Container();
817 |
818 | //The `create` method plots the grid
819 |
820 | let createGrid = () => {
821 |
822 | //Figure out the number of cells in the grid
823 | let length = columns * rows;
824 |
825 | //Create a sprite for each cell
826 | for(let i = 0; i < length; i++) {
827 |
828 | //Figure out the sprite's x/y placement in the grid
829 | let x = (i % columns) * cellWidth,
830 | y = Math.floor(i / columns) * cellHeight;
831 |
832 | //Use the `makeSprite` function supplied in the constructor
833 | //to make a sprite for the grid cell
834 | let sprite = makeSprite();
835 |
836 | //Add the sprite to the `container`
837 | container.addChild(sprite);
838 |
839 | //Should the sprite be centered in the cell?
840 |
841 | //No, it shouldn't be centered
842 | if (!centerCell) {
843 | sprite.x = x + xOffset;
844 | sprite.y = y + yOffset;
845 | }
846 |
847 | //Yes, it should be centered
848 | else {
849 | sprite.x
850 | = x + (cellWidth / 2)
851 | - (sprite.width / 2) + xOffset;
852 | sprite.y
853 | = y + (cellHeight / 2)
854 | - (sprite.width / 2) + yOffset;
855 | }
856 |
857 | //Run any optional extra code. This calls the
858 | //`extra` function supplied by the constructor
859 | if (extra) extra(sprite);
860 | }
861 | };
862 |
863 | //Run the `createGrid` method
864 | createGrid();
865 |
866 | //Return the `container` group back to the main program
867 | return container;
868 | }
869 |
870 | //Use `shoot` to create bullet sprites
871 | shoot(
872 | shooter, angle, x, y, container, bulletSpeed, bulletArray, bulletSprite
873 | ) {
874 |
875 | //Make a new sprite using the user-supplied `bulletSprite` function
876 | let bullet = bulletSprite();
877 |
878 | //Set the bullet's anchor point to its center
879 | bullet.anchor.set(0.5, 0.5);
880 |
881 | //Temporarily add the bullet to the shooter
882 | //so that we can position it relative to the
883 | //shooter's position
884 | shooter.addChild(bullet);
885 | bullet.x = x;
886 | bullet.y = y;
887 |
888 | //Find the bullet's global coordinates so that we can use
889 | //them to position the bullet on the new parent container
890 | let tempGx = bullet.getGlobalPosition().x,
891 | tempGy = bullet.getGlobalPosition().y;
892 |
893 | //Add the bullet to the new parent container using
894 | //the new global coordinates
895 | container.addChild(bullet);
896 | bullet.x = tempGx;
897 | bullet.y = tempGy;
898 |
899 | //Set the bullet's velocity
900 | bullet.vx = Math.cos(angle) * bulletSpeed;
901 | bullet.vy = Math.sin(angle) * bulletSpeed;
902 |
903 | //Push the bullet into the `bulletArray`
904 | bulletArray.push(bullet);
905 | }
906 |
907 | /*
908 | grid
909 | ----
910 |
911 | Helps you to automatically create a grid of sprites. `grid` returns a
912 | `group` sprite object that contains a sprite for every cell in the
913 | grid. You can define the rows and columns in the grid, whether or
914 | not the sprites should be centered inside each cell, or what their offset from the
915 | top left corner of each cell should be. Supply a function that
916 | returns the sprite that you want to make for each cell. You can
917 | supply an optional final function that runs any extra code after
918 | each sprite has been created. Here's the format for creating a grid:
919 |
920 | gridGroup = grid(
921 |
922 | //Set the grid's properties
923 | columns, rows, cellWidth, cellHeight,
924 | areSpirtesCentered?, xOffset, yOffset,
925 |
926 | //A function that returns a sprite
927 | () => g.circle(16, "blue"),
928 |
929 | //An optional final function that runs some extra code
930 | () => console.log("extra!")
931 | );
932 | */
933 |
934 | grid(
935 | columns = 0, rows = 0, cellWidth = 32, cellHeight = 32,
936 | centerCell = false, xOffset = 0, yOffset = 0,
937 | makeSprite = undefined,
938 | extra = undefined
939 | ){
940 |
941 | //Create an empty group called `container`. This `container`
942 | //group is what the function returns back to the main program.
943 | //All the sprites in the grid cells will be added
944 | //as children to this container
945 | let container = this.group();
946 |
947 | //The `create` method plots the grid
948 | let createGrid = () => {
949 |
950 | //Figure out the number of cells in the grid
951 | let length = columns * rows;
952 |
953 | //Create a sprite for each cell
954 | for(let i = 0; i < length; i++) {
955 |
956 | //Figure out the sprite's x/y placement in the grid
957 | let x = (i % columns) * cellWidth,
958 | y = Math.floor(i / columns) * cellHeight;
959 |
960 | //Use the `makeSprite` function supplied in the constructor
961 | //to make a sprite for the grid cell
962 | let sprite = makeSprite();
963 |
964 | //Add the sprite to the `container`
965 | container.addChild(sprite);
966 |
967 | //Should the sprite be centered in the cell?
968 |
969 | //No, it shouldn't be centered
970 | if (!centerCell) {
971 | sprite.x = x + xOffset;
972 | sprite.y = y + yOffset;
973 | }
974 |
975 | //Yes, it should be centered
976 | else {
977 | sprite.x
978 | = x + (cellWidth / 2)
979 | - sprite.halfWidth + xOffset;
980 | sprite.y
981 | = y + (cellHeight / 2)
982 | - sprite.halfHeight + yOffset;
983 | }
984 |
985 | //Run any optional extra code. This calls the
986 | //`extra` function supplied by the constructor
987 | if (extra) extra(sprite);
988 | }
989 | };
990 |
991 | //Run the `createGrid` method
992 | createGrid();
993 |
994 | //Return the `container` group back to the main program
995 | return container;
996 | }
997 |
998 | /*
999 | shake
1000 | -----
1001 |
1002 | Used to create a shaking effect, like a screen shake
1003 | */
1004 |
1005 | shake(sprite, magnitude = 16, angular = false) {
1006 |
1007 | //Get a reference to this current object so that
1008 | //it's easy to maintain scope in the nested sub-functions
1009 | let self = this;
1010 |
1011 | //A counter to count the number of shakes
1012 | let counter = 1;
1013 |
1014 | //The total number of shakes (there will be 1 shake per frame)
1015 | let numberOfShakes = 10;
1016 |
1017 | //Capture the sprite's position and angle so you can
1018 | //restore them after the shaking has finished
1019 | let startX = sprite.x,
1020 | startY = sprite.y,
1021 | startAngle = sprite.rotation;
1022 |
1023 | //Divide the magnitude into 10 units so that you can
1024 | //reduce the amount of shake by 10 percent each frame
1025 | let magnitudeUnit = magnitude / numberOfShakes;
1026 |
1027 | //The `randomInt` helper function
1028 | let randomInt = (min, max) => {
1029 | return Math.floor(Math.random() * (max - min + 1)) + min;
1030 | };
1031 |
1032 | //Add the sprite to the `shakingSprites` array if it
1033 | //isn't already there
1034 | if(self.shakingSprites.indexOf(sprite) === -1) {
1035 |
1036 | self.shakingSprites.push(sprite);
1037 |
1038 | //Add an `updateShake` method to the sprite.
1039 | //The `updateShake` method will be called each frame
1040 | //in the game loop. The shake effect type can be either
1041 | //up and down (x/y shaking) or angular (rotational shaking).
1042 | sprite.updateShake = () => {
1043 | if(angular) {
1044 | angularShake();
1045 | } else {
1046 | upAndDownShake();
1047 | }
1048 | };
1049 | }
1050 |
1051 | //The `upAndDownShake` function
1052 | function upAndDownShake() {
1053 |
1054 | //Shake the sprite while the `counter` is less than
1055 | //the `numberOfShakes`
1056 | if (counter < numberOfShakes) {
1057 |
1058 | //Reset the sprite's position at the start of each shake
1059 | sprite.x = startX;
1060 | sprite.y = startY;
1061 |
1062 | //Reduce the magnitude
1063 | magnitude -= magnitudeUnit;
1064 |
1065 | //Randomly change the sprite's position
1066 | sprite.x += randomInt(-magnitude, magnitude);
1067 | sprite.y += randomInt(-magnitude, magnitude);
1068 |
1069 | //Add 1 to the counter
1070 | counter += 1;
1071 | }
1072 |
1073 | //When the shaking is finished, restore the sprite to its original
1074 | //position and remove it from the `shakingSprites` array
1075 | if (counter >= numberOfShakes) {
1076 | sprite.x = startX;
1077 | sprite.y = startY;
1078 | self.shakingSprites.splice(self.shakingSprites.indexOf(sprite), 1);
1079 | }
1080 | }
1081 |
1082 | //The `angularShake` function
1083 | //First set the initial tilt angle to the right (+1)
1084 | let tiltAngle = 1;
1085 |
1086 | function angularShake() {
1087 | if (counter < numberOfShakes) {
1088 |
1089 | //Reset the sprite's rotation
1090 | sprite.rotation = startAngle;
1091 |
1092 | //Reduce the magnitude
1093 | magnitude -= magnitudeUnit;
1094 |
1095 | //Rotate the sprite left or right, depending on the direction,
1096 | //by an amount in radians that matches the magnitude
1097 | sprite.rotation = magnitude * tiltAngle;
1098 | counter += 1;
1099 |
1100 | //Reverse the tilt angle so that the sprite is tilted
1101 | //in the opposite direction for the next shake
1102 | tiltAngle *= -1;
1103 | }
1104 |
1105 | //When the shaking is finished, reset the sprite's angle and
1106 | //remove it from the `shakingSprites` array
1107 | if (counter >= numberOfShakes) {
1108 | sprite.rotation = startAngle;
1109 | self.shakingSprites.splice(self.shakingSprites.indexOf(sprite), 1);
1110 | }
1111 | }
1112 | }
1113 |
1114 | /*
1115 | _getCenter
1116 | ----------
1117 |
1118 | A utility that finds the center point of the sprite. If it's anchor point is the
1119 | sprite's top left corner, then the center is calculated from that point.
1120 | If the anchor point has been shifted, then the anchor x/y point is used as the sprite's center
1121 | */
1122 |
1123 | _getCenter(o, dimension, axis) {
1124 | if (o.anchor !== undefined) {
1125 | if (o.anchor[axis] !== 0) {
1126 | return 0;
1127 | } else {
1128 | return dimension / 2;
1129 | }
1130 | } else {
1131 | return dimension;
1132 | }
1133 | }
1134 |
1135 |
1136 |
1137 | /* Groups */
1138 |
1139 | //Group sprites into a container
1140 | group(...sprites) {
1141 | let container = new this.Container();
1142 | sprites.forEach(sprite => {
1143 | container.addChild(sprite);
1144 | });
1145 | return container;
1146 | }
1147 |
1148 | //Use the `batch` method to create a ParticleContainer
1149 | batch(size = 15000, options = {rotation: true, alpha: true, scale: true, uvs: true}) {
1150 | let o = new this.ParticleContainer(size, options);
1151 | return o;
1152 | }
1153 |
1154 | //`remove` is a global convenience method that will
1155 | //remove any sprite, or an argument list of sprites, from its parent.
1156 | remove(...sprites) {
1157 |
1158 | //Remove sprites that's aren't in an array
1159 | if (!(sprites[0] instanceof Array)) {
1160 | if (sprites.length > 1) {
1161 | sprites.forEach(sprite => {
1162 | sprite.parent.removeChild(sprite);
1163 | });
1164 | } else {
1165 | sprites[0].parent.removeChild(sprites[0]);
1166 | }
1167 | }
1168 |
1169 | //Remove sprites in an array of sprites
1170 | else {
1171 | let spritesArray = sprites[0];
1172 | if (spritesArray.length > 0) {
1173 | for (let i = spritesArray.length - 1; i >= 0; i--) {
1174 | let sprite = spritesArray[i];
1175 | sprite.parent.removeChild(sprite);
1176 | spritesArray.splice(spritesArray.indexOf(sprite), 1);
1177 | }
1178 | }
1179 | }
1180 | }
1181 |
1182 | /* Color conversion */
1183 | //From: http://stackoverflow.com/questions/1573053/javascript-function-to-convert-color-names-to-hex-codes
1184 | //Utilities to convert HTML color string names to hexadecimal codes
1185 |
1186 | colorToRGBA(color) {
1187 | // Returns the color as an array of [r, g, b, a] -- all range from 0 - 255
1188 | // color must be a valid canvas fillStyle. This will cover most anything
1189 | // you'd want to use.
1190 | // Examples:
1191 | // colorToRGBA('red') # [255, 0, 0, 255]
1192 | // colorToRGBA('#f00') # [255, 0, 0, 255]
1193 | var cvs, ctx;
1194 | cvs = document.createElement('canvas');
1195 | cvs.height = 1;
1196 | cvs.width = 1;
1197 | ctx = cvs.getContext('2d');
1198 | ctx.fillStyle = color;
1199 | ctx.fillRect(0, 0, 1, 1);
1200 | let data = ctx.getImageData(0, 0, 1, 1).data;
1201 | return data;
1202 | }
1203 |
1204 | byteToHex(num) {
1205 | // Turns a number (0-255) into a 2-character hex number (00-ff)
1206 | return ('0'+num.toString(16)).slice(-2);
1207 | }
1208 |
1209 | colorToHex(color) {
1210 | // Convert any CSS color to a hex representation
1211 | // Examples:
1212 | // colorToHex('red') # '#ff0000'
1213 | // colorToHex('rgb(255, 0, 0)') # '#ff0000'
1214 | var rgba, hex;
1215 | rgba = this.colorToRGBA(color);
1216 | hex = [0,1,2].map(
1217 | idx => this.byteToHex(rgba[idx])
1218 | ).join('');
1219 | return "0x" + hex;
1220 | }
1221 |
1222 | //A function to find out if the user entered a number (a hex color
1223 | //code) or a string (an HTML color string)
1224 | color(value) {
1225 |
1226 | //Check if it's a number
1227 | if(!isNaN(value)){
1228 |
1229 | //Yes, it is a number, so just return it
1230 | return value;
1231 | }
1232 |
1233 | //No it's not a number, so it must be a string
1234 | else {
1235 |
1236 | return parseInt(this.colorToHex(value));
1237 | /*
1238 |
1239 | //Find out what kind of color string it is.
1240 | //Let's first grab the first character of the string
1241 | let firstCharacter = value.charAt(0);
1242 |
1243 | //If the first character is a "#" or a number, then
1244 | //we know it must be a RGBA color
1245 | if (firstCharacter === "#") {
1246 | console.log("first character: " + value.charAt(0))
1247 | }
1248 | */
1249 | }
1250 |
1251 | /*
1252 | //Find out if the first character in the string is a number
1253 | if (!isNaN(parseInt(string.charAt(0)))) {
1254 |
1255 | //It's not, so convert it to a hex code
1256 | return colorToHex(string);
1257 |
1258 | //The use input a number, so it must be a hex code. Just return it
1259 | } else {
1260 |
1261 | return string;
1262 | }
1263 |
1264 | */
1265 |
1266 | }
1267 |
1268 | }
1269 |
1270 |
1271 |
1272 |
--------------------------------------------------------------------------------
/bin/spriteUtilities.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
4 |
5 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
6 |
7 | var SpriteUtilities = (function () {
8 | function SpriteUtilities() {
9 | var renderingEngine = arguments.length <= 0 || arguments[0] === undefined ? PIXI : arguments[0];
10 |
11 | _classCallCheck(this, SpriteUtilities);
12 |
13 | if (renderingEngine === undefined) throw new Error("Please supply a reference to PIXI in the SpriteUtilities constructor before using spriteUtilities.js");
14 |
15 | //Find out which rendering engine is being used (the default is Pixi)
16 | this.renderer = "";
17 |
18 | //If the `renderingEngine` is Pixi, set up Pixi object aliases
19 | if (renderingEngine.ParticleContainer && renderingEngine.Sprite) {
20 | this.renderer = "pixi";
21 | this.Container = renderingEngine.Container;
22 | this.ParticleContainer = renderingEngine.ParticleContainer;
23 | this.TextureCache = renderingEngine.utils.TextureCache;
24 | this.Texture = renderingEngine.Texture;
25 | this.Rectangle = renderingEngine.Rectangle;
26 | this.MovieClip = renderingEngine.extras.MovieClip;
27 | this.BitmapText = renderingEngine.extras.BitmapText;
28 | this.Sprite = renderingEngine.Sprite;
29 | this.TilingSprite = renderingEngine.extras.TilingSprite;
30 | this.Graphics = renderingEngine.Graphics;
31 | this.Text = renderingEngine.Text;
32 |
33 | //An array to store all the shaking sprites
34 | this.shakingSprites = [];
35 | }
36 | }
37 |
38 | _createClass(SpriteUtilities, [{
39 | key: "update",
40 | value: function update() {
41 | if (this.shakingSprites.length > 0) {
42 | for (var i = this.shakingSprites.length - 1; i >= 0; i--) {
43 | var shakingSprite = this.shakingSprites[i];
44 | if (shakingSprite.updateShake) shakingSprite.updateShake();
45 | }
46 | }
47 | }
48 | }, {
49 | key: "sprite",
50 | value: function sprite(source) {
51 | var x = arguments.length <= 1 || arguments[1] === undefined ? 0 : arguments[1];
52 | var y = arguments.length <= 2 || arguments[2] === undefined ? 0 : arguments[2];
53 | var tiling = arguments.length <= 3 || arguments[3] === undefined ? false : arguments[3];
54 | var width = arguments[4];
55 | var height = arguments[5];
56 |
57 | var o = undefined,
58 | texture = undefined;
59 |
60 | //Create a sprite if the `source` is a string
61 | if (typeof source === "string") {
62 |
63 | //Access the texture in the cache if it's there
64 | if (this.TextureCache[source]) {
65 | texture = this.TextureCache[source];
66 | }
67 |
68 | //If it's not is the cache, load it from the source file
69 | else {
70 | texture = this.Texture.fromImage(source);
71 | }
72 |
73 | //If the texture was created, make the o
74 | if (texture) {
75 |
76 | //If `tiling` is `false`, make a regular `Sprite`
77 | if (!tiling) {
78 | o = new this.Sprite(texture);
79 | }
80 |
81 | //If `tiling` is `true` make a `TilingSprite`
82 | else {
83 | o = new this.TilingSprite(texture, width, height);
84 | }
85 | }
86 | //But if the source still can't be found, alert the user
87 | else {
88 | throw new Error(source + " cannot be found");
89 | }
90 | }
91 |
92 | //Create a o if the `source` is a texture
93 | else if (source instanceof this.Texture) {
94 | if (!tiling) {
95 | o = new this.Sprite(source);
96 | } else {
97 | o = new this.TilingSprite(source, width, height);
98 | }
99 | }
100 |
101 | //Create a `MovieClip` o if the `source` is an array
102 | else if (source instanceof Array) {
103 |
104 | //Is it an array of frame ids or textures?
105 | if (typeof source[0] === "string") {
106 |
107 | //They're strings, but are they pre-existing texture or
108 | //paths to image files?
109 | //Check to see if the first element matches a texture in the
110 | //cache
111 | if (this.TextureCache[source[0]]) {
112 |
113 | //It does, so it's an array of frame ids
114 | o = this.MovieClip.fromFrames(source);
115 | } else {
116 |
117 | //It's not already in the cache, so let's load it
118 | o = this.MovieClip.fromImages(source);
119 | }
120 | }
121 |
122 | //If the `source` isn't an array of strings, check whether
123 | //it's an array of textures
124 | else if (source[0] instanceof this.Texture) {
125 |
126 | //Yes, it's an array of textures.
127 | //Use them to make a MovieClip o
128 | o = new this.MovieClip(source);
129 | }
130 | }
131 |
132 | //If the sprite was successfully created, intialize it
133 | if (o) {
134 |
135 | //Position the sprite
136 | o.x = x;
137 | o.y = y;
138 |
139 | //Set optional width and height
140 | if (width) o.width = width;
141 | if (height) o.height = height;
142 |
143 | //If the sprite is a MovieClip, add a state player so that
144 | //it's easier to control
145 | if (o instanceof this.MovieClip) this.addStatePlayer(o);
146 |
147 | //Assign the sprite
148 | return o;
149 | }
150 | }
151 | }, {
152 | key: "addStatePlayer",
153 | value: function addStatePlayer(sprite) {
154 |
155 | var frameCounter = 0,
156 | numberOfFrames = 0,
157 | startFrame = 0,
158 | endFrame = 0,
159 | timerInterval = undefined;
160 |
161 | //The `show` function (to display static states)
162 | function show(frameNumber) {
163 |
164 | //Reset any possible previous animations
165 | reset();
166 |
167 | //Find the new state on the sprite
168 | sprite.gotoAndStop(frameNumber);
169 | }
170 |
171 | //The `stop` function stops the animation at the current frame
172 | function stopAnimation() {
173 | reset();
174 | sprite.gotoAndStop(sprite.currentFrame);
175 | }
176 |
177 | //The `playSequence` function, to play a sequence of frames
178 | function playAnimation(sequenceArray) {
179 |
180 | //Reset any possible previous animations
181 | reset();
182 |
183 | //Figure out how many frames there are in the range
184 | if (!sequenceArray) {
185 | startFrame = 0;
186 | endFrame = sprite.totalFrames - 1;
187 | } else {
188 | startFrame = sequenceArray[0];
189 | endFrame = sequenceArray[1];
190 | }
191 |
192 | //Calculate the number of frames
193 | numberOfFrames = endFrame - startFrame;
194 |
195 | //Compensate for two edge cases:
196 | //1. If the `startFrame` happens to be `0`
197 | /*
198 | if (startFrame === 0) {
199 | numberOfFrames += 1;
200 | frameCounter += 1;
201 | }
202 | */
203 |
204 | //2. If only a two-frame sequence was provided
205 | /*
206 | if(numberOfFrames === 1) {
207 | numberOfFrames = 2;
208 | frameCounter += 1;
209 | }
210 | */
211 |
212 | //Calculate the frame rate. Set the default fps to 12
213 | if (!sprite.fps) sprite.fps = 12;
214 | var frameRate = 1000 / sprite.fps;
215 |
216 | //Set the sprite to the starting frame
217 | sprite.gotoAndStop(startFrame);
218 |
219 | //Set the `frameCounter` to the first frame
220 | frameCounter = 1;
221 |
222 | //If the state isn't already `playing`, start it
223 | if (!sprite.animating) {
224 | timerInterval = setInterval(advanceFrame.bind(this), frameRate);
225 | sprite.animating = true;
226 | }
227 | }
228 |
229 | //`advanceFrame` is called by `setInterval` to display the next frame
230 | //in the sequence based on the `frameRate`. When the frame sequence
231 | //reaches the end, it will either stop or loop
232 | function advanceFrame() {
233 |
234 | //Advance the frame if `frameCounter` is less than
235 | //the state's total frames
236 | if (frameCounter < numberOfFrames + 1) {
237 |
238 | //Advance the frame
239 | sprite.gotoAndStop(sprite.currentFrame + 1);
240 |
241 | //Update the frame counter
242 | frameCounter += 1;
243 |
244 | //If we've reached the last frame and `loop`
245 | //is `true`, then start from the first frame again
246 | } else {
247 | if (sprite.loop) {
248 | sprite.gotoAndStop(startFrame);
249 | frameCounter = 1;
250 | }
251 | }
252 | }
253 |
254 | function reset() {
255 |
256 | //Reset `sprite.playing` to `false`, set the `frameCounter` to 0, //and clear the `timerInterval`
257 | if (timerInterval !== undefined && sprite.animating === true) {
258 | sprite.animating = false;
259 | frameCounter = 0;
260 | startFrame = 0;
261 | endFrame = 0;
262 | numberOfFrames = 0;
263 | clearInterval(timerInterval);
264 | }
265 | }
266 |
267 | //Add the `show`, `play`, `stop`, and `playSequence` methods to the sprite
268 | sprite.show = show;
269 | sprite.stopAnimation = stopAnimation;
270 | sprite.playAnimation = playAnimation;
271 | }
272 |
273 | //`tilingSpirte` lets you quickly create Pixi tiling sprites
274 |
275 | }, {
276 | key: "tilingSprite",
277 | value: function tilingSprite(source, width, height, x, y) {
278 | if (width === undefined) {
279 | throw new Error("Please define a width as your second argument for the tiling sprite");
280 | }
281 | if (height === undefined) {
282 | throw new Error("Please define a height as your third argument for the tiling sprite");
283 | }
284 | var o = this.sprite(source, x, y, true, width, height);
285 |
286 | //Add `tileX`, `tileY`, `tileScaleX` and `tileScaleY` properties
287 | Object.defineProperties(o, {
288 | "tileX": {
289 | get: function get() {
290 | return o.tilePosition.x;
291 | },
292 | set: function set(value) {
293 | o.tilePosition.x = value;
294 | },
295 |
296 | enumerable: true, configurable: true
297 | },
298 | "tileY": {
299 | get: function get() {
300 | return o.tilePosition.y;
301 | },
302 | set: function set(value) {
303 | o.tilePosition.y = value;
304 | },
305 |
306 | enumerable: true, configurable: true
307 | },
308 | "tileScaleX": {
309 | get: function get() {
310 | return o.tileScale.x;
311 | },
312 | set: function set(value) {
313 | o.tileScale.x = value;
314 | },
315 |
316 | enumerable: true, configurable: true
317 | },
318 | "tileScaleY": {
319 | get: function get() {
320 | return o.tileScale.y;
321 | },
322 | set: function set(value) {
323 | o.tileScale.y = value;
324 | },
325 |
326 | enumerable: true, configurable: true
327 | }
328 | });
329 |
330 | return o;
331 | }
332 | }, {
333 | key: "filmstrip",
334 | value: function filmstrip(texture, frameWidth, frameHeight) {
335 | var spacing = arguments.length <= 3 || arguments[3] === undefined ? 0 : arguments[3];
336 |
337 | //An array to store the x/y positions of the frames
338 | var positions = [];
339 |
340 | //Find the width and height of the texture
341 | var textureWidth = this.TextureCache[texture].width,
342 | textureHeight = this.TextureCache[texture].height;
343 |
344 | //Find out how many columns and rows there are
345 | var columns = textureWidth / frameWidth,
346 | rows = textureHeight / frameHeight;
347 |
348 | //Find the total number of frames
349 | var numberOfFrames = columns * rows;
350 |
351 | for (var i = 0; i < numberOfFrames; i++) {
352 |
353 | //Find the correct row and column for each frame
354 | //and figure out its x and y position
355 | var x = i % columns * frameWidth,
356 | y = Math.floor(i / columns) * frameHeight;
357 |
358 | //Compensate for any optional spacing (padding) around the tiles if
359 | //there is any. This bit of code accumlates the spacing offsets from the
360 | //left side of the tileset and adds them to the current tile's position
361 | if (spacing > 0) {
362 | x += spacing + spacing * i % columns;
363 | y += spacing + spacing * Math.floor(i / columns);
364 | }
365 |
366 | //Add the x and y value of each frame to the `positions` array
367 | positions.push([x, y]);
368 | }
369 |
370 | //Return the frames
371 | return this.frames(texture, positions, frameWidth, frameHeight);
372 | }
373 |
374 | //Make a texture from a frame in another texture or image
375 |
376 | }, {
377 | key: "frame",
378 | value: function frame(source, x, y, width, height) {
379 |
380 | var texture = undefined,
381 | imageFrame = undefined;
382 |
383 | //If the source is a string, it's either a texture in the
384 | //cache or an image file
385 | if (typeof source === "string") {
386 | if (this.TextureCache[source]) {
387 | texture = new this.Texture(this.TextureCache[source]);
388 | }
389 | }
390 |
391 | //If the `source` is a texture, use it
392 | else if (source instanceof this.Texture) {
393 | texture = new this.Texture(source);
394 | }
395 | if (!texture) {
396 | throw new Error("Please load the " + source + " texture into the cache.");
397 | } else {
398 |
399 | //Make a rectangle the size of the sub-image
400 | imageFrame = new this.Rectangle(x, y, width, height);
401 | texture.frame = imageFrame;
402 | return texture;
403 | }
404 | }
405 |
406 | //Make an array of textures from a 2D array of frame x and y coordinates in
407 | //texture
408 |
409 | }, {
410 | key: "frames",
411 | value: function frames(source, coordinates, frameWidth, frameHeight) {
412 | var _this = this;
413 |
414 | var baseTexture = undefined,
415 | textures = undefined;
416 |
417 | //If the source is a string, it's either a texture in the
418 | //cache or an image file
419 | if (typeof source === "string") {
420 | if (this.TextureCache[source]) {
421 | baseTexture = new this.Texture(this.TextureCache[source]);
422 | }
423 | }
424 | //If the `source` is a texture, use it
425 | else if (source instanceof this.Texture) {
426 | baseTexture = new this.Texture(source);
427 | }
428 | if (!baseTexture) {
429 | throw new Error("Please load the " + source + " texture into the cache.");
430 | } else {
431 | var _textures = coordinates.map(function (position) {
432 | var x = position[0],
433 | y = position[1];
434 | var imageFrame = new _this.Rectangle(x, y, frameWidth, frameHeight);
435 | var frameTexture = new _this.Texture(baseTexture);
436 | frameTexture.frame = imageFrame;
437 | return frameTexture;
438 | });
439 | return _textures;
440 | }
441 | }
442 | }, {
443 | key: "frameSeries",
444 | value: function frameSeries() {
445 | var startNumber = arguments.length <= 0 || arguments[0] === undefined ? 0 : arguments[0];
446 | var endNumber = arguments.length <= 1 || arguments[1] === undefined ? 1 : arguments[1];
447 | var baseName = arguments.length <= 2 || arguments[2] === undefined ? "" : arguments[2];
448 | var extension = arguments.length <= 3 || arguments[3] === undefined ? "" : arguments[3];
449 |
450 | //Create an array to store the frame names
451 | var frames = [];
452 |
453 | for (var i = startNumber; i < endNumber + 1; i++) {
454 | var frame = this.TextureCache["" + (baseName + i + extension)];
455 | frames.push(frame);
456 | }
457 | return frames;
458 | }
459 |
460 | /* Text creation */
461 |
462 | //The`text` method is a quick way to create a Pixi Text sprite
463 |
464 | }, {
465 | key: "text",
466 | value: function text() {
467 | var content = arguments.length <= 0 || arguments[0] === undefined ? "message" : arguments[0];
468 | var font = arguments.length <= 1 || arguments[1] === undefined ? "16px sans" : arguments[1];
469 | var fillStyle = arguments.length <= 2 || arguments[2] === undefined ? "red" : arguments[2];
470 | var x = arguments.length <= 3 || arguments[3] === undefined ? 0 : arguments[3];
471 | var y = arguments.length <= 4 || arguments[4] === undefined ? 0 : arguments[4];
472 |
473 | //Create a Pixi Sprite object
474 | var message = new this.Text(content, { font: font, fill: fillStyle });
475 | message.x = x;
476 | message.y = y;
477 |
478 | //Add a `_text` property with a getter/setter
479 | message._content = content;
480 | Object.defineProperty(message, "content", {
481 | get: function get() {
482 | return this._content;
483 | },
484 | set: function set(value) {
485 | this._content = value;
486 | this.text = value;
487 | },
488 |
489 | enumerable: true, configurable: true
490 | });
491 |
492 | //Return the text object
493 | return message;
494 | }
495 |
496 | //The`bitmapText` method lets you create bitmap text
497 |
498 | }, {
499 | key: "bitmapText",
500 | value: function bitmapText() {
501 | var content = arguments.length <= 0 || arguments[0] === undefined ? "message" : arguments[0];
502 | var font = arguments[1];
503 | var align = arguments[2];
504 | var tint = arguments[3];
505 | var x = arguments.length <= 4 || arguments[4] === undefined ? 0 : arguments[4];
506 | var y = arguments.length <= 5 || arguments[5] === undefined ? 0 : arguments[5];
507 |
508 | //Create a Pixi Sprite object
509 | var message = new this.BitmapText(content, { font: font, align: align, tint: tint });
510 | message.x = x;
511 | message.y = y;
512 |
513 | //Add a `_text` property with a getter/setter
514 | message._content = content;
515 | Object.defineProperty(message, "content", {
516 | get: function get() {
517 | return this._content;
518 | },
519 | set: function set(value) {
520 | this._content = value;
521 | this.text = value;
522 | },
523 |
524 | enumerable: true, configurable: true
525 | });
526 |
527 | //Return the text object
528 | return message;
529 | }
530 |
531 | /* Shapes and lines */
532 |
533 | //Rectangle
534 |
535 | }, {
536 | key: "rectangle",
537 | value: function rectangle() {
538 | var width = arguments.length <= 0 || arguments[0] === undefined ? 32 : arguments[0];
539 | var height = arguments.length <= 1 || arguments[1] === undefined ? 32 : arguments[1];
540 | var fillStyle = arguments.length <= 2 || arguments[2] === undefined ? 0xFF3300 : arguments[2];
541 | var strokeStyle = arguments.length <= 3 || arguments[3] === undefined ? 0x0033CC : arguments[3];
542 | var lineWidth = arguments.length <= 4 || arguments[4] === undefined ? 0 : arguments[4];
543 | var x = arguments.length <= 5 || arguments[5] === undefined ? 0 : arguments[5];
544 | var y = arguments.length <= 6 || arguments[6] === undefined ? 0 : arguments[6];
545 |
546 | var o = new this.Graphics();
547 | o._sprite = undefined;
548 | o._width = width;
549 | o._height = height;
550 | o._fillStyle = this.color(fillStyle);
551 | o._strokeStyle = this.color(strokeStyle);
552 | o._lineWidth = lineWidth;
553 |
554 | //Draw the rectangle
555 | var draw = function draw(width, height, fillStyle, strokeStyle, lineWidth) {
556 | o.clear();
557 | o.beginFill(fillStyle);
558 | if (lineWidth > 0) {
559 | o.lineStyle(lineWidth, strokeStyle, 1);
560 | }
561 | o.drawRect(0, 0, width, height);
562 | o.endFill();
563 | };
564 |
565 | //Draw the line and capture the sprite that the `draw` function
566 | //returns
567 | draw(o._width, o._height, o._fillStyle, o._strokeStyle, o._lineWidth);
568 |
569 | //Generate a texture from the rectangle
570 | var texture = o.generateTexture();
571 |
572 | //Use the texture to create a sprite
573 | var sprite = new this.Sprite(texture);
574 |
575 | //Position the sprite
576 | sprite.x = x;
577 | sprite.y = y;
578 |
579 | //Add getters and setters to the sprite
580 | var self = this;
581 | Object.defineProperties(sprite, {
582 | "fillStyle": {
583 | get: function get() {
584 | return o._fillStyle;
585 | },
586 | set: function set(value) {
587 | o._fillStyle = self.color(value);
588 |
589 | //Draw the new rectangle
590 | draw(o._width, o._height, o._fillStyle, o._strokeStyle, o._lineWidth, o._x, o._y);
591 |
592 | //Generate a new texture and set it as the sprite's texture
593 | var texture = o.generateTexture();
594 | o._sprite.texture = texture;
595 | },
596 |
597 | enumerable: true, configurable: true
598 | },
599 | "strokeStyle": {
600 | get: function get() {
601 | return o._strokeStyle;
602 | },
603 | set: function set(value) {
604 | o._strokeStyle = self.color(value);
605 |
606 | //Draw the new rectangle
607 | draw(o._width, o._height, o._fillStyle, o._strokeStyle, o._lineWidth, o._x, o._y);
608 |
609 | //Generate a new texture and set it as the sprite's texture
610 | var texture = o.generateTexture();
611 | o._sprite.texture = texture;
612 | },
613 |
614 | enumerable: true, configurable: true
615 | },
616 | "lineWidth": {
617 | get: function get() {
618 | return o._lineWidth;
619 | },
620 | set: function set(value) {
621 | o._lineWidth = value;
622 |
623 | //Draw the new rectangle
624 | draw(o._width, o._height, o._fillStyle, o._strokeStyle, o._lineWidth, o._x, o._y);
625 |
626 | //Generate a new texture and set it as the sprite's texture
627 | var texture = o.generateTexture();
628 | o._sprite.texture = texture;
629 | },
630 |
631 | enumerable: true, configurable: true
632 | }
633 | });
634 |
635 | //Get a local reference to the sprite so that we can
636 | //change the rectangle properties later using the getters/setters
637 | o._sprite = sprite;
638 |
639 | //Return the sprite
640 | return sprite;
641 | }
642 |
643 | //Circle
644 |
645 | }, {
646 | key: "circle",
647 | value: function circle() {
648 | var diameter = arguments.length <= 0 || arguments[0] === undefined ? 32 : arguments[0];
649 | var fillStyle = arguments.length <= 1 || arguments[1] === undefined ? 0xFF3300 : arguments[1];
650 | var strokeStyle = arguments.length <= 2 || arguments[2] === undefined ? 0x0033CC : arguments[2];
651 | var lineWidth = arguments.length <= 3 || arguments[3] === undefined ? 0 : arguments[3];
652 | var x = arguments.length <= 4 || arguments[4] === undefined ? 0 : arguments[4];
653 | var y = arguments.length <= 5 || arguments[5] === undefined ? 0 : arguments[5];
654 |
655 | var o = new this.Graphics();
656 | o._diameter = diameter;
657 | o._fillStyle = this.color(fillStyle);
658 | o._strokeStyle = this.color(strokeStyle);
659 | o._lineWidth = lineWidth;
660 |
661 | //Draw the circle
662 | var draw = function draw(diameter, fillStyle, strokeStyle, lineWidth) {
663 | o.clear();
664 | o.beginFill(fillStyle);
665 | if (lineWidth > 0) {
666 | o.lineStyle(lineWidth, strokeStyle, 1);
667 | }
668 | o.drawCircle(0, 0, diameter / 2);
669 | o.endFill();
670 | };
671 |
672 | //Draw the cirlce
673 | draw(o._diameter, o._fillStyle, o._strokeStyle, o._lineWidth);
674 |
675 | //Generate a texture from the rectangle
676 | var texture = o.generateTexture();
677 |
678 | //Use the texture to create a sprite
679 | var sprite = new this.Sprite(texture);
680 |
681 | //Position the sprite
682 | sprite.x = x;
683 | sprite.y = y;
684 |
685 | //Add getters and setters to the sprite
686 | var self = this;
687 | Object.defineProperties(sprite, {
688 | "fillStyle": {
689 | get: function get() {
690 | return o._fillStyle;
691 | },
692 | set: function set(value) {
693 | o._fillStyle = self.color(value);
694 |
695 | //Draw the cirlce
696 | draw(o._diameter, o._fillStyle, o._strokeStyle, o._lineWidth);
697 |
698 | //Generate a new texture and set it as the sprite's texture
699 | var texture = o.generateTexture();
700 | o._sprite.texture = texture;
701 | },
702 |
703 | enumerable: true, configurable: true
704 | },
705 | "strokeStyle": {
706 | get: function get() {
707 | return o._strokeStyle;
708 | },
709 | set: function set(value) {
710 | o._strokeStyle = self.color(value);
711 |
712 | //Draw the cirlce
713 | draw(o._diameter, o._fillStyle, o._strokeStyle, o._lineWidth);
714 |
715 | //Generate a new texture and set it as the sprite's texture
716 | var texture = o.generateTexture();
717 | o._sprite.texture = texture;
718 | },
719 |
720 | enumerable: true, configurable: true
721 | },
722 | "diameter": {
723 | get: function get() {
724 | return o._diameter;
725 | },
726 | set: function set(value) {
727 | o._lineWidth = 10;
728 |
729 | //Draw the cirlce
730 | draw(o._diameter, o._fillStyle, o._strokeStyle, o._lineWidth);
731 |
732 | //Generate a new texture and set it as the sprite's texture
733 | var texture = o.generateTexture();
734 | o._sprite.texture = texture;
735 | },
736 |
737 | enumerable: true, configurable: true
738 | },
739 | "radius": {
740 | get: function get() {
741 | return o._diameter / 2;
742 | },
743 | set: function set(value) {
744 |
745 | //Draw the cirlce
746 | draw(value * 2, o._fillStyle, o._strokeStyle, o._lineWidth);
747 |
748 | //Generate a new texture and set it as the sprite's texture
749 | var texture = o.generateTexture();
750 | o._sprite.texture = texture;
751 | },
752 |
753 | enumerable: true, configurable: true
754 | }
755 | });
756 | //Get a local reference to the sprite so that we can
757 | //change the circle properties later using the getters/setters
758 | o._sprite = sprite;
759 |
760 | //Return the sprite
761 | return sprite;
762 | }
763 |
764 | //Line
765 |
766 | }, {
767 | key: "line",
768 | value: function line() {
769 | var strokeStyle = arguments.length <= 0 || arguments[0] === undefined ? 0x000000 : arguments[0];
770 | var lineWidth = arguments.length <= 1 || arguments[1] === undefined ? 1 : arguments[1];
771 | var ax = arguments.length <= 2 || arguments[2] === undefined ? 0 : arguments[2];
772 | var ay = arguments.length <= 3 || arguments[3] === undefined ? 0 : arguments[3];
773 | var bx = arguments.length <= 4 || arguments[4] === undefined ? 32 : arguments[4];
774 | var by = arguments.length <= 5 || arguments[5] === undefined ? 32 : arguments[5];
775 |
776 | //Create the line object
777 | var o = new this.Graphics();
778 |
779 | //Private properties
780 | o._strokeStyle = this.color(strokeStyle);
781 | o._width = lineWidth;
782 | o._ax = ax;
783 | o._ay = ay;
784 | o._bx = bx;
785 | o._by = by;
786 |
787 | //A helper function that draws the line
788 | var draw = function draw(strokeStyle, lineWidth, ax, ay, bx, by) {
789 | o.clear();
790 | o.lineStyle(lineWidth, strokeStyle, 1);
791 | o.moveTo(ax, ay);
792 | o.lineTo(bx, by);
793 | };
794 |
795 | //Draw the line
796 | draw(o._strokeStyle, o._width, o._ax, o._ay, o._bx, o._by);
797 |
798 | //Define getters and setters that redefine the line's start and
799 | //end points and re-draws it if they change
800 | var self = this;
801 | Object.defineProperties(o, {
802 | "ax": {
803 | get: function get() {
804 | return o._ax;
805 | },
806 | set: function set(value) {
807 | o._ax = value;
808 | draw(o._strokeStyle, o._width, o._ax, o._ay, o._bx, o._by);
809 | },
810 |
811 | enumerable: true, configurable: true
812 | },
813 | "ay": {
814 | get: function get() {
815 | return o._ay;
816 | },
817 | set: function set(value) {
818 | o._ay = value;
819 | draw(o._strokeStyle, o._width, o._ax, o._ay, o._bx, o._by);
820 | },
821 |
822 | enumerable: true, configurable: true
823 | },
824 | "bx": {
825 | get: function get() {
826 | return o._bx;
827 | },
828 | set: function set(value) {
829 | o._bx = value;
830 | draw(o._strokeStyle, o._width, o._ax, o._ay, o._bx, o._by);
831 | },
832 |
833 | enumerable: true, configurable: true
834 | },
835 | "by": {
836 | get: function get() {
837 | return o._by;
838 | },
839 | set: function set(value) {
840 | o._by = value;
841 | draw(o._strokeStyle, o._width, o._ax, o._ay, o._bx, o._by);
842 | },
843 |
844 | enumerable: true, configurable: true
845 | },
846 | "strokeStyle": {
847 | get: function get() {
848 | return o._strokeStyle;
849 | },
850 | set: function set(value) {
851 | o._strokeStyle = self.color(value);
852 |
853 | //Draw the line
854 | draw(o._strokeStyle, o._width, o._ax, o._ay, o._bx, o._by);
855 | },
856 |
857 | enumerable: true, configurable: true
858 | },
859 | "width": {
860 | get: function get() {
861 | return o._width;
862 | },
863 | set: function set(value) {
864 | o._width = value;
865 |
866 | //Draw the line
867 | draw(o._strokeStyle, o._width, o._ax, o._ay, o._bx, o._by);
868 | },
869 |
870 | enumerable: true, configurable: true
871 | }
872 | });
873 |
874 | //Return the line
875 | return o;
876 | }
877 |
878 | /* Compound sprites */
879 |
880 | //Use `grid` to create a grid of sprites
881 |
882 | }, {
883 | key: "grid",
884 | value: function grid() {
885 | var columns = arguments.length <= 0 || arguments[0] === undefined ? 0 : arguments[0];
886 | var rows = arguments.length <= 1 || arguments[1] === undefined ? 0 : arguments[1];
887 | var cellWidth = arguments.length <= 2 || arguments[2] === undefined ? 32 : arguments[2];
888 | var cellHeight = arguments.length <= 3 || arguments[3] === undefined ? 32 : arguments[3];
889 | var centerCell = arguments.length <= 4 || arguments[4] === undefined ? false : arguments[4];
890 | var xOffset = arguments.length <= 5 || arguments[5] === undefined ? 0 : arguments[5];
891 | var yOffset = arguments.length <= 6 || arguments[6] === undefined ? 0 : arguments[6];
892 | var makeSprite = arguments.length <= 7 || arguments[7] === undefined ? undefined : arguments[7];
893 | var extra = arguments.length <= 8 || arguments[8] === undefined ? undefined : arguments[8];
894 |
895 | //Create an empty group called `container`. This `container`
896 | //group is what the function returns back to the main program.
897 | //All the sprites in the grid cells will be added
898 | //as children to this container
899 | var container = new this.Container();
900 |
901 | //The `create` method plots the grid
902 |
903 | var createGrid = function createGrid() {
904 |
905 | //Figure out the number of cells in the grid
906 | var length = columns * rows;
907 |
908 | //Create a sprite for each cell
909 | for (var i = 0; i < length; i++) {
910 |
911 | //Figure out the sprite's x/y placement in the grid
912 | var x = i % columns * cellWidth,
913 | y = Math.floor(i / columns) * cellHeight;
914 |
915 | //Use the `makeSprite` function supplied in the constructor
916 | //to make a sprite for the grid cell
917 | var sprite = makeSprite();
918 |
919 | //Add the sprite to the `container`
920 | container.addChild(sprite);
921 |
922 | //Should the sprite be centered in the cell?
923 |
924 | //No, it shouldn't be centered
925 | if (!centerCell) {
926 | sprite.x = x + xOffset;
927 | sprite.y = y + yOffset;
928 | }
929 |
930 | //Yes, it should be centered
931 | else {
932 | sprite.x = x + cellWidth / 2 - sprite.width / 2 + xOffset;
933 | sprite.y = y + cellHeight / 2 - sprite.width / 2 + yOffset;
934 | }
935 |
936 | //Run any optional extra code. This calls the
937 | //`extra` function supplied by the constructor
938 | if (extra) extra(sprite);
939 | }
940 | };
941 |
942 | //Run the `createGrid` method
943 | createGrid();
944 |
945 | //Return the `container` group back to the main program
946 | return container;
947 | }
948 |
949 | //Use `shoot` to create bullet sprites
950 |
951 | }, {
952 | key: "shoot",
953 | value: function shoot(shooter, angle, x, y, container, bulletSpeed, bulletArray, bulletSprite) {
954 |
955 | //Make a new sprite using the user-supplied `bulletSprite` function
956 | var bullet = bulletSprite();
957 |
958 | //Set the bullet's anchor point to its center
959 | bullet.anchor.set(0.5, 0.5);
960 |
961 | //Temporarily add the bullet to the shooter
962 | //so that we can position it relative to the
963 | //shooter's position
964 | shooter.addChild(bullet);
965 | bullet.x = x;
966 | bullet.y = y;
967 |
968 | //Find the bullet's global coordinates so that we can use
969 | //them to position the bullet on the new parent container
970 | var tempGx = bullet.getGlobalPosition().x,
971 | tempGy = bullet.getGlobalPosition().y;
972 |
973 | //Add the bullet to the new parent container using
974 | //the new global coordinates
975 | container.addChild(bullet);
976 | bullet.x = tempGx;
977 | bullet.y = tempGy;
978 |
979 | //Set the bullet's velocity
980 | bullet.vx = Math.cos(angle) * bulletSpeed;
981 | bullet.vy = Math.sin(angle) * bulletSpeed;
982 |
983 | //Push the bullet into the `bulletArray`
984 | bulletArray.push(bullet);
985 | }
986 |
987 | /*
988 | grid
989 | ----
990 | Helps you to automatically create a grid of sprites. `grid` returns a
991 | `group` sprite object that contains a sprite for every cell in the
992 | grid. You can define the rows and columns in the grid, whether or
993 | not the sprites should be centered inside each cell, or what their offset from the
994 | top left corner of each cell should be. Supply a function that
995 | returns the sprite that you want to make for each cell. You can
996 | supply an optional final function that runs any extra code after
997 | each sprite has been created. Here's the format for creating a grid:
998 | gridGroup = grid(
999 | //Set the grid's properties
1000 | columns, rows, cellWidth, cellHeight,
1001 | areSpirtesCentered?, xOffset, yOffset,
1002 | //A function that returns a sprite
1003 | () => g.circle(16, "blue"),
1004 | //An optional final function that runs some extra code
1005 | () => console.log("extra!")
1006 | );
1007 | */
1008 |
1009 | }, {
1010 | key: "grid",
1011 | value: function grid() {
1012 | var columns = arguments.length <= 0 || arguments[0] === undefined ? 0 : arguments[0];
1013 | var rows = arguments.length <= 1 || arguments[1] === undefined ? 0 : arguments[1];
1014 | var cellWidth = arguments.length <= 2 || arguments[2] === undefined ? 32 : arguments[2];
1015 | var cellHeight = arguments.length <= 3 || arguments[3] === undefined ? 32 : arguments[3];
1016 | var centerCell = arguments.length <= 4 || arguments[4] === undefined ? false : arguments[4];
1017 | var xOffset = arguments.length <= 5 || arguments[5] === undefined ? 0 : arguments[5];
1018 | var yOffset = arguments.length <= 6 || arguments[6] === undefined ? 0 : arguments[6];
1019 | var makeSprite = arguments.length <= 7 || arguments[7] === undefined ? undefined : arguments[7];
1020 | var extra = arguments.length <= 8 || arguments[8] === undefined ? undefined : arguments[8];
1021 |
1022 | //Create an empty group called `container`. This `container`
1023 | //group is what the function returns back to the main program.
1024 | //All the sprites in the grid cells will be added
1025 | //as children to this container
1026 | var container = this.group();
1027 |
1028 | //The `create` method plots the grid
1029 | var createGrid = function createGrid() {
1030 |
1031 | //Figure out the number of cells in the grid
1032 | var length = columns * rows;
1033 |
1034 | //Create a sprite for each cell
1035 | for (var i = 0; i < length; i++) {
1036 |
1037 | //Figure out the sprite's x/y placement in the grid
1038 | var x = i % columns * cellWidth,
1039 | y = Math.floor(i / columns) * cellHeight;
1040 |
1041 | //Use the `makeSprite` function supplied in the constructor
1042 | //to make a sprite for the grid cell
1043 | var sprite = makeSprite();
1044 |
1045 | //Add the sprite to the `container`
1046 | container.addChild(sprite);
1047 |
1048 | //Should the sprite be centered in the cell?
1049 |
1050 | //No, it shouldn't be centered
1051 | if (!centerCell) {
1052 | sprite.x = x + xOffset;
1053 | sprite.y = y + yOffset;
1054 | }
1055 |
1056 | //Yes, it should be centered
1057 | else {
1058 | sprite.x = x + cellWidth / 2 - sprite.halfWidth + xOffset;
1059 | sprite.y = y + cellHeight / 2 - sprite.halfHeight + yOffset;
1060 | }
1061 |
1062 | //Run any optional extra code. This calls the
1063 | //`extra` function supplied by the constructor
1064 | if (extra) extra(sprite);
1065 | }
1066 | };
1067 |
1068 | //Run the `createGrid` method
1069 | createGrid();
1070 |
1071 | //Return the `container` group back to the main program
1072 | return container;
1073 | }
1074 |
1075 | /*
1076 | shake
1077 | -----
1078 | Used to create a shaking effect, like a screen shake
1079 | */
1080 |
1081 | }, {
1082 | key: "shake",
1083 | value: function shake(sprite) {
1084 | var magnitude = arguments.length <= 1 || arguments[1] === undefined ? 16 : arguments[1];
1085 | var angular = arguments.length <= 2 || arguments[2] === undefined ? false : arguments[2];
1086 |
1087 | //Get a reference to this current object so that
1088 | //it's easy to maintain scope in the nested sub-functions
1089 | var self = this;
1090 |
1091 | //A counter to count the number of shakes
1092 | var counter = 1;
1093 |
1094 | //The total number of shakes (there will be 1 shake per frame)
1095 | var numberOfShakes = 10;
1096 |
1097 | //Capture the sprite's position and angle so you can
1098 | //restore them after the shaking has finished
1099 | var startX = sprite.x,
1100 | startY = sprite.y,
1101 | startAngle = sprite.rotation;
1102 |
1103 | //Divide the magnitude into 10 units so that you can
1104 | //reduce the amount of shake by 10 percent each frame
1105 | var magnitudeUnit = magnitude / numberOfShakes;
1106 |
1107 | //The `randomInt` helper function
1108 | var randomInt = function randomInt(min, max) {
1109 | return Math.floor(Math.random() * (max - min + 1)) + min;
1110 | };
1111 |
1112 | //Add the sprite to the `shakingSprites` array if it
1113 | //isn't already there
1114 | if (self.shakingSprites.indexOf(sprite) === -1) {
1115 |
1116 | self.shakingSprites.push(sprite);
1117 |
1118 | //Add an `updateShake` method to the sprite.
1119 | //The `updateShake` method will be called each frame
1120 | //in the game loop. The shake effect type can be either
1121 | //up and down (x/y shaking) or angular (rotational shaking).
1122 | sprite.updateShake = function () {
1123 | if (angular) {
1124 | angularShake();
1125 | } else {
1126 | upAndDownShake();
1127 | }
1128 | };
1129 | }
1130 |
1131 | //The `upAndDownShake` function
1132 | function upAndDownShake() {
1133 |
1134 | //Shake the sprite while the `counter` is less than
1135 | //the `numberOfShakes`
1136 | if (counter < numberOfShakes) {
1137 |
1138 | //Reset the sprite's position at the start of each shake
1139 | sprite.x = startX;
1140 | sprite.y = startY;
1141 |
1142 | //Reduce the magnitude
1143 | magnitude -= magnitudeUnit;
1144 |
1145 | //Randomly change the sprite's position
1146 | sprite.x += randomInt(-magnitude, magnitude);
1147 | sprite.y += randomInt(-magnitude, magnitude);
1148 |
1149 | //Add 1 to the counter
1150 | counter += 1;
1151 | }
1152 |
1153 | //When the shaking is finished, restore the sprite to its original
1154 | //position and remove it from the `shakingSprites` array
1155 | if (counter >= numberOfShakes) {
1156 | sprite.x = startX;
1157 | sprite.y = startY;
1158 | self.shakingSprites.splice(self.shakingSprites.indexOf(sprite), 1);
1159 | }
1160 | }
1161 |
1162 | //The `angularShake` function
1163 | //First set the initial tilt angle to the right (+1)
1164 | var tiltAngle = 1;
1165 |
1166 | function angularShake() {
1167 | if (counter < numberOfShakes) {
1168 |
1169 | //Reset the sprite's rotation
1170 | sprite.rotation = startAngle;
1171 |
1172 | //Reduce the magnitude
1173 | magnitude -= magnitudeUnit;
1174 |
1175 | //Rotate the sprite left or right, depending on the direction,
1176 | //by an amount in radians that matches the magnitude
1177 | sprite.rotation = magnitude * tiltAngle;
1178 | counter += 1;
1179 |
1180 | //Reverse the tilt angle so that the sprite is tilted
1181 | //in the opposite direction for the next shake
1182 | tiltAngle *= -1;
1183 | }
1184 |
1185 | //When the shaking is finished, reset the sprite's angle and
1186 | //remove it from the `shakingSprites` array
1187 | if (counter >= numberOfShakes) {
1188 | sprite.rotation = startAngle;
1189 | self.shakingSprites.splice(self.shakingSprites.indexOf(sprite), 1);
1190 | }
1191 | }
1192 | }
1193 |
1194 | /*
1195 | _getCenter
1196 | ----------
1197 | A utility that finds the center point of the sprite. If it's anchor point is the
1198 | sprite's top left corner, then the center is calculated from that point.
1199 | If the anchor point has been shifted, then the anchor x/y point is used as the sprite's center
1200 | */
1201 |
1202 | }, {
1203 | key: "_getCenter",
1204 | value: function _getCenter(o, dimension, axis) {
1205 | if (o.anchor !== undefined) {
1206 | if (o.anchor[axis] !== 0) {
1207 | return 0;
1208 | } else {
1209 | return dimension / 2;
1210 | }
1211 | } else {
1212 | return dimension;
1213 | }
1214 | }
1215 |
1216 | /* Groups */
1217 |
1218 | //Group sprites into a container
1219 |
1220 | }, {
1221 | key: "group",
1222 | value: function group() {
1223 | var container = new this.Container();
1224 |
1225 | for (var _len = arguments.length, sprites = Array(_len), _key = 0; _key < _len; _key++) {
1226 | sprites[_key] = arguments[_key];
1227 | }
1228 |
1229 | sprites.forEach(function (sprite) {
1230 | container.addChild(sprite);
1231 | });
1232 | return container;
1233 | }
1234 |
1235 | //Use the `batch` method to create a ParticleContainer
1236 |
1237 | }, {
1238 | key: "batch",
1239 | value: function batch() {
1240 | var size = arguments.length <= 0 || arguments[0] === undefined ? 15000 : arguments[0];
1241 | var options = arguments.length <= 1 || arguments[1] === undefined ? { rotation: true, alpha: true, scale: true, uvs: true } : arguments[1];
1242 |
1243 | var o = new this.ParticleContainer(size, options);
1244 | return o;
1245 | }
1246 |
1247 | //`remove` is a global convenience method that will
1248 | //remove any sprite, or an argument list of sprites, from its parent.
1249 |
1250 | }, {
1251 | key: "remove",
1252 | value: function remove() {
1253 | for (var _len2 = arguments.length, sprites = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
1254 | sprites[_key2] = arguments[_key2];
1255 | }
1256 |
1257 | //Remove sprites that's aren't in an array
1258 | if (!(sprites[0] instanceof Array)) {
1259 | if (sprites.length > 1) {
1260 | sprites.forEach(function (sprite) {
1261 | sprite.parent.removeChild(sprite);
1262 | });
1263 | } else {
1264 | sprites[0].parent.removeChild(sprites[0]);
1265 | }
1266 | }
1267 |
1268 | //Remove sprites in an array of sprites
1269 | else {
1270 | var spritesArray = sprites[0];
1271 | if (spritesArray.length > 0) {
1272 | for (var i = spritesArray.length - 1; i >= 0; i--) {
1273 | var sprite = spritesArray[i];
1274 | sprite.parent.removeChild(sprite);
1275 | spritesArray.splice(spritesArray.indexOf(sprite), 1);
1276 | }
1277 | }
1278 | }
1279 | }
1280 |
1281 | /* Color conversion */
1282 | //From: http://stackoverflow.com/questions/1573053/javascript-function-to-convert-color-names-to-hex-codes
1283 | //Utilities to convert HTML color string names to hexadecimal codes
1284 |
1285 | }, {
1286 | key: "colorToRGBA",
1287 | value: function colorToRGBA(color) {
1288 | // Returns the color as an array of [r, g, b, a] -- all range from 0 - 255
1289 | // color must be a valid canvas fillStyle. This will cover most anything
1290 | // you'd want to use.
1291 | // Examples:
1292 | // colorToRGBA('red') # [255, 0, 0, 255]
1293 | // colorToRGBA('#f00') # [255, 0, 0, 255]
1294 | var cvs, ctx;
1295 | cvs = document.createElement('canvas');
1296 | cvs.height = 1;
1297 | cvs.width = 1;
1298 | ctx = cvs.getContext('2d');
1299 | ctx.fillStyle = color;
1300 | ctx.fillRect(0, 0, 1, 1);
1301 | var data = ctx.getImageData(0, 0, 1, 1).data;
1302 | return data;
1303 | }
1304 | }, {
1305 | key: "byteToHex",
1306 | value: function byteToHex(num) {
1307 | // Turns a number (0-255) into a 2-character hex number (00-ff)
1308 | return ('0' + num.toString(16)).slice(-2);
1309 | }
1310 | }, {
1311 | key: "colorToHex",
1312 | value: function colorToHex(color) {
1313 | var _this2 = this;
1314 |
1315 | // Convert any CSS color to a hex representation
1316 | // Examples:
1317 | // colorToHex('red') # '#ff0000'
1318 | // colorToHex('rgb(255, 0, 0)') # '#ff0000'
1319 | var rgba, hex;
1320 | rgba = this.colorToRGBA(color);
1321 | hex = [0, 1, 2].map(function (idx) {
1322 | return _this2.byteToHex(rgba[idx]);
1323 | }).join('');
1324 | return "0x" + hex;
1325 | }
1326 |
1327 | //A function to find out if the user entered a number (a hex color
1328 | //code) or a string (an HTML color string)
1329 |
1330 | }, {
1331 | key: "color",
1332 | value: function color(value) {
1333 |
1334 | //Check if it's a number
1335 | if (!isNaN(value)) {
1336 |
1337 | //Yes, it is a number, so just return it
1338 | return value;
1339 | }
1340 |
1341 | //No it's not a number, so it must be a string
1342 | else {
1343 |
1344 | return parseInt(this.colorToHex(value));
1345 | /*
1346 | //Find out what kind of color string it is.
1347 | //Let's first grab the first character of the string
1348 | let firstCharacter = value.charAt(0);
1349 | //If the first character is a "#" or a number, then
1350 | //we know it must be a RGBA color
1351 | if (firstCharacter === "#") {
1352 | console.log("first character: " + value.charAt(0))
1353 | }
1354 | */
1355 | }
1356 |
1357 | /*
1358 | //Find out if the first character in the string is a number
1359 | if (!isNaN(parseInt(string.charAt(0)))) {
1360 |
1361 | //It's not, so convert it to a hex code
1362 | return colorToHex(string);
1363 |
1364 | //The use input a number, so it must be a hex code. Just return it
1365 | } else {
1366 |
1367 | return string;
1368 | }
1369 |
1370 | */
1371 | }
1372 | }]);
1373 |
1374 | return SpriteUtilities;
1375 | })();
1376 | //# sourceMappingURL=spriteUtilities.js.map
--------------------------------------------------------------------------------
/bin/spriteUtilities.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["../src/spriteUtilities.js"],"names":[],"mappings":";;;;;;IAAM,eAAe;AACnB,WADI,eAAe,GACiB;QAAxB,eAAe,yDAAG,IAAI;;0BAD9B,eAAe;;AAEjB,QAAI,eAAe,KAAK,SAAS,EAAE,MAAM,IAAI,KAAK,CAAC,sGAAsG,CAAC,CAAC;;;AAAA,AAG3J,QAAI,CAAC,QAAQ,GAAG,EAAE;;;AAAC,AAGnB,QAAI,eAAe,CAAC,iBAAiB,IAAI,eAAe,CAAC,MAAM,EAAE;AAC/D,UAAI,CAAC,QAAQ,GAAG,MAAM,CAAC;AACvB,UAAI,CAAC,SAAS,GAAG,eAAe,CAAC,SAAS,CAAC;AAC3C,UAAI,CAAC,iBAAiB,GAAG,eAAe,CAAC,iBAAiB,CAAC;AAC3D,UAAI,CAAC,YAAY,GAAG,eAAe,CAAC,KAAK,CAAC,YAAY,CAAC;AACvD,UAAI,CAAC,OAAO,GAAG,eAAe,CAAC,OAAO,CAAC;AACvC,UAAI,CAAC,SAAS,GAAG,eAAe,CAAC,SAAS,CAAC;AAC3C,UAAI,CAAC,SAAS,GAAG,eAAe,CAAC,MAAM,CAAC,SAAS,CAAC;AAClD,UAAI,CAAC,UAAU,GAAG,eAAe,CAAC,MAAM,CAAC,UAAU,CAAC;AACpD,UAAI,CAAC,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC;AACrC,UAAI,CAAC,YAAY,GAAG,eAAe,CAAC,MAAM,CAAC,YAAY,CAAC;AACxD,UAAI,CAAC,QAAQ,GAAG,eAAe,CAAC,QAAQ,CAAC;AACzC,UAAI,CAAC,IAAI,GAAG,eAAe,CAAC,IAAI;;;AAAC,AAGjC,UAAI,CAAC,cAAc,GAAG,EAAE,CAAC;KAC1B;GACF;;eAzBG,eAAe;;6BA2BV;AACP,UAAI,IAAI,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE;AAClC,aAAI,IAAI,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE;AACvD,cAAI,aAAa,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;AAC3C,cAAI,aAAa,CAAC,WAAW,EAAE,aAAa,CAAC,WAAW,EAAE,CAAC;SAC5D;OACF;KACF;;;2BAEM,MAAM,EAA+C;UAA7C,CAAC,yDAAG,CAAC;UAAE,CAAC,yDAAG,CAAC;UAAE,MAAM,yDAAG,KAAK;UAAE,KAAK;UAAE,MAAM;;AAExD,UAAI,CAAC,YAAA;UAAE,OAAO,YAAA;;;AAAC,AAGf,UAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;;;AAG9B,YAAI,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE;AAC7B,iBAAO,GAAG,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;;;;AACrC,aAGI;AACH,mBAAO,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;WAC1C;;;AAAA,AAGD,YAAI,OAAO,EAAE;;;AAGX,cAAI,CAAC,MAAM,EAAE;AACX,aAAC,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;;;;AAC9B,eAGI;AACH,eAAC,GAAG,IAAI,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;aACnD;;;AACF,aAEI;AACH,kBAAM,IAAI,KAAK,CAAI,MAAM,sBAAmB,CAAC;WAC9C;;;;AACF,WAGI,IAAI,MAAM,YAAY,IAAI,CAAC,OAAO,EAAE;AACvC,cAAI,CAAC,MAAM,EAAE;AACX,aAAC,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;WAC7B,MAAM;AACL,aAAC,GAAG,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;WAClD;;;;AACF,aAGI,IAAI,MAAM,YAAY,KAAK,EAAE;;;AAGhC,gBAAI,OAAO,MAAM,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE;;;;;;AAMjC,kBAAI,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE;;;AAGhC,iBAAC,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;eACvC,MAAM;;;AAGL,iBAAC,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;eACvC;;;;;AACF,iBAII,IAAI,MAAM,CAAC,CAAC,CAAC,YAAY,IAAI,CAAC,OAAO,EAAE;;;;AAI1C,iBAAC,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;eAChC;WACF;;;AAAA,AAGD,UAAI,CAAC,EAAE;;;AAGL,SAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AACR,SAAC,CAAC,CAAC,GAAG,CAAC;;;AAAC,AAGR,YAAI,KAAK,EAAE,CAAC,CAAC,KAAK,GAAG,KAAK,CAAC;AAC3B,YAAI,MAAM,EAAE,CAAC,CAAC,MAAM,GAAG,MAAM,CAAC;;;;AAAA,AAI9B,YAAI,CAAC,YAAY,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;;;AAAA,AAGxD,eAAO,CAAC,CAAC;OACV;KACF;;;mCAEc,MAAM,EAAE;;AAErB,UAAI,YAAY,GAAG,CAAC;UAClB,cAAc,GAAG,CAAC;UAClB,UAAU,GAAG,CAAC;UACd,QAAQ,GAAG,CAAC;UACZ,aAAa,GAAG,SAAS;;;AAAC,AAG5B,eAAS,IAAI,CAAC,WAAW,EAAE;;;AAGzB,aAAK,EAAE;;;AAAC,AAGR,cAAM,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;OACjC;;;AAAA,AAGD,eAAS,aAAa,GAAG;AACvB,aAAK,EAAE,CAAC;AACR,cAAM,CAAC,WAAW,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;OACzC;;;AAAA,AAGD,eAAS,aAAa,CAAC,aAAa,EAAE;;;AAGpC,aAAK,EAAE;;;AAAC,AAGR,YAAI,CAAC,aAAa,EAAE;AAClB,oBAAU,GAAG,CAAC,CAAC;AACf,kBAAQ,GAAG,MAAM,CAAC,WAAW,GAAG,CAAC,CAAC;SACnC,MAAM;AACL,oBAAU,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;AAC9B,kBAAQ,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;SAC7B;;;AAAA,AAGD,sBAAc,GAAG,QAAQ,GAAG,UAAU;;;;;;;;;;;;;;;;;;;;AAAC,AAoBvC,YAAI,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,GAAG,EAAE,CAAC;AACjC,YAAI,SAAS,GAAG,IAAI,GAAG,MAAM,CAAC,GAAG;;;AAAC,AAGlC,cAAM,CAAC,WAAW,CAAC,UAAU,CAAC;;;AAAC,AAG/B,oBAAY,GAAG,CAAC;;;AAAC,AAGjB,YAAI,CAAC,MAAM,CAAC,SAAS,EAAE;AACrB,uBAAa,GAAG,WAAW,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,CAAC;AAChE,gBAAM,CAAC,SAAS,GAAG,IAAI,CAAC;SACzB;OACF;;;;;AAAA,AAKD,eAAS,YAAY,GAAG;;;;AAItB,YAAI,YAAY,GAAG,cAAc,GAAG,CAAC,EAAE;;;AAGrC,gBAAM,CAAC,WAAW,CAAC,MAAM,CAAC,YAAY,GAAG,CAAC,CAAC;;;AAAC,AAG5C,sBAAY,IAAI,CAAC;;;;AAAC,SAInB,MAAM;AACL,gBAAI,MAAM,CAAC,IAAI,EAAE;AACf,oBAAM,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;AAC/B,0BAAY,GAAG,CAAC,CAAC;aAClB;WACF;OACF;;AAED,eAAS,KAAK,GAAG;;;AAGf,YAAI,aAAa,KAAK,SAAS,IAAI,MAAM,CAAC,SAAS,KAAK,IAAI,EAAE;AAC5D,gBAAM,CAAC,SAAS,GAAG,KAAK,CAAC;AACzB,sBAAY,GAAG,CAAC,CAAC;AACjB,oBAAU,GAAG,CAAC,CAAC;AACf,kBAAQ,GAAG,CAAC,CAAC;AACb,wBAAc,GAAG,CAAC,CAAC;AACnB,uBAAa,CAAC,aAAa,CAAC,CAAC;SAC9B;OACF;;;AAAA,AAGD,YAAM,CAAC,IAAI,GAAG,IAAI,CAAC;AACnB,YAAM,CAAC,aAAa,GAAG,aAAa,CAAC;AACrC,YAAM,CAAC,aAAa,GAAG,aAAa,CAAC;KACtC;;;;;;iCAGY,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE;AACxC,UAAI,KAAK,KAAK,SAAS,EAAE;AACvB,cAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAC;OACxF;AACD,UAAI,MAAM,KAAK,SAAS,EAAE;AACxB,cAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAC;OACxF;AACD,UAAI,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC;;;AAAC,AAGvD,YAAM,CAAC,gBAAgB,CAAC,CAAC,EAAE;AACzB,eAAO,EAAE;AACP,aAAG,iBAAG;AACJ,mBAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC;WACzB;AACD,aAAG,eAAC,KAAK,EAAE;AACT,aAAC,CAAC,YAAY,CAAC,CAAC,GAAG,KAAK,CAAC;WAC1B;;AACD,oBAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI;SACrC;AACD,eAAO,EAAE;AACP,aAAG,iBAAG;AACJ,mBAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC;WACzB;AACD,aAAG,eAAC,KAAK,EAAE;AACT,aAAC,CAAC,YAAY,CAAC,CAAC,GAAG,KAAK,CAAC;WAC1B;;AACD,oBAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI;SACrC;AACD,oBAAY,EAAE;AACZ,aAAG,iBAAG;AACJ,mBAAO,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;WACtB;AACD,aAAG,eAAC,KAAK,EAAE;AACT,aAAC,CAAC,SAAS,CAAC,CAAC,GAAG,KAAK,CAAC;WACvB;;AACD,oBAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI;SACrC;AACD,oBAAY,EAAE;AACZ,aAAG,iBAAG;AACJ,mBAAO,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;WACtB;AACD,aAAG,eAAC,KAAK,EAAE;AACT,aAAC,CAAC,SAAS,CAAC,CAAC,GAAG,KAAK,CAAC;WACvB;;AACD,oBAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI;SACrC;OACF,CAAC,CAAC;;AAEH,aAAO,CAAC,CAAA;KACT;;;8BAGC,OAAO,EACP,UAAU,EACV,WAAW,EAEX;UADA,OAAO,yDAAG,CAAC;;;AAIX,UAAI,SAAS,GAAG,EAAE;;;AAAC,AAGnB,UAAI,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,KAAK;UACjD,aAAa,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,MAAM;;;AAAC,AAGpD,UAAI,OAAO,GAAG,YAAY,GAAG,UAAU;UACrC,IAAI,GAAG,aAAa,GAAG,WAAW;;;AAAC,AAGrC,UAAI,cAAc,GAAG,OAAO,GAAG,IAAI,CAAC;;AAEpC,WAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,cAAc,EAAE,CAAC,EAAE,EAAE;;;;AAIvC,YAAI,CAAC,GAAG,AAAC,CAAC,GAAG,OAAO,GAAI,UAAU;YAChC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,OAAO,CAAC,GAAG,WAAW;;;;;AAAC,AAK5C,YAAI,OAAO,GAAG,CAAC,EAAE;AACf,WAAC,IAAI,OAAO,GAAI,OAAO,GAAG,CAAC,GAAG,OAAO,AAAC,CAAC;AACvC,WAAC,IAAI,OAAO,GAAI,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,OAAO,CAAC,AAAC,CAAC;SACpD;;;AAAA,AAGD,iBAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;OACxB;;;AAAA,AAGD,aAAO,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;KACjE;;;;;;0BAGK,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE;;AAEjC,UAAI,OAAO,YAAA;UAAE,UAAU,YAAA;;;;AAAC,AAIxB,UAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;AAC9B,YAAI,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE;AAC7B,iBAAO,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC;SACvD;;;;AACF,WAGI,IAAI,MAAM,YAAY,IAAI,CAAC,OAAO,EAAE;AACvC,iBAAO,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;SACpC;AACD,UAAI,CAAC,OAAO,EAAE;AACZ,cAAM,IAAI,KAAK,sBAAoB,MAAM,8BAA2B,CAAC;OACtE,MAAM;;;AAGL,kBAAU,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;AACrD,eAAO,CAAC,KAAK,GAAG,UAAU,CAAC;AAC3B,eAAO,OAAO,CAAC;OAChB;KACF;;;;;;;2BAIM,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE;;;AAEnD,UAAI,WAAW,YAAA;UAAE,QAAQ,YAAA;;;;AAAC,AAI1B,UAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;AAC9B,YAAI,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE;AAC7B,qBAAW,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC;SAC3D;;;AACF,WAEI,IAAI,MAAM,YAAY,IAAI,CAAC,OAAO,EAAE;AACvC,qBAAW,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;SACxC;AACD,UAAI,CAAC,WAAW,EAAE;AAChB,cAAM,IAAI,KAAK,sBAAoB,MAAM,8BAA2B,CAAC;OACtE,MAAM;AACL,YAAI,SAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,UAAC,QAAQ,EAAK;AAC3C,cAAI,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;cACjB,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;AAClB,cAAI,UAAU,GAAG,IAAI,MAAK,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;AACnE,cAAI,YAAY,GAAG,IAAI,MAAK,OAAO,CAAC,WAAW,CAAC,CAAC;AACjD,sBAAY,CAAC,KAAK,GAAG,UAAU,CAAC;AAChC,iBAAO,YAAY,CAAA;SACpB,CAAC,CAAC;AACH,eAAO,SAAQ,CAAC;OACjB;KACF;;;kCAE0E;UAA/D,WAAW,yDAAG,CAAC;UAAE,SAAS,yDAAG,CAAC;UAAE,QAAQ,yDAAG,EAAE;UAAE,SAAS,yDAAG,EAAE;;;AAGvE,UAAI,MAAM,GAAG,EAAE,CAAC;;AAEhB,WAAK,IAAI,CAAC,GAAG,WAAW,EAAE,CAAC,GAAG,SAAS,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;AAChD,YAAI,KAAK,GAAG,IAAI,CAAC,YAAY,OAAI,QAAQ,GAAG,CAAC,GAAG,SAAS,CAAA,CAAG,CAAC;AAC7D,cAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;OACpB;AACD,aAAO,MAAM,CAAC;KACf;;;;;;;;2BAK8E;UAA1E,OAAO,yDAAG,SAAS;UAAE,IAAI,yDAAG,WAAW;UAAE,SAAS,yDAAG,KAAK;UAAE,CAAC,yDAAG,CAAC;UAAE,CAAC,yDAAG,CAAC;;;AAG3E,UAAI,OAAO,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAC,CAAC,CAAC;AACpE,aAAO,CAAC,CAAC,GAAG,CAAC,CAAC;AACd,aAAO,CAAC,CAAC,GAAG,CAAC;;;AAAC,AAGd,aAAO,CAAC,QAAQ,GAAG,OAAO,CAAC;AAC3B,YAAM,CAAC,cAAc,CAAC,OAAO,EAAE,SAAS,EAAE;AACxC,WAAG,iBAAG;AACJ,iBAAO,IAAI,CAAC,QAAQ,CAAC;SACtB;AACD,WAAG,eAAC,KAAK,EAAE;AACT,cAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;AACtB,cAAI,CAAC,IAAI,GAAG,KAAK,CAAC;SACnB;;AACD,kBAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI;OACrC,CAAC;;;AAAC,AAGH,aAAO,OAAO,CAAC;KAChB;;;;;;iCAGgE;UAAtD,OAAO,yDAAG,SAAS;UAAE,IAAI;UAAE,KAAK;UAAE,IAAI;UAAE,CAAC,yDAAG,CAAC;UAAE,CAAC,yDAAG,CAAC;;;AAG7D,UAAI,OAAO,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,EAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAC,CAAC,CAAC;AACnF,aAAO,CAAC,CAAC,GAAG,CAAC,CAAC;AACd,aAAO,CAAC,CAAC,GAAG,CAAC;;;AAAC,AAGd,aAAO,CAAC,QAAQ,GAAG,OAAO,CAAC;AAC3B,YAAM,CAAC,cAAc,CAAC,OAAO,EAAE,SAAS,EAAE;AACxC,WAAG,iBAAG;AACJ,iBAAO,IAAI,CAAC,QAAQ,CAAC;SACtB;AACD,WAAG,eAAC,KAAK,EAAE;AACT,cAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;AACtB,cAAI,CAAC,IAAI,GAAG,KAAK,CAAC;SACnB;;AACD,kBAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI;OACrC,CAAC;;;AAAC,AAGH,aAAO,OAAO,CAAC;KAChB;;;;;;;;gCAaE;UAPC,KAAK,yDAAG,EAAE;UACV,MAAM,yDAAG,EAAE;UACX,SAAS,yDAAG,QAAQ;UACpB,WAAW,yDAAG,QAAQ;UACtB,SAAS,yDAAG,CAAC;UACb,CAAC,yDAAG,CAAC;UACL,CAAC,yDAAG,CAAC;;AAGP,UAAI,CAAC,GAAG,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;AAC5B,OAAC,CAAC,OAAO,GAAG,SAAS,CAAC;AACtB,OAAC,CAAC,MAAM,GAAG,KAAK,CAAC;AACjB,OAAC,CAAC,OAAO,GAAG,MAAM,CAAC;AACnB,OAAC,CAAC,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;AACrC,OAAC,CAAC,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;AACzC,OAAC,CAAC,UAAU,GAAG,SAAS;;;AAAC,AAGzB,UAAI,IAAI,GAAG,SAAP,IAAI,CAAI,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAK;AAC/D,SAAC,CAAC,KAAK,EAAE,CAAC;AACV,SAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;AACvB,YAAI,SAAS,GAAG,CAAC,EAAE;AACjB,WAAC,CAAC,SAAS,CAAC,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC;SACxC;AACD,SAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;AAChC,SAAC,CAAC,OAAO,EAAE,CAAC;OACb;;;;AAAC,AAIF,UAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,UAAU,CAAC;;;AAAC,AAGtE,UAAI,OAAO,GAAG,CAAC,CAAC,eAAe,EAAE;;;AAAC,AAGlC,UAAI,MAAM,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;;;AAAC,AAGtC,YAAM,CAAC,CAAC,GAAG,CAAC,CAAC;AACb,YAAM,CAAC,CAAC,GAAG,CAAC;;;AAAC,AAGb,UAAI,IAAI,GAAG,IAAI,CAAC;AAChB,YAAM,CAAC,gBAAgB,CAAC,MAAM,EAAE;AAC9B,mBAAW,EAAE;AACX,aAAG,iBAAG;AACJ,mBAAO,CAAC,CAAC,UAAU,CAAC;WACrB;AACD,aAAG,eAAC,KAAK,EAAE;AACT,aAAC,CAAC,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;;;AAAC,AAGjC,gBAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC;;;AAAC,AAGlF,gBAAI,OAAO,GAAG,CAAC,CAAC,eAAe,EAAE,CAAC;AAClC,aAAC,CAAC,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC;WAC7B;;AACD,oBAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI;SACrC;AACD,qBAAa,EAAE;AACb,aAAG,iBAAG;AACJ,mBAAO,CAAC,CAAC,YAAY,CAAC;WACvB;AACD,aAAG,eAAC,KAAK,EAAE;AACT,aAAC,CAAC,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;;;AAAC,AAGnC,gBAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC;;;AAAC,AAGlF,gBAAI,OAAO,GAAG,CAAC,CAAC,eAAe,EAAE,CAAC;AAClC,aAAC,CAAC,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC;WAC7B;;AACD,oBAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI;SACrC;AACD,mBAAW,EAAE;AACX,aAAG,iBAAG;AACJ,mBAAO,CAAC,CAAC,UAAU,CAAC;WACrB;AACD,aAAG,eAAC,KAAK,EAAE;AACT,aAAC,CAAC,UAAU,GAAG,KAAK;;;AAAC,AAGrB,gBAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC;;;AAAC,AAGlF,gBAAI,OAAO,GAAG,CAAC,CAAC,eAAe,EAAE,CAAC;AAClC,aAAC,CAAC,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC;WAC7B;;AACD,oBAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI;SACrC;OACF,CAAC;;;;AAAC,AAIH,OAAC,CAAC,OAAO,GAAG,MAAM;;;AAAC,AAGnB,aAAO,MAAM,CAAC;KACf;;;;;;6BAUE;UANC,QAAQ,yDAAG,EAAE;UACb,SAAS,yDAAG,QAAQ;UACpB,WAAW,yDAAG,QAAQ;UACtB,SAAS,yDAAG,CAAC;UACb,CAAC,yDAAG,CAAC;UACL,CAAC,yDAAG,CAAC;;AAGP,UAAI,CAAC,GAAG,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;AAC5B,OAAC,CAAC,SAAS,GAAG,QAAQ,CAAC;AACvB,OAAC,CAAC,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;AACrC,OAAC,CAAC,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;AACzC,OAAC,CAAC,UAAU,GAAG,SAAS;;;AAAC,AAGzB,UAAI,IAAI,GAAG,SAAP,IAAI,CAAI,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAK;AAC1D,SAAC,CAAC,KAAK,EAAE,CAAC;AACV,SAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;AACvB,YAAI,SAAS,GAAG,CAAC,EAAE;AACjB,WAAC,CAAC,SAAS,CAAC,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC;SACxC;AACD,SAAC,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAC;AACjC,SAAC,CAAC,OAAO,EAAE,CAAC;OACb;;;AAAC,AAGF,UAAI,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,UAAU,CAAC;;;AAAC,AAG9D,UAAI,OAAO,GAAG,CAAC,CAAC,eAAe,EAAE;;;AAAC,AAGlC,UAAI,MAAM,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;;;AAAC,AAGtC,YAAM,CAAC,CAAC,GAAG,CAAC,CAAC;AACb,YAAM,CAAC,CAAC,GAAG,CAAC;;;AAAC,AAGb,UAAI,IAAI,GAAG,IAAI,CAAC;AAChB,YAAM,CAAC,gBAAgB,CAAC,MAAM,EAAE;AAC9B,mBAAW,EAAE;AACX,aAAG,iBAAG;AACJ,mBAAO,CAAC,CAAC,UAAU,CAAC;WACrB;AACD,aAAG,eAAC,KAAK,EAAE;AACT,aAAC,CAAC,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;;;AAAC,AAGjC,gBAAI,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,UAAU,CAAC;;;AAAC,AAG9D,gBAAI,OAAO,GAAG,CAAC,CAAC,eAAe,EAAE,CAAC;AAClC,aAAC,CAAC,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC;WAC7B;;AACD,oBAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI;SACrC;AACD,qBAAa,EAAE;AACb,aAAG,iBAAG;AACJ,mBAAO,CAAC,CAAC,YAAY,CAAC;WACvB;AACD,aAAG,eAAC,KAAK,EAAE;AACT,aAAC,CAAC,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;;;AAAC,AAGnC,gBAAI,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,UAAU,CAAC;;;AAAC,AAG9D,gBAAI,OAAO,GAAG,CAAC,CAAC,eAAe,EAAE,CAAC;AAClC,aAAC,CAAC,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC;WAC7B;;AACD,oBAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI;SACrC;AACD,kBAAU,EAAE;AACV,aAAG,iBAAG;AACJ,mBAAO,CAAC,CAAC,SAAS,CAAC;WACpB;AACD,aAAG,eAAC,KAAK,EAAE;AACT,aAAC,CAAC,UAAU,GAAG,EAAE;;;AAAC,AAGlB,gBAAI,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,UAAU,CAAC;;;AAAC,AAG9D,gBAAI,OAAO,GAAG,CAAC,CAAC,eAAe,EAAE,CAAC;AAClC,aAAC,CAAC,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC;WAC7B;;AACD,oBAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI;SACrC;AACD,gBAAQ,EAAE;AACR,aAAG,iBAAG;AACJ,mBAAO,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC;WACxB;AACD,aAAG,eAAC,KAAK,EAAE;;;AAGT,gBAAI,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,UAAU,CAAC;;;AAAC,AAG5D,gBAAI,OAAO,GAAG,CAAC,CAAC,eAAe,EAAE,CAAC;AAClC,aAAC,CAAC,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC;WAC7B;;AACD,oBAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI;SACrC;OACF,CAAC;;;AAAC,AAGH,OAAC,CAAC,OAAO,GAAG,MAAM;;;AAAC,AAGnB,aAAO,MAAM,CAAC;KACf;;;;;;2BAUE;UANC,WAAW,yDAAG,QAAQ;UACtB,SAAS,yDAAG,CAAC;UACb,EAAE,yDAAG,CAAC;UACN,EAAE,yDAAG,CAAC;UACN,EAAE,yDAAG,EAAE;UACP,EAAE,yDAAG,EAAE;;;AAIT,UAAI,CAAC,GAAG,IAAI,IAAI,CAAC,QAAQ,EAAE;;;AAAC,AAG5B,OAAC,CAAC,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;AACzC,OAAC,CAAC,MAAM,GAAG,SAAS,CAAC;AACrB,OAAC,CAAC,GAAG,GAAG,EAAE,CAAC;AACX,OAAC,CAAC,GAAG,GAAG,EAAE,CAAC;AACX,OAAC,CAAC,GAAG,GAAG,EAAE,CAAC;AACX,OAAC,CAAC,GAAG,GAAG,EAAE;;;AAAC,AAGX,UAAI,IAAI,GAAG,SAAP,IAAI,CAAI,WAAW,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAK;AACrD,SAAC,CAAC,KAAK,EAAE,CAAC;AACV,SAAC,CAAC,SAAS,CAAC,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC;AACvC,SAAC,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;AACjB,SAAC,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;OAClB;;;AAAC,AAGF,UAAI,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC;;;;AAAC,AAI3D,UAAI,IAAI,GAAG,IAAI,CAAC;AAChB,YAAM,CAAC,gBAAgB,CAAC,CAAC,EAAE;AACzB,YAAI,EAAE;AACJ,aAAG,iBAAG;AACJ,mBAAO,CAAC,CAAC,GAAG,CAAC;WACd;AACD,aAAG,eAAC,KAAK,EAAE;AACT,aAAC,CAAC,GAAG,GAAG,KAAK,CAAC;AACd,gBAAI,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;WAC5D;;AACD,oBAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI;SACrC;AACD,YAAI,EAAE;AACJ,aAAG,iBAAG;AACJ,mBAAO,CAAC,CAAC,GAAG,CAAC;WACd;AACD,aAAG,eAAC,KAAK,EAAE;AACT,aAAC,CAAC,GAAG,GAAG,KAAK,CAAC;AACd,gBAAI,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;WAC5D;;AACD,oBAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI;SACrC;AACD,YAAI,EAAE;AACJ,aAAG,iBAAG;AACJ,mBAAO,CAAC,CAAC,GAAG,CAAC;WACd;AACD,aAAG,eAAC,KAAK,EAAE;AACT,aAAC,CAAC,GAAG,GAAG,KAAK,CAAC;AACd,gBAAI,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;WAC5D;;AACD,oBAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI;SACrC;AACD,YAAI,EAAE;AACJ,aAAG,iBAAG;AACJ,mBAAO,CAAC,CAAC,GAAG,CAAC;WACd;AACD,aAAG,eAAC,KAAK,EAAE;AACT,aAAC,CAAC,GAAG,GAAG,KAAK,CAAC;AACd,gBAAI,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;WAC5D;;AACD,oBAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI;SACrC;AACD,qBAAa,EAAE;AACb,aAAG,iBAAG;AACJ,mBAAO,CAAC,CAAC,YAAY,CAAC;WACvB;AACD,aAAG,eAAC,KAAK,EAAE;AACT,aAAC,CAAC,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;;;AAAC,AAGnC,gBAAI,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;WAC5D;;AACD,oBAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI;SACrC;AACD,eAAO,EAAE;AACP,aAAG,iBAAG;AACJ,mBAAO,CAAC,CAAC,MAAM,CAAC;WACjB;AACD,aAAG,eAAC,KAAK,EAAE;AACT,aAAC,CAAC,MAAM,GAAG,KAAK;;;AAAC,AAGjB,gBAAI,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;WAC5D;;AACD,oBAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI;SACrC;OACF,CAAC;;;AAAC,AAGH,aAAO,CAAC,CAAC;KACV;;;;;;;;2BAUA;UAJC,OAAO,yDAAG,CAAC;UAAE,IAAI,yDAAG,CAAC;UAAE,SAAS,yDAAG,EAAE;UAAE,UAAU,yDAAG,EAAE;UACtD,UAAU,yDAAG,KAAK;UAAE,OAAO,yDAAG,CAAC;UAAE,OAAO,yDAAG,CAAC;UAC5C,UAAU,yDAAG,SAAS;UACtB,KAAK,yDAAG,SAAS;;;;;;AAOjB,UAAI,SAAS,GAAG,IAAI,IAAI,CAAC,SAAS,EAAE;;;;AAAC,AAIrC,UAAI,UAAU,GAAG,SAAb,UAAU,GAAS;;;AAGrB,YAAI,MAAM,GAAG,OAAO,GAAG,IAAI;;;AAAC,AAG5B,aAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE;;;AAG9B,cAAI,CAAC,GAAG,AAAC,CAAC,GAAG,OAAO,GAAI,SAAS;cAC7B,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,OAAO,CAAC,GAAG,UAAU;;;;AAAC,AAI7C,cAAI,MAAM,GAAG,UAAU,EAAE;;;AAAC,AAG1B,mBAAS,CAAC,QAAQ,CAAC,MAAM,CAAC;;;;;AAAC,AAK3B,cAAI,CAAC,UAAU,EAAE;AACf,kBAAM,CAAC,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC;AACvB,kBAAM,CAAC,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC;;;;AACxB,eAGI;AACH,oBAAM,CAAC,CAAC,GACJ,CAAC,GAAI,SAAS,GAAG,CAAC,AAAC,GAClB,MAAM,CAAC,KAAK,GAAG,CAAC,AAAC,GAAG,OAAO,CAAC;AACjC,oBAAM,CAAC,CAAC,GACJ,CAAC,GAAI,UAAU,GAAG,CAAC,AAAC,GACnB,MAAM,CAAC,KAAK,GAAG,CAAC,AAAC,GAAG,OAAO,CAAC;aAClC;;;;AAAA,AAID,cAAI,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;SAC1B;OACF;;;AAAC,AAGF,gBAAU,EAAE;;;AAAC,AAGb,aAAO,SAAS,CAAC;KAClB;;;;;;0BAIC,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EACvE;;;AAGA,UAAI,MAAM,GAAG,YAAY,EAAE;;;AAAC,AAG5B,YAAM,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC;;;;;AAAC,AAK5B,aAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AACzB,YAAM,CAAC,CAAC,GAAG,CAAC,CAAC;AACb,YAAM,CAAC,CAAC,GAAG,CAAC;;;;AAAC,AAIb,UAAI,MAAM,GAAG,MAAM,CAAC,iBAAiB,EAAE,CAAC,CAAC;UACrC,MAAM,GAAG,MAAM,CAAC,iBAAiB,EAAE,CAAC,CAAC;;;;AAAC,AAI1C,eAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC3B,YAAM,CAAC,CAAC,GAAG,MAAM,CAAC;AAClB,YAAM,CAAC,CAAC,GAAG,MAAM;;;AAAC,AAGlB,YAAM,CAAC,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,WAAW,CAAC;AAC1C,YAAM,CAAC,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,WAAW;;;AAAC,AAG1C,iBAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;KAC1B;;;;;;;;;;;;;;;;;;;;;;;;;;2BAkCA;UAJC,OAAO,yDAAG,CAAC;UAAE,IAAI,yDAAG,CAAC;UAAE,SAAS,yDAAG,EAAE;UAAE,UAAU,yDAAG,EAAE;UACtD,UAAU,yDAAG,KAAK;UAAE,OAAO,yDAAG,CAAC;UAAE,OAAO,yDAAG,CAAC;UAC5C,UAAU,yDAAG,SAAS;UACtB,KAAK,yDAAG,SAAS;;;;;;AAOjB,UAAI,SAAS,GAAG,IAAI,CAAC,KAAK,EAAE;;;AAAC,AAG7B,UAAI,UAAU,GAAG,SAAb,UAAU,GAAS;;;AAGrB,YAAI,MAAM,GAAG,OAAO,GAAG,IAAI;;;AAAC,AAG5B,aAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE;;;AAG9B,cAAI,CAAC,GAAG,AAAC,CAAC,GAAG,OAAO,GAAI,SAAS;cAC7B,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,OAAO,CAAC,GAAG,UAAU;;;;AAAC,AAI7C,cAAI,MAAM,GAAG,UAAU,EAAE;;;AAAC,AAG1B,mBAAS,CAAC,QAAQ,CAAC,MAAM,CAAC;;;;;AAAC,AAK3B,cAAI,CAAC,UAAU,EAAE;AACf,kBAAM,CAAC,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC;AACvB,kBAAM,CAAC,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC;;;;AACxB,eAGI;AACH,oBAAM,CAAC,CAAC,GACJ,CAAC,GAAI,SAAS,GAAG,CAAC,AAAC,GACnB,MAAM,CAAC,SAAS,GAAG,OAAO,CAAC;AAC/B,oBAAM,CAAC,CAAC,GACJ,CAAC,GAAI,UAAU,GAAG,CAAC,AAAC,GACpB,MAAM,CAAC,UAAU,GAAG,OAAO,CAAC;aACjC;;;;AAAA,AAID,cAAI,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;SAC1B;OACF;;;AAAC,AAGF,gBAAU,EAAE;;;AAAC,AAGb,aAAO,SAAS,CAAC;KAClB;;;;;;;;;;0BASK,MAAM,EAAmC;UAAjC,SAAS,yDAAG,EAAE;UAAE,OAAO,yDAAG,KAAK;;;;AAI3C,UAAI,IAAI,GAAG,IAAI;;;AAAC,AAGhB,UAAI,OAAO,GAAG,CAAC;;;AAAC,AAGhB,UAAI,cAAc,GAAG,EAAE;;;;AAAC,AAIxB,UAAI,MAAM,GAAG,MAAM,CAAC,CAAC;UACjB,MAAM,GAAG,MAAM,CAAC,CAAC;UACjB,UAAU,GAAG,MAAM,CAAC,QAAQ;;;;AAAC,AAIjC,UAAI,aAAa,GAAG,SAAS,GAAG,cAAc;;;AAAC,AAG/C,UAAI,SAAS,GAAG,SAAZ,SAAS,CAAI,GAAG,EAAE,GAAG,EAAK;AAC5B,eAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,GAAG,GAAG,GAAG,GAAG,CAAC,CAAA,AAAC,CAAC,GAAG,GAAG,CAAC;OAC1D;;;;AAAC,AAIF,UAAG,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE;;AAE7C,YAAI,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC;;;;;;AAAC,AAMjC,cAAM,CAAC,WAAW,GAAG,YAAM;AACzB,cAAG,OAAO,EAAE;AACV,wBAAY,EAAE,CAAC;WAChB,MAAM;AACL,0BAAc,EAAE,CAAC;WAClB;SACF,CAAC;OACH;;;AAAA,AAGD,eAAS,cAAc,GAAG;;;;AAIxB,YAAI,OAAO,GAAG,cAAc,EAAE;;;AAG5B,gBAAM,CAAC,CAAC,GAAG,MAAM,CAAC;AAClB,gBAAM,CAAC,CAAC,GAAG,MAAM;;;AAAC,AAGlB,mBAAS,IAAI,aAAa;;;AAAC,AAG3B,gBAAM,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;AAC7C,gBAAM,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,SAAS,EAAE,SAAS,CAAC;;;AAAC,AAG7C,iBAAO,IAAI,CAAC,CAAC;SACd;;;;AAAA,AAID,YAAI,OAAO,IAAI,cAAc,EAAE;AAC7B,gBAAM,CAAC,CAAC,GAAG,MAAM,CAAC;AAClB,gBAAM,CAAC,CAAC,GAAG,MAAM,CAAC;AAClB,cAAI,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;SACpE;OACF;;;;AAAA,AAID,UAAI,SAAS,GAAG,CAAC,CAAC;;AAElB,eAAS,YAAY,GAAG;AACtB,YAAI,OAAO,GAAG,cAAc,EAAE;;;AAG5B,gBAAM,CAAC,QAAQ,GAAG,UAAU;;;AAAC,AAG7B,mBAAS,IAAI,aAAa;;;;AAAC,AAI3B,gBAAM,CAAC,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;AACxC,iBAAO,IAAI,CAAC;;;;AAAC,AAIb,mBAAS,IAAI,CAAC,CAAC,CAAC;SACjB;;;;AAAA,AAID,YAAI,OAAO,IAAI,cAAc,EAAE;AAC7B,gBAAM,CAAC,QAAQ,GAAG,UAAU,CAAC;AAC7B,cAAI,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;SACpE;OACF;KACF;;;;;;;;;;;;+BAWU,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE;AAC7B,UAAI,CAAC,CAAC,MAAM,KAAK,SAAS,EAAE;AAC1B,YAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;AACxB,iBAAO,CAAC,CAAC;SACV,MAAM;AACL,iBAAO,SAAS,GAAG,CAAC,CAAC;SACtB;OACF,MAAM;AACL,eAAO,SAAS,CAAC;OAClB;KACF;;;;;;;;4BAOiB;AAChB,UAAI,SAAS,GAAG,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;;wCAD9B,OAAO;AAAP,eAAO;;;AAEd,aAAO,CAAC,OAAO,CAAC,UAAA,MAAM,EAAI;AACxB,iBAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;OAC5B,CAAC,CAAC;AACH,aAAO,SAAS,CAAC;KAClB;;;;;;4BAGoF;UAA/E,IAAI,yDAAG,KAAK;UAAE,OAAO,yDAAG,EAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAC;;AACjF,UAAI,CAAC,GAAG,IAAI,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAClD,aAAO,CAAC,CAAC;KACV;;;;;;;6BAIkB;yCAAT,OAAO;AAAP,eAAO;;;;AAGf,UAAI,EAAE,OAAO,CAAC,CAAC,CAAC,YAAY,KAAK,CAAA,AAAC,EAAE;AAClC,YAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE;AACtB,iBAAO,CAAC,OAAO,CAAC,UAAA,MAAM,EAAK;AACzB,kBAAM,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;WACnC,CAAC,CAAC;SACJ,MAAM;AACL,iBAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;SAC3C;;;;AACF,WAGI;AACH,cAAI,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AAC9B,cAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE;AAC3B,iBAAK,IAAI,CAAC,GAAG,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE;AACjD,kBAAI,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;AAC7B,oBAAM,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;AAClC,0BAAY,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;aACtD;WACF;SACF;KACF;;;;;;;;gCAMW,KAAK,EAAE;;;;;;;AAOjB,UAAI,GAAG,EAAE,GAAG,CAAC;AACb,SAAG,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;AACvC,SAAG,CAAC,MAAM,GAAG,CAAC,CAAC;AACf,SAAG,CAAC,KAAK,GAAG,CAAC,CAAC;AACd,SAAG,GAAG,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;AAC3B,SAAG,CAAC,SAAS,GAAG,KAAK,CAAC;AACtB,SAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AACzB,UAAI,IAAI,GAAG,GAAG,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7C,aAAO,IAAI,CAAC;KACb;;;8BAES,GAAG,EAAE;;AAEb,aAAO,CAAC,GAAG,GAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA,CAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;KACzC;;;+BAEU,KAAK,EAAE;;;;;;;AAKhB,UAAI,IAAI,EAAE,GAAG,CAAC;AACd,UAAI,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;AAC/B,SAAG,GAAG,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,CAAC,GAAG,CACf,UAAA,GAAG;eAAI,OAAK,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;OAAA,CAC/B,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACb,aAAO,IAAI,GAAG,GAAG,CAAC;KACnB;;;;;;;0BAIK,KAAK,EAAE;;;AAGX,UAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAC;;;AAGf,eAAO,KAAK,CAAC;;;;AACd,WAGI;;AAEH,iBAAO,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;;;;;;;;;;;AAAC,SAazC;;;;;;;;;;;;;;;;KAiBF;AAjBE;;SAhuCC,eAAe","file":"spriteUtilities.js","sourcesContent":["class SpriteUtilities{\n constructor(renderingEngine = PIXI) {\n if (renderingEngine === undefined) throw new Error(\"Please supply a reference to PIXI in the SpriteUtilities constructor before using spriteUtilities.js\"); \n\n //Find out which rendering engine is being used (the default is Pixi)\n this.renderer = \"\";\n\n //If the `renderingEngine` is Pixi, set up Pixi object aliases\n if (renderingEngine.ParticleContainer && renderingEngine.Sprite) {\n this.renderer = \"pixi\";\n this.Container = renderingEngine.Container;\n this.ParticleContainer = renderingEngine.ParticleContainer;\n this.TextureCache = renderingEngine.utils.TextureCache;\n this.Texture = renderingEngine.Texture;\n this.Rectangle = renderingEngine.Rectangle;\n this.MovieClip = renderingEngine.extras.MovieClip;\n this.BitmapText = renderingEngine.extras.BitmapText;\n this.Sprite = renderingEngine.Sprite;\n this.TilingSprite = renderingEngine.extras.TilingSprite;\n this.Graphics = renderingEngine.Graphics;\n this.Text = renderingEngine.Text;\n \n //An array to store all the shaking sprites\n this.shakingSprites = [];\n }\n }\n\n update() {\n if (this.shakingSprites.length > 0) {\n for(let i = this.shakingSprites.length - 1; i >= 0; i--) {\n let shakingSprite = this.shakingSprites[i];\n if (shakingSprite.updateShake) shakingSprite.updateShake();\n } \n }\n }\n\n sprite(source, x = 0, y = 0, tiling = false, width, height) {\n\n let o, texture;\n\n //Create a sprite if the `source` is a string \n if (typeof source === \"string\") {\n\n //Access the texture in the cache if it's there\n if (this.TextureCache[source]) {\n texture = this.TextureCache[source];\n }\n\n //If it's not is the cache, load it from the source file\n else {\n texture = this.Texture.fromImage(source);\n }\n\n //If the texture was created, make the o\n if (texture) {\n\n //If `tiling` is `false`, make a regular `Sprite`\n if (!tiling) {\n o = new this.Sprite(texture);\n }\n\n //If `tiling` is `true` make a `TilingSprite`\n else {\n o = new this.TilingSprite(texture, width, height);\n }\n }\n //But if the source still can't be found, alert the user\n else {\n throw new Error(`${source} cannot be found`);\n }\n }\n\n //Create a o if the `source` is a texture\n else if (source instanceof this.Texture) {\n if (!tiling) {\n o = new this.Sprite(source);\n } else {\n o = new this.TilingSprite(source, width, height);\n }\n }\n\n //Create a `MovieClip` o if the `source` is an array\n else if (source instanceof Array) {\n\n //Is it an array of frame ids or textures?\n if (typeof source[0] === \"string\") {\n\n //They're strings, but are they pre-existing texture or\n //paths to image files?\n //Check to see if the first element matches a texture in the\n //cache\n if (this.TextureCache[source[0]]) {\n\n //It does, so it's an array of frame ids\n o = this.MovieClip.fromFrames(source);\n } else {\n\n //It's not already in the cache, so let's load it\n o = this.MovieClip.fromImages(source);\n }\n }\n\n //If the `source` isn't an array of strings, check whether\n //it's an array of textures\n else if (source[0] instanceof this.Texture) {\n\n //Yes, it's an array of textures. \n //Use them to make a MovieClip o \n o = new this.MovieClip(source);\n }\n }\n\n //If the sprite was successfully created, intialize it\n if (o) {\n\n //Position the sprite\n o.x = x;\n o.y = y;\n\n //Set optional width and height\n if (width) o.width = width;\n if (height) o.height = height;\n\n //If the sprite is a MovieClip, add a state player so that\n //it's easier to control\n if (o instanceof this.MovieClip) this.addStatePlayer(o);\n\n //Assign the sprite\n return o;\n }\n }\n\n addStatePlayer(sprite) {\n\n let frameCounter = 0,\n numberOfFrames = 0,\n startFrame = 0,\n endFrame = 0,\n timerInterval = undefined;\n\n //The `show` function (to display static states)\n function show(frameNumber) {\n\n //Reset any possible previous animations\n reset();\n\n //Find the new state on the sprite\n sprite.gotoAndStop(frameNumber);\n }\n\n //The `stop` function stops the animation at the current frame\n function stopAnimation() {\n reset();\n sprite.gotoAndStop(sprite.currentFrame);\n }\n\n //The `playSequence` function, to play a sequence of frames\n function playAnimation(sequenceArray) {\n\n //Reset any possible previous animations\n reset();\n\n //Figure out how many frames there are in the range\n if (!sequenceArray) {\n startFrame = 0;\n endFrame = sprite.totalFrames - 1;\n } else {\n startFrame = sequenceArray[0];\n endFrame = sequenceArray[1];\n }\n\n //Calculate the number of frames\n numberOfFrames = endFrame - startFrame;\n\n //Compensate for two edge cases:\n //1. If the `startFrame` happens to be `0`\n /*\n if (startFrame === 0) {\n numberOfFrames += 1;\n frameCounter += 1;\n }\n */\n\n //2. If only a two-frame sequence was provided\n /*\n if(numberOfFrames === 1) {\n numberOfFrames = 2;\n frameCounter += 1;\n } \n */\n\n //Calculate the frame rate. Set the default fps to 12\n if (!sprite.fps) sprite.fps = 12;\n let frameRate = 1000 / sprite.fps;\n\n //Set the sprite to the starting frame\n sprite.gotoAndStop(startFrame);\n\n //Set the `frameCounter` to the first frame \n frameCounter = 1;\n\n //If the state isn't already `playing`, start it\n if (!sprite.animating) {\n timerInterval = setInterval(advanceFrame.bind(this), frameRate);\n sprite.animating = true;\n }\n }\n\n //`advanceFrame` is called by `setInterval` to display the next frame \n //in the sequence based on the `frameRate`. When the frame sequence \n //reaches the end, it will either stop or loop\n function advanceFrame() {\n\n //Advance the frame if `frameCounter` is less than \n //the state's total frames\n if (frameCounter < numberOfFrames + 1) {\n\n //Advance the frame\n sprite.gotoAndStop(sprite.currentFrame + 1);\n\n //Update the frame counter\n frameCounter += 1;\n\n //If we've reached the last frame and `loop`\n //is `true`, then start from the first frame again\n } else {\n if (sprite.loop) {\n sprite.gotoAndStop(startFrame);\n frameCounter = 1;\n }\n }\n }\n\n function reset() {\n\n //Reset `sprite.playing` to `false`, set the `frameCounter` to 0, //and clear the `timerInterval`\n if (timerInterval !== undefined && sprite.animating === true) {\n sprite.animating = false;\n frameCounter = 0;\n startFrame = 0;\n endFrame = 0;\n numberOfFrames = 0;\n clearInterval(timerInterval);\n }\n }\n\n //Add the `show`, `play`, `stop`, and `playSequence` methods to the sprite\n sprite.show = show;\n sprite.stopAnimation = stopAnimation;\n sprite.playAnimation = playAnimation;\n }\n\n //`tilingSpirte` lets you quickly create Pixi tiling sprites\n tilingSprite(source, width, height, x, y) {\n if (width === undefined) {\n throw new Error(\"Please define a width as your second argument for the tiling sprite\");\n }\n if (height === undefined) {\n throw new Error(\"Please define a height as your third argument for the tiling sprite\");\n }\n let o = this.sprite(source, x, y, true, width, height);\n\n //Add `tileX`, `tileY`, `tileScaleX` and `tileScaleY` properties\n Object.defineProperties(o, {\n \"tileX\": {\n get() {\n return o.tilePosition.x;\n },\n set(value) {\n o.tilePosition.x = value;\n }, \n enumerable: true, configurable: true\n },\n \"tileY\": {\n get() {\n return o.tilePosition.y;\n },\n set(value) {\n o.tilePosition.y = value;\n }, \n enumerable: true, configurable: true\n },\n \"tileScaleX\": {\n get() {\n return o.tileScale.x;\n },\n set(value) {\n o.tileScale.x = value;\n }, \n enumerable: true, configurable: true\n },\n \"tileScaleY\": {\n get() {\n return o.tileScale.y;\n },\n set(value) {\n o.tileScale.y = value;\n }, \n enumerable: true, configurable: true\n },\n });\n \n return o\n }\n\n filmstrip(\n texture,\n frameWidth,\n frameHeight,\n spacing = 0\n ) {\n\n //An array to store the x/y positions of the frames\n let positions = [];\n\n //Find the width and height of the texture\n let textureWidth = this.TextureCache[texture].width,\n textureHeight = this.TextureCache[texture].height;\n\n //Find out how many columns and rows there are\n let columns = textureWidth / frameWidth,\n rows = textureHeight / frameHeight;\n\n //Find the total number of frames\n let numberOfFrames = columns * rows;\n\n for (let i = 0; i < numberOfFrames; i++) {\n\n //Find the correct row and column for each frame\n //and figure out its x and y position\n let x = (i % columns) * frameWidth,\n y = Math.floor(i / columns) * frameHeight;\n\n //Compensate for any optional spacing (padding) around the tiles if\n //there is any. This bit of code accumlates the spacing offsets from the \n //left side of the tileset and adds them to the current tile's position \n if (spacing > 0) {\n x += spacing + (spacing * i % columns);\n y += spacing + (spacing * Math.floor(i / columns));\n }\n\n //Add the x and y value of each frame to the `positions` array\n positions.push([x, y]);\n }\n\n //Return the frames\n return this.frames(texture, positions, frameWidth, frameHeight);\n }\n\n //Make a texture from a frame in another texture or image\n frame(source, x, y, width, height) {\n\n let texture, imageFrame;\n\n //If the source is a string, it's either a texture in the\n //cache or an image file\n if (typeof source === \"string\") {\n if (this.TextureCache[source]) {\n texture = new this.Texture(this.TextureCache[source]);\n }\n }\n\n //If the `source` is a texture, use it\n else if (source instanceof this.Texture) {\n texture = new this.Texture(source);\n }\n if (!texture) {\n throw new Error(`Please load the ${source} texture into the cache.`);\n } else {\n\n //Make a rectangle the size of the sub-image\n imageFrame = new this.Rectangle(x, y, width, height);\n texture.frame = imageFrame;\n return texture;\n }\n }\n\n //Make an array of textures from a 2D array of frame x and y coordinates in\n //texture\n frames(source, coordinates, frameWidth, frameHeight) {\n\n let baseTexture, textures;\n\n //If the source is a string, it's either a texture in the\n //cache or an image file\n if (typeof source === \"string\") {\n if (this.TextureCache[source]) {\n baseTexture = new this.Texture(this.TextureCache[source]);\n }\n }\n //If the `source` is a texture, use it\n else if (source instanceof this.Texture) {\n baseTexture = new this.Texture(source);\n }\n if (!baseTexture) {\n throw new Error(`Please load the ${source} texture into the cache.`);\n } else {\n let textures = coordinates.map((position) => {\n let x = position[0],\n y = position[1];\n let imageFrame = new this.Rectangle(x, y, frameWidth, frameHeight);\n let frameTexture = new this.Texture(baseTexture);\n frameTexture.frame = imageFrame;\n return frameTexture\n });\n return textures;\n }\n }\n\n frameSeries(startNumber = 0, endNumber = 1, baseName = \"\", extension = \"\") {\n\n //Create an array to store the frame names\n let frames = [];\n\n for (let i = startNumber; i < endNumber + 1; i++) {\n let frame = this.TextureCache[`${baseName + i + extension}`];\n frames.push(frame);\n }\n return frames;\n }\n\n /* Text creation */\n\n //The`text` method is a quick way to create a Pixi Text sprite\n text(content = \"message\", font = \"16px sans\", fillStyle = \"red\", x = 0, y = 0) {\n\n //Create a Pixi Sprite object\n let message = new this.Text(content, {font: font, fill: fillStyle});\n message.x = x;\n message.y = y;\n\n //Add a `_text` property with a getter/setter\n message._content = content;\n Object.defineProperty(message, \"content\", {\n get() {\n return this._content;\n },\n set(value) {\n this._content = value;\n this.text = value;\n },\n enumerable: true, configurable: true\n });\n\n //Return the text object\n return message;\n }\n\n //The`bitmapText` method lets you create bitmap text\n bitmapText(content = \"message\", font, align, tint, x = 0, y = 0) {\n\n //Create a Pixi Sprite object\n let message = new this.BitmapText(content, {font: font, align: align, tint: tint});\n message.x = x;\n message.y = y;\n\n //Add a `_text` property with a getter/setter\n message._content = content;\n Object.defineProperty(message, \"content\", {\n get() {\n return this._content;\n },\n set(value) {\n this._content = value;\n this.text = value;\n },\n enumerable: true, configurable: true\n });\n\n //Return the text object\n return message;\n }\n\n /* Shapes and lines */\n\n //Rectangle\n rectangle(\n width = 32, \n height = 32, \n fillStyle = 0xFF3300, \n strokeStyle = 0x0033CC, \n lineWidth = 0,\n x = 0, \n y = 0 \n ){\n\n let o = new this.Graphics();\n o._sprite = undefined;\n o._width = width;\n o._height = height;\n o._fillStyle = this.color(fillStyle);\n o._strokeStyle = this.color(strokeStyle);\n o._lineWidth = lineWidth;\n\n //Draw the rectangle\n let draw = (width, height, fillStyle, strokeStyle, lineWidth) => {\n o.clear();\n o.beginFill(fillStyle);\n if (lineWidth > 0) {\n o.lineStyle(lineWidth, strokeStyle, 1);\n }\n o.drawRect(0, 0, width, height);\n o.endFill();\n };\n\n //Draw the line and capture the sprite that the `draw` function\n //returns\n draw(o._width, o._height, o._fillStyle, o._strokeStyle, o._lineWidth);\n\n //Generate a texture from the rectangle\n let texture = o.generateTexture();\n\n //Use the texture to create a sprite\n let sprite = new this.Sprite(texture);\n\n //Position the sprite\n sprite.x = x;\n sprite.y = y;\n\n //Add getters and setters to the sprite\n let self = this;\n Object.defineProperties(sprite, {\n \"fillStyle\": {\n get() {\n return o._fillStyle;\n },\n set(value) {\n o._fillStyle = self.color(value);\n\n //Draw the new rectangle \n draw(o._width, o._height, o._fillStyle, o._strokeStyle, o._lineWidth, o._x, o._y);\n\n //Generate a new texture and set it as the sprite's texture\n let texture = o.generateTexture();\n o._sprite.texture = texture;\n }, \n enumerable: true, configurable: true\n },\n \"strokeStyle\": {\n get() {\n return o._strokeStyle;\n },\n set(value) {\n o._strokeStyle = self.color(value);\n\n //Draw the new rectangle \n draw(o._width, o._height, o._fillStyle, o._strokeStyle, o._lineWidth, o._x, o._y);\n\n //Generate a new texture and set it as the sprite's texture\n let texture = o.generateTexture();\n o._sprite.texture = texture;\n }, \n enumerable: true, configurable: true\n },\n \"lineWidth\": {\n get() {\n return o._lineWidth;\n },\n set(value) {\n o._lineWidth = value;\n\n //Draw the new rectangle \n draw(o._width, o._height, o._fillStyle, o._strokeStyle, o._lineWidth, o._x, o._y);\n\n //Generate a new texture and set it as the sprite's texture\n let texture = o.generateTexture();\n o._sprite.texture = texture;\n }, \n enumerable: true, configurable: true\n }\n });\n \n //Get a local reference to the sprite so that we can \n //change the rectangle properties later using the getters/setters\n o._sprite = sprite;\n\n //Return the sprite\n return sprite;\n }\n\n //Circle\n circle(\n diameter = 32, \n fillStyle = 0xFF3300, \n strokeStyle = 0x0033CC, \n lineWidth = 0,\n x = 0, \n y = 0 \n ){\n\n let o = new this.Graphics();\n o._diameter = diameter;\n o._fillStyle = this.color(fillStyle);\n o._strokeStyle = this.color(strokeStyle);\n o._lineWidth = lineWidth;\n\n //Draw the circle\n let draw = (diameter, fillStyle, strokeStyle, lineWidth) => {\n o.clear(); \n o.beginFill(fillStyle);\n if (lineWidth > 0) {\n o.lineStyle(lineWidth, strokeStyle, 1);\n }\n o.drawCircle(0, 0, diameter / 2);\n o.endFill();\n };\n\n //Draw the cirlce\n draw(o._diameter, o._fillStyle, o._strokeStyle, o._lineWidth);\n\n //Generate a texture from the rectangle\n let texture = o.generateTexture();\n\n //Use the texture to create a sprite\n let sprite = new this.Sprite(texture);\n\n //Position the sprite\n sprite.x = x;\n sprite.y = y;\n\n //Add getters and setters to the sprite\n let self = this;\n Object.defineProperties(sprite, {\n \"fillStyle\": {\n get() {\n return o._fillStyle;\n },\n set(value) {\n o._fillStyle = self.color(value);\n\n //Draw the cirlce\n draw(o._diameter, o._fillStyle, o._strokeStyle, o._lineWidth);\n\n //Generate a new texture and set it as the sprite's texture\n let texture = o.generateTexture();\n o._sprite.texture = texture;\n }, \n enumerable: true, configurable: true\n },\n \"strokeStyle\": {\n get() {\n return o._strokeStyle;\n },\n set(value) {\n o._strokeStyle = self.color(value);\n\n //Draw the cirlce\n draw(o._diameter, o._fillStyle, o._strokeStyle, o._lineWidth);\n\n //Generate a new texture and set it as the sprite's texture\n let texture = o.generateTexture();\n o._sprite.texture = texture;\n }, \n enumerable: true, configurable: true\n },\n \"diameter\": {\n get() {\n return o._diameter;\n },\n set(value) {\n o._lineWidth = 10;\n\n //Draw the cirlce\n draw(o._diameter, o._fillStyle, o._strokeStyle, o._lineWidth);\n\n //Generate a new texture and set it as the sprite's texture\n let texture = o.generateTexture();\n o._sprite.texture = texture;\n }, \n enumerable: true, configurable: true\n },\n \"radius\": {\n get() {\n return o._diameter / 2;\n },\n set(value) {\n\n //Draw the cirlce\n draw(value * 2, o._fillStyle, o._strokeStyle, o._lineWidth);\n\n //Generate a new texture and set it as the sprite's texture\n let texture = o.generateTexture();\n o._sprite.texture = texture;\n }, \n enumerable: true, configurable: true\n },\n });\n //Get a local reference to the sprite so that we can \n //change the circle properties later using the getters/setters\n o._sprite = sprite;\n\n //Return the sprite\n return sprite;\n }\n\n //Line\n line(\n strokeStyle = 0x000000, \n lineWidth = 1, \n ax = 0, \n ay = 0, \n bx = 32, \n by = 32\n ){\n\n //Create the line object\n let o = new this.Graphics();\n\n //Private properties\n o._strokeStyle = this.color(strokeStyle);\n o._width = lineWidth;\n o._ax = ax;\n o._ay = ay;\n o._bx = bx;\n o._by = by;\n\n //A helper function that draws the line\n let draw = (strokeStyle, lineWidth, ax, ay, bx, by) => {\n o.clear();\n o.lineStyle(lineWidth, strokeStyle, 1);\n o.moveTo(ax, ay);\n o.lineTo(bx, by);\n };\n \n //Draw the line\n draw(o._strokeStyle, o._width, o._ax, o._ay, o._bx, o._by);\n\n //Define getters and setters that redefine the line's start and \n //end points and re-draws it if they change\n let self = this;\n Object.defineProperties(o, {\n \"ax\": {\n get() {\n return o._ax;\n },\n set(value) {\n o._ax = value;\n draw(o._strokeStyle, o._width, o._ax, o._ay, o._bx, o._by);\n }, \n enumerable: true, configurable: true\n },\n \"ay\": {\n get() {\n return o._ay;\n },\n set(value) {\n o._ay = value;\n draw(o._strokeStyle, o._width, o._ax, o._ay, o._bx, o._by);\n }, \n enumerable: true, configurable: true\n },\n \"bx\": {\n get() {\n return o._bx;\n },\n set(value) {\n o._bx = value;\n draw(o._strokeStyle, o._width, o._ax, o._ay, o._bx, o._by);\n }, \n enumerable: true, configurable: true\n },\n \"by\": {\n get() {\n return o._by;\n },\n set(value) {\n o._by = value;\n draw(o._strokeStyle, o._width, o._ax, o._ay, o._bx, o._by);\n }, \n enumerable: true, configurable: true\n },\n \"strokeStyle\": {\n get() {\n return o._strokeStyle;\n },\n set(value) {\n o._strokeStyle = self.color(value);\n\n //Draw the line\n draw(o._strokeStyle, o._width, o._ax, o._ay, o._bx, o._by);\n }, \n enumerable: true, configurable: true\n },\n \"width\": {\n get() {\n return o._width;\n },\n set(value) {\n o._width = value;\n\n //Draw the line\n draw(o._strokeStyle, o._width, o._ax, o._ay, o._bx, o._by);\n }, \n enumerable: true, configurable: true\n }\n });\n\n //Return the line\n return o;\n }\n\n /* Compound sprites */\n\n //Use `grid` to create a grid of sprites\n grid(\n columns = 0, rows = 0, cellWidth = 32, cellHeight = 32,\n centerCell = false, xOffset = 0, yOffset = 0,\n makeSprite = undefined,\n extra = undefined\n ){\n\n //Create an empty group called `container`. This `container`\n //group is what the function returns back to the main program.\n //All the sprites in the grid cells will be added\n //as children to this container\n let container = new this.Container();\n\n //The `create` method plots the grid\n\n let createGrid = () => {\n\n //Figure out the number of cells in the grid\n let length = columns * rows;\n\n //Create a sprite for each cell\n for(let i = 0; i < length; i++) {\n\n //Figure out the sprite's x/y placement in the grid\n let x = (i % columns) * cellWidth,\n y = Math.floor(i / columns) * cellHeight;\n\n //Use the `makeSprite` function supplied in the constructor\n //to make a sprite for the grid cell\n let sprite = makeSprite();\n\n //Add the sprite to the `container`\n container.addChild(sprite);\n\n //Should the sprite be centered in the cell?\n\n //No, it shouldn't be centered\n if (!centerCell) {\n sprite.x = x + xOffset;\n sprite.y = y + yOffset;\n }\n\n //Yes, it should be centered\n else {\n sprite.x \n = x + (cellWidth / 2) \n - (sprite.width / 2) + xOffset;\n sprite.y \n = y + (cellHeight / 2) \n - (sprite.width / 2) + yOffset;\n }\n\n //Run any optional extra code. This calls the\n //`extra` function supplied by the constructor\n if (extra) extra(sprite);\n }\n };\n\n //Run the `createGrid` method\n createGrid();\n\n //Return the `container` group back to the main program\n return container;\n }\n\n //Use `shoot` to create bullet sprites \n shoot(\n shooter, angle, x, y, container, bulletSpeed, bulletArray, bulletSprite\n ) {\n\n //Make a new sprite using the user-supplied `bulletSprite` function\n let bullet = bulletSprite();\n\n //Set the bullet's anchor point to its center\n bullet.anchor.set(0.5, 0.5);\n\n //Temporarily add the bullet to the shooter\n //so that we can position it relative to the\n //shooter's position\n shooter.addChild(bullet);\n bullet.x = x;\n bullet.y = y;\n\n //Find the bullet's global coordinates so that we can use\n //them to position the bullet on the new parent container\n let tempGx = bullet.getGlobalPosition().x,\n tempGy = bullet.getGlobalPosition().y;\n\n //Add the bullet to the new parent container using\n //the new global coordinates\n container.addChild(bullet);\n bullet.x = tempGx;\n bullet.y = tempGy;\n\n //Set the bullet's velocity\n bullet.vx = Math.cos(angle) * bulletSpeed;\n bullet.vy = Math.sin(angle) * bulletSpeed;\n\n //Push the bullet into the `bulletArray`\n bulletArray.push(bullet);\n }\n\n /*\n grid\n ----\n\n Helps you to automatically create a grid of sprites. `grid` returns a\n `group` sprite object that contains a sprite for every cell in the\n grid. You can define the rows and columns in the grid, whether or\n not the sprites should be centered inside each cell, or what their offset from the\n top left corner of each cell should be. Supply a function that\n returns the sprite that you want to make for each cell. You can\n supply an optional final function that runs any extra code after\n each sprite has been created. Here's the format for creating a grid:\n\n gridGroup = grid(\n\n //Set the grid's properties\n columns, rows, cellWidth, cellHeight,\n areSpirtesCentered?, xOffset, yOffset,\n\n //A function that returns a sprite\n () => g.circle(16, \"blue\"),\n\n //An optional final function that runs some extra code\n () => console.log(\"extra!\")\n );\n */\n\n grid(\n columns = 0, rows = 0, cellWidth = 32, cellHeight = 32,\n centerCell = false, xOffset = 0, yOffset = 0,\n makeSprite = undefined,\n extra = undefined\n ){\n\n //Create an empty group called `container`. This `container`\n //group is what the function returns back to the main program.\n //All the sprites in the grid cells will be added\n //as children to this container\n let container = this.group();\n\n //The `create` method plots the grid\n let createGrid = () => {\n\n //Figure out the number of cells in the grid\n let length = columns * rows;\n\n //Create a sprite for each cell\n for(let i = 0; i < length; i++) {\n\n //Figure out the sprite's x/y placement in the grid\n let x = (i % columns) * cellWidth,\n y = Math.floor(i / columns) * cellHeight;\n\n //Use the `makeSprite` function supplied in the constructor\n //to make a sprite for the grid cell\n let sprite = makeSprite();\n\n //Add the sprite to the `container`\n container.addChild(sprite);\n\n //Should the sprite be centered in the cell?\n\n //No, it shouldn't be centered\n if (!centerCell) {\n sprite.x = x + xOffset;\n sprite.y = y + yOffset;\n }\n\n //Yes, it should be centered\n else {\n sprite.x \n = x + (cellWidth / 2) \n - sprite.halfWidth + xOffset;\n sprite.y \n = y + (cellHeight / 2) \n - sprite.halfHeight + yOffset;\n }\n\n //Run any optional extra code. This calls the\n //`extra` function supplied by the constructor\n if (extra) extra(sprite);\n }\n };\n\n //Run the `createGrid` method\n createGrid();\n\n //Return the `container` group back to the main program\n return container;\n }\n\n /*\n shake\n -----\n\n Used to create a shaking effect, like a screen shake\n */\n\n shake(sprite, magnitude = 16, angular = false) {\n\n //Get a reference to this current object so that\n //it's easy to maintain scope in the nested sub-functions\n let self = this;\n\n //A counter to count the number of shakes\n let counter = 1;\n\n //The total number of shakes (there will be 1 shake per frame)\n let numberOfShakes = 10;\n\n //Capture the sprite's position and angle so you can\n //restore them after the shaking has finished\n let startX = sprite.x,\n startY = sprite.y,\n startAngle = sprite.rotation;\n\n //Divide the magnitude into 10 units so that you can \n //reduce the amount of shake by 10 percent each frame\n let magnitudeUnit = magnitude / numberOfShakes;\n \n //The `randomInt` helper function\n let randomInt = (min, max) => {\n return Math.floor(Math.random() * (max - min + 1)) + min;\n };\n \n //Add the sprite to the `shakingSprites` array if it\n //isn't already there\n if(self.shakingSprites.indexOf(sprite) === -1) {\n\n self.shakingSprites.push(sprite);\n \n //Add an `updateShake` method to the sprite.\n //The `updateShake` method will be called each frame\n //in the game loop. The shake effect type can be either\n //up and down (x/y shaking) or angular (rotational shaking).\n sprite.updateShake = () => {\n if(angular) {\n angularShake();\n } else {\n upAndDownShake();\n }\n };\n }\n\n //The `upAndDownShake` function\n function upAndDownShake() {\n\n //Shake the sprite while the `counter` is less than \n //the `numberOfShakes`\n if (counter < numberOfShakes) {\n\n //Reset the sprite's position at the start of each shake\n sprite.x = startX;\n sprite.y = startY;\n\n //Reduce the magnitude\n magnitude -= magnitudeUnit;\n\n //Randomly change the sprite's position\n sprite.x += randomInt(-magnitude, magnitude);\n sprite.y += randomInt(-magnitude, magnitude);\n\n //Add 1 to the counter\n counter += 1;\n }\n\n //When the shaking is finished, restore the sprite to its original \n //position and remove it from the `shakingSprites` array\n if (counter >= numberOfShakes) {\n sprite.x = startX;\n sprite.y = startY;\n self.shakingSprites.splice(self.shakingSprites.indexOf(sprite), 1);\n }\n }\n \n //The `angularShake` function\n //First set the initial tilt angle to the right (+1) \n let tiltAngle = 1;\n\n function angularShake() {\n if (counter < numberOfShakes) {\n\n //Reset the sprite's rotation\n sprite.rotation = startAngle;\n\n //Reduce the magnitude\n magnitude -= magnitudeUnit;\n\n //Rotate the sprite left or right, depending on the direction,\n //by an amount in radians that matches the magnitude\n sprite.rotation = magnitude * tiltAngle;\n counter += 1;\n\n //Reverse the tilt angle so that the sprite is tilted\n //in the opposite direction for the next shake\n tiltAngle *= -1;\n }\n\n //When the shaking is finished, reset the sprite's angle and\n //remove it from the `shakingSprites` array\n if (counter >= numberOfShakes) {\n sprite.rotation = startAngle;\n self.shakingSprites.splice(self.shakingSprites.indexOf(sprite), 1);\n }\n }\n }\n\n /*\n _getCenter\n ----------\n\n A utility that finds the center point of the sprite. If it's anchor point is the\n sprite's top left corner, then the center is calculated from that point.\n If the anchor point has been shifted, then the anchor x/y point is used as the sprite's center\n */\n\n _getCenter(o, dimension, axis) {\n if (o.anchor !== undefined) {\n if (o.anchor[axis] !== 0) {\n return 0;\n } else {\n return dimension / 2;\n }\n } else {\n return dimension; \n }\n }\n \n\n\n /* Groups */\n\n //Group sprites into a container\n group(...sprites) {\n let container = new this.Container();\n sprites.forEach(sprite => {\n container.addChild(sprite);\n });\n return container;\n }\n\n //Use the `batch` method to create a ParticleContainer\n batch(size = 15000, options = {rotation: true, alpha: true, scale: true, uvs: true}) {\n let o = new this.ParticleContainer(size, options);\n return o;\n }\n\n //`remove` is a global convenience method that will\n //remove any sprite, or an argument list of sprites, from its parent.\n remove(...sprites) {\n\n //Remove sprites that's aren't in an array\n if (!(sprites[0] instanceof Array)) {\n if (sprites.length > 1) {\n sprites.forEach(sprite => {\n sprite.parent.removeChild(sprite);\n });\n } else {\n sprites[0].parent.removeChild(sprites[0]);\n }\n }\n\n //Remove sprites in an array of sprites\n else {\n let spritesArray = sprites[0];\n if (spritesArray.length > 0) {\n for (let i = spritesArray.length - 1; i >= 0; i--) {\n let sprite = spritesArray[i];\n sprite.parent.removeChild(sprite);\n spritesArray.splice(spritesArray.indexOf(sprite), 1);\n }\n }\n }\n }\n\n /* Color conversion */\n //From: http://stackoverflow.com/questions/1573053/javascript-function-to-convert-color-names-to-hex-codes\n //Utilities to convert HTML color string names to hexadecimal codes\n\n colorToRGBA(color) {\n // Returns the color as an array of [r, g, b, a] -- all range from 0 - 255\n // color must be a valid canvas fillStyle. This will cover most anything\n // you'd want to use.\n // Examples:\n // colorToRGBA('red') # [255, 0, 0, 255]\n // colorToRGBA('#f00') # [255, 0, 0, 255]\n var cvs, ctx;\n cvs = document.createElement('canvas');\n cvs.height = 1;\n cvs.width = 1;\n ctx = cvs.getContext('2d');\n ctx.fillStyle = color;\n ctx.fillRect(0, 0, 1, 1);\n let data = ctx.getImageData(0, 0, 1, 1).data; \n return data;\n }\n\n byteToHex(num) {\n // Turns a number (0-255) into a 2-character hex number (00-ff)\n return ('0'+num.toString(16)).slice(-2);\n }\n\n colorToHex(color) {\n // Convert any CSS color to a hex representation\n // Examples:\n // colorToHex('red') # '#ff0000'\n // colorToHex('rgb(255, 0, 0)') # '#ff0000'\n var rgba, hex;\n rgba = this.colorToRGBA(color);\n hex = [0,1,2].map(\n idx => this.byteToHex(rgba[idx])\n ).join('');\n return \"0x\" + hex;\n }\n\n //A function to find out if the user entered a number (a hex color\n //code) or a string (an HTML color string)\n color(value) {\n\n //Check if it's a number\n if(!isNaN(value)){\n\n //Yes, it is a number, so just return it\n return value;\n }\n\n //No it's not a number, so it must be a string \n else {\n\n return parseInt(this.colorToHex(value));\n /*\n\n //Find out what kind of color string it is.\n //Let's first grab the first character of the string\n let firstCharacter = value.charAt(0);\n\n //If the first character is a \"#\" or a number, then\n //we know it must be a RGBA color\n if (firstCharacter === \"#\") {\n console.log(\"first character: \" + value.charAt(0))\n }\n */\n }\n \n /*\n //Find out if the first character in the string is a number\n if (!isNaN(parseInt(string.charAt(0)))) {\n \n //It's not, so convert it to a hex code\n return colorToHex(string);\n \n //The use input a number, so it must be a hex code. Just return it\n } else {\n \n return string;\n }\n \n */\n\n }\n \n}\n\n\n\n"]}
--------------------------------------------------------------------------------