littlejsengine 1.9.9 → 1.9.11

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.
@@ -1549,9 +1549,9 @@ class EngineObject
1549
1549
 
1550
1550
  // apply physics
1551
1551
  const oldPos = this.pos.copy();
1552
- this.velocity.y += gravity * this.gravityScale;
1553
1552
  this.pos.x += this.velocity.x *= this.damping;
1554
- this.pos.y += this.velocity.y *= this.damping;
1553
+ this.pos.y += this.velocity.y = this.damping * this.velocity.y
1554
+ + gravity * this.gravityScale;
1555
1555
  this.angle += this.angleVelocity *= this.angleDamping;
1556
1556
 
1557
1557
  // physics sanity checks
@@ -1680,19 +1680,22 @@ class EngineObject
1680
1680
  const isBlockedX = tileCollisionTest(vec2(this.pos.x, oldPos.y), this.size, this);
1681
1681
  if (isBlockedY || !isBlockedX)
1682
1682
  {
1683
- // set if landed on ground
1684
- this.groundObject = wasMovingDown;
1685
-
1686
1683
  // bounce velocity
1687
1684
  this.velocity.y *= -this.elasticity;
1688
1685
 
1689
- // adjust next velocity to settle on ground
1690
- const o = (oldPos.y - this.size.y/2|0) - (oldPos.y - this.size.y/2);
1691
- if (o < 0 && o > this.damping * this.velocity.y + gravity * this.gravityScale)
1692
- this.velocity.y = this.damping ? (o - gravity * this.gravityScale) / this.damping : 0;
1693
-
1694
- // move to previous position
1695
- this.pos.y = oldPos.y;
1686
+ // set if landed on ground
1687
+ if (this.groundObject = wasMovingDown)
1688
+ {
1689
+ // adjust position to slightly above nearest tile boundary
1690
+ // this prevents gap between object and ground
1691
+ const epsilon = .0001;
1692
+ this.pos.y = (oldPos.y-this.size.y/2|0)+this.size.y/2+epsilon;
1693
+ }
1694
+ else
1695
+ {
1696
+ // move to previous position
1697
+ this.pos.y = oldPos.y;
1698
+ }
1696
1699
  }
1697
1700
  if (isBlockedX)
1698
1701
  {
@@ -2542,6 +2545,10 @@ function inputInit()
2542
2545
  // mouse event handlers
2543
2546
  onmousedown = (e)=>
2544
2547
  {
2548
+ // fix stalled audio requiring user interaction
2549
+ if (soundEnable && !headlessMode && audioContext && audioContext.state != 'running')
2550
+ audioContext.resume();
2551
+
2545
2552
  isUsingGamepad = false;
2546
2553
  inputData[0][e.button] = 3;
2547
2554
  mousePosScreen = mouseToScreen(e);
@@ -2553,7 +2560,7 @@ function inputInit()
2553
2560
  oncontextmenu = (e)=> false; // prevent right click menu
2554
2561
 
2555
2562
  // init touch input
2556
- if (isTouchDevice && touchInputEnable && !headlessMode)
2563
+ if (isTouchDevice && touchInputEnable)
2557
2564
  touchInputInit();
2558
2565
  }
2559
2566
 
@@ -2710,8 +2717,8 @@ function touchInputInit()
2710
2717
  function handleTouchDefault(e)
2711
2718
  {
2712
2719
  // fix stalled audio requiring user interaction
2713
- if (soundEnable && audioContext && audioContext.state != 'running')
2714
- zzfx(0);
2720
+ if (soundEnable && !headlessMode && audioContext && audioContext.state != 'running')
2721
+ audioContext.resume();
2715
2722
 
2716
2723
  // check if touching and pass to mouse events
2717
2724
  const touching = e.touches.length;
@@ -2924,6 +2931,7 @@ class Sound
2924
2931
  // generate zzfx sound now for fast playback
2925
2932
  const defaultRandomness = .05;
2926
2933
  this.randomness = zzfxSound[1] || defaultRandomness;
2934
+ zzfxSound[1] = 0; // generate without randomness
2927
2935
  this.sampleChannels = [zzfxG(...zzfxSound)];
2928
2936
  this.sampleRate = zzfxR;
2929
2937
  }
@@ -3156,10 +3164,6 @@ function getNoteFrequency(semitoneOffset, rootFrequency=220)
3156
3164
 
3157
3165
  ///////////////////////////////////////////////////////////////////////////////
3158
3166
 
3159
- // internal tracking if audio was suspended when last sound was played
3160
- // allows first suspended sound to play when audio is resumed
3161
- let audioSuspended = false;
3162
-
3163
3167
  /** Play cached audio samples with given settings
3164
3168
  * @param {Array} sampleChannels - Array of arrays of samples to play (for stereo playback)
3165
3169
  * @param {Number} [volume] - How much to scale volume by
@@ -3175,20 +3179,21 @@ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=false, sample
3175
3179
  if (!soundEnable || headlessMode) return;
3176
3180
 
3177
3181
  // prevent sounds from building up if they can't be played
3178
- const audioWasSuspended = audioSuspended;
3179
- if (audioSuspended = audioContext.state != 'running')
3182
+ if (audioContext.state != 'running')
3180
3183
  {
3181
3184
  // fix stalled audio
3182
- audioContext.resume();
3185
+ audioContext.resume().then(()=>
3186
+ playSamples(sampleChannels, volume, rate, pan, loop, sampleRate, gainNode));
3183
3187
 
3184
3188
  // prevent suspended sounds from building up
3185
- if (audioWasSuspended)
3186
- return;
3189
+ return;
3187
3190
  }
3188
3191
 
3189
3192
  // create buffer and source
3190
- const buffer = audioContext.createBuffer(sampleChannels.length, sampleChannels[0].length, sampleRate),
3191
- source = audioContext.createBufferSource();
3193
+ const channelCount = sampleChannels.length;
3194
+ const sampleLength = sampleChannels[0].length;
3195
+ const buffer = audioContext.createBuffer(channelCount, sampleLength, sampleRate);
3196
+ const source = audioContext.createBufferSource();
3192
3197
 
3193
3198
  // copy samples to buffer and setup source
3194
3199
  sampleChannels.forEach((c,i)=> buffer.getChannelData(i).set(c));
@@ -3202,7 +3207,8 @@ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=false, sample
3202
3207
  gainNode.connect(audioGainNode);
3203
3208
 
3204
3209
  // connect source to stereo panner and gain
3205
- source.connect(new StereoPannerNode(audioContext, {'pan':clamp(pan, -1, 1)})).connect(gainNode);
3210
+ const pannerNode = new StereoPannerNode(audioContext, {'pan':clamp(pan, -1, 1)});
3211
+ source.connect(pannerNode).connect(gainNode);
3206
3212
 
3207
3213
  // play and return sound
3208
3214
  source.start();
@@ -3218,7 +3224,7 @@ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=false, sample
3218
3224
  * @param {Array} zzfxSound - Array of ZzFX parameters, ex. [.5,.5]
3219
3225
  * @return {AudioBufferSourceNode} - The audio node of the sound played
3220
3226
  * @memberof Audio */
3221
- function zzfx(...zzfxSound) { return new Sound(zzfxSound).play(); }
3227
+ function zzfx(...zzfxSound) { return playSamples([zzfxG(...zzfxSound)]); }
3222
3228
 
3223
3229
  /** Sample rate used for all ZzFX sounds
3224
3230
  * @default 44100
@@ -3227,7 +3233,7 @@ const zzfxR = 44100;
3227
3233
 
3228
3234
  /** Generate samples for a ZzFX sound
3229
3235
  * @param {Number} [volume] - Volume scale (percent)
3230
- * @param {Number} [randomness] - Unused in this fuction, handled by Sound class
3236
+ * @param {Number} [randomness] - How much to randomize frequency (percent Hz)
3231
3237
  * @param {Number} [frequency] - Frequency of sound (Hz)
3232
3238
  * @param {Number} [attack] - Attack time, how fast sound starts (seconds)
3233
3239
  * @param {Number} [sustain] - Sustain time, how long sound holds (seconds)
@@ -3253,7 +3259,7 @@ const zzfxR = 44100;
3253
3259
  function zzfxG
3254
3260
  (
3255
3261
  // parameters
3256
- volume = 1, randomness = 0, frequency = 220, attack = 0, sustain = 0,
3262
+ volume = 1, randomness = .05, frequency = 220, attack = 0, sustain = 0,
3257
3263
  release = .1, shape = 0, shapeCurve = 1, slide = 0, deltaSlide = 0,
3258
3264
  pitchJump = 0, pitchJumpTime = 0, repeatTime = 0, noise = 0, modulation = 0,
3259
3265
  bitCrush = 0, delay = 0, sustainVolume = 1, decay = 0, tremolo = 0, filter = 0
@@ -3264,7 +3270,8 @@ function zzfxG
3264
3270
  // init parameters
3265
3271
  let PI2 = PI*2, sampleRate = zzfxR,
3266
3272
  startSlide = slide *= 500 * PI2 / sampleRate / sampleRate,
3267
- startFrequency = frequency *= PI2 / sampleRate,
3273
+ startFrequency = frequency *=
3274
+ rand(1 + randomness, 1-randomness) * PI2 / sampleRate,
3268
3275
  b = [], t = 0, tm = 0, i = 0, j = 1, r = 0, c = 0, s = 0, f, length,
3269
3276
 
3270
3277
  // biquad LP/HP filter
@@ -4664,7 +4671,7 @@ const engineName = 'LittleJS';
4664
4671
  * @type {String}
4665
4672
  * @default
4666
4673
  * @memberof Engine */
4667
- const engineVersion = '1.9.9';
4674
+ const engineVersion = '1.9.11';
4668
4675
 
4669
4676
  /** Frames per second to update
4670
4677
  * @type {Number}
@@ -16,12 +16,13 @@ setShowSplashScreen(true);
16
16
  //box2dDebug = 1; // enable box2d debug draw
17
17
 
18
18
  // game variables
19
- const maxScenes = 9;
19
+ const maxScenes = 11;
20
20
  let scene = 0;
21
21
  let sceneName;
22
22
  let groundObject;
23
23
  let mouseJoint;
24
- let carWheelJoint;
24
+ let car;
25
+ let repeatSpawnTimer = new Timer;
25
26
 
26
27
  ///////////////////////////////////////////////////////////////////////////////
27
28
  function gameInit()
@@ -54,13 +55,25 @@ function gameUpdate()
54
55
  mouseJoint = 0;
55
56
  }
56
57
  }
57
- if (mouseWasPressed(1) || keyWasPressed('KeyZ'))
58
- spawnRandomObject(mousePos);
58
+ if (mouseIsDown(1) || mouseIsDown('KeyZ'))
59
+ {
60
+ const isSet = repeatSpawnTimer.isSet();
61
+ if (!isSet || repeatSpawnTimer.elapsed())
62
+ {
63
+ // spawn continuously after a delay
64
+ isSet || repeatSpawnTimer.set(.5);
65
+ spawnRandomObject(mousePos);
66
+ }
67
+ }
68
+ else
69
+ repeatSpawnTimer.unset();
59
70
  if (mouseWasPressed(2) || keyWasPressed('KeyX'))
60
71
  explosion(mousePos);
61
72
  if (mouseJoint)
62
73
  mouseJoint.SetTarget(mousePos.getBox2d());
63
74
 
75
+ if (keyWasPressed('KeyR'))
76
+ loadScene(scene); // reset scene
64
77
  if (keyWasPressed('ArrowUp') || keyWasPressed('ArrowDown'))
65
78
  {
66
79
  // change scene
@@ -69,13 +82,11 @@ function gameUpdate()
69
82
  loadScene(scene);
70
83
  }
71
84
 
72
- if (carWheelJoint)
85
+ if (car)
73
86
  {
74
87
  // update car control
75
- const control = keyIsDown('ArrowLeft') - keyIsDown('ArrowRight');
76
- let s = carWheelJoint.GetMotorSpeed();
77
- s = control ? clamp(s + control, -40, 40) : s * .8;
78
- carWheelJoint.SetMotorSpeed(s);
88
+ const input = keyIsDown('ArrowLeft') - keyIsDown('ArrowRight');
89
+ car.applyMotorInput(input);
79
90
  }
80
91
  }
81
92
 
@@ -110,6 +121,14 @@ function gameRender()
110
121
  ///////////////////////////////////////////////////////////////////////////////
111
122
  function gameRenderPost()
112
123
  {
124
+ if (mouseJoint)
125
+ {
126
+ // draw mouse joint
127
+ const ab = vec2(mouseJoint.GetAnchorB());
128
+ drawTile(ab, vec2(.3), tile(0), BLACK);
129
+ drawLine(mousePos, ab, .1, BLACK);
130
+ }
131
+
113
132
  // draw to overlay canvas for hud rendering
114
133
  const pos = vec2(mainCanvasSize.x/2, 50);
115
134
  drawText('LittleJS Box2D Demo', 80, 80);