q5play 4.1.2 → 4.2.2
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/package.json +1 -1
- package/py.typed +0 -0
- package/q5play.d.ts +1382 -160
- package/q5play.js +847 -204
- package/q5play.pyi +5007 -0
package/q5play.js
CHANGED
|
@@ -12,21 +12,19 @@
|
|
|
12
12
|
* |__/ |__/ \______/
|
|
13
13
|
*
|
|
14
14
|
* @package q5play
|
|
15
|
-
* @version 4.
|
|
15
|
+
* @version 4.2
|
|
16
16
|
* @author quinton-ashley
|
|
17
17
|
* @website https://q5play.org
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
let q5play_version = '4.
|
|
20
|
+
let q5play_version = '4.2';
|
|
21
21
|
|
|
22
|
-
if (typeof globalThis.Q5 == 'undefined') {
|
|
22
|
+
if (typeof globalThis.Q5 == 'undefined' && typeof globalThis.p5 == 'undefined') {
|
|
23
23
|
console.error('q5play requires q5.js to be loaded first. Visit https://q5js.org to learn more.');
|
|
24
|
-
if (typeof globalThis.p5 != 'undefined') {
|
|
25
|
-
console.error('p5.js is not compatible with q5play. https://github.com/processing/p5.js/issues/7737');
|
|
26
|
-
}
|
|
27
24
|
}
|
|
28
25
|
|
|
29
|
-
let box2dPromise
|
|
26
|
+
let box2dPromise,
|
|
27
|
+
using_p5 = false;
|
|
30
28
|
|
|
31
29
|
// called when a new instance of Q5 is created
|
|
32
30
|
async function q5playPreSetup(q) {
|
|
@@ -150,6 +148,7 @@ async function q5playPreSetup(q) {
|
|
|
150
148
|
b2CreateChain,
|
|
151
149
|
b2Chain_GetSegmentCount,
|
|
152
150
|
b2Chain_GetSegments,
|
|
151
|
+
b2DestroyChain,
|
|
153
152
|
|
|
154
153
|
/* Body */
|
|
155
154
|
b2BodyType,
|
|
@@ -249,7 +248,7 @@ async function q5playPreSetup(q) {
|
|
|
249
248
|
this.context = 'web';
|
|
250
249
|
|
|
251
250
|
this.update = () => q5playUpdate.call($, q);
|
|
252
|
-
this.
|
|
251
|
+
this.draw = () => q5playPostDraw.call($, q);
|
|
253
252
|
|
|
254
253
|
if (window.matchMedia) {
|
|
255
254
|
this.hasMouse = window.matchMedia('(any-hover: none)').matches ? false : true;
|
|
@@ -327,7 +326,7 @@ async function q5playPreSetup(q) {
|
|
|
327
326
|
|
|
328
327
|
async splashScreen() {
|
|
329
328
|
if (document.getElementById('made-with-q5play')) return;
|
|
330
|
-
if (!
|
|
329
|
+
if (!using_p5) $._incrementPreload();
|
|
331
330
|
let d = document.createElement('div');
|
|
332
331
|
d.id = 'made-with-q5play';
|
|
333
332
|
d.style =
|
|
@@ -359,27 +358,30 @@ async function q5playPreSetup(q) {
|
|
|
359
358
|
d.style.display = 'none';
|
|
360
359
|
d.remove();
|
|
361
360
|
document.getElementById('made-with-q5play')?.remove();
|
|
362
|
-
if (!
|
|
361
|
+
if (!using_p5) $._decrementPreload();
|
|
363
362
|
}
|
|
364
363
|
};
|
|
365
364
|
|
|
366
365
|
$.q5play = new $.Q5Play();
|
|
367
366
|
delete $.Q5Play;
|
|
368
367
|
|
|
369
|
-
|
|
370
|
-
|
|
368
|
+
using_p5 = !$._q5;
|
|
369
|
+
if (using_p5 && p5.VERSION[0] != 2) {
|
|
370
|
+
throw new Error(`q5play requires q5.js or p5.js v2. Detected version: ${p5.VERSION}. Please upgrade.`);
|
|
371
|
+
}
|
|
371
372
|
|
|
372
|
-
// in q5play the default angle mode is degrees
|
|
373
373
|
const DEGREES = $.DEGREES,
|
|
374
374
|
DEGTORAD = Math.PI / 180,
|
|
375
375
|
RADTODEG = 180 / Math.PI;
|
|
376
|
+
|
|
377
|
+
// in q5play the default angle mode is degrees
|
|
376
378
|
$.angleMode(DEGREES);
|
|
377
379
|
|
|
378
380
|
// in q5play the default color mode is float RGB
|
|
379
|
-
$.colorMode($.RGB, 1);
|
|
381
|
+
if (!using_p5) $.colorMode($.RGB, 1);
|
|
380
382
|
|
|
381
383
|
// in q5play the default image mode is center
|
|
382
|
-
$.imageMode($.CENTER);
|
|
384
|
+
if (!using_p5) $.imageMode($.CENTER);
|
|
383
385
|
|
|
384
386
|
const ZERO_VEC = new b2Vec2(0, 0),
|
|
385
387
|
ZERO_ROT = b2MakeRot(0),
|
|
@@ -396,7 +398,9 @@ async function q5playPreSetup(q) {
|
|
|
396
398
|
const scaleFrom = (x, y) => ({ x: x * meterSize, y: y * meterSize });
|
|
397
399
|
|
|
398
400
|
const linearSlop = 0.005,
|
|
399
|
-
angularSlop = 0.
|
|
401
|
+
angularSlop = 0.0333;
|
|
402
|
+
|
|
403
|
+
let visualSlop = 0.5;
|
|
400
404
|
|
|
401
405
|
const isSlop = (val) => Math.abs(val) <= linearSlop;
|
|
402
406
|
const fixRound = (val) => {
|
|
@@ -490,13 +494,13 @@ async function q5playPreSetup(q) {
|
|
|
490
494
|
geom = this.geom;
|
|
491
495
|
|
|
492
496
|
if (type == 0) {
|
|
493
|
-
let hw = geom._hw * scaleX,
|
|
494
|
-
hh = geom._hh * scaleY,
|
|
497
|
+
let hw = geom._hw * Math.abs(scaleX),
|
|
498
|
+
hh = geom._hh * Math.abs(scaleY),
|
|
495
499
|
rr;
|
|
496
500
|
|
|
497
501
|
if (!geom._rr) geom = b2MakeBox(hw, hh);
|
|
498
502
|
else {
|
|
499
|
-
rr = geom._rr * Math.min(scaleX, scaleY);
|
|
503
|
+
rr = geom._rr * Math.min(Math.abs(scaleX), Math.abs(scaleY));
|
|
500
504
|
geom = b2MakeRoundedBox(hw, hh, rr);
|
|
501
505
|
}
|
|
502
506
|
b2Shape_SetPolygon(id, geom);
|
|
@@ -504,11 +508,44 @@ async function q5playPreSetup(q) {
|
|
|
504
508
|
geom._hh = hh;
|
|
505
509
|
geom._rr = rr;
|
|
506
510
|
this.geom = geom;
|
|
511
|
+
} else if (type == 1) {
|
|
512
|
+
// convex polygon
|
|
513
|
+
geom = b2Shape_GetPolygon(id);
|
|
514
|
+
let verts = [];
|
|
515
|
+
for (let i = 0; i < geom.count; i++) {
|
|
516
|
+
const v = geom.GetVertex(i);
|
|
517
|
+
verts.push({ x: v.x * scaleX, y: v.y * scaleY });
|
|
518
|
+
}
|
|
519
|
+
let hull = b2ComputeHull(verts);
|
|
520
|
+
let rr = geom.radius * Math.min(scaleX, scaleY);
|
|
521
|
+
geom = rr ? b2MakeOffsetRoundedPolygon(hull, ZERO_VEC, ZERO_ROT, rr) : b2MakePolygon(hull, 0);
|
|
522
|
+
b2Shape_SetPolygon(id, geom);
|
|
523
|
+
this.geom = geom;
|
|
507
524
|
} else if (type == 3) {
|
|
508
|
-
geom.radius *= scaleX;
|
|
525
|
+
geom.radius *= Math.abs(scaleX);
|
|
509
526
|
b2Shape_SetCircle(id, geom);
|
|
510
527
|
this.geom = geom;
|
|
528
|
+
} else if (type == 4 || type == 7) {
|
|
529
|
+
// capsule (single or capsule chain segment)
|
|
530
|
+
geom = b2Shape_GetCapsule(id);
|
|
531
|
+
geom.center1.x *= scaleX;
|
|
532
|
+
geom.center1.y *= scaleY;
|
|
533
|
+
geom.center2.x *= scaleX;
|
|
534
|
+
geom.center2.y *= scaleY;
|
|
535
|
+
geom.radius *= Math.min(scaleX, scaleY);
|
|
536
|
+
b2Shape_SetCapsule(id, geom);
|
|
537
|
+
this.geom = geom;
|
|
538
|
+
} else if (type == 5) {
|
|
539
|
+
// segment
|
|
540
|
+
geom = b2Shape_GetSegment(id);
|
|
541
|
+
geom.point1.x *= scaleX;
|
|
542
|
+
geom.point1.y *= scaleY;
|
|
543
|
+
geom.point2.x *= scaleX;
|
|
544
|
+
geom.point2.y *= scaleY;
|
|
545
|
+
b2Shape_SetSegment(id, geom);
|
|
546
|
+
this.geom = geom;
|
|
511
547
|
}
|
|
548
|
+
// type 6 (chain) - handled by sprite's scaleBy, which rescales and sets all segments
|
|
512
549
|
}
|
|
513
550
|
|
|
514
551
|
_enableContactEvents(val = true) {
|
|
@@ -835,7 +872,13 @@ async function q5playPreSetup(q) {
|
|
|
835
872
|
if (flipY) ani.scale.y = -ani.scale.y;
|
|
836
873
|
|
|
837
874
|
if (start < 0) start = ani.length + start;
|
|
838
|
-
if (start !== undefined)
|
|
875
|
+
if (start !== undefined) {
|
|
876
|
+
ani._frame = start;
|
|
877
|
+
} else {
|
|
878
|
+
// reset so recycled animations don't immediately resolve
|
|
879
|
+
ani._frame = 0;
|
|
880
|
+
ani.playing = true;
|
|
881
|
+
}
|
|
839
882
|
|
|
840
883
|
if (end !== undefined) ani.goToFrame(end);
|
|
841
884
|
else if (ani._frame == ani.lastFrame) resolve();
|
|
@@ -952,7 +995,7 @@ async function q5playPreSetup(q) {
|
|
|
952
995
|
|
|
953
996
|
this._posX = x;
|
|
954
997
|
this._posY = y;
|
|
955
|
-
this._pos = $.createVector.call(
|
|
998
|
+
this._pos = $.createVector.call($, 0, 0);
|
|
956
999
|
|
|
957
1000
|
let _this = this;
|
|
958
1001
|
Object.defineProperties(this._pos, {
|
|
@@ -974,7 +1017,7 @@ async function q5playPreSetup(q) {
|
|
|
974
1017
|
}
|
|
975
1018
|
});
|
|
976
1019
|
|
|
977
|
-
this._canvasPos = $.createVector.call(
|
|
1020
|
+
this._canvasPos = $.createVector.call($, 0, 0);
|
|
978
1021
|
|
|
979
1022
|
Object.defineProperties(this._canvasPos, {
|
|
980
1023
|
x: {
|
|
@@ -994,16 +1037,16 @@ async function q5playPreSetup(q) {
|
|
|
994
1037
|
});
|
|
995
1038
|
|
|
996
1039
|
this._direction = 0;
|
|
997
|
-
this.
|
|
998
|
-
this.
|
|
1040
|
+
this.vx = 0;
|
|
1041
|
+
this.vy = 0;
|
|
999
1042
|
this._velSynced = true;
|
|
1000
|
-
this._vel = $.createVector.call(
|
|
1043
|
+
this._vel = $.createVector.call($, 0, 0);
|
|
1001
1044
|
this._vel._useCache = true;
|
|
1002
1045
|
|
|
1003
1046
|
this._syncVel = () => {
|
|
1004
1047
|
let v = b2Body_GetLinearVelocity(this.bdID);
|
|
1005
|
-
this.
|
|
1006
|
-
this.
|
|
1048
|
+
this.vx = v.x;
|
|
1049
|
+
this.vy = v.y;
|
|
1007
1050
|
this._velSynced = true;
|
|
1008
1051
|
};
|
|
1009
1052
|
|
|
@@ -1013,13 +1056,13 @@ async function q5playPreSetup(q) {
|
|
|
1013
1056
|
if (!_this._velSynced && _this._physicsEnabled) {
|
|
1014
1057
|
_this._syncVel();
|
|
1015
1058
|
}
|
|
1016
|
-
return _this.
|
|
1059
|
+
return _this.vx;
|
|
1017
1060
|
},
|
|
1018
1061
|
set(val) {
|
|
1019
1062
|
if (_this._physicsEnabled) {
|
|
1020
1063
|
b2Body_SetLinearVelocity(_this.bdID, new b2Vec2(val, this.y));
|
|
1021
1064
|
}
|
|
1022
|
-
_this.
|
|
1065
|
+
_this.vx = val;
|
|
1023
1066
|
this._magCached = this._directionCached = false;
|
|
1024
1067
|
}
|
|
1025
1068
|
},
|
|
@@ -1028,13 +1071,13 @@ async function q5playPreSetup(q) {
|
|
|
1028
1071
|
if (!_this._velSynced && _this._physicsEnabled) {
|
|
1029
1072
|
_this._syncVel();
|
|
1030
1073
|
}
|
|
1031
|
-
return _this.
|
|
1074
|
+
return _this.vy;
|
|
1032
1075
|
},
|
|
1033
1076
|
set(val) {
|
|
1034
1077
|
if (_this._physicsEnabled) {
|
|
1035
1078
|
b2Body_SetLinearVelocity(_this.bdID, new b2Vec2(this.x, val));
|
|
1036
1079
|
}
|
|
1037
|
-
_this.
|
|
1080
|
+
_this.vy = val;
|
|
1038
1081
|
this._magCached = this._directionCached = false;
|
|
1039
1082
|
}
|
|
1040
1083
|
}
|
|
@@ -1153,8 +1196,7 @@ async function q5playPreSetup(q) {
|
|
|
1153
1196
|
set(val) {
|
|
1154
1197
|
if (!val || val == this._x) return;
|
|
1155
1198
|
if (_this.watch) _this.mod[26] = true;
|
|
1156
|
-
|
|
1157
|
-
_this.scaleBy(scaleX, 1);
|
|
1199
|
+
_this.scaleBy(val / this._x, 1);
|
|
1158
1200
|
this._x = val;
|
|
1159
1201
|
this._avg = (this._x + this._y) * 0.5;
|
|
1160
1202
|
_this._shouldScale = this._avg != 1;
|
|
@@ -1168,8 +1210,7 @@ async function q5playPreSetup(q) {
|
|
|
1168
1210
|
set(val) {
|
|
1169
1211
|
if (!val || val == this._y) return;
|
|
1170
1212
|
if (_this.watch) _this.mod[26] = true;
|
|
1171
|
-
|
|
1172
|
-
_this.scaleBy(1, scaleY);
|
|
1213
|
+
_this.scaleBy(1, val / this._y);
|
|
1173
1214
|
this._y = val;
|
|
1174
1215
|
this._avg = (this._x + this._y) * 0.5;
|
|
1175
1216
|
_this._shouldScale = this._avg != 1;
|
|
@@ -1199,10 +1240,10 @@ async function q5playPreSetup(q) {
|
|
|
1199
1240
|
else this.addCollider(...args);
|
|
1200
1241
|
}
|
|
1201
1242
|
|
|
1202
|
-
this.
|
|
1243
|
+
this.prevX = x;
|
|
1244
|
+
this.prevY = y;
|
|
1203
1245
|
this.prevRotation = 0;
|
|
1204
|
-
|
|
1205
|
-
this._destIdx = 0;
|
|
1246
|
+
|
|
1206
1247
|
this._debug = false;
|
|
1207
1248
|
|
|
1208
1249
|
if (!group._isAllSpritesGroup) $.allSprites.push(this);
|
|
@@ -1512,10 +1553,10 @@ async function q5playPreSetup(q) {
|
|
|
1512
1553
|
geom.center2 = vecs[i];
|
|
1513
1554
|
geom.radius = rr ? rr / meterSize : 0.02;
|
|
1514
1555
|
id = b2CreateCapsuleShape(bdID, shape.def, geom);
|
|
1515
|
-
let
|
|
1516
|
-
|
|
1517
|
-
shapes.push(
|
|
1518
|
-
shapeDict[id.index1] =
|
|
1556
|
+
let sh = new Collider(this);
|
|
1557
|
+
sh._init(id, 7, geom);
|
|
1558
|
+
shapes.push(sh);
|
|
1559
|
+
shapeDict[id.index1] = sh;
|
|
1519
1560
|
}
|
|
1520
1561
|
shape = null;
|
|
1521
1562
|
this.isSuperFast = true;
|
|
@@ -1533,12 +1574,17 @@ async function q5playPreSetup(q) {
|
|
|
1533
1574
|
|
|
1534
1575
|
id = b2CreateChain(bdID, shape.def);
|
|
1535
1576
|
shape._init(id, 6);
|
|
1577
|
+
shape.friction = 0.5;
|
|
1578
|
+
shape._points = vecs.map((v) => ({ x: v.x, y: v.y }));
|
|
1579
|
+
shape._isLoopChain = vecs.isLoop;
|
|
1580
|
+
this._chain = shape;
|
|
1536
1581
|
|
|
1537
1582
|
let count = b2Chain_GetSegmentCount(id);
|
|
1538
1583
|
let segments = b2Chain_GetSegments(id, count);
|
|
1539
1584
|
for (let segID of segments) {
|
|
1540
1585
|
let sh = new Collider(this);
|
|
1541
1586
|
sh._init(segID, 6);
|
|
1587
|
+
sh.friction = 0.5;
|
|
1542
1588
|
shapes.push(sh);
|
|
1543
1589
|
shapeDict[segID.index1] = sh;
|
|
1544
1590
|
}
|
|
@@ -1891,7 +1937,7 @@ async function q5playPreSetup(q) {
|
|
|
1891
1937
|
}
|
|
1892
1938
|
const speed = this._vel.mag();
|
|
1893
1939
|
if (speed) {
|
|
1894
|
-
this.
|
|
1940
|
+
this.__setVel($.cos(val) * speed, $.sin(val) * speed);
|
|
1895
1941
|
this._vel._magCached = false;
|
|
1896
1942
|
}
|
|
1897
1943
|
this._vel._direction = val;
|
|
@@ -1999,19 +2045,17 @@ async function q5playPreSetup(q) {
|
|
|
1999
2045
|
this._opacity = val;
|
|
2000
2046
|
}
|
|
2001
2047
|
|
|
2002
|
-
get
|
|
2003
|
-
return this.
|
|
2048
|
+
get previousX() {
|
|
2049
|
+
return this.prevX;
|
|
2004
2050
|
}
|
|
2005
|
-
|
|
2006
|
-
|
|
2051
|
+
|
|
2052
|
+
get previousY() {
|
|
2053
|
+
return this.prevY;
|
|
2007
2054
|
}
|
|
2008
2055
|
|
|
2009
2056
|
get previousRotation() {
|
|
2010
2057
|
return this.prevRotation;
|
|
2011
2058
|
}
|
|
2012
|
-
set previousRotation(val) {
|
|
2013
|
-
this.prevRotation = val;
|
|
2014
|
-
}
|
|
2015
2059
|
|
|
2016
2060
|
get pixelPerfect() {
|
|
2017
2061
|
return this._pixelPerfect;
|
|
@@ -2035,8 +2079,9 @@ async function q5playPreSetup(q) {
|
|
|
2035
2079
|
get rotation() {
|
|
2036
2080
|
if (!this._physicsEnabled || !usePhysics) return this._rotation || 0;
|
|
2037
2081
|
let val = b2Body_GetRotation(this.bdID).GetAngle();
|
|
2082
|
+
if ($._angleMode == DEGREES) val = $.degrees(val);
|
|
2038
2083
|
if (friendlyRounding) val = fixRoundAngular(val);
|
|
2039
|
-
return (this._rotation =
|
|
2084
|
+
return (this._rotation = val);
|
|
2040
2085
|
}
|
|
2041
2086
|
set rotation(val) {
|
|
2042
2087
|
this._rotation = val;
|
|
@@ -2089,17 +2134,85 @@ async function q5playPreSetup(q) {
|
|
|
2089
2134
|
scaleBy(x, y) {
|
|
2090
2135
|
if (y === undefined) y = x;
|
|
2091
2136
|
|
|
2137
|
+
const ax = Math.abs(x),
|
|
2138
|
+
ay = Math.abs(y);
|
|
2139
|
+
|
|
2092
2140
|
if (this._shapes) {
|
|
2093
2141
|
for (let shape of this._shapes) {
|
|
2094
2142
|
shape.scaleBy(x, y);
|
|
2095
2143
|
}
|
|
2096
2144
|
}
|
|
2097
2145
|
|
|
2098
|
-
this.
|
|
2099
|
-
|
|
2146
|
+
if (this._hasChain) this._rebuildChain(x, y);
|
|
2147
|
+
|
|
2148
|
+
this._w *= ax;
|
|
2149
|
+
this._hw *= ax;
|
|
2100
2150
|
if (this._h) {
|
|
2101
|
-
this._h *=
|
|
2102
|
-
this._hh *=
|
|
2151
|
+
this._h *= ay;
|
|
2152
|
+
this._hh *= ay;
|
|
2153
|
+
}
|
|
2154
|
+
}
|
|
2155
|
+
|
|
2156
|
+
_rebuildChain(scaleX, scaleY) {
|
|
2157
|
+
const chain = this._chain;
|
|
2158
|
+
const shapes = this._shapes;
|
|
2159
|
+
|
|
2160
|
+
// save properties from existing segments before removing them
|
|
2161
|
+
const firstCollider = this.colliders[0];
|
|
2162
|
+
const savedFriction = firstCollider?._friction ?? 0.5;
|
|
2163
|
+
const savedSurfaceSpeed = firstCollider?._tangentSpeed ?? 0;
|
|
2164
|
+
const savedBounciness = firstCollider?._restitution ?? 0.2;
|
|
2165
|
+
// negate surfaceSpeed when the chain is flipped (odd number of axes negated)
|
|
2166
|
+
const newSurfaceSpeed = scaleX * scaleY < 0 ? -savedSurfaceSpeed : savedSurfaceSpeed;
|
|
2167
|
+
|
|
2168
|
+
// scale the stored points (already in Box2D meter coordinates)
|
|
2169
|
+
for (let p of chain._points) {
|
|
2170
|
+
p.x *= scaleX;
|
|
2171
|
+
p.y *= scaleY;
|
|
2172
|
+
}
|
|
2173
|
+
|
|
2174
|
+
// when an odd number of axes are negated, the winding order reverses,
|
|
2175
|
+
// flipping the collision normal; reverse the point order to compensate
|
|
2176
|
+
if (scaleX * scaleY < 0) chain._points.reverse();
|
|
2177
|
+
|
|
2178
|
+
// clean up old chain segment JS references
|
|
2179
|
+
for (let i = shapes.length - 1; i >= 0; i--) {
|
|
2180
|
+
if (shapes[i].type === 6) {
|
|
2181
|
+
delete shapeDict[shapes[i].id.index1];
|
|
2182
|
+
this.colliders.splice(this.colliders.indexOf(shapes[i]), 1);
|
|
2183
|
+
shapes.splice(i, 1);
|
|
2184
|
+
}
|
|
2185
|
+
}
|
|
2186
|
+
|
|
2187
|
+
// destroy old chain (Box2D frees all segment physics objects)
|
|
2188
|
+
b2DestroyChain(chain.id);
|
|
2189
|
+
|
|
2190
|
+
// recompute packed material data
|
|
2191
|
+
const packedData = ((chain._isFirstShape ? 1 : 0) << 26) | this._uid;
|
|
2192
|
+
|
|
2193
|
+
// create new chain with scaled points
|
|
2194
|
+
const chainDef = new b2DefaultChainDef();
|
|
2195
|
+
chainDef.SetPoints([chain._points[0], ...chain._points, chain._points.at(-1)]);
|
|
2196
|
+
chainDef.isLoop = chain._isLoopChain;
|
|
2197
|
+
chainDef.SetMaterials([{ customColor: packedData }]);
|
|
2198
|
+
|
|
2199
|
+
const newId = b2CreateChain(this.bdID, chainDef);
|
|
2200
|
+
chain._init(newId, 6);
|
|
2201
|
+
chain.friction = savedFriction;
|
|
2202
|
+
chain._tangentSpeed = newSurfaceSpeed;
|
|
2203
|
+
|
|
2204
|
+
// register new chain segments with restored properties
|
|
2205
|
+
const count = b2Chain_GetSegmentCount(newId);
|
|
2206
|
+
const segments = b2Chain_GetSegments(newId, count);
|
|
2207
|
+
for (let segID of segments) {
|
|
2208
|
+
let sh = new Collider(this);
|
|
2209
|
+
sh._init(segID, 6);
|
|
2210
|
+
sh.friction = savedFriction;
|
|
2211
|
+
sh.bounciness = savedBounciness;
|
|
2212
|
+
if (newSurfaceSpeed) sh.surfaceSpeed = newSurfaceSpeed;
|
|
2213
|
+
shapes.push(sh);
|
|
2214
|
+
this.colliders.push(sh);
|
|
2215
|
+
shapeDict[segID.index1] = sh;
|
|
2103
2216
|
}
|
|
2104
2217
|
}
|
|
2105
2218
|
|
|
@@ -2123,10 +2236,7 @@ async function q5playPreSetup(q) {
|
|
|
2123
2236
|
|
|
2124
2237
|
if (this.watch) this.mod[26] = true;
|
|
2125
2238
|
|
|
2126
|
-
|
|
2127
|
-
let scaleY = Math.abs(y / sc._y);
|
|
2128
|
-
|
|
2129
|
-
this.scaleBy(scaleX, scaleY);
|
|
2239
|
+
this.scaleBy(x / sc._x, y / sc._y);
|
|
2130
2240
|
|
|
2131
2241
|
sc._x = x;
|
|
2132
2242
|
sc._y = y;
|
|
@@ -2153,14 +2263,14 @@ async function q5playPreSetup(q) {
|
|
|
2153
2263
|
return this._vel.mag();
|
|
2154
2264
|
}
|
|
2155
2265
|
set speed(val) {
|
|
2156
|
-
if (!val) this.
|
|
2266
|
+
if (!val) this.__setVel(0, 0);
|
|
2157
2267
|
else {
|
|
2158
2268
|
const mag = this._vel.mag();
|
|
2159
2269
|
if (mag > 0) {
|
|
2160
|
-
this.
|
|
2270
|
+
this.__setVel((this._vel.x / mag) * val, (this._vel.y / mag) * val);
|
|
2161
2271
|
} else {
|
|
2162
2272
|
const dir = this._vel.direction();
|
|
2163
|
-
this.
|
|
2273
|
+
this.__setVel($.cos(dir) * val, $.sin(dir) * val);
|
|
2164
2274
|
}
|
|
2165
2275
|
}
|
|
2166
2276
|
this._vel._mag = val;
|
|
@@ -2168,7 +2278,7 @@ async function q5playPreSetup(q) {
|
|
|
2168
2278
|
}
|
|
2169
2279
|
|
|
2170
2280
|
setSpeedAndDirection(speed, direction) {
|
|
2171
|
-
this.
|
|
2281
|
+
this.__setVel($.cos(direction) * speed, $.sin(direction) * speed);
|
|
2172
2282
|
this._vel._mag = speed;
|
|
2173
2283
|
this._vel._direction = direction;
|
|
2174
2284
|
this._vel._magCached = this._vel._directionCached = true;
|
|
@@ -2180,6 +2290,10 @@ async function q5playPreSetup(q) {
|
|
|
2180
2290
|
}
|
|
2181
2291
|
set surfaceSpeed(val) {
|
|
2182
2292
|
if (this.watch) this.mod[21] = true;
|
|
2293
|
+
if (this._hasCapsuleChain) {
|
|
2294
|
+
return console.error('Can not set surfaceSpeed of a capsule chain.');
|
|
2295
|
+
}
|
|
2296
|
+
if (this._hasChain) this._chain.surfaceSpeed = val;
|
|
2183
2297
|
for (let collider of this.colliders) {
|
|
2184
2298
|
collider.surfaceSpeed = val;
|
|
2185
2299
|
}
|
|
@@ -2230,7 +2344,7 @@ async function q5playPreSetup(q) {
|
|
|
2230
2344
|
}
|
|
2231
2345
|
|
|
2232
2346
|
get pos() {
|
|
2233
|
-
return this.
|
|
2347
|
+
return { x: this._posX, y: this._posY };
|
|
2234
2348
|
}
|
|
2235
2349
|
set pos(val) {
|
|
2236
2350
|
if (val == $.mouse && !$.mouse.isActive) return;
|
|
@@ -2409,23 +2523,32 @@ async function q5playPreSetup(q) {
|
|
|
2409
2523
|
}
|
|
2410
2524
|
set vel(val) {
|
|
2411
2525
|
this._setVel(val[0] ?? val.x, val[1] ?? val.y);
|
|
2412
|
-
|
|
2526
|
+
}
|
|
2527
|
+
|
|
2528
|
+
get velocity() {
|
|
2529
|
+
return this._vel;
|
|
2530
|
+
}
|
|
2531
|
+
set velocity(val) {
|
|
2532
|
+
this.vel = val;
|
|
2413
2533
|
}
|
|
2414
2534
|
|
|
2415
2535
|
_setVel(x, y) {
|
|
2416
2536
|
if (this._physicsEnabled) {
|
|
2417
2537
|
b2Body_SetLinearVelocity(this.bdID, new b2Vec2(x, y));
|
|
2418
2538
|
}
|
|
2419
|
-
this.
|
|
2420
|
-
this.
|
|
2539
|
+
this.vx = x;
|
|
2540
|
+
this.vy = y;
|
|
2421
2541
|
this._velSynced = true;
|
|
2542
|
+
this._vel._magCached = this._vel._directionCached = false;
|
|
2422
2543
|
}
|
|
2423
2544
|
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
this.
|
|
2545
|
+
__setVel(x, y) {
|
|
2546
|
+
if (this._physicsEnabled) {
|
|
2547
|
+
b2Body_SetLinearVelocity(this.bdID, new b2Vec2(x, y));
|
|
2548
|
+
}
|
|
2549
|
+
this.vx = x;
|
|
2550
|
+
this.vy = y;
|
|
2551
|
+
this._velSynced = true;
|
|
2429
2552
|
}
|
|
2430
2553
|
|
|
2431
2554
|
get grabbable() {
|
|
@@ -2447,6 +2570,9 @@ async function q5playPreSetup(q) {
|
|
|
2447
2570
|
|
|
2448
2571
|
_update() {
|
|
2449
2572
|
if (this._customUpdate) this._customUpdate();
|
|
2573
|
+
this.prevX = this._posX;
|
|
2574
|
+
this.prevY = this._posY;
|
|
2575
|
+
this.prevRotation = this.rotation;
|
|
2450
2576
|
if (this.autoUpdate) this.autoUpdate = null;
|
|
2451
2577
|
}
|
|
2452
2578
|
|
|
@@ -2455,8 +2581,8 @@ async function q5playPreSetup(q) {
|
|
|
2455
2581
|
if (this._life <= 0) {
|
|
2456
2582
|
this.delete();
|
|
2457
2583
|
} else if (!this._physicsEnabled || !usePhysics) {
|
|
2458
|
-
this._posX += this.
|
|
2459
|
-
this._posY += this.
|
|
2584
|
+
this._posX += this.vx * timeScale;
|
|
2585
|
+
this._posY += this.vy * timeScale;
|
|
2460
2586
|
this._rotation += this._rotationSpeed * timeScale;
|
|
2461
2587
|
}
|
|
2462
2588
|
|
|
@@ -2468,6 +2594,70 @@ async function q5playPreSetup(q) {
|
|
|
2468
2594
|
}
|
|
2469
2595
|
}
|
|
2470
2596
|
|
|
2597
|
+
if (this._destArrivalTime !== undefined && $.world.physicsTime >= this._destArrivalTime) {
|
|
2598
|
+
const x = this._posX,
|
|
2599
|
+
y = this._posY,
|
|
2600
|
+
prevX = this.prevX,
|
|
2601
|
+
prevY = this.prevY,
|
|
2602
|
+
destX = this._destX,
|
|
2603
|
+
destY = this._destY;
|
|
2604
|
+
|
|
2605
|
+
const destReachedX =
|
|
2606
|
+
destX === undefined || (destX >= Math.min(prevX, x) - visualSlop && destX <= Math.max(prevX, x) + visualSlop);
|
|
2607
|
+
const destReachedY =
|
|
2608
|
+
destY === undefined || (destY >= Math.min(prevY, y) - visualSlop && destY <= Math.max(prevY, y) + visualSlop);
|
|
2609
|
+
const destReached = destReachedX && destReachedY;
|
|
2610
|
+
|
|
2611
|
+
if (destReached) {
|
|
2612
|
+
this._setVel(0, 0);
|
|
2613
|
+
this.rotationSpeed = 0;
|
|
2614
|
+
this.pos = [this._destX ?? this._posX, this._destY ?? this._posY];
|
|
2615
|
+
if (this._destRot !== undefined) {
|
|
2616
|
+
this.rotation = this._destRot;
|
|
2617
|
+
}
|
|
2618
|
+
}
|
|
2619
|
+
|
|
2620
|
+
if (this._destResolve) {
|
|
2621
|
+
this._destResolve(destReached);
|
|
2622
|
+
this._destResolve = undefined;
|
|
2623
|
+
}
|
|
2624
|
+
|
|
2625
|
+
this._destX = this._destY = this._destRot = this._destArrivalTime = undefined;
|
|
2626
|
+
}
|
|
2627
|
+
|
|
2628
|
+
if (this._destRotArrivalTime !== undefined && $.world.physicsTime >= this._destRotArrivalTime) {
|
|
2629
|
+
const isDeg = $._angleMode == DEGREES,
|
|
2630
|
+
full = isDeg ? 360 : $.TWO_PI,
|
|
2631
|
+
half = isDeg ? 180 : Math.PI,
|
|
2632
|
+
prevRot = this.prevRotation,
|
|
2633
|
+
currRot = this.rotation,
|
|
2634
|
+
destRot = this._destRot;
|
|
2635
|
+
|
|
2636
|
+
// normalize destRot to [-half, half) to match this.rotation's range
|
|
2637
|
+
let nd = ((destRot % full) + full) % full;
|
|
2638
|
+
if (nd >= half) nd -= full;
|
|
2639
|
+
|
|
2640
|
+
// when the sprite crosses the ±half boundary, prevRot and currRot jump
|
|
2641
|
+
// by ~full°; invert the range check so nd is tested against the arc that
|
|
2642
|
+
// was actually traversed rather than the gap between them
|
|
2643
|
+
const crossed180 = Math.abs(prevRot - currRot) > half;
|
|
2644
|
+
const rotReached = crossed180
|
|
2645
|
+
? nd >= Math.max(prevRot, currRot) - visualSlop || nd <= Math.min(prevRot, currRot) + visualSlop
|
|
2646
|
+
: nd >= Math.min(prevRot, currRot) - visualSlop && nd <= Math.max(prevRot, currRot) + visualSlop;
|
|
2647
|
+
|
|
2648
|
+
if (rotReached) {
|
|
2649
|
+
this.rotationSpeed = 0;
|
|
2650
|
+
this.rotation = nd;
|
|
2651
|
+
}
|
|
2652
|
+
|
|
2653
|
+
if (this._destRotationResolve) {
|
|
2654
|
+
this._destRotationResolve(rotReached);
|
|
2655
|
+
this._destRotationResolve = undefined;
|
|
2656
|
+
}
|
|
2657
|
+
|
|
2658
|
+
this._destRot = this._destRotArrivalTime = undefined;
|
|
2659
|
+
}
|
|
2660
|
+
|
|
2471
2661
|
if (!this._physicsEnabled && !this._deleted) return;
|
|
2472
2662
|
|
|
2473
2663
|
this.__step();
|
|
@@ -2699,8 +2889,9 @@ async function q5playPreSetup(q) {
|
|
|
2699
2889
|
args[2] = args[1];
|
|
2700
2890
|
args[1] = undefined;
|
|
2701
2891
|
}
|
|
2702
|
-
|
|
2703
|
-
|
|
2892
|
+
const v = this._args2Vec(args[0], args[1]),
|
|
2893
|
+
o = {};
|
|
2894
|
+
o.forceVector = new b2Vec2(v.x, v.y);
|
|
2704
2895
|
if (args[2] !== undefined) {
|
|
2705
2896
|
o.poa = this._args2Vec(args[2], args[3]);
|
|
2706
2897
|
o.poa = scaleTo(o.poa.x, o.poa.y);
|
|
@@ -2776,30 +2967,70 @@ async function q5playPreSetup(q) {
|
|
|
2776
2967
|
wind.delete();
|
|
2777
2968
|
}
|
|
2778
2969
|
|
|
2779
|
-
|
|
2780
|
-
if (
|
|
2781
|
-
|
|
2782
|
-
|
|
2970
|
+
move(distance, direction, speed) {
|
|
2971
|
+
if (!distance) return;
|
|
2972
|
+
|
|
2973
|
+
if (typeof direction == 'string') {
|
|
2974
|
+
directionNamed = true;
|
|
2975
|
+
this._heading = direction;
|
|
2976
|
+
direction = this._getDirectionAngle(direction);
|
|
2783
2977
|
}
|
|
2784
|
-
|
|
2978
|
+
direction ??= this.direction;
|
|
2979
|
+
|
|
2980
|
+
const x = $.cos(direction) * distance + this.x,
|
|
2981
|
+
y = $.sin(direction) * distance + this.y;
|
|
2982
|
+
return this.moveTo(x, y, speed);
|
|
2785
2983
|
}
|
|
2786
2984
|
|
|
2787
|
-
|
|
2788
|
-
if (
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2985
|
+
moveTo(x, y, speed) {
|
|
2986
|
+
if (x === undefined && (y === undefined || y === null)) return;
|
|
2987
|
+
|
|
2988
|
+
if (x !== null && x !== undefined && typeof x != 'number') {
|
|
2989
|
+
let pos = x;
|
|
2990
|
+
if (pos == $.mouse && !$.mouse.isActive) return;
|
|
2991
|
+
speed = y;
|
|
2992
|
+
y = pos.y;
|
|
2993
|
+
x = pos.x;
|
|
2792
2994
|
}
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2995
|
+
|
|
2996
|
+
const moveX = x !== null && x !== undefined;
|
|
2997
|
+
const moveY = y !== null && y !== undefined;
|
|
2998
|
+
|
|
2999
|
+
speed ||= this.speed || 1;
|
|
3000
|
+
|
|
3001
|
+
const dist =
|
|
3002
|
+
moveX && moveY
|
|
3003
|
+
? Math.hypot(x - this._posX, y - this._posY)
|
|
3004
|
+
: moveX
|
|
3005
|
+
? Math.abs(x - this._posX)
|
|
3006
|
+
: Math.abs(y - this._posY);
|
|
3007
|
+
|
|
3008
|
+
if (this._destResolve) {
|
|
3009
|
+
this._destResolve(false);
|
|
3010
|
+
this._destResolve = undefined;
|
|
2796
3011
|
}
|
|
2797
|
-
return this.angleTo(x, y) + (facing || 0);
|
|
2798
|
-
}
|
|
2799
3012
|
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
3013
|
+
this._destX = moveX ? x : undefined;
|
|
3014
|
+
this._destY = moveY ? y : undefined;
|
|
3015
|
+
this._destArrivalTime = $.world.physicsTime + dist / (speed * $.world._updateRate);
|
|
3016
|
+
|
|
3017
|
+
if (dist > 0) {
|
|
3018
|
+
if (moveX && moveY) {
|
|
3019
|
+
this.setSpeedAndDirection(speed, $.atan2(y - this.y, x - this.x));
|
|
3020
|
+
} else if (moveX) {
|
|
3021
|
+
this._setVel(x > this._posX ? speed : -speed, this.vy);
|
|
3022
|
+
} else {
|
|
3023
|
+
this._setVel(this.vx, y > this._posY ? speed : -speed);
|
|
3024
|
+
}
|
|
3025
|
+
}
|
|
3026
|
+
|
|
3027
|
+
if ($._py) return new Promise((resolve) => (this._destResolve = resolve));
|
|
3028
|
+
|
|
3029
|
+
return {
|
|
3030
|
+
then: (onFulfilled) => {
|
|
3031
|
+
this._destResolve = onFulfilled;
|
|
3032
|
+
}
|
|
3033
|
+
};
|
|
2803
3034
|
}
|
|
2804
3035
|
|
|
2805
3036
|
moveTowards(x, y, tracking) {
|
|
@@ -2816,21 +3047,120 @@ async function q5playPreSetup(q) {
|
|
|
2816
3047
|
|
|
2817
3048
|
let velX, velY;
|
|
2818
3049
|
|
|
2819
|
-
if (x !== null) {
|
|
3050
|
+
if (x !== null && x !== undefined) {
|
|
2820
3051
|
let diffX = x - this.x;
|
|
2821
3052
|
if (!isSlop(diffX)) {
|
|
2822
3053
|
velX = diffX * tracking;
|
|
2823
3054
|
} else velX = 0;
|
|
2824
|
-
} else velX = this.
|
|
2825
|
-
if (y !== null) {
|
|
3055
|
+
} else velX = this.vx;
|
|
3056
|
+
if (y !== null && y !== undefined) {
|
|
2826
3057
|
let diffY = y - this.y;
|
|
2827
3058
|
if (!isSlop(diffY)) {
|
|
2828
3059
|
velY = diffY * tracking;
|
|
2829
3060
|
} else velY = 0;
|
|
2830
|
-
} else velY = this.
|
|
3061
|
+
} else velY = this.vy;
|
|
2831
3062
|
|
|
2832
3063
|
this._setVel(velX, velY);
|
|
2833
|
-
|
|
3064
|
+
}
|
|
3065
|
+
|
|
3066
|
+
angleTo(x, y, facing = 0) {
|
|
3067
|
+
if (typeof x == 'object') {
|
|
3068
|
+
facing = y || 0;
|
|
3069
|
+
y = x.y;
|
|
3070
|
+
x = x.x;
|
|
3071
|
+
}
|
|
3072
|
+
// if the sprite is too close to the position, don't rotate
|
|
3073
|
+
if (Math.abs(x - this.x) < 0.01 && Math.abs(y - this.y) < 0.01) {
|
|
3074
|
+
return this.rotation;
|
|
3075
|
+
}
|
|
3076
|
+
return $.atan2(y - this.y, x - this.x) + facing;
|
|
3077
|
+
}
|
|
3078
|
+
|
|
3079
|
+
angleDistTo(x, y, facing = 0) {
|
|
3080
|
+
if (typeof x == 'object') {
|
|
3081
|
+
facing = y || 0;
|
|
3082
|
+
y = x.y;
|
|
3083
|
+
x = x.x;
|
|
3084
|
+
}
|
|
3085
|
+
// if the sprite is too close to the position, don't rotate
|
|
3086
|
+
if (Math.abs(x - this.x) < 0.01 && Math.abs(y - this.y) < 0.01) {
|
|
3087
|
+
return 0;
|
|
3088
|
+
}
|
|
3089
|
+
return minAngleDist($.atan2(y - this.y, x - this.x) + facing, this.rotation);
|
|
3090
|
+
}
|
|
3091
|
+
|
|
3092
|
+
rotateTo(angle, speed) {
|
|
3093
|
+
let args = arguments;
|
|
3094
|
+
let x, y, facing;
|
|
3095
|
+
if (typeof args[0] != 'number') {
|
|
3096
|
+
x = args[0].x;
|
|
3097
|
+
y = args[0].y;
|
|
3098
|
+
speed = args[1];
|
|
3099
|
+
facing = args[2];
|
|
3100
|
+
} else if (arguments.length > 2) {
|
|
3101
|
+
x = args[0];
|
|
3102
|
+
y = args[1];
|
|
3103
|
+
speed = args[2];
|
|
3104
|
+
facing = args[3];
|
|
3105
|
+
}
|
|
3106
|
+
|
|
3107
|
+
if (x !== undefined) angle = this.angleTo(x, y, facing);
|
|
3108
|
+
|
|
3109
|
+
const full = $._angleMode == DEGREES ? 360 : $.TWO_PI;
|
|
3110
|
+
let angleDist = (angle - this.rotation) % full;
|
|
3111
|
+
if (angleDist < 0 && speed > 0) angleDist += full;
|
|
3112
|
+
if (angleDist > 0 && speed < 0) angleDist -= full;
|
|
3113
|
+
|
|
3114
|
+
return this.rotate(angleDist, speed);
|
|
3115
|
+
}
|
|
3116
|
+
|
|
3117
|
+
rotateMinTo(angle, speed, facing) {
|
|
3118
|
+
let args = arguments;
|
|
3119
|
+
let x, y;
|
|
3120
|
+
if (typeof args[0] != 'number') {
|
|
3121
|
+
x = args[0].x;
|
|
3122
|
+
y = args[0].y;
|
|
3123
|
+
speed = args[1];
|
|
3124
|
+
facing = args[2];
|
|
3125
|
+
} else if (args.length > 2) {
|
|
3126
|
+
x = args[0];
|
|
3127
|
+
y = args[1];
|
|
3128
|
+
speed = args[2];
|
|
3129
|
+
facing = args[3];
|
|
3130
|
+
}
|
|
3131
|
+
|
|
3132
|
+
if (x !== undefined) angle = this.angleTo(x, y, facing);
|
|
3133
|
+
|
|
3134
|
+
return this.rotate(minAngleDist(angle, this.rotation), speed);
|
|
3135
|
+
}
|
|
3136
|
+
|
|
3137
|
+
rotate(angleDist, speed) {
|
|
3138
|
+
if (Math.abs(angleDist) <= angularSlop) return;
|
|
3139
|
+
|
|
3140
|
+
speed ||= this.rotationSpeed || 1;
|
|
3141
|
+
speed = Math.abs(speed) * Math.sign(angleDist);
|
|
3142
|
+
|
|
3143
|
+
// cap speed so the sprite doesn't overshoot the destination in one physics step
|
|
3144
|
+
if (Math.abs(speed) > Math.abs(angleDist)) speed = angleDist;
|
|
3145
|
+
|
|
3146
|
+
this._destRotArrivalTime = $.world.physicsTime + Math.abs(angleDist) / (Math.abs(speed) * $.world._updateRate);
|
|
3147
|
+
|
|
3148
|
+
this._destRot = this.rotation + angleDist;
|
|
3149
|
+
|
|
3150
|
+
if (this._destRotationResolve) {
|
|
3151
|
+
this._destRotationResolve(false);
|
|
3152
|
+
this._destRotationResolve = undefined;
|
|
3153
|
+
}
|
|
3154
|
+
|
|
3155
|
+
this.rotationSpeed = speed;
|
|
3156
|
+
|
|
3157
|
+
if ($._py) return new Promise((resolve) => (this._destRotationResolve = resolve));
|
|
3158
|
+
|
|
3159
|
+
return {
|
|
3160
|
+
then: (onFulfilled) => {
|
|
3161
|
+
this._destRotationResolve = onFulfilled;
|
|
3162
|
+
}
|
|
3163
|
+
};
|
|
2834
3164
|
}
|
|
2835
3165
|
|
|
2836
3166
|
rotateTowards(angle, tracking) {
|
|
@@ -2848,18 +3178,31 @@ async function q5playPreSetup(q) {
|
|
|
2848
3178
|
facing = args[3];
|
|
2849
3179
|
}
|
|
2850
3180
|
|
|
2851
|
-
if (x !== undefined) angle = this.
|
|
3181
|
+
if (x !== undefined) angle = this.angleDistTo(x, y, facing);
|
|
2852
3182
|
else angle -= this.rotation;
|
|
2853
3183
|
|
|
2854
3184
|
tracking ??= 0.1;
|
|
2855
3185
|
this.rotationSpeed = angle * tracking;
|
|
2856
3186
|
}
|
|
2857
3187
|
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
3188
|
+
transformTowards(x, y, rotation, tracking = 0.1) {
|
|
3189
|
+
if (x === undefined) return;
|
|
3190
|
+
|
|
3191
|
+
if (typeof x != 'number') {
|
|
3192
|
+
let pos = x;
|
|
3193
|
+
if (pos == $.mouse && !$.mouse.isActive) return;
|
|
3194
|
+
tracking = rotation ?? tracking;
|
|
3195
|
+
rotation = y;
|
|
3196
|
+
y = pos.y;
|
|
3197
|
+
x = pos.x;
|
|
3198
|
+
}
|
|
3199
|
+
|
|
3200
|
+
const t = new b2Transform();
|
|
3201
|
+
t.p = scaleTo(x ?? this._posX, y ?? this._posY);
|
|
3202
|
+
rotation ??= this._rotation;
|
|
3203
|
+
if ($._angleMode == DEGREES) rotation = (rotation % 360) * DEGTORAD;
|
|
2861
3204
|
t.q = b2MakeRot(rotation);
|
|
2862
|
-
b2Body_SetTargetTransform(this.bdID, t, $.world._timeStep);
|
|
3205
|
+
b2Body_SetTargetTransform(this.bdID, t, $.world._timeStep / tracking);
|
|
2863
3206
|
}
|
|
2864
3207
|
|
|
2865
3208
|
delete() {
|
|
@@ -4083,7 +4426,7 @@ async function q5playPreSetup(q) {
|
|
|
4083
4426
|
for (let vecProp of vecProps) {
|
|
4084
4427
|
vecProp = '_' + vecProp;
|
|
4085
4428
|
if (vecProp != 'vel') this[vecProp] = {};
|
|
4086
|
-
else this[vecProp] = $.createVector.call(
|
|
4429
|
+
else this[vecProp] = $.createVector.call($, 0, 0);
|
|
4087
4430
|
this[vecProp]._x = undefined;
|
|
4088
4431
|
this[vecProp]._y = undefined;
|
|
4089
4432
|
for (let prop of ['x', 'y']) {
|
|
@@ -4532,6 +4875,193 @@ async function q5playPreSetup(q) {
|
|
|
4532
4875
|
}
|
|
4533
4876
|
}
|
|
4534
4877
|
|
|
4878
|
+
rotateTowards() {
|
|
4879
|
+
for (let s of this) {
|
|
4880
|
+
s.rotateTowards(...arguments);
|
|
4881
|
+
}
|
|
4882
|
+
}
|
|
4883
|
+
|
|
4884
|
+
rotateTo(angle, speed) {
|
|
4885
|
+
const thenables = [];
|
|
4886
|
+
for (let s of this) {
|
|
4887
|
+
thenables.push(s.rotateTo(...arguments));
|
|
4888
|
+
}
|
|
4889
|
+
|
|
4890
|
+
if ($._py) {
|
|
4891
|
+
return new Promise((resolve) => {
|
|
4892
|
+
let pending = thenables.length;
|
|
4893
|
+
if (!pending) return resolve(true);
|
|
4894
|
+
let allReached = true;
|
|
4895
|
+
for (let t of thenables) {
|
|
4896
|
+
t.then((reached) => {
|
|
4897
|
+
if (!reached) allReached = false;
|
|
4898
|
+
if (--pending === 0) resolve(allReached);
|
|
4899
|
+
});
|
|
4900
|
+
}
|
|
4901
|
+
});
|
|
4902
|
+
}
|
|
4903
|
+
|
|
4904
|
+
return {
|
|
4905
|
+
then: (onFulfilled) => {
|
|
4906
|
+
let pending = thenables.length;
|
|
4907
|
+
if (!pending) return onFulfilled(true);
|
|
4908
|
+
let allReached = true;
|
|
4909
|
+
for (let t of thenables) {
|
|
4910
|
+
t.then((reached) => {
|
|
4911
|
+
if (!reached) allReached = false;
|
|
4912
|
+
if (--pending === 0) onFulfilled(allReached);
|
|
4913
|
+
});
|
|
4914
|
+
}
|
|
4915
|
+
}
|
|
4916
|
+
};
|
|
4917
|
+
}
|
|
4918
|
+
|
|
4919
|
+
rotate(angle, speed) {
|
|
4920
|
+
const thenables = [];
|
|
4921
|
+
for (let s of this) {
|
|
4922
|
+
thenables.push(s.rotate(...arguments));
|
|
4923
|
+
}
|
|
4924
|
+
|
|
4925
|
+
if ($._py) {
|
|
4926
|
+
return new Promise((resolve) => {
|
|
4927
|
+
let pending = thenables.length;
|
|
4928
|
+
if (!pending) return resolve(true);
|
|
4929
|
+
let allReached = true;
|
|
4930
|
+
for (let t of thenables) {
|
|
4931
|
+
t.then((reached) => {
|
|
4932
|
+
if (!reached) allReached = false;
|
|
4933
|
+
if (--pending === 0) resolve(allReached);
|
|
4934
|
+
});
|
|
4935
|
+
}
|
|
4936
|
+
});
|
|
4937
|
+
}
|
|
4938
|
+
|
|
4939
|
+
return {
|
|
4940
|
+
then: (onFulfilled) => {
|
|
4941
|
+
let pending = thenables.length;
|
|
4942
|
+
if (!pending) return onFulfilled(true);
|
|
4943
|
+
let allReached = true;
|
|
4944
|
+
for (let t of thenables) {
|
|
4945
|
+
t.then((reached) => {
|
|
4946
|
+
if (!reached) allReached = false;
|
|
4947
|
+
if (--pending === 0) onFulfilled(allReached);
|
|
4948
|
+
});
|
|
4949
|
+
}
|
|
4950
|
+
}
|
|
4951
|
+
};
|
|
4952
|
+
}
|
|
4953
|
+
|
|
4954
|
+
rotateMinTo(angle, speed) {
|
|
4955
|
+
const thenables = [];
|
|
4956
|
+
for (let s of this) {
|
|
4957
|
+
thenables.push(s.rotateMinTo(...arguments));
|
|
4958
|
+
}
|
|
4959
|
+
|
|
4960
|
+
if ($._py) {
|
|
4961
|
+
return new Promise((resolve) => {
|
|
4962
|
+
let pending = thenables.length;
|
|
4963
|
+
if (!pending) return resolve(true);
|
|
4964
|
+
let allReached = true;
|
|
4965
|
+
for (let t of thenables) {
|
|
4966
|
+
t.then((reached) => {
|
|
4967
|
+
if (!reached) allReached = false;
|
|
4968
|
+
if (--pending === 0) resolve(allReached);
|
|
4969
|
+
});
|
|
4970
|
+
}
|
|
4971
|
+
});
|
|
4972
|
+
}
|
|
4973
|
+
|
|
4974
|
+
return {
|
|
4975
|
+
then: (onFulfilled) => {
|
|
4976
|
+
let pending = thenables.length;
|
|
4977
|
+
if (!pending) return onFulfilled(true);
|
|
4978
|
+
let allReached = true;
|
|
4979
|
+
for (let t of thenables) {
|
|
4980
|
+
t.then((reached) => {
|
|
4981
|
+
if (!reached) allReached = false;
|
|
4982
|
+
if (--pending === 0) onFulfilled(allReached);
|
|
4983
|
+
});
|
|
4984
|
+
}
|
|
4985
|
+
}
|
|
4986
|
+
};
|
|
4987
|
+
}
|
|
4988
|
+
|
|
4989
|
+
transformTowards(x, y, rotation, tracking = 0.1) {
|
|
4990
|
+
if (x === undefined) return;
|
|
4991
|
+
|
|
4992
|
+
if (typeof x != 'number') {
|
|
4993
|
+
let pos = x;
|
|
4994
|
+
if (pos == $.mouse && !$.mouse.isActive) return;
|
|
4995
|
+
tracking = rotation ?? tracking;
|
|
4996
|
+
rotation = y;
|
|
4997
|
+
y = pos.y;
|
|
4998
|
+
x = pos.x;
|
|
4999
|
+
}
|
|
5000
|
+
|
|
5001
|
+
this._resetCentroid();
|
|
5002
|
+
|
|
5003
|
+
for (let s of this) {
|
|
5004
|
+
if (s.distCentroid === undefined) {
|
|
5005
|
+
this._resetDistancesFromCentroid();
|
|
5006
|
+
}
|
|
5007
|
+
s.transformTowards(s.distCentroid.x + x, s.distCentroid.y + y, rotation, tracking);
|
|
5008
|
+
}
|
|
5009
|
+
}
|
|
5010
|
+
|
|
5011
|
+
moveTo(x, y, speed) {
|
|
5012
|
+
if (x === undefined && (y === undefined || y === null)) return;
|
|
5013
|
+
|
|
5014
|
+
let nullX = x === null || x === undefined;
|
|
5015
|
+
let nullY = y === null || y === undefined;
|
|
5016
|
+
|
|
5017
|
+
if (!nullX && typeof x != 'number') {
|
|
5018
|
+
let pos = x;
|
|
5019
|
+
if (pos == $.mouse && !$.mouse.isActive) return;
|
|
5020
|
+
speed = y;
|
|
5021
|
+
y = pos.y;
|
|
5022
|
+
x = pos.x;
|
|
5023
|
+
nullX = nullY = false;
|
|
5024
|
+
}
|
|
5025
|
+
|
|
5026
|
+
this._resetCentroid();
|
|
5027
|
+
this._resetDistancesFromCentroid();
|
|
5028
|
+
|
|
5029
|
+
const thenables = [];
|
|
5030
|
+
for (let s of this) {
|
|
5031
|
+
const tx = nullX ? null : s.distCentroid.x + x;
|
|
5032
|
+
const ty = nullY ? null : s.distCentroid.y + y;
|
|
5033
|
+
thenables.push(s.moveTo(tx, ty, speed));
|
|
5034
|
+
}
|
|
5035
|
+
|
|
5036
|
+
if ($._py) {
|
|
5037
|
+
return new Promise((resolve) => {
|
|
5038
|
+
let pending = thenables.length;
|
|
5039
|
+
if (!pending) return resolve(true);
|
|
5040
|
+
let allReached = true;
|
|
5041
|
+
for (let t of thenables) {
|
|
5042
|
+
t.then((reached) => {
|
|
5043
|
+
if (!reached) allReached = false;
|
|
5044
|
+
if (--pending === 0) resolve(allReached);
|
|
5045
|
+
});
|
|
5046
|
+
}
|
|
5047
|
+
});
|
|
5048
|
+
}
|
|
5049
|
+
|
|
5050
|
+
return {
|
|
5051
|
+
then: (onFulfilled) => {
|
|
5052
|
+
let pending = thenables.length;
|
|
5053
|
+
if (!pending) return onFulfilled(true);
|
|
5054
|
+
let allReached = true;
|
|
5055
|
+
for (let t of thenables) {
|
|
5056
|
+
t.then((reached) => {
|
|
5057
|
+
if (!reached) allReached = false;
|
|
5058
|
+
if (--pending === 0) onFulfilled(allReached);
|
|
5059
|
+
});
|
|
5060
|
+
}
|
|
5061
|
+
}
|
|
5062
|
+
};
|
|
5063
|
+
}
|
|
5064
|
+
|
|
4535
5065
|
toString() {
|
|
4536
5066
|
return 'g' + this.idNum;
|
|
4537
5067
|
}
|
|
@@ -5040,6 +5570,7 @@ async function q5playPreSetup(q) {
|
|
|
5040
5570
|
}
|
|
5041
5571
|
set meterSize(val) {
|
|
5042
5572
|
meterSize = val;
|
|
5573
|
+
visualSlop = meterSize / 120;
|
|
5043
5574
|
}
|
|
5044
5575
|
|
|
5045
5576
|
get profile() {
|
|
@@ -5155,6 +5686,8 @@ async function q5playPreSetup(q) {
|
|
|
5155
5686
|
|
|
5156
5687
|
this.physicsTime += timeStep;
|
|
5157
5688
|
|
|
5689
|
+
this._sync();
|
|
5690
|
+
|
|
5158
5691
|
let sprites = Object.values($.q5play.sprites);
|
|
5159
5692
|
let groups = Object.values($.q5play.groups);
|
|
5160
5693
|
|
|
@@ -5171,6 +5704,71 @@ async function q5playPreSetup(q) {
|
|
|
5171
5704
|
if (this.autoStep) this.autoStep = null;
|
|
5172
5705
|
}
|
|
5173
5706
|
|
|
5707
|
+
_sync() {
|
|
5708
|
+
jointStack = [];
|
|
5709
|
+
shapeStack = [];
|
|
5710
|
+
|
|
5711
|
+
b2World_Draw(wID, drawCmds.GetDebugDraw());
|
|
5712
|
+
|
|
5713
|
+
let cmdPtr = drawCmds.GetCommandsData(),
|
|
5714
|
+
cmdSize = drawCmds.GetCommandsSize(),
|
|
5715
|
+
cmdStride = drawCmds.GetCommandStride(),
|
|
5716
|
+
offset = cmdPtr,
|
|
5717
|
+
renderJointForces = $.q5play.renderJointForces,
|
|
5718
|
+
s;
|
|
5719
|
+
|
|
5720
|
+
for (let i = 0; i < cmdSize; i++, offset += cmdStride) {
|
|
5721
|
+
// workaround that unpacks data from
|
|
5722
|
+
// the shape material's customColor
|
|
5723
|
+
const customColor = Box2D.HEAPU32[(offset + 4) >> 2],
|
|
5724
|
+
uid = customColor & 0xffffff,
|
|
5725
|
+
isSensor = (customColor >>> 25) & 0x1,
|
|
5726
|
+
isFirstShape = (customColor >>> 26) & 0x1;
|
|
5727
|
+
|
|
5728
|
+
s = $.q5play.sprites[uid];
|
|
5729
|
+
|
|
5730
|
+
let type = Box2D.HEAPU8[offset];
|
|
5731
|
+
|
|
5732
|
+
if (type == 7) {
|
|
5733
|
+
continue;
|
|
5734
|
+
}
|
|
5735
|
+
|
|
5736
|
+
let vertexCount = Box2D.HEAPU16[(offset + 8) >> 1];
|
|
5737
|
+
|
|
5738
|
+
let dataLen = 4;
|
|
5739
|
+
if (type == 1) dataLen = 5 + vertexCount * 2;
|
|
5740
|
+
else if (type == 3 || type == 4) dataLen = 5;
|
|
5741
|
+
let data = new Float32Array(Box2D.HEAPU8.buffer, offset + 12, dataLen);
|
|
5742
|
+
|
|
5743
|
+
if (!s) {
|
|
5744
|
+
if (type == 0 && renderJointForces) jointStack.push(data);
|
|
5745
|
+
continue;
|
|
5746
|
+
}
|
|
5747
|
+
|
|
5748
|
+
// always keep position in sync since it has a low performance cost
|
|
5749
|
+
// unless the shape is a chain
|
|
5750
|
+
if (type < 4 || (type == 4 && !s._hasCapsuleChain)) {
|
|
5751
|
+
s._posX = data[0] * meterSize;
|
|
5752
|
+
s._posY = data[1] * meterSize;
|
|
5753
|
+
}
|
|
5754
|
+
|
|
5755
|
+
s._velSynced = false;
|
|
5756
|
+
s._vel._magCached = false;
|
|
5757
|
+
|
|
5758
|
+
if (!s.visible) {
|
|
5759
|
+
continue;
|
|
5760
|
+
}
|
|
5761
|
+
|
|
5762
|
+
if (s._hasImagery || s._userDefinedDraw) {
|
|
5763
|
+
s._rotation = Math.atan2(data[2], data[3]) * RADTODEG;
|
|
5764
|
+
}
|
|
5765
|
+
|
|
5766
|
+
if (s.debug || (!s._hasImagery && !s._userDefinedDraw)) {
|
|
5767
|
+
shapeStack.push({ type, sprite: s, isSensor, isFirstShape, data, vertexCount });
|
|
5768
|
+
}
|
|
5769
|
+
}
|
|
5770
|
+
}
|
|
5771
|
+
|
|
5174
5772
|
get realTime() {
|
|
5175
5773
|
return $.millis() / 1000;
|
|
5176
5774
|
}
|
|
@@ -5278,7 +5876,7 @@ async function q5playPreSetup(q) {
|
|
|
5278
5876
|
$.Camera = class {
|
|
5279
5877
|
constructor() {
|
|
5280
5878
|
// camera position
|
|
5281
|
-
this._pos = $.createVector.call(
|
|
5879
|
+
this._pos = $.createVector.call($, 0, 0);
|
|
5282
5880
|
|
|
5283
5881
|
// camera translation
|
|
5284
5882
|
this.__pos = { x: 0, y: 0, rounded: {} };
|
|
@@ -5298,7 +5896,7 @@ async function q5playPreSetup(q) {
|
|
|
5298
5896
|
}
|
|
5299
5897
|
|
|
5300
5898
|
get pos() {
|
|
5301
|
-
return this._pos;
|
|
5899
|
+
return { x: this._pos.x, y: this._pos.y };
|
|
5302
5900
|
}
|
|
5303
5901
|
set pos(val) {
|
|
5304
5902
|
this.x = val[0] ?? val.x;
|
|
@@ -6548,10 +7146,18 @@ async function q5playPreSetup(q) {
|
|
|
6548
7146
|
};
|
|
6549
7147
|
|
|
6550
7148
|
$.delay = (milliseconds) => {
|
|
6551
|
-
if (!milliseconds)
|
|
7149
|
+
if (!milliseconds) {
|
|
7150
|
+
return new Promise((resolve) => {
|
|
7151
|
+
requestAnimationFrame(() => {
|
|
7152
|
+
if (!$._removed) resolve();
|
|
7153
|
+
});
|
|
7154
|
+
});
|
|
7155
|
+
}
|
|
6552
7156
|
// else it wraps setTimeout in a Promise
|
|
6553
7157
|
return new Promise((resolve) => {
|
|
6554
|
-
setTimeout(
|
|
7158
|
+
setTimeout(() => {
|
|
7159
|
+
if (!$._removed) resolve();
|
|
7160
|
+
}, milliseconds);
|
|
6555
7161
|
});
|
|
6556
7162
|
};
|
|
6557
7163
|
|
|
@@ -6601,6 +7207,8 @@ async function q5playPreSetup(q) {
|
|
|
6601
7207
|
$.Canvas = $.createCanvas = function (w, h) {
|
|
6602
7208
|
let args = [...arguments];
|
|
6603
7209
|
|
|
7210
|
+
if (using_p5 && !didCreateCanvas && w == 100 && h == 100) return _createCanvas.call($, ...args);
|
|
7211
|
+
|
|
6604
7212
|
// prevent p5 v1 overriding the user's canvas with a new default canvas
|
|
6605
7213
|
if (didCreateCanvas && w == 100 && h == 100) return;
|
|
6606
7214
|
|
|
@@ -6631,7 +7239,7 @@ async function q5playPreSetup(q) {
|
|
|
6631
7239
|
let rend = _createCanvas.call($, ...args);
|
|
6632
7240
|
$.ctx = $.drawingContext;
|
|
6633
7241
|
let c = rend.canvas || rend;
|
|
6634
|
-
window.canvas = c;
|
|
7242
|
+
if (using_p5) window.canvas = c;
|
|
6635
7243
|
if (rend.GL) {
|
|
6636
7244
|
c.renderer = 'webgl';
|
|
6637
7245
|
$._webgl = true;
|
|
@@ -6698,7 +7306,7 @@ async function q5playPreSetup(q) {
|
|
|
6698
7306
|
return rend;
|
|
6699
7307
|
};
|
|
6700
7308
|
|
|
6701
|
-
$.canvas = $.canvas;
|
|
7309
|
+
$.canvas = $.canvas; // for brython
|
|
6702
7310
|
|
|
6703
7311
|
const _resizeCanvas = $.resizeCanvas;
|
|
6704
7312
|
|
|
@@ -6826,7 +7434,7 @@ async function q5playPreSetup(q) {
|
|
|
6826
7434
|
|
|
6827
7435
|
$.allSprites = new $.Group();
|
|
6828
7436
|
$.world = new $.World();
|
|
6829
|
-
$.camera = new $.Camera();
|
|
7437
|
+
$.camera = $._camera = new $.Camera();
|
|
6830
7438
|
|
|
6831
7439
|
$.InputDevice = class {
|
|
6832
7440
|
constructor() {
|
|
@@ -6901,7 +7509,6 @@ async function q5playPreSetup(q) {
|
|
|
6901
7509
|
|
|
6902
7510
|
this.x = 0;
|
|
6903
7511
|
this.y = 0;
|
|
6904
|
-
this.canvasPos = {};
|
|
6905
7512
|
this.isOnCanvas = false;
|
|
6906
7513
|
this.isActive = false;
|
|
6907
7514
|
this.left = 0;
|
|
@@ -6913,7 +7520,7 @@ async function q5playPreSetup(q) {
|
|
|
6913
7520
|
let _this = this;
|
|
6914
7521
|
|
|
6915
7522
|
// this.x and this.y store the actual position values of the mouse
|
|
6916
|
-
this._pos = $.createVector.call(
|
|
7523
|
+
this._pos = $.createVector.call($, 0, 0);
|
|
6917
7524
|
|
|
6918
7525
|
Object.defineProperty(this._pos, 'x', {
|
|
6919
7526
|
get() {
|
|
@@ -6954,10 +7561,20 @@ async function q5playPreSetup(q) {
|
|
|
6954
7561
|
}
|
|
6955
7562
|
|
|
6956
7563
|
_update() {
|
|
6957
|
-
let cam = $.camera
|
|
6958
|
-
|
|
6959
|
-
|
|
6960
|
-
|
|
7564
|
+
let cam = $.camera,
|
|
7565
|
+
m = this,
|
|
7566
|
+
mx = $.mouseX,
|
|
7567
|
+
my = $.mouseY;
|
|
7568
|
+
|
|
7569
|
+
if (using_p5) {
|
|
7570
|
+
if ($._webgpuFallback) {
|
|
7571
|
+
mx -= $.halfWidth;
|
|
7572
|
+
my -= $.halfHeight;
|
|
7573
|
+
}
|
|
7574
|
+
}
|
|
7575
|
+
|
|
7576
|
+
m.x = mx / cam.zoom + cam.x;
|
|
7577
|
+
m.y = my / cam.zoom + cam.y;
|
|
6961
7578
|
|
|
6962
7579
|
if (m.scroll < 0) m.scroll = 0;
|
|
6963
7580
|
if (m.scrollDelta.x == 0 && m.scrollDelta.y == 0) {
|
|
@@ -6966,7 +7583,7 @@ async function q5playPreSetup(q) {
|
|
|
6966
7583
|
}
|
|
6967
7584
|
|
|
6968
7585
|
get pos() {
|
|
6969
|
-
return this.
|
|
7586
|
+
return { x: this.x, y: this.y };
|
|
6970
7587
|
}
|
|
6971
7588
|
get position() {
|
|
6972
7589
|
return this._pos;
|
|
@@ -7691,7 +8308,7 @@ async function q5playPreSetup(q) {
|
|
|
7691
8308
|
this[indexB] = tmp;
|
|
7692
8309
|
if (indexA == 0 || indexB == 0) {
|
|
7693
8310
|
$.contro = this[0];
|
|
7694
|
-
if (
|
|
8311
|
+
if (using_p5 && $._isGlobal) {
|
|
7695
8312
|
window.contro = this[0];
|
|
7696
8313
|
}
|
|
7697
8314
|
}
|
|
@@ -7778,7 +8395,7 @@ async function q5playPreSetup(q) {
|
|
|
7778
8395
|
fpsPos = 0,
|
|
7779
8396
|
fpsMin = 60,
|
|
7780
8397
|
fpsMax = 240;
|
|
7781
|
-
let statsColor = $.color('lime');
|
|
8398
|
+
let statsColor = $._q5 ? $.color('lime') : 'lime';
|
|
7782
8399
|
|
|
7783
8400
|
$.renderStats = () => {
|
|
7784
8401
|
let rs = $.q5play._renderStats;
|
|
@@ -7879,78 +8496,23 @@ async function q5playPreSetup(q) {
|
|
|
7879
8496
|
jointStack = [],
|
|
7880
8497
|
shapeStack = [];
|
|
7881
8498
|
|
|
7882
|
-
$._syncWorld = () => {
|
|
7883
|
-
jointStack = [];
|
|
7884
|
-
shapeStack = [];
|
|
7885
|
-
|
|
7886
|
-
b2World_Draw(wID, drawCmds.GetDebugDraw());
|
|
7887
|
-
|
|
7888
|
-
let cmdPtr = drawCmds.GetCommandsData(),
|
|
7889
|
-
cmdSize = drawCmds.GetCommandsSize(),
|
|
7890
|
-
cmdStride = drawCmds.GetCommandStride(),
|
|
7891
|
-
offset = cmdPtr,
|
|
7892
|
-
renderJointForces = $.q5play.renderJointForces,
|
|
7893
|
-
s;
|
|
7894
|
-
|
|
7895
|
-
for (let i = 0; i < cmdSize; i++, offset += cmdStride) {
|
|
7896
|
-
// workaround that unpacks data from
|
|
7897
|
-
// the shape material's customColor
|
|
7898
|
-
const customColor = Box2D.HEAPU32[(offset + 4) >> 2],
|
|
7899
|
-
uid = customColor & 0xffffff,
|
|
7900
|
-
isSensor = (customColor >>> 25) & 0x1,
|
|
7901
|
-
isFirstShape = (customColor >>> 26) & 0x1;
|
|
7902
|
-
|
|
7903
|
-
s = $.q5play.sprites[uid];
|
|
7904
|
-
|
|
7905
|
-
let type = Box2D.HEAPU8[offset];
|
|
7906
|
-
|
|
7907
|
-
if (type == 7) {
|
|
7908
|
-
continue;
|
|
7909
|
-
}
|
|
7910
|
-
|
|
7911
|
-
let vertexCount = Box2D.HEAPU16[(offset + 8) >> 1];
|
|
7912
|
-
|
|
7913
|
-
let dataLen = 4;
|
|
7914
|
-
if (type == 1) dataLen = 5 + vertexCount * 2;
|
|
7915
|
-
else if (type == 3 || type == 4) dataLen = 5;
|
|
7916
|
-
let data = new Float32Array(Box2D.HEAPU8.buffer, offset + 12, dataLen);
|
|
7917
|
-
|
|
7918
|
-
if (!s) {
|
|
7919
|
-
if (type == 0 && renderJointForces) jointStack.push(data);
|
|
7920
|
-
continue;
|
|
7921
|
-
}
|
|
7922
|
-
|
|
7923
|
-
// always keep position in sync since it has a low performance cost
|
|
7924
|
-
// unless the shape is a chain
|
|
7925
|
-
if (type < 4 || (type == 4 && !s._hasCapsuleChain)) {
|
|
7926
|
-
s._posX = data[0] * meterSize;
|
|
7927
|
-
s._posY = data[1] * meterSize;
|
|
7928
|
-
}
|
|
7929
|
-
|
|
7930
|
-
s._velSynced = false;
|
|
7931
|
-
s._vel._magCached = false;
|
|
7932
|
-
|
|
7933
|
-
if (!s.visible) {
|
|
7934
|
-
continue;
|
|
7935
|
-
}
|
|
7936
|
-
|
|
7937
|
-
if (s._hasImagery || s._userDefinedDraw) {
|
|
7938
|
-
s._rotation = Math.atan2(data[2], data[3]) * RADTODEG;
|
|
7939
|
-
}
|
|
7940
|
-
|
|
7941
|
-
if (s.debug || (!s._hasImagery && !s._userDefinedDraw)) {
|
|
7942
|
-
shapeStack.push({ type, sprite: s, isSensor, isFirstShape, data, vertexCount });
|
|
7943
|
-
}
|
|
7944
|
-
}
|
|
7945
|
-
};
|
|
7946
|
-
|
|
7947
8499
|
const colorMax = $._colorFormat,
|
|
7948
|
-
debugGreen = $.color(0, colorMax, 0, colorMax * 0.9),
|
|
7949
|
-
debugGreenFill = $.color(0, colorMax, 0, colorMax * 0.1),
|
|
7950
|
-
debugYellow = $.color(colorMax, colorMax, 0, colorMax * 0.9),
|
|
7951
|
-
debugYellowFill = $.color(colorMax, colorMax, 0, colorMax * 0.1);
|
|
7952
|
-
|
|
7953
|
-
if (
|
|
8500
|
+
debugGreen = $._q5 ? $.color(0, colorMax, 0, colorMax * 0.9) : 'lime',
|
|
8501
|
+
debugGreenFill = $._q5 ? $.color(0, colorMax, 0, colorMax * 0.1) : 'lime',
|
|
8502
|
+
debugYellow = $._q5 ? $.color(colorMax, colorMax, 0, colorMax * 0.9) : 'yellow',
|
|
8503
|
+
debugYellowFill = $._q5 ? $.color(colorMax, colorMax, 0, colorMax * 0.1) : 'yellow';
|
|
8504
|
+
|
|
8505
|
+
if (using_p5) {
|
|
8506
|
+
$._getFillIdx = () => $._renderer.states.fillColor;
|
|
8507
|
+
$._setFillIdx = (v) => $.fill(v);
|
|
8508
|
+
$._getStrokeIdx = () => $._renderer.states.strokeColor;
|
|
8509
|
+
$._setStrokeIdx = (v) => {
|
|
8510
|
+
if ($._renderer.states.strokeSet) $.stroke(v);
|
|
8511
|
+
};
|
|
8512
|
+
$._getStrokeWeight = () => [$._renderer.states.strokeWeight];
|
|
8513
|
+
$._setStrokeWeight = (v) => $.strokeWeight(...v);
|
|
8514
|
+
$._getImageMode = () => $._renderer.states.imageMode;
|
|
8515
|
+
} else if ($.canvas.c2d) {
|
|
7954
8516
|
// polyfill for q5 WebGPU high efficiency functions
|
|
7955
8517
|
$._getFillIdx = () => $._fill;
|
|
7956
8518
|
$._setFillIdx = (v) => ($._fill = v);
|
|
@@ -8136,12 +8698,17 @@ async function q5playPreSetup(q) {
|
|
|
8136
8698
|
};
|
|
8137
8699
|
|
|
8138
8700
|
// prettier-ignore
|
|
8139
|
-
let q5playGlobals = ['q5play','Box2D','DYN','DYNAMIC','STA','STATIC','KIN','KINEMATIC','Sprite','Group','allSprites','Ani','Anis','Visual','Visuals','
|
|
8701
|
+
let q5playGlobals = ['q5play','Box2D','DYN','DYNAMIC','STA','STATIC','KIN','KINEMATIC','Sprite','Group','allSprites','Ani','Anis','Visual','Visuals','Joint','GlueJoint','DistanceJoint','WheelJoint','HingeJoint','SliderJoint','GrabberJoint','world','kb','keyboard','mouse','contro','contros','controllers','pointer','pointers','spriteArt','EmojiImage','getFPS','animation','parseTextureAtlas','delay'];
|
|
8140
8702
|
|
|
8141
8703
|
// manually propagate q5play stuff to the global window object
|
|
8142
8704
|
if ($._isGlobal) {
|
|
8143
8705
|
for (let p of q5playGlobals) {
|
|
8144
|
-
window
|
|
8706
|
+
Object.defineProperty(window, p, {
|
|
8707
|
+
value: $[p],
|
|
8708
|
+
configurable: true,
|
|
8709
|
+
writable: false,
|
|
8710
|
+
enumerable: true
|
|
8711
|
+
});
|
|
8145
8712
|
}
|
|
8146
8713
|
}
|
|
8147
8714
|
|
|
@@ -8152,10 +8719,31 @@ async function q5playPreSetup(q) {
|
|
|
8152
8719
|
function q5playPostSetup() {
|
|
8153
8720
|
const $ = this;
|
|
8154
8721
|
|
|
8155
|
-
if ($._isGlobal && window.update)
|
|
8156
|
-
|
|
8722
|
+
if ($._isGlobal && window.update) $.update = window.update;
|
|
8723
|
+
|
|
8724
|
+
if (using_p5) {
|
|
8157
8725
|
// p5 won't run the draw loop without a draw function defined
|
|
8158
|
-
|
|
8726
|
+
window.draw = () => {};
|
|
8727
|
+
|
|
8728
|
+
$.loge = $.log;
|
|
8729
|
+
$.log = console.log;
|
|
8730
|
+
$.camera = $._camera;
|
|
8731
|
+
|
|
8732
|
+
if ($._isGlobal) {
|
|
8733
|
+
Object.defineProperty(window, 'log', {
|
|
8734
|
+
value: console.log
|
|
8735
|
+
});
|
|
8736
|
+
Object.defineProperty(window, 'loge', {
|
|
8737
|
+
value: $.loge
|
|
8738
|
+
});
|
|
8739
|
+
$.camera3D = window.camera;
|
|
8740
|
+
Object.defineProperty(window, 'camera3D', {
|
|
8741
|
+
value: $.camera3D
|
|
8742
|
+
});
|
|
8743
|
+
Object.defineProperty(window, 'camera', {
|
|
8744
|
+
value: $.camera
|
|
8745
|
+
});
|
|
8746
|
+
}
|
|
8159
8747
|
}
|
|
8160
8748
|
|
|
8161
8749
|
$.update ??= $.clear;
|
|
@@ -8167,9 +8755,11 @@ function q5playPostSetup() {
|
|
|
8167
8755
|
function q5playUpdate() {
|
|
8168
8756
|
const $ = this;
|
|
8169
8757
|
|
|
8170
|
-
if (
|
|
8758
|
+
if (using_p5) {
|
|
8171
8759
|
$.q5play._preDrawFrameTime = performance.now();
|
|
8760
|
+
$.resetMatrix();
|
|
8172
8761
|
}
|
|
8762
|
+
|
|
8173
8763
|
$.q5play.spritesDrawn = 0;
|
|
8174
8764
|
|
|
8175
8765
|
$.contros._update();
|
|
@@ -8242,7 +8832,6 @@ function q5playUpdate() {
|
|
|
8242
8832
|
|
|
8243
8833
|
if ($.world.autoStep && $.world.timeScale > 0) {
|
|
8244
8834
|
$.world.physicsUpdate();
|
|
8245
|
-
$._syncWorld();
|
|
8246
8835
|
}
|
|
8247
8836
|
$.world.autoStep ??= true;
|
|
8248
8837
|
|
|
@@ -8313,7 +8902,7 @@ function q5playPostDraw() {
|
|
|
8313
8902
|
else if ($.kb[k] > 0) $.kb[k]++;
|
|
8314
8903
|
}
|
|
8315
8904
|
|
|
8316
|
-
if (
|
|
8905
|
+
if (using_p5) {
|
|
8317
8906
|
$.q5play._postDrawFrameTime = performance.now();
|
|
8318
8907
|
$.q5play._fps = Math.round(1000 / ($.q5play._postDrawFrameTime - $.q5play._preDrawFrameTime)) || 1;
|
|
8319
8908
|
}
|
|
@@ -8321,6 +8910,7 @@ function q5playPostDraw() {
|
|
|
8321
8910
|
}
|
|
8322
8911
|
|
|
8323
8912
|
function q5playRemove() {
|
|
8913
|
+
this._removed = true;
|
|
8324
8914
|
this.world?.delete();
|
|
8325
8915
|
}
|
|
8326
8916
|
|
|
@@ -8405,16 +8995,19 @@ addAnis -> es:añadirAnis
|
|
|
8405
8995
|
changeAni -> es:cambiarAni
|
|
8406
8996
|
playAni -> es:reproducirAni
|
|
8407
8997
|
playAnis -> es:reproducirAnis
|
|
8998
|
+
moveTo -> es:moverA
|
|
8408
8999
|
moveTowards -> es:moverHacia
|
|
9000
|
+
rotateTo -> es:rotarA
|
|
8409
9001
|
rotateTowards -> es:rotarHacia
|
|
9002
|
+
transformTowards -> es:transformarHacia
|
|
8410
9003
|
applyForce -> es:aplicarFuerza
|
|
8411
9004
|
applyForceScaled -> es:aplicarFuerzaEscalada
|
|
8412
9005
|
attractTo -> es:atraerA
|
|
8413
9006
|
repelFrom -> es:repelerDe
|
|
8414
9007
|
applyTorque -> es:aplicarTorque
|
|
8415
|
-
|
|
8416
|
-
|
|
8417
|
-
|
|
9008
|
+
applyWind -> es:aplicarViento
|
|
9009
|
+
angleTo -> es:ánguloA
|
|
9010
|
+
angleDistTo -> es:distÁnguloA
|
|
8418
9011
|
setSpeedAndDirection -> es:establecerVelocidadYDirección
|
|
8419
9012
|
scaleBy -> es:escalarPor
|
|
8420
9013
|
resetMass -> es:reiniciarMasa
|
|
@@ -8518,6 +9111,56 @@ pressure -> es:presión
|
|
|
8518
9111
|
};
|
|
8519
9112
|
q5playClassLangs.Group += q5playClassLangs.Sprite;
|
|
8520
9113
|
|
|
9114
|
+
if (typeof globalThis.Q5 == 'undefined') {
|
|
9115
|
+
console.warn('p5.js v2 is not fully compatible with q5play. Consider using q5 instead: https://q5js.org');
|
|
9116
|
+
|
|
9117
|
+
p5.addHook = (hook, fn) => {
|
|
9118
|
+
p5.registerAddon((p5, proto, lifecycles) => {
|
|
9119
|
+
lifecycles[hook] = fn;
|
|
9120
|
+
});
|
|
9121
|
+
};
|
|
9122
|
+
|
|
9123
|
+
// p5.js v2 compatibility layer
|
|
9124
|
+
globalThis.Canvas = (...args) => {
|
|
9125
|
+
return new Promise((resolve) => {
|
|
9126
|
+
window.setup = async function () {
|
|
9127
|
+
const $ = p5.instance;
|
|
9128
|
+
$._webgpu = $._webgpuFallback = true;
|
|
9129
|
+
|
|
9130
|
+
$.Canvas(...args);
|
|
9131
|
+
|
|
9132
|
+
// q5play defaults
|
|
9133
|
+
colorMode(RGB, 1);
|
|
9134
|
+
imageMode(CENTER);
|
|
9135
|
+
|
|
9136
|
+
$.halfWidth = width / 2;
|
|
9137
|
+
$.halfHeight = height / 2;
|
|
9138
|
+
|
|
9139
|
+
let _resetMatrix = $.resetMatrix;
|
|
9140
|
+
|
|
9141
|
+
$.resetMatrix = () => {
|
|
9142
|
+
_resetMatrix.call($);
|
|
9143
|
+
$.translate($.halfWidth, $.halfHeight);
|
|
9144
|
+
};
|
|
9145
|
+
|
|
9146
|
+
Object.defineProperty(p5, 'update', {
|
|
9147
|
+
set(fn) {
|
|
9148
|
+
$.update = fn;
|
|
9149
|
+
},
|
|
9150
|
+
get() {
|
|
9151
|
+
return $.update;
|
|
9152
|
+
},
|
|
9153
|
+
configurable: true
|
|
9154
|
+
});
|
|
9155
|
+
|
|
9156
|
+
resolve();
|
|
9157
|
+
};
|
|
9158
|
+
});
|
|
9159
|
+
};
|
|
9160
|
+
|
|
9161
|
+
globalThis.Q5 = globalThis.q5 = p5;
|
|
9162
|
+
}
|
|
9163
|
+
|
|
8521
9164
|
Q5.addHook('presetup', q5playPreSetup);
|
|
8522
9165
|
Q5.addHook('postsetup', q5playPostSetup);
|
|
8523
9166
|
Q5.addHook('predraw', q5playUpdate);
|