littlejsengine 1.17.5 → 1.17.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -19,50 +19,62 @@ const tileCollisionLayers = [];
19
19
 
20
20
  /** Get tile collision data for a given cell in the grid
21
21
  * @param {Vector2} pos
22
+ * @param {boolean} [solidOnly] - Only check solid layers?
22
23
  * @return {number}
23
24
  * @memberof TileLayers */
24
- function tileCollisionGetData(pos)
25
+ function tileCollisionGetData(pos, solidOnly=true)
25
26
  {
26
27
  // check all tile collision layers
27
28
  for (const layer of tileCollisionLayers)
29
+ if (!solidOnly || layer.isSolid)
28
30
  if (pos.arrayCheck(layer.size))
29
- return layer.getCollisionData(pos);
31
+ {
32
+ const data = layer.getCollisionData(pos);
33
+ if (data) return data;
34
+ }
30
35
  return 0;
31
36
  }
32
37
 
33
38
  /** Check if a tile layer collides with another object
34
- * @param {Vector2} pos
35
- * @param {Vector2} [size=vec2()]
36
- * @param {EngineObject} [object] - An object or undefined for generic test
37
- * @param {boolean} [solidOnly] - Only check solid layers if true
39
+ * @param {Vector2} pos
40
+ * @param {Vector2} [size=vec2()]
41
+ * @param {EngineObject|TileCollisionCallback} [callbackObject] - Callback, engine object, or undefined
42
+ * @param {boolean} [solidOnly] - Only check solid layers?
38
43
  * @return {TileCollisionLayer}
39
44
  * @memberof TileLayers */
40
- function tileCollisionTest(pos, size=vec2(), object, solidOnly=true)
45
+ function tileCollisionTest(pos, size=vec2(), callbackObject, solidOnly=true)
41
46
  {
42
47
  for (const layer of tileCollisionLayers)
43
48
  {
44
49
  if (!solidOnly || layer.isSolid)
45
- if (layer.collisionTest(pos, size, object))
50
+ if (layer.collisionTest(pos, size, callbackObject))
46
51
  return layer;
47
52
  }
48
53
  }
49
54
 
55
+ /**
56
+ * @callback TileCollisionCallback - Function to handle a tile collision test
57
+ * @param {number} tileData - the value of the tile at the position
58
+ * @param {Vector2} pos - world space position of tile where the collision occurred
59
+ * @memberof TileLayers
60
+ */
61
+
50
62
  /** Return the exact position of the boundary of first tile hit, undefined if nothing was hit.
51
- * The point will be inside the colliding tile if it hits (may have a tiny shift)
52
- * @param {Vector2} posStart
53
- * @param {Vector2} posEnd
54
- * @param {EngineObject} [object] - An object or undefined for generic test
55
- * @param {Vector2} [normal] - Optional normal of the surface hit
56
- * @param {boolean} [solidOnly=true] - Only check solid layers if true
63
+ * The point will be inside the colliding tile if it hits
64
+ * @param {Vector2} posStart
65
+ * @param {Vector2} posEnd
66
+ * @param {EngineObject|TileCollisionCallback} [callbackObject] - Callback, engine object, or undefined
67
+ * @param {Vector2} [normal] - Optional normal of the surface hit
68
+ * @param {boolean} [solidOnly=true] - Only check solid layers?
57
69
  * @return {Vector2|undefined} - position of the center of the tile hit or undefined if no hit
58
70
  * @memberof TileLayers */
59
- function tileCollisionRaycast(posStart, posEnd, object, normal, solidOnly=true)
71
+ function tileCollisionRaycast(posStart, posEnd, callbackObject, normal, solidOnly=true)
60
72
  {
61
73
  for (const layer of tileCollisionLayers)
62
74
  {
63
75
  if (!solidOnly || layer.isSolid)
64
76
  {
65
- const hitPos = layer.collisionRaycast(posStart, posEnd, object, normal)
77
+ const hitPos = layer.collisionRaycast(posStart, posEnd, callbackObject, normal)
66
78
  if (hitPos) return hitPos;
67
79
  }
68
80
  }
@@ -626,18 +638,22 @@ class TileCollisionLayer extends TileLayer
626
638
  /** Check if collision with another object should occur
627
639
  * @param {Vector2} pos
628
640
  * @param {Vector2} [size=vec2()]
629
- * @param {EngineObject} [object]
641
+ * @param {EngineObject|TileCollisionCallback} [callbackObject] - Callback, engine object, or undefined
630
642
  * @return {boolean} */
631
- collisionTest(pos, size=new Vector2, object)
643
+ collisionTest(pos, size=new Vector2, callbackObject)
632
644
  {
633
645
  ASSERT(isVector2(pos) && isVector2(size), 'pos and size must be Vector2s');
634
- ASSERT(!object || object instanceof EngineObject, 'object must be an EngineObject');
635
-
636
- // transform to local layer space
637
- const posX = pos.x - this.pos.x;
638
- const posY = pos.y - this.pos.y;
646
+ ASSERT(!callbackObject || typeof callbackObject === 'function' || callbackObject instanceof EngineObject, 'callbackObject must be a funtion or EngineObject');
647
+
648
+ // make function to check for collision
649
+ const collisionTest = callbackObject ? typeof callbackObject === 'function' ?
650
+ (tileData, pos)=> callbackObject(tileData, pos) :
651
+ (tileData, pos)=> callbackObject.collideWithTile(tileData, pos) :
652
+ ()=> true;
639
653
 
640
654
  // check any tiles in the area for collision
655
+ const posX = pos.x - this.pos.x;
656
+ const posY = pos.y - this.pos.y;
641
657
  const minX = max(posX - size.x/2|0, 0);
642
658
  const minY = max(posY - size.y/2|0, 0);
643
659
  const maxX = min(posX + size.x/2, this.size.x);
@@ -648,9 +664,7 @@ class TileCollisionLayer extends TileLayer
648
664
  {
649
665
  // check if the object should collide with this tile
650
666
  const tileData = this.collisionData[y*this.size.x+x];
651
- if (tileData)
652
- if (!object || object.collideWithTile(tileData,
653
- hitPos.set(x + this.pos.x, y + this.pos.y)))
667
+ if (tileData && collisionTest(tileData, hitPos.set(x+this.pos.x, y+this.pos.y)))
654
668
  return true;
655
669
  }
656
670
  return false;
@@ -658,35 +672,39 @@ class TileCollisionLayer extends TileLayer
658
672
 
659
673
  /** Return the exact position of the boundary of first tile hit, undefined if nothing was hit.
660
674
  * The point will be inside the colliding tile if it hits (may have a tiny shift)
661
- * @param {Vector2} posStart
662
- * @param {Vector2} posEnd
663
- * @param {EngineObject} [object] - An object or undefined for generic test
664
- * @param {Vector2} [normal] - Optional normal of the surface hit
675
+ * @param {Vector2} posStart
676
+ * @param {Vector2} posEnd
677
+ * @param {EngineObject|TileCollisionCallback} [callbackObject] - Callback, engine object, or undefined
678
+ * @param {Vector2} [normal] - Optional normal of the surface hit
665
679
  * @return {Vector2|undefined} */
666
- collisionRaycast(posStart, posEnd, object, normal)
680
+ collisionRaycast(posStart, posEnd, callbackObject, normal)
667
681
  {
668
682
  ASSERT(isVector2(posStart) && isVector2(posEnd), 'positions must be Vector2s');
669
- ASSERT(!object || object instanceof EngineObject, 'object must be an EngineObject');
670
-
671
- const localPos = new Vector2;
672
- const collisionTest = (pos)=>
683
+ ASSERT(!callbackObject || typeof callbackObject === 'function' || callbackObject instanceof EngineObject, 'callbackObject must be a funtion or EngineObject');
684
+
685
+ // make function to check for collision
686
+ const collisionTest = callbackObject ? typeof callbackObject === 'function' ?
687
+ (tileData, pos)=> callbackObject(tileData, pos) :
688
+ (tileData, pos)=> callbackObject.collideWithTile(tileData, pos) :
689
+ (tileData)=> tileData > 0;
690
+ const testFunction = (pos)=>
673
691
  {
674
- // check for tile collision
675
- localPos.set(pos.x - this.pos.x, pos.y - this.pos.y);
676
- const tileData = this.getCollisionData(localPos);
677
- return tileData && (!object || object.collideWithTile(tileData, pos));
692
+ const tileData = this.getCollisionData(localPos.set(pos.x - this.pos.x, pos.y - this.pos.y));
693
+ return tileData && collisionTest(tileData, pos);
678
694
  }
679
- debugRaycast && debugLine(posStart, posEnd, '#00f', .02);
680
- const hitPos = lineTest(posStart, posEnd, collisionTest, normal);
681
- if (hitPos)
695
+
696
+ // use line test against tile collision
697
+ const localPos = new Vector2;
698
+ const hitPos = lineTest(posStart, posEnd, testFunction, normal);
699
+ if (debugRaycast && hitPos)
682
700
  {
683
701
  const tilePos = hitPos.floor().add(vec2(.5));
684
- debugRaycast && debugRect(tilePos, vec2(1), '#f008');
685
- debugRaycast && debugLine(posStart, hitPos, '#f00', .02);
686
- debugRaycast && debugPoint(hitPos, '#0f0');
687
- debugRaycast && normal &&
688
- debugLine(hitPos, hitPos.add(normal), '#ff0', .02);
689
- return hitPos;
702
+ debugRect(tilePos, vec2(1), '#f008');
703
+ debugLine(posStart, posEnd, '#00f', .02);
704
+ debugLine(posStart, hitPos, '#f00', .02);
705
+ debugPoint(hitPos, '#0f0');
706
+ normal && debugLine(hitPos, hitPos.add(normal), '#ff0', .02);
690
707
  }
708
+ return hitPos;
691
709
  }
692
710
  }
@@ -7,6 +7,90 @@
7
7
 
8
8
  'use strict';
9
9
 
10
+ /**
11
+ * Timer object tracks how long has passed since it was set
12
+ * @memberof Engine
13
+ * @example
14
+ * let a = new Timer; // creates a timer that is not set
15
+ * a.set(3); // sets the timer to 3 seconds
16
+ *
17
+ * let b = new Timer(1); // creates a timer with 1 second left
18
+ * b.unset(); // unset the timer
19
+ */
20
+ class Timer
21
+ {
22
+ /** Create a timer object set time passed in
23
+ * @param {number} [timeLeft] - How much time left before the timer
24
+ * @param {boolean} [useRealTime] - Should the timer keep running even when the game is paused? (useful for UI) */
25
+ constructor(timeLeft, useRealTime=false)
26
+ {
27
+ ASSERT(timeLeft === undefined || isNumber(timeLeft), 'Constructed Timer is invalid.', timeLeft);
28
+ this.useRealTime = useRealTime;
29
+ const globalTime = this.getGlobalTime();
30
+ this.time = timeLeft === undefined ? undefined : globalTime + timeLeft;
31
+ this.setTime = timeLeft;
32
+ }
33
+
34
+ /** Set the timer with seconds passed in
35
+ * @param {number} [timeLeft] - How much time left before the timer is elapsed in seconds */
36
+ set(timeLeft=0)
37
+ {
38
+ ASSERT(isNumber(timeLeft), 'Timer is invalid.', timeLeft);
39
+ const globalTime = this.getGlobalTime();
40
+ this.time = globalTime + timeLeft;
41
+ this.setTime = timeLeft;
42
+ }
43
+
44
+ /** Set if the timer should keep running even when the game is paused
45
+ * @param {boolean} [useRealTime] */
46
+ setUseRealTime(useRealTime=true)
47
+ {
48
+ ASSERT(!this.isSet(), 'Cannot change global time setting while timer is set.');
49
+ this.useRealTime = useRealTime;
50
+ }
51
+
52
+ /** Unset the timer */
53
+ unset() { this.time = undefined; }
54
+
55
+ /** Returns true if set
56
+ * @return {boolean} */
57
+ isSet() { return this.time !== undefined; }
58
+
59
+ /** Returns true if set and has not elapsed
60
+ * @return {boolean} */
61
+ active() { return this.getGlobalTime() < this.time; }
62
+
63
+ /** Returns true if set and elapsed
64
+ * @return {boolean} */
65
+ elapsed() { return this.getGlobalTime() >= this.time; }
66
+
67
+ /** Get how long since elapsed, returns 0 if not set (returns negative if currently active)
68
+ * @return {number} */
69
+ get() { return this.isSet()? this.getGlobalTime() - this.time : 0; }
70
+
71
+ /** Get percentage elapsed based on time it was set to, returns 0 if not set
72
+ * @return {number} */
73
+ getPercent() { return this.isSet()? 1-percent(this.time - this.getGlobalTime(), 0, this.setTime) : 0; }
74
+
75
+ /** Get the time this timer was set to, returns 0 if not set
76
+ * @return {number} */
77
+ getSetTime() { return this.isSet() ? this.setTime : 0; }
78
+
79
+ /** Get the current global time this timer is based on
80
+ * @return {number} */
81
+ getGlobalTime() { return this.useRealTime ? timeReal : time; }
82
+
83
+ /** Returns this timer expressed as a string
84
+ * @return {string} */
85
+ toString() { return this.isSet() ? abs(this.get()) + ' seconds ' + (this.get()<0 ? 'before' : 'after' ) : 'unset'; }
86
+
87
+ /** Get how long since elapsed, returns 0 if not set (returns negative if currently active)
88
+ * @return {number} */
89
+ valueOf() { return this.get(); }
90
+ }
91
+
92
+ ///////////////////////////////////////////////////////////////////////////////
93
+
10
94
  /** Formats seconds to mm:ss style for display purposes
11
95
  * @param {number} t - time in seconds
12
96
  * @return {string}
@@ -93,84 +177,27 @@ function shareURL(title, url, callback)
93
177
 
94
178
  ///////////////////////////////////////////////////////////////////////////////
95
179
 
96
- /**
97
- * Timer object tracks how long has passed since it was set
98
- * @memberof Engine
99
- * @example
100
- * let a = new Timer; // creates a timer that is not set
101
- * a.set(3); // sets the timer to 3 seconds
102
- *
103
- * let b = new Timer(1); // creates a timer with 1 second left
104
- * b.unset(); // unset the timer
105
- */
106
- class Timer
180
+ /** Read save data from local storage
181
+ * @param {string} saveName - unique name for the game/save
182
+ * @param {Object} [defaultSaveData] - default values for save
183
+ * @return {Object}
184
+ * @memberof Utilities */
185
+ function readSaveData(saveName, defaultSaveData)
107
186
  {
108
- /** Create a timer object set time passed in
109
- * @param {number} [timeLeft] - How much time left before the timer
110
- * @param {boolean} [useRealTime] - Should the timer keep running even when the game is paused? (useful for UI) */
111
- constructor(timeLeft, useRealTime=false)
112
- {
113
- ASSERT(timeLeft === undefined || isNumber(timeLeft), 'Constructed Timer is invalid.', timeLeft);
114
- this.useRealTime = useRealTime;
115
- const globalTime = this.getGlobalTime();
116
- this.time = timeLeft === undefined ? undefined : globalTime + timeLeft;
117
- this.setTime = timeLeft;
118
- }
119
-
120
- /** Set the timer with seconds passed in
121
- * @param {number} [timeLeft] - How much time left before the timer is elapsed in seconds */
122
- set(timeLeft=0)
123
- {
124
- ASSERT(isNumber(timeLeft), 'Timer is invalid.', timeLeft);
125
- const globalTime = this.getGlobalTime();
126
- this.time = globalTime + timeLeft;
127
- this.setTime = timeLeft;
128
- }
129
-
130
- /** Set if the timer should keep running even when the game is paused
131
- * @param {boolean} [useRealTime] */
132
- setUseRealTime(useRealTime=true)
133
- {
134
- ASSERT(!this.isSet(), 'Cannot change global time setting while timer is set.');
135
- this.useRealTime = useRealTime;
136
- }
137
-
138
- /** Unset the timer */
139
- unset() { this.time = undefined; }
140
-
141
- /** Returns true if set
142
- * @return {boolean} */
143
- isSet() { return this.time !== undefined; }
144
-
145
- /** Returns true if set and has not elapsed
146
- * @return {boolean} */
147
- active() { return this.getGlobalTime() < this.time; }
148
-
149
- /** Returns true if set and elapsed
150
- * @return {boolean} */
151
- elapsed() { return this.getGlobalTime() >= this.time; }
152
-
153
- /** Get how long since elapsed, returns 0 if not set (returns negative if currently active)
154
- * @return {number} */
155
- get() { return this.isSet()? this.getGlobalTime() - this.time : 0; }
156
-
157
- /** Get percentage elapsed based on time it was set to, returns 0 if not set
158
- * @return {number} */
159
- getPercent() { return this.isSet()? 1-percent(this.time - this.getGlobalTime(), 0, this.setTime) : 0; }
160
-
161
- /** Get the time this timer was set to, returns 0 if not set
162
- * @return {number} */
163
- getSetTime() { return this.isSet() ? this.setTime : 0; }
164
-
165
- /** Get the current global time this timer is based on
166
- * @return {number} */
167
- getGlobalTime() { return this.useRealTime ? timeReal : time; }
168
-
169
- /** Returns this timer expressed as a string
170
- * @return {string} */
171
- toString() { return this.isSet() ? abs(this.get()) + ' seconds ' + (this.get()<0 ? 'before' : 'after' ) : 'unset'; }
187
+ ASSERT(isString(saveName), 'loadData requires saveName string');
188
+
189
+ // replace undefined values with defaults
190
+ const data = localStorage[saveName];
191
+ const loadedData = data ? JSON.parse(data) : {};
192
+ return { ...defaultSaveData, ...loadedData };
193
+ }
172
194
 
173
- /** Get how long since elapsed, returns 0 if not set (returns negative if currently active)
174
- * @return {number} */
175
- valueOf() { return this.get(); }
195
+ /** Write save data to local storage
196
+ * @param {string} saveName - unique name for the game/save
197
+ * @param {Object} saveData - object containing data to be saved
198
+ * @memberof Utilities */
199
+ function writeSaveData(saveName, saveData)
200
+ {
201
+ ASSERT(isString(saveName), 'saveData requires saveName string');
202
+ localStorage[saveName] = JSON.stringify(saveData);
176
203
  }
@@ -1,17 +0,0 @@
1
- Copyright (c) 2006-2010 Erin Catto http://www.gphysics.com
2
-
3
- This software is provided 'as-is', without any express or implied
4
- warranty. In no event will the authors be held liable for any damages
5
- arising from the use of this software.
6
-
7
- Permission is granted to anyone to use this software for any purpose,
8
- including commercial applications, and to alter it and redistribute it
9
- freely, subject to the following restrictions:
10
-
11
- 1. The origin of this software must not be misrepresented; you must not
12
- claim that you wrote the original software. If you use this software
13
- in a product, an acknowledgment in the product documentation would be
14
- appreciated but is not required.
15
- 2. Altered source versions must be plainly marked as such, and must not be
16
- misrepresented as being the original software.
17
- 3. This notice may not be removed or altered from any source distribution.