@litecanvas/utils 0.3.2 → 0.4.0
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.
- package/README.md +1 -0
- package/dist/all.js +200 -1
- package/dist/all.min.js +2 -1
- package/dist/grid.js +202 -0
- package/dist/grid.min.js +2 -0
- package/dist/vector.js +1 -1
- package/dist/vector.min.js +1 -1
- package/package.json +1 -1
- package/src/collision/README.md +2 -0
- package/src/grid/README.md +45 -0
- package/src/grid/_web.js +3 -0
- package/src/grid/index.js +205 -57
- package/src/index.js +1 -0
- package/src/vector/index.js +1 -1
package/README.md
CHANGED
|
@@ -6,6 +6,7 @@ Small collection of tools for developing games with [Litecanvas](https://github.
|
|
|
6
6
|
|
|
7
7
|
- **Camera**: Move-, zoom- and rotatable camera with shake. [Usage & Docs](https://github.com/litecanvas/utils/tree/main/src/camera)
|
|
8
8
|
- **Vector**: Modular 2D vector. [Usage & Docs](https://github.com/litecanvas/utils/tree/main/src/vector)
|
|
9
|
+
- **Grid** class. [Usage & Docs](https://github.com/litecanvas/utils/tree/main/src/grid)
|
|
9
10
|
- **Collision** utilities. [Usage & Docs](https://github.com/litecanvas/utils/tree/main/src/collision)
|
|
10
11
|
- And [some math utilities](https://github.com/litecanvas/utils/tree/main/src/math)
|
|
11
12
|
|
package/dist/all.js
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
__export(src_exports, {
|
|
11
11
|
Camera: () => Camera,
|
|
12
12
|
DOWN: () => DOWN,
|
|
13
|
+
Grid: () => Grid,
|
|
13
14
|
LEFT: () => LEFT,
|
|
14
15
|
ONE: () => ONE,
|
|
15
16
|
RIGHT: () => RIGHT,
|
|
@@ -198,6 +199,204 @@
|
|
|
198
199
|
}
|
|
199
200
|
};
|
|
200
201
|
|
|
202
|
+
// src/grid/index.js
|
|
203
|
+
var Grid = class _Grid {
|
|
204
|
+
/** @type {number} The grid width */
|
|
205
|
+
_w;
|
|
206
|
+
/** @type {number} The grid height */
|
|
207
|
+
_h;
|
|
208
|
+
/** @type {any[]} The grid cells */
|
|
209
|
+
_c;
|
|
210
|
+
/**
|
|
211
|
+
* @static
|
|
212
|
+
* @param {number} width
|
|
213
|
+
* @param {number} height
|
|
214
|
+
* @param {any[]} values
|
|
215
|
+
*/
|
|
216
|
+
static fromArray(width, height, values) {
|
|
217
|
+
const grid = new _Grid(width, height);
|
|
218
|
+
for (let i = 0; i < values.length; i++) {
|
|
219
|
+
grid._c[i] = values[i];
|
|
220
|
+
}
|
|
221
|
+
return grid;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* @param {number} width The grid width
|
|
225
|
+
* @param {number} height The grid height
|
|
226
|
+
*/
|
|
227
|
+
constructor(width, height) {
|
|
228
|
+
this.width = width;
|
|
229
|
+
this.height = height;
|
|
230
|
+
this.clear();
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Delete all cell values.
|
|
234
|
+
*/
|
|
235
|
+
clear() {
|
|
236
|
+
this._c = Array(this._w * this._h);
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* @param {number} value
|
|
240
|
+
*/
|
|
241
|
+
set width(value) {
|
|
242
|
+
this._w = Math.max(1, ~~value);
|
|
243
|
+
}
|
|
244
|
+
get width() {
|
|
245
|
+
return this._w;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* @param {number} value
|
|
249
|
+
*/
|
|
250
|
+
set height(value) {
|
|
251
|
+
this._h = Math.max(1, ~~value);
|
|
252
|
+
}
|
|
253
|
+
get height() {
|
|
254
|
+
return this._h;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* The the value of a grid's cell.
|
|
258
|
+
*
|
|
259
|
+
* @param {number} x
|
|
260
|
+
* @param {number} y
|
|
261
|
+
* @param {any} value
|
|
262
|
+
*/
|
|
263
|
+
set(x, y, value) {
|
|
264
|
+
this._c[this.pointToIndex(x, y)] = value;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Returns the value of a grid's cell.
|
|
268
|
+
*
|
|
269
|
+
* @param {number} x
|
|
270
|
+
* @param {number} y
|
|
271
|
+
* @returns {any}
|
|
272
|
+
*/
|
|
273
|
+
get(x, y) {
|
|
274
|
+
return this._c[this.pointToIndex(x, y)];
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Returns true if the which cell has any value not equal to `null` or `undefined`.
|
|
278
|
+
*
|
|
279
|
+
* @param {number} x
|
|
280
|
+
* @param {number} y
|
|
281
|
+
* @returns {boolean}
|
|
282
|
+
*/
|
|
283
|
+
has(x, y) {
|
|
284
|
+
return this.get(x, y) != null;
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Returns the total of cells.
|
|
288
|
+
*
|
|
289
|
+
* @returns {number}
|
|
290
|
+
*/
|
|
291
|
+
get length() {
|
|
292
|
+
return this._w * this._h;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Convert a grid point (X, Y) to a index.
|
|
296
|
+
*
|
|
297
|
+
* @param {number} x
|
|
298
|
+
* @param {number} y
|
|
299
|
+
* @returns {number} The index
|
|
300
|
+
*/
|
|
301
|
+
pointToIndex(x, y) {
|
|
302
|
+
return this.clampX(~~x) + this.clampY(~~y) * this._w;
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Convert index to a grid point X.
|
|
306
|
+
*
|
|
307
|
+
* @param {number} index
|
|
308
|
+
* @returns {number}
|
|
309
|
+
*/
|
|
310
|
+
indexToPointX(index) {
|
|
311
|
+
return index % this._w;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Convert index to a grid point Y.
|
|
315
|
+
*
|
|
316
|
+
* @param {number} index
|
|
317
|
+
* @returns {number}
|
|
318
|
+
*/
|
|
319
|
+
indexToPointY(index) {
|
|
320
|
+
return Math.floor(index / this._w);
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Loops over all grid cells.
|
|
324
|
+
*
|
|
325
|
+
* @callback GridForEachCallback
|
|
326
|
+
* @param {number} x
|
|
327
|
+
* @param {number} y
|
|
328
|
+
* @param {any} value
|
|
329
|
+
* @param {Grid} grid
|
|
330
|
+
* @returns {boolean?} returns `false` to stop/break the loop
|
|
331
|
+
*
|
|
332
|
+
* @param {GridForEachCallback} handler
|
|
333
|
+
* @param {boolean} [reverse=false]
|
|
334
|
+
*/
|
|
335
|
+
forEach(handler, reverse = false) {
|
|
336
|
+
let i = reverse ? this.length - 1 : 0, limit = reverse ? -1 : this.length, step = reverse ? -1 : 1;
|
|
337
|
+
while (i !== limit) {
|
|
338
|
+
const x = this.indexToPointX(i), y = this.indexToPointY(i), cellValue = this._c[i];
|
|
339
|
+
if (false === handler(x, y, cellValue, this)) break;
|
|
340
|
+
i += step;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* @param {*} value
|
|
345
|
+
*/
|
|
346
|
+
fill(value) {
|
|
347
|
+
this.forEach((x, y) => {
|
|
348
|
+
this.set(x, y, value);
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* @returns {Grid} the cloned grid
|
|
353
|
+
*/
|
|
354
|
+
clone() {
|
|
355
|
+
return _Grid.fromArray(this._w, this._h, this._c);
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* @param {number} y
|
|
359
|
+
* @returns {number}
|
|
360
|
+
*/
|
|
361
|
+
clampX(x) {
|
|
362
|
+
return _clamp(x, 0, this._w - 1);
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* @param {number} y
|
|
366
|
+
* @returns {number}
|
|
367
|
+
*/
|
|
368
|
+
clampY(y) {
|
|
369
|
+
return _clamp(y, 0, this._h - 1);
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Returns the cell values in a single array.
|
|
373
|
+
*
|
|
374
|
+
* @returns {any[]}
|
|
375
|
+
*/
|
|
376
|
+
toArray() {
|
|
377
|
+
return this._c.slice(0);
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* @param {string} separator
|
|
381
|
+
* @param {boolean} format
|
|
382
|
+
* @returns {string}
|
|
383
|
+
*/
|
|
384
|
+
toString(separator = " ", format = true) {
|
|
385
|
+
if (!format) return this._c.join(separator);
|
|
386
|
+
const rows = [];
|
|
387
|
+
this.forEach((x, y, value) => {
|
|
388
|
+
rows[y] = rows[y] || "";
|
|
389
|
+
rows[y] += value + separator;
|
|
390
|
+
});
|
|
391
|
+
return rows.join("\n");
|
|
392
|
+
}
|
|
393
|
+
};
|
|
394
|
+
function _clamp(value, min, max) {
|
|
395
|
+
if (value < min) return min;
|
|
396
|
+
if (value > max) return max;
|
|
397
|
+
return value;
|
|
398
|
+
}
|
|
399
|
+
|
|
201
400
|
// src/vector/index.js
|
|
202
401
|
var Vector = class {
|
|
203
402
|
/** @type {number} */
|
|
@@ -224,7 +423,7 @@
|
|
|
224
423
|
if (isvector(x)) {
|
|
225
424
|
return veceq(v, x.x, x.y);
|
|
226
425
|
}
|
|
227
|
-
return v.x === x && v.y ===
|
|
426
|
+
return v.x === x && v.y === y;
|
|
228
427
|
};
|
|
229
428
|
var veccopy = (v) => vec(v.x, v.y);
|
|
230
429
|
var vecset = (v, x, y = x) => {
|
package/dist/all.min.js
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
(()=>{var
|
|
1
|
+
(()=>{var j=Object.defineProperty;var D=(e,t)=>{for(var s in t)j(e,s,{get:t[s],enumerable:!0})};var T={};D(T,{Camera:()=>f,DOWN:()=>Q,Grid:()=>p,LEFT:()=>tt,ONE:()=>C,RIGHT:()=>K,UP:()=>J,Vector:()=>u,ZERO:()=>B,diff:()=>I,fract:()=>L,intersection:()=>_,isvector:()=>c,resolve:()=>X,vec:()=>h,vecadd:()=>z,vecconfig:()=>k,veccopy:()=>G,veccross:()=>V,vecdir:()=>F,vecdist:()=>W,vecdist2:()=>$,vecdiv:()=>y,vecdot:()=>U,veceq:()=>q,veclerp:()=>Z,veclimit:()=>S,vecmag:()=>O,vecmag2:()=>b,vecmult:()=>M,vecnorm:()=>R,vecrand:()=>v,vecrot:()=>N,vecset:()=>A,vecsub:()=>H,wave:()=>P});var I=(e,t)=>Math.abs(t-e)||0;var L=e=>e%1||0;var P=(e,t,s,i=Math.sin)=>e+(i(s)+1)/2*(t-e);var _=(e,t,s,i,r,o,n,a)=>{let l=Math.max(e,r),E=Math.min(e+s,r+n)-l,d=Math.max(t,o),g=Math.min(t+i,o+a)-d;return[l,d,E,g]};var X=(e,t,s,i,r,o,n,a)=>{let[l,E,d,g]=_(e,t,s,i,r,o,n,a),x="",m=e,w=t;return d<g?e<r?(x="right",m=r-s):(x="left",m=r+n):t<o?(x="bottom",w=o-i):(x="top",w=o+a),{direction:x,x:m,y:w}};var f=class{_engine=null;x=0;y=0;width=0;height=0;rotation=0;scale=1;_shake={x:0,y:0,removeListener:null};constructor(t=null){t=t||globalThis,this._engine=t,this.size(t.WIDTH||0,t.HEIGHT||0),this.x=this.width/2,this.y=this.height/2}size(t,s){this.width=t,this.height=s}start(t=!1){let s=this.width/2,i=this.height/2;this._engine.push(),this._engine.translate(s,i),this._engine.scale(this.scale),this._engine.rotate(this.rotation),this._engine.translate(-this.x+this._shake.x,-this.y+this._shake.y),t&&this._engine.cliprect(this.x,this.y,this.width,this.height)}end(){this._engine.pop()}lookAt(t,s){this.x=t,this.y=s}move(t,s){this.x+=t,this.y+=s}zoom(t){this.scale*=t}zoomTo(t){this.scale=t}rotate(t){this.rotation+=t}rotateTo(t){this.rotation=t}shake(t=.3,s=1){this.shaking()||(this._shake.removeListener=this._engine.listen("update",i=>{this._shake.x=this._engine.randi(-s,s),this._shake.y=this._engine.randi(-s,s),t-=i,t<=0&&this.unshake()}))}unshake(){this.shaking()&&(this._shake.removeListener(),this._shake.removeListener=null,this._shake.x=this._shake.y=0)}shaking(){return this._shake.removeListener!==null}};var p=class e{_w;_h;_c;static fromArray(t,s,i){let r=new e(t,s);for(let o=0;o<i.length;o++)r._c[o]=i[o];return r}constructor(t,s){this.width=t,this.height=s,this.clear()}clear(){this._c=Array(this._w*this._h)}set width(t){this._w=Math.max(1,~~t)}get width(){return this._w}set height(t){this._h=Math.max(1,~~t)}get height(){return this._h}set(t,s,i){this._c[this.pointToIndex(t,s)]=i}get(t,s){return this._c[this.pointToIndex(t,s)]}has(t,s){return this.get(t,s)!=null}get length(){return this._w*this._h}pointToIndex(t,s){return this.clampX(~~t)+this.clampY(~~s)*this._w}indexToPointX(t){return t%this._w}indexToPointY(t){return Math.floor(t/this._w)}forEach(t,s=!1){let i=s?this.length-1:0,r=s?-1:this.length,o=s?-1:1;for(;i!==r;){let n=this.indexToPointX(i),a=this.indexToPointY(i),l=this._c[i];if(t(n,a,l,this)===!1)break;i+=o}}fill(t){this.forEach((s,i)=>{this.set(s,i,t)})}clone(){return e.fromArray(this._w,this._h,this._c)}clampX(t){return Y(t,0,this._w-1)}clampY(t){return Y(t,0,this._h-1)}toArray(){return this._c.slice(0)}toString(t=" ",s=!0){if(!s)return this._c.join(t);let i=[];return this.forEach((r,o,n)=>{i[o]=i[o]||"",i[o]+=n+t}),i.join(`
|
|
2
|
+
`)}};function Y(e,t,s){return e<t?t:e>s?s:e}var u=class{x;y;constructor(t=0,s=t){this.x=t,this.y=s}toString(){return`Vector (${this.x}, ${this.y})`}},h=(e=0,t=e)=>new u(e,t),q=(e,t,s=t)=>c(t)?q(e,t.x,t.y):e.x===t&&e.y===s,G=e=>h(e.x,e.y),A=(e,t,s=t)=>{c(t)?A(e,t.x,t.y):(e.x=t,e.y=s)},z=(e,t,s=t)=>{c(t)?z(e,t.x,t.y):(e.x+=t,e.y+=s)},H=(e,t,s=t)=>{c(t)?H(e,t.x,t.y):(e.x-=t,e.y-=s)},M=(e,t,s=t)=>{c(t)?M(e,t.x,t.y):(e.x*=t,e.y*=s)},y=(e,t,s=t)=>{c(t)?y(e,t.x,t.y):(e.x/=t,e.y/=s)},N=(e,t)=>{let s=Math.cos(t),i=Math.sin(t);e.x=s*e.x-i*e.y,e.y=i*e.x+s*e.y},O=e=>Math.sqrt(e.x*e.x+e.y*e.y),b=e=>e.x*e.x+e.y*e.y,R=e=>{let t=O(e);t>0&&y(e,t)},S=(e,t)=>{let s=b(e);s>t*t&&(y(e,Math.sqrt(s)),M(e,t))},W=(e,t)=>{let s=e.x-t.x,i=e.y-t.y;return Math.sqrt(s*s+i*i)},$=(e,t)=>{let s=e.x-t.x,i=e.y-t.y;return s*s+i*i},F=e=>Math.atan2(e.y,e.x),U=(e,t)=>e.x*t.x+e.y*t.y,V=(e,t)=>e.x*t.y-e.y*t.x,Z=(e,t,s)=>{e.x+=(t.x-e.x)*s||0,e.y+=(t.y-e.y)*s||0},v=(e=1,t=e)=>{let s=k.random()*2*Math.PI,i=k.random()*(t-e)+e;return h(Math.cos(s)*i,Math.sin(s)*i)},c=e=>e instanceof u,k={random:()=>globalThis.rand?rand():Math.random()},B=h(0,0),C=h(1,1),J=h(0,-1),K=h(1,0),Q=h(0,1),tt=h(-1,0);globalThis.utils=T;})();
|
package/dist/grid.js
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
// src/grid/index.js
|
|
3
|
+
var Grid = class _Grid {
|
|
4
|
+
/** @type {number} The grid width */
|
|
5
|
+
_w;
|
|
6
|
+
/** @type {number} The grid height */
|
|
7
|
+
_h;
|
|
8
|
+
/** @type {any[]} The grid cells */
|
|
9
|
+
_c;
|
|
10
|
+
/**
|
|
11
|
+
* @static
|
|
12
|
+
* @param {number} width
|
|
13
|
+
* @param {number} height
|
|
14
|
+
* @param {any[]} values
|
|
15
|
+
*/
|
|
16
|
+
static fromArray(width, height, values) {
|
|
17
|
+
const grid = new _Grid(width, height);
|
|
18
|
+
for (let i = 0; i < values.length; i++) {
|
|
19
|
+
grid._c[i] = values[i];
|
|
20
|
+
}
|
|
21
|
+
return grid;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* @param {number} width The grid width
|
|
25
|
+
* @param {number} height The grid height
|
|
26
|
+
*/
|
|
27
|
+
constructor(width, height) {
|
|
28
|
+
this.width = width;
|
|
29
|
+
this.height = height;
|
|
30
|
+
this.clear();
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Delete all cell values.
|
|
34
|
+
*/
|
|
35
|
+
clear() {
|
|
36
|
+
this._c = Array(this._w * this._h);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* @param {number} value
|
|
40
|
+
*/
|
|
41
|
+
set width(value) {
|
|
42
|
+
this._w = Math.max(1, ~~value);
|
|
43
|
+
}
|
|
44
|
+
get width() {
|
|
45
|
+
return this._w;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* @param {number} value
|
|
49
|
+
*/
|
|
50
|
+
set height(value) {
|
|
51
|
+
this._h = Math.max(1, ~~value);
|
|
52
|
+
}
|
|
53
|
+
get height() {
|
|
54
|
+
return this._h;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The the value of a grid's cell.
|
|
58
|
+
*
|
|
59
|
+
* @param {number} x
|
|
60
|
+
* @param {number} y
|
|
61
|
+
* @param {any} value
|
|
62
|
+
*/
|
|
63
|
+
set(x, y, value) {
|
|
64
|
+
this._c[this.pointToIndex(x, y)] = value;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Returns the value of a grid's cell.
|
|
68
|
+
*
|
|
69
|
+
* @param {number} x
|
|
70
|
+
* @param {number} y
|
|
71
|
+
* @returns {any}
|
|
72
|
+
*/
|
|
73
|
+
get(x, y) {
|
|
74
|
+
return this._c[this.pointToIndex(x, y)];
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Returns true if the which cell has any value not equal to `null` or `undefined`.
|
|
78
|
+
*
|
|
79
|
+
* @param {number} x
|
|
80
|
+
* @param {number} y
|
|
81
|
+
* @returns {boolean}
|
|
82
|
+
*/
|
|
83
|
+
has(x, y) {
|
|
84
|
+
return this.get(x, y) != null;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Returns the total of cells.
|
|
88
|
+
*
|
|
89
|
+
* @returns {number}
|
|
90
|
+
*/
|
|
91
|
+
get length() {
|
|
92
|
+
return this._w * this._h;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Convert a grid point (X, Y) to a index.
|
|
96
|
+
*
|
|
97
|
+
* @param {number} x
|
|
98
|
+
* @param {number} y
|
|
99
|
+
* @returns {number} The index
|
|
100
|
+
*/
|
|
101
|
+
pointToIndex(x, y) {
|
|
102
|
+
return this.clampX(~~x) + this.clampY(~~y) * this._w;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Convert index to a grid point X.
|
|
106
|
+
*
|
|
107
|
+
* @param {number} index
|
|
108
|
+
* @returns {number}
|
|
109
|
+
*/
|
|
110
|
+
indexToPointX(index) {
|
|
111
|
+
return index % this._w;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Convert index to a grid point Y.
|
|
115
|
+
*
|
|
116
|
+
* @param {number} index
|
|
117
|
+
* @returns {number}
|
|
118
|
+
*/
|
|
119
|
+
indexToPointY(index) {
|
|
120
|
+
return Math.floor(index / this._w);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Loops over all grid cells.
|
|
124
|
+
*
|
|
125
|
+
* @callback GridForEachCallback
|
|
126
|
+
* @param {number} x
|
|
127
|
+
* @param {number} y
|
|
128
|
+
* @param {any} value
|
|
129
|
+
* @param {Grid} grid
|
|
130
|
+
* @returns {boolean?} returns `false` to stop/break the loop
|
|
131
|
+
*
|
|
132
|
+
* @param {GridForEachCallback} handler
|
|
133
|
+
* @param {boolean} [reverse=false]
|
|
134
|
+
*/
|
|
135
|
+
forEach(handler, reverse = false) {
|
|
136
|
+
let i = reverse ? this.length - 1 : 0, limit = reverse ? -1 : this.length, step = reverse ? -1 : 1;
|
|
137
|
+
while (i !== limit) {
|
|
138
|
+
const x = this.indexToPointX(i), y = this.indexToPointY(i), cellValue = this._c[i];
|
|
139
|
+
if (false === handler(x, y, cellValue, this)) break;
|
|
140
|
+
i += step;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* @param {*} value
|
|
145
|
+
*/
|
|
146
|
+
fill(value) {
|
|
147
|
+
this.forEach((x, y) => {
|
|
148
|
+
this.set(x, y, value);
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* @returns {Grid} the cloned grid
|
|
153
|
+
*/
|
|
154
|
+
clone() {
|
|
155
|
+
return _Grid.fromArray(this._w, this._h, this._c);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* @param {number} y
|
|
159
|
+
* @returns {number}
|
|
160
|
+
*/
|
|
161
|
+
clampX(x) {
|
|
162
|
+
return _clamp(x, 0, this._w - 1);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* @param {number} y
|
|
166
|
+
* @returns {number}
|
|
167
|
+
*/
|
|
168
|
+
clampY(y) {
|
|
169
|
+
return _clamp(y, 0, this._h - 1);
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Returns the cell values in a single array.
|
|
173
|
+
*
|
|
174
|
+
* @returns {any[]}
|
|
175
|
+
*/
|
|
176
|
+
toArray() {
|
|
177
|
+
return this._c.slice(0);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* @param {string} separator
|
|
181
|
+
* @param {boolean} format
|
|
182
|
+
* @returns {string}
|
|
183
|
+
*/
|
|
184
|
+
toString(separator = " ", format = true) {
|
|
185
|
+
if (!format) return this._c.join(separator);
|
|
186
|
+
const rows = [];
|
|
187
|
+
this.forEach((x, y, value) => {
|
|
188
|
+
rows[y] = rows[y] || "";
|
|
189
|
+
rows[y] += value + separator;
|
|
190
|
+
});
|
|
191
|
+
return rows.join("\n");
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
function _clamp(value, min, max) {
|
|
195
|
+
if (value < min) return min;
|
|
196
|
+
if (value > max) return max;
|
|
197
|
+
return value;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// src/grid/_web.js
|
|
201
|
+
globalThis.utils = Object.assign(globalThis.utils || {}, { Grid });
|
|
202
|
+
})();
|
package/dist/grid.min.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
(()=>{var e=class s{_w;_h;_c;static fromArray(t,i,h){let n=new s(t,i);for(let r=0;r<h.length;r++)n._c[r]=h[r];return n}constructor(t,i){this.width=t,this.height=i,this.clear()}clear(){this._c=Array(this._w*this._h)}set width(t){this._w=Math.max(1,~~t)}get width(){return this._w}set height(t){this._h=Math.max(1,~~t)}get height(){return this._h}set(t,i,h){this._c[this.pointToIndex(t,i)]=h}get(t,i){return this._c[this.pointToIndex(t,i)]}has(t,i){return this.get(t,i)!=null}get length(){return this._w*this._h}pointToIndex(t,i){return this.clampX(~~t)+this.clampY(~~i)*this._w}indexToPointX(t){return t%this._w}indexToPointY(t){return Math.floor(t/this._w)}forEach(t,i=!1){let h=i?this.length-1:0,n=i?-1:this.length,r=i?-1:1;for(;h!==n;){let o=this.indexToPointX(h),c=this.indexToPointY(h),_=this._c[h];if(t(o,c,_,this)===!1)break;h+=r}}fill(t){this.forEach((i,h)=>{this.set(i,h,t)})}clone(){return s.fromArray(this._w,this._h,this._c)}clampX(t){return l(t,0,this._w-1)}clampY(t){return l(t,0,this._h-1)}toArray(){return this._c.slice(0)}toString(t=" ",i=!0){if(!i)return this._c.join(t);let h=[];return this.forEach((n,r,o)=>{h[r]=h[r]||"",h[r]+=o+t}),h.join(`
|
|
2
|
+
`)}};function l(s,t,i){return s<t?t:s>i?i:s}globalThis.utils=Object.assign(globalThis.utils||{},{Grid:e});})();
|
package/dist/vector.js
CHANGED
package/dist/vector.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{var M=Object.defineProperty;var g=(t,o)=>{for(var s in o)M(t,s,{get:o[s],enumerable:!0})};var i={};g(i,{DOWN:()=>G,LEFT:()=>H,ONE:()=>w,RIGHT:()=>F,UP:()=>D,Vector:()=>n,ZERO:()=>j,isvector:()=>r,vec:()=>c,vecadd:()=>l,vecconfig:()=>
|
|
1
|
+
(()=>{var M=Object.defineProperty;var g=(t,o)=>{for(var s in o)M(t,s,{get:o[s],enumerable:!0})};var i={};g(i,{DOWN:()=>G,LEFT:()=>H,ONE:()=>w,RIGHT:()=>F,UP:()=>D,Vector:()=>n,ZERO:()=>j,isvector:()=>r,vec:()=>c,vecadd:()=>l,vecconfig:()=>y,veccopy:()=>m,veccross:()=>R,vecdir:()=>N,vecdist:()=>E,vecdist2:()=>I,vecdiv:()=>x,vecdot:()=>P,veceq:()=>a,veclerp:()=>U,veclimit:()=>O,vecmag:()=>u,vecmag2:()=>f,vecmult:()=>p,vecnorm:()=>T,vecrand:()=>$,vecrot:()=>q,vecset:()=>d,vecsub:()=>h});var n=class{x;y;constructor(o=0,s=o){this.x=o,this.y=s}toString(){return`Vector (${this.x}, ${this.y})`}},c=(t=0,o=t)=>new n(t,o),a=(t,o,s=o)=>r(o)?a(t,o.x,o.y):t.x===o&&t.y===s,m=t=>c(t.x,t.y),d=(t,o,s=o)=>{r(o)?d(t,o.x,o.y):(t.x=o,t.y=s)},l=(t,o,s=o)=>{r(o)?l(t,o.x,o.y):(t.x+=o,t.y+=s)},h=(t,o,s=o)=>{r(o)?h(t,o.x,o.y):(t.x-=o,t.y-=s)},p=(t,o,s=o)=>{r(o)?p(t,o.x,o.y):(t.x*=o,t.y*=s)},x=(t,o,s=o)=>{r(o)?x(t,o.x,o.y):(t.x/=o,t.y/=s)},q=(t,o)=>{let s=Math.cos(o),e=Math.sin(o);t.x=s*t.x-e*t.y,t.y=e*t.x+s*t.y},u=t=>Math.sqrt(t.x*t.x+t.y*t.y),f=t=>t.x*t.x+t.y*t.y,T=t=>{let o=u(t);o>0&&x(t,o)},O=(t,o)=>{let s=f(t);s>o*o&&(x(t,Math.sqrt(s)),p(t,o))},E=(t,o)=>{let s=t.x-o.x,e=t.y-o.y;return Math.sqrt(s*s+e*e)},I=(t,o)=>{let s=t.x-o.x,e=t.y-o.y;return s*s+e*e},N=t=>Math.atan2(t.y,t.x),P=(t,o)=>t.x*o.x+t.y*o.y,R=(t,o)=>t.x*o.y-t.y*o.x,U=(t,o,s)=>{t.x+=(o.x-t.x)*s||0,t.y+=(o.y-t.y)*s||0},$=(t=1,o=t)=>{let s=y.random()*2*Math.PI,e=y.random()*(o-t)+t;return c(Math.cos(s)*e,Math.sin(s)*e)},r=t=>t instanceof n,y={random:()=>globalThis.rand?rand():Math.random()},j=c(0,0),w=c(1,1),D=c(0,-1),F=c(1,0),G=c(0,1),H=c(-1,0);globalThis.utils=Object.assign(globalThis.utils||{},i);})();
|
package/package.json
CHANGED
package/src/collision/README.md
CHANGED
|
@@ -40,6 +40,8 @@ function draw() {
|
|
|
40
40
|
|
|
41
41
|
Syntax: `resolve(x1, y1, w1, h1, x2, y2, w2, h2): { direction: string, x: number, y: number }`
|
|
42
42
|
|
|
43
|
+
> Note: possible values for `direction` is `"top"`, `"botton"`, `"left"`, `"right"` or `""` (empty string, if no collision).
|
|
44
|
+
|
|
43
45
|
```js
|
|
44
46
|
import litecanvas from "litecanvas"
|
|
45
47
|
import { resolve } from "@litecanvas/utils"
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Grid
|
|
2
|
+
|
|
3
|
+
**CDN**: https://unpkg.com/@litecanvas/utils/dist/grid.js
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
Lets build an arena with [ASCII graphics](https://en.wikipedia.org/wiki/ASCII_art) like in classic roguelikes.
|
|
8
|
+
|
|
9
|
+
```js
|
|
10
|
+
// make a grid 13x13
|
|
11
|
+
let grid = new utils.Grid(13, 13)
|
|
12
|
+
|
|
13
|
+
// fill the entire grid with "."
|
|
14
|
+
grid.fill(".")
|
|
15
|
+
|
|
16
|
+
// put a '@' in the middle
|
|
17
|
+
grid.set(grid.width / 2, grid.height / 2, "@")
|
|
18
|
+
|
|
19
|
+
// put '#' around the grid
|
|
20
|
+
grid.forEach((x, y, cellValue) => {
|
|
21
|
+
if (x === 0 || y === 0 || x === grid.width - 1 || y === grid.height - 1) {
|
|
22
|
+
grid.set(x, y, "#")
|
|
23
|
+
}
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
document.body.innerHTML = "<pre>" + grid.toString() + "</pre>"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The result:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
# # # # # # # # # # # # #
|
|
33
|
+
# . . . . . . . . . . . #
|
|
34
|
+
# . . . . . . . . . . . #
|
|
35
|
+
# . . . . . . . . . . . #
|
|
36
|
+
# . . . . . . . . . . . #
|
|
37
|
+
# . . . . . . . . . . . #
|
|
38
|
+
# . . . . . @ . . . . . #
|
|
39
|
+
# . . . . . . . . . . . #
|
|
40
|
+
# . . . . . . . . . . . #
|
|
41
|
+
# . . . . . . . . . . . #
|
|
42
|
+
# . . . . . . . . . . . #
|
|
43
|
+
# . . . . . . . . . . . #
|
|
44
|
+
# # # # # # # # # # # # #
|
|
45
|
+
```
|
package/src/grid/_web.js
ADDED
package/src/grid/index.js
CHANGED
|
@@ -1,91 +1,239 @@
|
|
|
1
|
-
class Grid {
|
|
1
|
+
export default class Grid {
|
|
2
|
+
/** @type {number} The grid width */
|
|
3
|
+
_w
|
|
4
|
+
|
|
5
|
+
/** @type {number} The grid height */
|
|
6
|
+
_h
|
|
7
|
+
|
|
8
|
+
/** @type {any[]} The grid cells */
|
|
9
|
+
_c
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @static
|
|
13
|
+
* @param {number} width
|
|
14
|
+
* @param {number} height
|
|
15
|
+
* @param {any[]} values
|
|
16
|
+
*/
|
|
17
|
+
static fromArray(width, height, values) {
|
|
18
|
+
const grid = new Grid(width, height)
|
|
19
|
+
for (let i = 0; i < values.length; i++) {
|
|
20
|
+
grid._c[i] = values[i]
|
|
21
|
+
}
|
|
22
|
+
return grid
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @param {number} width The grid width
|
|
27
|
+
* @param {number} height The grid height
|
|
28
|
+
*/
|
|
2
29
|
constructor(width, height) {
|
|
3
|
-
this.
|
|
4
|
-
this.
|
|
30
|
+
this.width = width
|
|
31
|
+
this.height = height
|
|
5
32
|
this.clear()
|
|
6
33
|
}
|
|
7
34
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Delete all cell values.
|
|
37
|
+
*/
|
|
38
|
+
clear() {
|
|
39
|
+
this._c = Array(this._w * this._h)
|
|
11
40
|
}
|
|
12
41
|
|
|
13
|
-
|
|
14
|
-
|
|
42
|
+
/**
|
|
43
|
+
* @param {number} value
|
|
44
|
+
*/
|
|
45
|
+
set width(value) {
|
|
46
|
+
this._w = Math.max(1, ~~value)
|
|
15
47
|
}
|
|
16
48
|
|
|
17
|
-
|
|
18
|
-
return this.
|
|
49
|
+
get width() {
|
|
50
|
+
return this._w
|
|
19
51
|
}
|
|
20
52
|
|
|
21
|
-
|
|
22
|
-
|
|
53
|
+
/**
|
|
54
|
+
* @param {number} value
|
|
55
|
+
*/
|
|
56
|
+
set height(value) {
|
|
57
|
+
this._h = Math.max(1, ~~value)
|
|
23
58
|
}
|
|
24
59
|
|
|
25
60
|
get height() {
|
|
26
|
-
return this.
|
|
61
|
+
return this._h
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The the value of a grid's cell.
|
|
66
|
+
*
|
|
67
|
+
* @param {number} x
|
|
68
|
+
* @param {number} y
|
|
69
|
+
* @param {any} value
|
|
70
|
+
*/
|
|
71
|
+
set(x, y, value) {
|
|
72
|
+
this._c[this.pointToIndex(x, y)] = value
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Returns the value of a grid's cell.
|
|
77
|
+
*
|
|
78
|
+
* @param {number} x
|
|
79
|
+
* @param {number} y
|
|
80
|
+
* @returns {any}
|
|
81
|
+
*/
|
|
82
|
+
get(x, y) {
|
|
83
|
+
return this._c[this.pointToIndex(x, y)]
|
|
27
84
|
}
|
|
28
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Returns true if the which cell has any value not equal to `null` or `undefined`.
|
|
88
|
+
*
|
|
89
|
+
* @param {number} x
|
|
90
|
+
* @param {number} y
|
|
91
|
+
* @returns {boolean}
|
|
92
|
+
*/
|
|
93
|
+
has(x, y) {
|
|
94
|
+
return this.get(x, y) != null
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Returns the total of cells.
|
|
99
|
+
*
|
|
100
|
+
* @returns {number}
|
|
101
|
+
*/
|
|
29
102
|
get length() {
|
|
30
|
-
return this.
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
103
|
+
return this._w * this._h
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Convert a grid point (X, Y) to a index.
|
|
108
|
+
*
|
|
109
|
+
* @param {number} x
|
|
110
|
+
* @param {number} y
|
|
111
|
+
* @returns {number} The index
|
|
112
|
+
*/
|
|
113
|
+
pointToIndex(x, y) {
|
|
114
|
+
return this.clampX(~~x) + this.clampY(~~y) * this._w
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Convert index to a grid point X.
|
|
119
|
+
*
|
|
120
|
+
* @param {number} index
|
|
121
|
+
* @returns {number}
|
|
122
|
+
*/
|
|
123
|
+
indexToPointX(index) {
|
|
124
|
+
return index % this._w
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Convert index to a grid point Y.
|
|
129
|
+
*
|
|
130
|
+
* @param {number} index
|
|
131
|
+
* @returns {number}
|
|
132
|
+
*/
|
|
133
|
+
indexToPointY(index) {
|
|
134
|
+
return Math.floor(index / this._w)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Loops over all grid cells.
|
|
139
|
+
*
|
|
140
|
+
* @callback GridForEachCallback
|
|
141
|
+
* @param {number} x
|
|
142
|
+
* @param {number} y
|
|
143
|
+
* @param {any} value
|
|
144
|
+
* @param {Grid} grid
|
|
145
|
+
* @returns {boolean?} returns `false` to stop/break the loop
|
|
146
|
+
*
|
|
147
|
+
* @param {GridForEachCallback} handler
|
|
148
|
+
* @param {boolean} [reverse=false]
|
|
149
|
+
*/
|
|
150
|
+
forEach(handler, reverse = false) {
|
|
151
|
+
let i = reverse ? this.length - 1 : 0,
|
|
152
|
+
limit = reverse ? -1 : this.length,
|
|
153
|
+
step = reverse ? -1 : 1
|
|
154
|
+
|
|
155
|
+
while (i !== limit) {
|
|
156
|
+
const x = this.indexToPointX(i),
|
|
157
|
+
y = this.indexToPointY(i),
|
|
158
|
+
cellValue = this._c[i]
|
|
159
|
+
|
|
160
|
+
if (false === handler(x, y, cellValue, this)) break
|
|
161
|
+
|
|
162
|
+
i += step
|
|
52
163
|
}
|
|
53
|
-
return this
|
|
54
164
|
}
|
|
55
165
|
|
|
56
|
-
|
|
57
|
-
|
|
166
|
+
/**
|
|
167
|
+
* @param {*} value
|
|
168
|
+
*/
|
|
169
|
+
fill(value) {
|
|
170
|
+
this.forEach((x, y) => {
|
|
171
|
+
this.set(x, y, value)
|
|
172
|
+
})
|
|
58
173
|
}
|
|
59
174
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
175
|
+
/**
|
|
176
|
+
* @returns {Grid} the cloned grid
|
|
177
|
+
*/
|
|
178
|
+
clone() {
|
|
179
|
+
return Grid.fromArray(this._w, this._h, this._c)
|
|
63
180
|
}
|
|
64
181
|
|
|
65
|
-
|
|
66
|
-
|
|
182
|
+
/**
|
|
183
|
+
* @param {number} y
|
|
184
|
+
* @returns {number}
|
|
185
|
+
*/
|
|
186
|
+
clampX(x) {
|
|
187
|
+
return _clamp(x, 0, this._w - 1)
|
|
67
188
|
}
|
|
68
189
|
|
|
69
|
-
|
|
70
|
-
|
|
190
|
+
/**
|
|
191
|
+
* @param {number} y
|
|
192
|
+
* @returns {number}
|
|
193
|
+
*/
|
|
194
|
+
clampY(y) {
|
|
195
|
+
return _clamp(y, 0, this._h - 1)
|
|
71
196
|
}
|
|
72
197
|
|
|
198
|
+
/**
|
|
199
|
+
* Returns the cell values in a single array.
|
|
200
|
+
*
|
|
201
|
+
* @returns {any[]}
|
|
202
|
+
*/
|
|
73
203
|
toArray() {
|
|
74
|
-
return this.
|
|
204
|
+
return this._c.slice(0)
|
|
75
205
|
}
|
|
76
206
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
207
|
+
/**
|
|
208
|
+
* @param {string} separator
|
|
209
|
+
* @param {boolean} format
|
|
210
|
+
* @returns {string}
|
|
211
|
+
*/
|
|
212
|
+
toString(separator = " ", format = true) {
|
|
213
|
+
if (!format) return this._c.join(separator)
|
|
80
214
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
215
|
+
const rows = []
|
|
216
|
+
this.forEach((x, y, value) => {
|
|
217
|
+
rows[y] = rows[y] || ""
|
|
218
|
+
rows[y] += value + separator
|
|
219
|
+
})
|
|
87
220
|
|
|
88
|
-
|
|
89
|
-
return Math.min(Math.max(n, min), max)
|
|
221
|
+
return rows.join("\n")
|
|
90
222
|
}
|
|
91
223
|
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Constrains a number between `min` and `max`.
|
|
227
|
+
*
|
|
228
|
+
* @param {number} value
|
|
229
|
+
* @param {number} min
|
|
230
|
+
* @param {number} max
|
|
231
|
+
* @returns {number}
|
|
232
|
+
*/
|
|
233
|
+
function _clamp(value, min, max) {
|
|
234
|
+
if (value < min) return min
|
|
235
|
+
if (value > max) return max
|
|
236
|
+
return value
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function _fill(x, y) {}
|
package/src/index.js
CHANGED
|
@@ -4,4 +4,5 @@ export { default as wave } from "./math/wave.js"
|
|
|
4
4
|
export { default as resolve } from "./collision/resolve.js"
|
|
5
5
|
export { default as intersection } from "./collision/intersection.js"
|
|
6
6
|
export { default as Camera } from "./camera/index.js"
|
|
7
|
+
export { default as Grid } from "./grid/index.js"
|
|
7
8
|
export * from "./vector/index.js"
|