q5play 4.0.2 → 4.0.5

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.
Files changed (3) hide show
  1. package/package.json +1 -1
  2. package/q5play.d.ts +0 -16
  3. package/q5play.js +277 -64
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "q5play",
3
- "version": "4.0.2",
3
+ "version": "4.0.5",
4
4
  "author": "quinton-ashley",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "description": "A web-based game engine that uses q5.js WebGPU for graphics and Box2D v3 WASM for physics.",
package/q5play.d.ts CHANGED
@@ -41,17 +41,6 @@ declare global {
41
41
  * @default true
42
42
  */
43
43
  friendlyRounding: boolean;
44
- /**
45
- * Snaps sprites to the nearest `q5play.gridSize`
46
- * increment when they are moved.
47
- * @default false
48
- */
49
- snapToGrid: boolean;
50
- /**
51
- * The size of the grid cells that sprites are snapped to.
52
- * @default 0.5
53
- */
54
- gridSize: number;
55
44
  /**
56
45
  * Information about the operating system being used.
57
46
  */
@@ -596,11 +585,6 @@ declare global {
596
585
  */
597
586
  get heading(): string;
598
587
  set heading(val: string);
599
- /**
600
- * True if the sprite is moving.
601
- * @readonly
602
- */
603
- get isMoving(): boolean;
604
588
  /**
605
589
  * Set this to true if the sprite goes really fast to prevent
606
590
  * inaccurate physics simulation.
package/q5play.js CHANGED
@@ -30,8 +30,9 @@ if (typeof globalThis.Q5 == 'undefined') {
30
30
  let box2dPromise;
31
31
 
32
32
  // called when a new instance of Q5 is created
33
- async function q5playPreSetup($, q) {
34
- const log = console.log;
33
+ async function q5playPreSetup(q) {
34
+ const $ = this,
35
+ log = console.log;
35
36
 
36
37
  if (!box2dPromise) {
37
38
  box2dPromise = (async () => {
@@ -243,8 +244,6 @@ async function q5playPreSetup($, q) {
243
244
  this.spritesDrawn = 0;
244
245
  this.images = {};
245
246
  this.palettes = [];
246
- this.snapToGrid = false;
247
- this.gridSize = 0.5;
248
247
  this.emojiScale = 1;
249
248
  this.os = {};
250
249
  this.context = 'web';
@@ -1022,18 +1021,17 @@ async function q5playPreSetup($, q) {
1022
1021
  else y = 0;
1023
1022
  }
1024
1023
 
1025
- let rr;
1026
-
1027
1024
  let forcedBoxShape = false;
1028
1025
  if (w === undefined) {
1029
1026
  w = group.w || group.width || group.d || group.diameter;
1030
1027
  if (!h && !group.d && !group.diameter) {
1031
1028
  h = group.h || group.height;
1032
1029
  forcedBoxShape = true;
1033
- rr = group.roundedRadius;
1034
1030
  }
1035
1031
  }
1036
1032
 
1033
+ let rr = group.roundedRadius;
1034
+
1037
1035
  if (typeof x == 'function') x = x(group.length);
1038
1036
  if (typeof y == 'function') y = y(group.length);
1039
1037
  if (typeof w == 'function') w = w(group.length);
@@ -1506,11 +1504,11 @@ async function q5playPreSetup($, q) {
1506
1504
  } else {
1507
1505
  let hw = (w * 0.5) / meterSize;
1508
1506
  let hh = (h * 0.5) / meterSize;
1509
- rr /= meterSize;
1507
+ let _rr = rr / meterSize;
1510
1508
 
1511
1509
  if (rr) {
1512
- hw = Math.max(hw - rr, 0.001);
1513
- hh = Math.max(hh - rr, 0.001);
1510
+ hw = Math.max(hw - _rr, 0.001);
1511
+ hh = Math.max(hh - _rr, 0.001);
1514
1512
  }
1515
1513
 
1516
1514
  if (offsetX || offsetY) {
@@ -1518,26 +1516,29 @@ async function q5playPreSetup($, q) {
1518
1516
 
1519
1517
  if (!rr) geom = b2MakeOffsetBox(hw, hh, offset, ZERO_ROT);
1520
1518
  else {
1521
- geom = b2MakeOffsetRoundedBox(hw, hh, offset, ZERO_ROT, rr);
1519
+ geom = b2MakeOffsetRoundedBox(hw, hh, offset, ZERO_ROT, _rr);
1522
1520
  }
1523
1521
  } else {
1524
1522
  if (!rr) geom = b2MakeBox(hw, hh);
1525
- else geom = b2MakeRoundedBox(hw, hh, rr);
1523
+ else geom = b2MakeRoundedBox(hw, hh, _rr);
1526
1524
  }
1527
1525
 
1528
1526
  geom._hw = hw;
1529
1527
  geom._hh = hh;
1530
- geom._rr = rr;
1528
+ geom._rr = _rr;
1531
1529
 
1532
1530
  id = b2CreatePolygonShape(bdID, shape.def, geom);
1533
1531
  shape._init(id, 0, geom);
1534
1532
  }
1535
1533
 
1536
1534
  // TODO: use AABB to get extents
1537
- this._w = w;
1538
- this._hw = w * 0.5;
1539
- this._h = h;
1540
- this._hh = h * 0.5;
1535
+ if (!shapes.length) {
1536
+ this._w = w;
1537
+ this._hw = w * 0.5;
1538
+ this._h = h;
1539
+ this._hh = h * 0.5;
1540
+ this._roundedRadius = rr;
1541
+ }
1541
1542
  }
1542
1543
 
1543
1544
  if (shape) {
@@ -1875,10 +1876,6 @@ async function q5playPreSetup($, q) {
1875
1876
  this.direction = val;
1876
1877
  }
1877
1878
 
1878
- get isMoving() {
1879
- return this.vel.x != 0 || this.vel.y != 0;
1880
- }
1881
-
1882
1879
  get isSuperFast() {
1883
1880
  return b2Body_IsBullet(this.bdID);
1884
1881
  }
@@ -2301,6 +2298,21 @@ async function q5playPreSetup($, q) {
2301
2298
  this.d = val;
2302
2299
  }
2303
2300
 
2301
+ get roundedRadius() {
2302
+ return this._roundedRadius;
2303
+ }
2304
+ set roundedRadius(val) {
2305
+ if (val == this._roundedRadius) return;
2306
+
2307
+ this._roundedRadius = val;
2308
+ if (this.watch) this.mod[37] = true;
2309
+
2310
+ while (this._shapes.length) {
2311
+ this._shapes.at(-1).delete();
2312
+ }
2313
+ this._add(false, 0, 0, this._w, this._h, val);
2314
+ }
2315
+
2304
2316
  /*
2305
2317
  * Validates convexity.
2306
2318
  */
@@ -2338,13 +2350,6 @@ async function q5playPreSetup($, q) {
2338
2350
  this._customUpdate = val;
2339
2351
  }
2340
2352
 
2341
- get postDraw() {
2342
- return this._postDraw;
2343
- }
2344
- set postDraw(val) {
2345
- this._customPostDraw = val;
2346
- }
2347
-
2348
2353
  get vel() {
2349
2354
  return this._vel;
2350
2355
  }
@@ -2619,13 +2624,6 @@ async function q5playPreSetup($, q) {
2619
2624
  }
2620
2625
  }
2621
2626
 
2622
- _postDraw() {
2623
- if (this._customPostDraw) this._customPostDraw();
2624
-
2625
- this.autoDraw ??= true;
2626
- this.autoUpdate ??= true;
2627
- }
2628
-
2629
2627
  _args2Vec(x, y) {
2630
2628
  if (Array.isArray(x)) {
2631
2629
  return { x: x[0], y: x[1] };
@@ -3114,8 +3112,9 @@ async function q5playPreSetup($, q) {
3114
3112
 
3115
3113
  // exclude props that are inherited in a special way or not traits
3116
3114
  const spriteStdInheritedProps = $.Sprite.propsAll.filter(
3115
+ // prettier-ignore
3117
3116
  (p) =>
3118
- !['ani', 'd', 'diameter', 'h', 'height', 'physics', 'scale', 'tile', 'w', 'width', 'vel', 'x', 'y'].includes(p)
3117
+ !['ani', 'd', 'diameter', 'h', 'height', 'physics', 'scale', 'tile', 'w', 'width', 'vel', 'x', 'y', 'roundedRadius'].includes(p)
3119
3118
  );
3120
3119
 
3121
3120
  let groupKeys = {};
@@ -3176,9 +3175,12 @@ async function q5playPreSetup($, q) {
3176
3175
  }
3177
3176
 
3178
3177
  // loading promise
3179
- this.promise = new Promise((resolve) => {
3180
- this._resolve = resolve;
3181
- });
3178
+ if (args.length) {
3179
+ this.promise = new Promise((resolve) => {
3180
+ this._resolve = resolve;
3181
+ });
3182
+ $._loaders.push(this.promise);
3183
+ }
3182
3184
 
3183
3185
  this._frame = 0;
3184
3186
  this._cycles = 0;
@@ -3393,12 +3395,16 @@ async function q5playPreSetup($, q) {
3393
3395
 
3394
3396
  // play by default but a single frame ani doesn't need to play
3395
3397
  this.playing = this.length != 1 && anis.playing != false;
3398
+
3399
+ if (this.length > 0 && !this.spriteSheet) {
3400
+ Promise.all(this.map((img) => img.promise)).then(() => this._resolve(this));
3401
+ }
3396
3402
  }
3397
3403
 
3398
- // make loading Ani objects awaitable
3399
- // then(resolve, reject) {
3400
- // return this.promise.then(resolve, reject);
3401
- // }
3404
+ // use a plain Array constructor for map/filter/etc.
3405
+ static get [Symbol.species]() {
3406
+ return Array;
3407
+ }
3402
3408
 
3403
3409
  get frame() {
3404
3410
  return this._frame;
@@ -4724,12 +4730,6 @@ async function q5playPreSetup($, q) {
4724
4730
 
4725
4731
  $.imageMode(ogImgMode);
4726
4732
  }
4727
-
4728
- postDraw() {
4729
- for (let s of this) {
4730
- s.postDraw();
4731
- }
4732
- }
4733
4733
  };
4734
4734
 
4735
4735
  $.Group.prototype.__step = $.Sprite.prototype.__step;
@@ -6120,8 +6120,11 @@ async function q5playPreSetup($, q) {
6120
6120
  }
6121
6121
 
6122
6122
  function isArrowFunction(fn) {
6123
- return !/^(?:(?:\/\*[^(?:\*\/)]*\*\/\s*)|(?:\/\/[^\r\n]*))*\s*(?:(?:(?:async\s(?:(?:\/\*[^(?:\*\/)]*\*\/\s*)|(?:\/\/[^\r\n]*))*\s*)?function|class)(?:\s|(?:(?:\/\*[^(?:\*\/)]*\*\/\s*)|(?:\/\/[^\r\n]*))*)|(?:[_$\w][\w0-9_$]*\s*(?:\/\*[^(?:\*\/)]*\*\/\s*)*\s*\()|(?:\[\s*(?:\/\*[^(?:\*\/)]*\*\/\s*)*\s*(?:(?:['][^']+['])|(?:["][^"]+["]))\s*(?:\/\*[^(?:\*\/)]*\*\/\s*)*\s*\]\())/.test(
6124
- fn.toString()
6123
+ return (
6124
+ fn.name == 'jsobj' || // brython lambda function check
6125
+ !/^(?:(?:\/\*[^(?:\*\/)]*\*\/\s*)|(?:\/\/[^\r\n]*))*\s*(?:(?:(?:async\s(?:(?:\/\*[^(?:\*\/)]*\*\/\s*)|(?:\/\/[^\r\n]*))*\s*)?function|class)(?:\s|(?:(?:\/\*[^(?:\*\/)]*\*\/\s*)|(?:\/\/[^\r\n]*))*)|(?:[_$\w][\w0-9_$]*\s*(?:\/\*[^(?:\*\/)]*\*\/\s*)*\s*\()|(?:\[\s*(?:\/\*[^(?:\*\/)]*\*\/\s*)*\s*(?:(?:['][^']+['])|(?:["][^"]+["]))\s*(?:\/\*[^(?:\*\/)]*\*\/\s*)*\s*\]\())/.test(
6126
+ fn.toString()
6127
+ )
6125
6128
  );
6126
6129
  }
6127
6130
 
@@ -6238,6 +6241,8 @@ async function q5playPreSetup($, q) {
6238
6241
 
6239
6242
  let img = g.get(left, top, right - left + 1, bottom - top + 1);
6240
6243
  img.src = emoji;
6244
+ img.defaultWidth = img.width;
6245
+ img.defaultHeight = img.height;
6241
6246
 
6242
6247
  g.remove();
6243
6248
 
@@ -6482,6 +6487,7 @@ async function q5playPreSetup($, q) {
6482
6487
  args[0] = window.innerWidth;
6483
6488
  args[1] = window.innerHeight;
6484
6489
  }
6490
+ args[1] ??= args[0];
6485
6491
  args[0] = Math.floor(args[0] / 2) * 2;
6486
6492
  args[1] = Math.floor(args[1] / 2) * 2;
6487
6493
  let rend = _createCanvas.call($, ...args);
@@ -7057,18 +7063,26 @@ async function q5playPreSetup($, q) {
7057
7063
  super();
7058
7064
  this._default = ' ';
7059
7065
 
7060
- this.alt = 0;
7061
- this.arrowUp = 0;
7062
- this.arrowDown = 0;
7063
- this.arrowLeft = 0;
7064
- this.arrowRight = 0;
7065
- this.backspace = 0;
7066
- this.capsLock = 0;
7067
- this.control = 0;
7068
- this.enter = 0;
7069
- this.meta = 0;
7070
- this.shift = 0;
7071
- this.tab = 0;
7066
+ let keys = [
7067
+ ' ',
7068
+ 'alt',
7069
+ 'arrowUp',
7070
+ 'arrowDown',
7071
+ 'arrowLeft',
7072
+ 'arrowRight',
7073
+ 'backspace',
7074
+ 'capsLock',
7075
+ 'control',
7076
+ 'enter',
7077
+ 'meta',
7078
+ 'shift',
7079
+ 'tab'
7080
+ ];
7081
+ keys = keys.concat("abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-=[];,./'".split(''));
7082
+ // initializing these props to 0 makes brython happy
7083
+ for (let key of keys) {
7084
+ this[key] = 0;
7085
+ }
7072
7086
 
7073
7087
  let k = (this._simpleKeyControls = {
7074
7088
  arrowUp: 'up',
@@ -7992,6 +8006,8 @@ async function q5playPreSetup($, q) {
7992
8006
  window[p] = $[p];
7993
8007
  }
7994
8008
  }
8009
+
8010
+ if (Q5.applyLang) Q5.applyLang(q, q5playLibLangs, q5playClassLangs);
7995
8011
  }
7996
8012
 
7997
8013
  // called once after setup
@@ -8120,7 +8136,10 @@ function q5playPostDraw() {
8120
8136
 
8121
8137
  if (cam.isActive) cam.off();
8122
8138
 
8123
- $.allSprites.postDraw();
8139
+ for (let s of $.allSprites) {
8140
+ s.autoDraw ??= true;
8141
+ s.autoUpdate ??= true;
8142
+ }
8124
8143
 
8125
8144
  if ($.q5play.renderStats) $.renderStats();
8126
8145
 
@@ -8167,6 +8186,200 @@ function q5playRemove() {
8167
8186
  this.world?.delete();
8168
8187
  }
8169
8188
 
8189
+ const q5playLibLangs = `
8190
+ allSprites -> es:todosLosSprites
8191
+ world -> es:mundo
8192
+ camera -> es:cámara
8193
+ mouse -> es:ratón
8194
+ kb -> es:tec
8195
+ keyboard -> es:teclado
8196
+ contro -> es:mando
8197
+ controllers -> es:mandos
8198
+ pointer -> es:puntero
8199
+ pointers -> es:punteros
8200
+ spriteArt -> es:arteSprite
8201
+ delay -> es:esperar
8202
+ animation -> es:animación
8203
+ renderStats -> es:estadísticasRenderizado
8204
+ EmojiImage -> es:ImagenEmoji
8205
+ parseTextureAtlas -> es:parsearAtlasTextura
8206
+ DYNAMIC -> es:DINÁMICO
8207
+ STATIC -> es:ESTÁTICO
8208
+ KINEMATIC -> es:CINEMÁTICO
8209
+ Group -> es:Grupo
8210
+ Joint -> es:Articulación
8211
+ `;
8212
+
8213
+ const q5playClassLangs = {
8214
+ Sprite: `
8215
+ rotation -> es:rotación
8216
+ rotationSpeed -> es:velocidadRotación
8217
+ rotationDrag -> es:resistenciaRotación
8218
+ rotationLock -> es:bloqueoRotación
8219
+ speed -> es:velocidad
8220
+ direction -> es:dirección
8221
+ drag -> es:amortiguación
8222
+ mass -> es:masa
8223
+ density -> es:densidad
8224
+ bounciness -> es:elasticidad
8225
+ friction -> es:fricción
8226
+ physicsEnabled -> es:físicaActivada
8227
+ physicsType -> es:tipoFísica
8228
+ physics -> es:física
8229
+ sleeping -> es:durmiendo
8230
+ allowSleeping -> es:permitirDormir
8231
+ layer -> es:capa
8232
+ life -> es:vida
8233
+ scale -> es:escala
8234
+ tint -> es:tinte
8235
+ opacity -> es:opacidad
8236
+ visible -> es:visible
8237
+ debug -> es:depurar
8238
+ deleted -> es:eliminado
8239
+ bearing -> es:rumbo
8240
+ heading -> es:orientación
8241
+ isSuperFast -> es:esUltraRápido
8242
+ pixelPerfect -> es:perfectoEnPíxeles
8243
+ gravityScale -> es:escalaGravedad
8244
+ diameter -> es:diámetro
8245
+ roundedRadius -> es:radioRedondeado
8246
+ centerOfMass -> es:centroMasa
8247
+ previousPosition -> es:posiciónAnterior
8248
+ previousRotation -> es:rotaciónAnterior
8249
+ velocity -> es:vectorVelocidad
8250
+ position -> es:posición
8251
+ canvasPos -> es:posiciónLienzo
8252
+ addCollider -> es:añadirColisionador
8253
+ addSensor -> es:añadirSensor
8254
+ deleteColliders -> es:eliminarColisionadores
8255
+ deleteSensors -> es:eliminarSensores
8256
+ collide -> es:colisionar
8257
+ collides -> es:colisiona
8258
+ colliding -> es:colisionando
8259
+ collided -> es:colisionó
8260
+ overlap -> es:solapar
8261
+ overlaps -> es:solapa
8262
+ overlapping -> es:solapando
8263
+ overlapped -> es:solapó
8264
+ passes -> es:pasa
8265
+ addAni -> es:añadirAni
8266
+ addAnis -> es:añadirAnis
8267
+ changeAni -> es:cambiarAni
8268
+ playAni -> es:reproducirAni
8269
+ playAnis -> es:reproducirAnis
8270
+ moveTowards -> es:moverHacia
8271
+ rotateTowards -> es:rotarHacia
8272
+ applyForce -> es:aplicarFuerza
8273
+ applyForceScaled -> es:aplicarFuerzaEscalada
8274
+ attractTo -> es:atraerA
8275
+ repelFrom -> es:repelerDe
8276
+ applyTorque -> es:aplicarTorque
8277
+ angleTo -> es:ánguloHacia
8278
+ rotationToFace -> es:rotaciónParaMirar
8279
+ angleToFace -> es:ánguloParaMirar
8280
+ setSpeedAndDirection -> es:establecerVelocidadYDirección
8281
+ scaleBy -> es:escalarPor
8282
+ resetMass -> es:reiniciarMasa
8283
+ distanceTo -> es:distanciaA
8284
+ delete -> es:eliminar
8285
+ addDefaultSensors -> es:añadirSensoresDefecto
8286
+ autoDraw -> es:autoDibujar
8287
+ draw -> es:dibujar
8288
+ autoUpdate -> es:autoActualizar
8289
+ update -> es:actualizar
8290
+ `,
8291
+ Group: `
8292
+ Group -> es:Grupo
8293
+ amount -> es:cantidad
8294
+ autoCull -> es:descartarFueraCampo
8295
+ cull -> es:descartar
8296
+ contains -> es:contiene
8297
+ remove -> es:quitar
8298
+ removeAll -> es:quitarTodo
8299
+ delete -> es:eliminar
8300
+ deleteAll -> es:eliminarTodo
8301
+ `,
8302
+ World: `
8303
+ gravity -> es:gravedad
8304
+ timeScale -> es:escalaVelocidad
8305
+ meterSize -> es:tamañoMetro
8306
+ allowSleeping -> es:permitirDormir
8307
+ awakeBodies -> es:cuerposDespiertos
8308
+ bounceThreshold -> es:umbralRebote
8309
+ hitThreshold -> es:umbralGolpe
8310
+ autoStep -> es:pasoAutomático
8311
+ subSteps -> es:subPasos
8312
+ explodeAt -> es:explosionEn
8313
+ delete -> es:eliminar
8314
+ `,
8315
+ Camera: `
8316
+ position -> es:posición
8317
+ zoom ->
8318
+ moveTo -> es:moverA
8319
+ zoomTo -> es:acercarA
8320
+ on -> es:activar
8321
+ off -> es:desactivar
8322
+ `,
8323
+ Ani: `
8324
+ play -> es:reproducir
8325
+ pause -> es:pausar
8326
+ stop -> es:parar
8327
+ loop -> es:bucle
8328
+ noLoop -> es:sinBucle
8329
+ rewind -> es:rebobinar
8330
+ nextFrame -> es:siguienteFotograma
8331
+ previousFrame -> es:fotogramaAnterior
8332
+ goToFrame -> es:irAlFotograma
8333
+ clone -> es:clonar
8334
+ frame -> es:fotograma
8335
+ lastFrame -> es:últimoFotograma
8336
+ frameImage -> es:imagenFotograma
8337
+ playing -> es:reproduciendo
8338
+ looping -> es:enBucle
8339
+ frameDelay -> es:retardoFotograma
8340
+ `,
8341
+ InputDevice: `
8342
+ presses -> es:presiona
8343
+ pressing -> es:presionando
8344
+ holds -> es:mantiene
8345
+ holding -> es:manteniendo
8346
+ held -> es:mantuvo
8347
+ released -> es:soltó
8348
+ releases -> es:suelta
8349
+ holdThreshold -> es:umbralMantener
8350
+ `,
8351
+ _Mouse: `
8352
+ position -> es:posición
8353
+ visible -> es:visible
8354
+ isOnCanvas -> es:estaEnLienzo
8355
+ scroll -> es:desplazamiento
8356
+ drags -> es:arrastra
8357
+ dragging -> es:arrastrando
8358
+ dragged -> es:arrastró
8359
+ scrolls -> es:desplaza
8360
+ scrolling -> es:desplazando
8361
+ scrolled -> es:desplazó
8362
+ `,
8363
+ _Pointer: `
8364
+ prev -> es:previo
8365
+ canvasPos -> es:posEnLienzo
8366
+ type -> es:tipo
8367
+ duration -> es:duración
8368
+ holdThreshold -> es:umbralDeSostenido
8369
+ drags -> es:arrastra
8370
+ dragging -> es:arrastrando
8371
+ dragged -> es:arrastró
8372
+ grabs -> es:agarra
8373
+ grabbing -> es:agarrando
8374
+ grabbed -> es:agarró
8375
+ overlaps -> es:superpone
8376
+ overlapping -> es:superponiendo
8377
+ overlapped -> es:superpuso
8378
+ pressure -> es:presión
8379
+ `
8380
+ };
8381
+ q5playClassLangs.Group += q5playClassLangs.Sprite;
8382
+
8170
8383
  Q5.addHook('presetup', q5playPreSetup);
8171
8384
  Q5.addHook('postsetup', q5playPostSetup);
8172
8385
  Q5.addHook('predraw', q5playPreDraw);