pxt-common-packages 9.4.3 → 9.4.4
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/built/common-sim.d.ts +8 -0
- package/built/common-sim.js +74 -0
- package/libs/game/docs/reference/scene/set-tile-at.md +2 -2
- package/libs/game/docs/reference/scene/tile-at-location-equals.md +1 -1
- package/libs/game/docs/reference/sprites/sprite/ax.md +34 -3
- package/libs/game/docs/reference/sprites/sprite/ay.md +34 -3
- package/libs/game/docs/reference/sprites/sprite/fx.md +123 -0
- package/libs/game/docs/reference/sprites/sprite/fy.md +123 -0
- package/libs/game/docs/reference/sprites.md +2 -0
- package/libs/text-to-speech/pxt.json +14 -0
- package/libs/text-to-speech/shims.d.ts +47 -0
- package/libs/text-to-speech/sim/tts.ts +72 -0
- package/libs/text-to-speech/tts.ts +70 -0
- package/package.json +1 -1
package/built/common-sim.d.ts
CHANGED
|
@@ -1119,6 +1119,14 @@ declare namespace pxsim.input {
|
|
|
1119
1119
|
function onSwitchMoved(direction: number, body: RefAction): void;
|
|
1120
1120
|
function switchRight(): boolean;
|
|
1121
1121
|
}
|
|
1122
|
+
declare namespace pxsim.tts {
|
|
1123
|
+
function _getLanguageCode(): string;
|
|
1124
|
+
function _speakAsync(text: string, pitch?: number, rate?: number, volume?: number, language?: string, onStart?: RefAction, onBoundary?: RefAction): Promise<void>;
|
|
1125
|
+
function _pause(): void;
|
|
1126
|
+
function _isPaused(): boolean;
|
|
1127
|
+
function _resume(): void;
|
|
1128
|
+
function _cancel(): void;
|
|
1129
|
+
}
|
|
1122
1130
|
declare namespace pxsim {
|
|
1123
1131
|
interface TemperatureBoard extends CommonBoard {
|
|
1124
1132
|
thermometerState: AnalogSensorState;
|
package/built/common-sim.js
CHANGED
|
@@ -4568,6 +4568,80 @@ var pxsim;
|
|
|
4568
4568
|
})(input = pxsim.input || (pxsim.input = {}));
|
|
4569
4569
|
})(pxsim || (pxsim = {}));
|
|
4570
4570
|
var pxsim;
|
|
4571
|
+
(function (pxsim) {
|
|
4572
|
+
var tts;
|
|
4573
|
+
(function (tts) {
|
|
4574
|
+
function _getLanguageCode() {
|
|
4575
|
+
return window.navigator.language;
|
|
4576
|
+
}
|
|
4577
|
+
tts._getLanguageCode = _getLanguageCode;
|
|
4578
|
+
function _speakAsync(text, pitch, rate, volume, language, onStart, onBoundary) {
|
|
4579
|
+
return new Promise((resolve, reject) => {
|
|
4580
|
+
const utterance = new SpeechSynthesisUtterance(text);
|
|
4581
|
+
utterance.voice = getVoiceForLanguage(language || _getLanguageCode());
|
|
4582
|
+
if (pitch != undefined)
|
|
4583
|
+
utterance.pitch = pitch;
|
|
4584
|
+
if (rate != undefined)
|
|
4585
|
+
utterance.rate = rate;
|
|
4586
|
+
if (volume != undefined)
|
|
4587
|
+
utterance.volume = volume;
|
|
4588
|
+
utterance.onend = () => resolve();
|
|
4589
|
+
utterance.onerror = reject;
|
|
4590
|
+
if (onStart) {
|
|
4591
|
+
utterance.onstart = () => pxsim.runtime.runFiberAsync(onStart);
|
|
4592
|
+
}
|
|
4593
|
+
if (onBoundary) {
|
|
4594
|
+
utterance.onboundary = event => {
|
|
4595
|
+
const offset = event.charIndex;
|
|
4596
|
+
const nextWord = text.substring(offset).split(/\s/).shift();
|
|
4597
|
+
pxsim.runtime.runFiberAsync(onBoundary, offset, nextWord, text);
|
|
4598
|
+
};
|
|
4599
|
+
}
|
|
4600
|
+
speechSynthesis.speak(utterance);
|
|
4601
|
+
});
|
|
4602
|
+
}
|
|
4603
|
+
tts._speakAsync = _speakAsync;
|
|
4604
|
+
function _pause() {
|
|
4605
|
+
speechSynthesis.pause();
|
|
4606
|
+
}
|
|
4607
|
+
tts._pause = _pause;
|
|
4608
|
+
function _isPaused() {
|
|
4609
|
+
return speechSynthesis.paused;
|
|
4610
|
+
}
|
|
4611
|
+
tts._isPaused = _isPaused;
|
|
4612
|
+
function _resume() {
|
|
4613
|
+
speechSynthesis.resume();
|
|
4614
|
+
}
|
|
4615
|
+
tts._resume = _resume;
|
|
4616
|
+
function _cancel() {
|
|
4617
|
+
speechSynthesis.cancel();
|
|
4618
|
+
}
|
|
4619
|
+
tts._cancel = _cancel;
|
|
4620
|
+
function getVoiceForLanguage(language) {
|
|
4621
|
+
language = language.toLowerCase();
|
|
4622
|
+
const generalCode = language.substring(0, 2);
|
|
4623
|
+
let bestMatch;
|
|
4624
|
+
let bestNonlocalMatch;
|
|
4625
|
+
for (const voice of speechSynthesis.getVoices()) {
|
|
4626
|
+
const current = voice.lang.toLowerCase();
|
|
4627
|
+
if (current === language) {
|
|
4628
|
+
if (voice.localService)
|
|
4629
|
+
return voice;
|
|
4630
|
+
else
|
|
4631
|
+
bestNonlocalMatch = voice;
|
|
4632
|
+
}
|
|
4633
|
+
else if (current.substring(0, 2) === generalCode) {
|
|
4634
|
+
if (!bestMatch && voice.localService)
|
|
4635
|
+
bestMatch = voice;
|
|
4636
|
+
if (!bestNonlocalMatch && !voice.localService)
|
|
4637
|
+
bestNonlocalMatch = voice;
|
|
4638
|
+
}
|
|
4639
|
+
}
|
|
4640
|
+
return bestMatch || bestNonlocalMatch || (language !== "en-us" ? getVoiceForLanguage("en-US") : undefined);
|
|
4641
|
+
}
|
|
4642
|
+
})(tts = pxsim.tts || (pxsim.tts = {}));
|
|
4643
|
+
})(pxsim || (pxsim = {}));
|
|
4644
|
+
var pxsim;
|
|
4571
4645
|
(function (pxsim) {
|
|
4572
4646
|
function thermometerState() {
|
|
4573
4647
|
return pxsim.board().thermometerState;
|
|
@@ -3,15 +3,15 @@
|
|
|
3
3
|
Set a tile at a location in the tilemap.
|
|
4
4
|
|
|
5
5
|
```sig
|
|
6
|
-
tiles.setTileAt(
|
|
6
|
+
tiles.setTileAt(tiles.getTileLocation(0, 0), null)
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
You can set a tile at a specific column and row in the tilemap using a tile location object. Specify a tile to set in the tilemap and a location for it.
|
|
10
10
|
|
|
11
11
|
## Parameters
|
|
12
12
|
|
|
13
|
-
* **tile**: the to set in the tilemap.
|
|
14
13
|
* **loc**: a tile location in the tilemap.
|
|
14
|
+
* **tile**: the to set in the tilemap.
|
|
15
15
|
|
|
16
16
|
## Example #example
|
|
17
17
|
|
|
@@ -36,13 +36,15 @@ mySprite.ax = 0
|
|
|
36
36
|
|
|
37
37
|
* **value**: the new horizontal acceleration for the sprite in pixels per second, per second.
|
|
38
38
|
|
|
39
|
-
## Sprite acceleration
|
|
39
|
+
## Sprite horizontal acceleration
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
The value for acceleration determines how quickly the speed of the sprite will change. Acceleration of a sprite makes it speed up in a direction toward the right or left. A positive value causes the sprite's speed in the `right` direction to increase. A negative value causes the sprite's speed in the `left` direction to increase.
|
|
42
|
+
|
|
43
|
+
Acceleration can be used as an opposing force too. If a sprite is travelling toward the right at a certain speed and a negative horizontal acceleration is applied, the sprite will keep moving to the right but it will slow down. When the sprite's speed reaches `0`, the sprite will begin to move to the left.
|
|
42
44
|
|
|
43
45
|
### ~ hint
|
|
44
46
|
|
|
45
|
-
|
|
47
|
+
#### How speed changes
|
|
46
48
|
|
|
47
49
|
Speed, or velocity, is how much distance an object moves during some period of time. Distance in your game is measured in pixels so the speed of a sprite is in _pixels per second_. Speed is changed by _accelerating_ an object. In your game, a sprite is accelerated by some amount of change in speed per second. So, acceleration is measured in _pixels per second per second_.
|
|
48
50
|
|
|
@@ -131,6 +133,35 @@ game.onUpdateInterval(1000, function () {
|
|
|
131
133
|
})
|
|
132
134
|
```
|
|
133
135
|
|
|
136
|
+
### Opposite force #ex3
|
|
137
|
+
|
|
138
|
+
Make a sprite move from the left side of the screen to the right side. Apply acceleration in the opposite direction to slow the sprite down and send back to the left.
|
|
139
|
+
|
|
140
|
+
```blocks
|
|
141
|
+
let mySprite = sprites.create(img`
|
|
142
|
+
. . . . . . . . . . . . . . . .
|
|
143
|
+
. . . . . . . . . . . . . . . .
|
|
144
|
+
. . . . . 5 5 5 5 5 5 . . . . .
|
|
145
|
+
. . . 5 5 5 5 5 5 5 5 5 5 . . .
|
|
146
|
+
. . . 5 5 5 5 5 5 5 5 5 5 . . .
|
|
147
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
148
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
149
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
150
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
151
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
152
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
153
|
+
. . . 5 5 5 5 5 5 5 5 5 5 . . .
|
|
154
|
+
. . . 5 5 5 5 5 5 5 5 5 5 . . .
|
|
155
|
+
. . . . . 5 5 5 5 5 5 . . . . .
|
|
156
|
+
. . . . . . . . . . . . . . . .
|
|
157
|
+
. . . . . . . . . . . . . . . .
|
|
158
|
+
`, SpriteKind.Player)
|
|
159
|
+
mySprite.setStayInScreen(true)
|
|
160
|
+
mySprite.left = 0
|
|
161
|
+
mySprite.vx = 100
|
|
162
|
+
mySprite.ax = -35
|
|
163
|
+
```
|
|
164
|
+
|
|
134
165
|
## See also #seealso
|
|
135
166
|
|
|
136
167
|
[ay](/reference/sprites/sprite/ay),
|
|
@@ -36,13 +36,16 @@ mySprite.ay = 0
|
|
|
36
36
|
|
|
37
37
|
* **value**: the new vertical acceleration for the sprite in pixels per second, per second.
|
|
38
38
|
|
|
39
|
-
## Sprite acceleration
|
|
39
|
+
## Sprite vertical acceleration
|
|
40
|
+
|
|
41
|
+
The value for acceleration determines how quickly the speed of the sprite will change. Acceleration of a sprite makes it speed up in a direction toward the bottom or top. A positive value causes the sprite's speed in the `bottom` direction to increase. A negative value causes the sprite's speed in the `top` direction to increase.
|
|
42
|
+
|
|
43
|
+
Acceleration can be used as an opposing force too. If a sprite is travelling toward the bottom at a certain speed and a negative vertical acceleration is applied, the sprite will keep moving to the bottom but it will slow down. When the sprite's speed reaches `0`, the sprite will begin to move to the top.
|
|
40
44
|
|
|
41
|
-
Acceleration of a sprite makes it speed up or slow down. The value for acceleration determines how quickly the speed of the sprite will change. A positive value makes the sprite speed up as it moves. A negative value causes the sprite to slow down while it moves.
|
|
42
45
|
|
|
43
46
|
### ~ hint
|
|
44
47
|
|
|
45
|
-
|
|
48
|
+
#### How speed changes
|
|
46
49
|
|
|
47
50
|
Speed, or velocity, is how much distance an object moves during some period of time. Distance in your game is measured in pixels so the speed of a sprite is in _pixels per second_. Speed is changed by _accelerating_ an object. In your game, a sprite is accelerated by some amount of change in speed per second. So, acceleration is measured in _pixels per second per second_.
|
|
48
51
|
|
|
@@ -129,6 +132,34 @@ game.onUpdateInterval(1000, function () {
|
|
|
129
132
|
interval += 1
|
|
130
133
|
})
|
|
131
134
|
```
|
|
135
|
+
### Opposite force #ex3
|
|
136
|
+
|
|
137
|
+
Make a sprite move from the top of the screen to the bottom. Apply acceleration in the opposite direction to slow the sprite down and send back to the top.
|
|
138
|
+
|
|
139
|
+
```blocks
|
|
140
|
+
let mySprite = sprites.create(img`
|
|
141
|
+
. . . . . . . . . . . . . . . .
|
|
142
|
+
. . . . . . . . . . . . . . . .
|
|
143
|
+
. . . . . 5 5 5 5 5 5 . . . . .
|
|
144
|
+
. . . 5 5 5 5 5 5 5 5 5 5 . . .
|
|
145
|
+
. . . 5 5 5 5 5 5 5 5 5 5 . . .
|
|
146
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
147
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
148
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
149
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
150
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
151
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
152
|
+
. . . 5 5 5 5 5 5 5 5 5 5 . . .
|
|
153
|
+
. . . 5 5 5 5 5 5 5 5 5 5 . . .
|
|
154
|
+
. . . . . 5 5 5 5 5 5 . . . . .
|
|
155
|
+
. . . . . . . . . . . . . . . .
|
|
156
|
+
. . . . . . . . . . . . . . . .
|
|
157
|
+
`, SpriteKind.Player)
|
|
158
|
+
mySprite.setStayInScreen(true)
|
|
159
|
+
mySprite.top = 0
|
|
160
|
+
mySprite.vy = 80
|
|
161
|
+
mySprite.ay = -35
|
|
162
|
+
```
|
|
132
163
|
|
|
133
164
|
## See also #seealso
|
|
134
165
|
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# fy (property)
|
|
2
|
+
|
|
3
|
+
Get or set the friction opposing a sprite's motion in the vertical direction.
|
|
4
|
+
|
|
5
|
+
## Get
|
|
6
|
+
|
|
7
|
+
Get the vertical friction on the sprite.
|
|
8
|
+
|
|
9
|
+
```block
|
|
10
|
+
let mySprite: Sprite = null
|
|
11
|
+
|
|
12
|
+
let horzAccel = mySprite.fy
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```typescript-ignorelet
|
|
16
|
+
horzAccel = mySprite.fy
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Returns
|
|
20
|
+
|
|
21
|
+
* a [number](/types/number) that is the current vertical friction of the sprite.
|
|
22
|
+
|
|
23
|
+
## Set
|
|
24
|
+
|
|
25
|
+
Set the vertical friction for the sprite.
|
|
26
|
+
|
|
27
|
+
```block
|
|
28
|
+
let mySprite: Sprite = null
|
|
29
|
+
|
|
30
|
+
mySprite.fy = 0
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
```typescript-ignore
|
|
34
|
+
mySprite.fy = 0
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Parameter
|
|
38
|
+
|
|
39
|
+
* **value**: the new vertical friction opposing the sprite's motion in pixels per second, per second.
|
|
40
|
+
|
|
41
|
+
## Sprite vertical friction
|
|
42
|
+
|
|
43
|
+
Friction is an opposing force against the motion of a sprite. If a sprite has a vertical velocity (`vy`), it's friction will slow the sprite down until it's vertical velocity becomes `0`. This is similar to setting an opposite vertical acceleration but the opposite acceleration goes away once the sprite stops.
|
|
44
|
+
|
|
45
|
+
## Examples #example
|
|
46
|
+
|
|
47
|
+
### Measure stopping time #ex1
|
|
48
|
+
|
|
49
|
+
Move the sprite from top to bottom across the screen. Use the correct amount of friction (`fy`) to make the sprite stop at `3` seconds.
|
|
50
|
+
|
|
51
|
+
```blocks
|
|
52
|
+
let stopTime = 0
|
|
53
|
+
let counting = true
|
|
54
|
+
let mySprite = sprites.create(img`
|
|
55
|
+
. . . . . . . . . . . . . . . .
|
|
56
|
+
. . . . . . . . . . . . . . . .
|
|
57
|
+
. . . . . 5 5 5 5 5 5 . . . . .
|
|
58
|
+
. . . 5 5 5 5 5 5 5 5 5 5 . . .
|
|
59
|
+
. . . 5 5 5 5 5 5 5 5 5 5 . . .
|
|
60
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
61
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
62
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
63
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
64
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
65
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
66
|
+
. . . 5 5 5 5 5 5 5 5 5 5 . . .
|
|
67
|
+
. . . 5 5 5 5 5 5 5 5 5 5 . . .
|
|
68
|
+
. . . . . 5 5 5 5 5 5 . . . . .
|
|
69
|
+
. . . . . . . . . . . . . . . .
|
|
70
|
+
. . . . . . . . . . . . . . . .
|
|
71
|
+
`, SpriteKind.Player)
|
|
72
|
+
mySprite.setStayInScreen(true)
|
|
73
|
+
mySprite.top = 0
|
|
74
|
+
mySprite.fy = 20
|
|
75
|
+
mySprite.vy = 60
|
|
76
|
+
game.onUpdateInterval(100, function () {
|
|
77
|
+
if (counting) {
|
|
78
|
+
stopTime += 0.1
|
|
79
|
+
if (mySprite.vy == 0) {
|
|
80
|
+
counting = false
|
|
81
|
+
mySprite.sayText("" + stopTime + "sec", 5000, false)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Skipppng sprite #ex2
|
|
88
|
+
|
|
89
|
+
Make a sprite move from the top to the bottom. Make it skip to the right once every second.
|
|
90
|
+
|
|
91
|
+
```blocks
|
|
92
|
+
let mySprite = sprites.create(img`
|
|
93
|
+
. . . . . . . . . . . . . . . .
|
|
94
|
+
. . . . . . . . . . . . . . . .
|
|
95
|
+
. . . . . 5 5 5 5 5 5 . . . . .
|
|
96
|
+
. . . 5 5 5 5 5 5 5 5 5 5 . . .
|
|
97
|
+
. . . 5 5 5 5 5 5 5 5 5 5 . . .
|
|
98
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
99
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
100
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
101
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
102
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
103
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
104
|
+
. . . 5 5 5 5 5 5 5 5 5 5 . . .
|
|
105
|
+
. . . 5 5 5 5 5 5 5 5 5 5 . . .
|
|
106
|
+
. . . . . 5 5 5 5 5 5 . . . . .
|
|
107
|
+
. . . . . . . . . . . . . . . .
|
|
108
|
+
. . . . . . . . . . . . . . . .
|
|
109
|
+
`, SpriteKind.Player)
|
|
110
|
+
mySprite.setStayInScreen(true)
|
|
111
|
+
mySprite.top = 0
|
|
112
|
+
mySprite.fy = 60
|
|
113
|
+
mySprite.vy = 60
|
|
114
|
+
for (let index = 0; index < 3; index++) {
|
|
115
|
+
mySprite.vy = 60
|
|
116
|
+
pause(1000)
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## See also #seealso
|
|
121
|
+
|
|
122
|
+
[fx](/reference/sprites/sprite/fx),
|
|
123
|
+
[ay](/reference/sprites/sprite/ay)
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# fy (property)
|
|
2
|
+
|
|
3
|
+
Get or set the friction opposing a sprite's motion in the horizontal direction.
|
|
4
|
+
|
|
5
|
+
## Get
|
|
6
|
+
|
|
7
|
+
Get the horizontal friction on the sprite.
|
|
8
|
+
|
|
9
|
+
```block
|
|
10
|
+
let mySprite: Sprite = null
|
|
11
|
+
|
|
12
|
+
let horzAccel = mySprite.fx
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```typescript-ignorelet
|
|
16
|
+
horzAccel = mySprite.fx
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Returns
|
|
20
|
+
|
|
21
|
+
* a [number](/types/number) that is the current horizontal friction of the sprite.
|
|
22
|
+
|
|
23
|
+
## Set
|
|
24
|
+
|
|
25
|
+
Set the horizontal friction for the sprite.
|
|
26
|
+
|
|
27
|
+
```block
|
|
28
|
+
let mySprite: Sprite = null
|
|
29
|
+
|
|
30
|
+
mySprite.fx = 0
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
```typescript-ignore
|
|
34
|
+
mySprite.fx = 0
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Parameter
|
|
38
|
+
|
|
39
|
+
* **value**: the new horizontal friction opposing the sprite's motion in pixels per second, per second.
|
|
40
|
+
|
|
41
|
+
## Sprite horizontal friction
|
|
42
|
+
|
|
43
|
+
Friction is an opposing force against the motion of a sprite. If a sprite has a horizontal velocity (`vx`), it's friction will slow the sprite down until it's horizontal velocity becomes `0`. This is similar to setting an opposite horizontal acceleration but the opposite acceleration goes away once the sprite stops.
|
|
44
|
+
|
|
45
|
+
## Examples #example
|
|
46
|
+
|
|
47
|
+
### Measure stopping time #ex1
|
|
48
|
+
|
|
49
|
+
Move the sprite from left to right across the screen. Use the correct amount of friction (`fx`) to make the sprite stop at `3` seconds.
|
|
50
|
+
|
|
51
|
+
```blocks
|
|
52
|
+
let stopTime = 0
|
|
53
|
+
let counting = true
|
|
54
|
+
let mySprite = sprites.create(img`
|
|
55
|
+
. . . . . . . . . . . . . . . .
|
|
56
|
+
. . . . . . . . . . . . . . . .
|
|
57
|
+
. . . . . 5 5 5 5 5 5 . . . . .
|
|
58
|
+
. . . 5 5 5 5 5 5 5 5 5 5 . . .
|
|
59
|
+
. . . 5 5 5 5 5 5 5 5 5 5 . . .
|
|
60
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
61
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
62
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
63
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
64
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
65
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
66
|
+
. . . 5 5 5 5 5 5 5 5 5 5 . . .
|
|
67
|
+
. . . 5 5 5 5 5 5 5 5 5 5 . . .
|
|
68
|
+
. . . . . 5 5 5 5 5 5 . . . . .
|
|
69
|
+
. . . . . . . . . . . . . . . .
|
|
70
|
+
. . . . . . . . . . . . . . . .
|
|
71
|
+
`, SpriteKind.Player)
|
|
72
|
+
mySprite.setStayInScreen(true)
|
|
73
|
+
mySprite.left = 0
|
|
74
|
+
mySprite.fx = 30
|
|
75
|
+
mySprite.vx = 90
|
|
76
|
+
game.onUpdateInterval(100, function () {
|
|
77
|
+
if (counting) {
|
|
78
|
+
stopTime += 0.1
|
|
79
|
+
if (mySprite.vx == 0) {
|
|
80
|
+
counting = false
|
|
81
|
+
mySprite.sayText("" + stopTime + "sec", 5000, false)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Skipppng sprite #ex2
|
|
88
|
+
|
|
89
|
+
Make a sprite move from the left to the right. Make it skip to the right once every second.
|
|
90
|
+
|
|
91
|
+
```blocks
|
|
92
|
+
let mySprite = sprites.create(img`
|
|
93
|
+
. . . . . . . . . . . . . . . .
|
|
94
|
+
. . . . . . . . . . . . . . . .
|
|
95
|
+
. . . . . 5 5 5 5 5 5 . . . . .
|
|
96
|
+
. . . 5 5 5 5 5 5 5 5 5 5 . . .
|
|
97
|
+
. . . 5 5 5 5 5 5 5 5 5 5 . . .
|
|
98
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
99
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
100
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
101
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
102
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
103
|
+
. . 5 5 5 5 5 5 5 5 5 5 5 5 . .
|
|
104
|
+
. . . 5 5 5 5 5 5 5 5 5 5 . . .
|
|
105
|
+
. . . 5 5 5 5 5 5 5 5 5 5 . . .
|
|
106
|
+
. . . . . 5 5 5 5 5 5 . . . . .
|
|
107
|
+
. . . . . . . . . . . . . . . .
|
|
108
|
+
. . . . . . . . . . . . . . . .
|
|
109
|
+
`, SpriteKind.Player)
|
|
110
|
+
mySprite.setStayInScreen(true)
|
|
111
|
+
mySprite.left = 0
|
|
112
|
+
mySprite.fx = 80
|
|
113
|
+
mySprite.vx = 80
|
|
114
|
+
for (let index = 0; index < 3; index++) {
|
|
115
|
+
mySprite.vx = 80
|
|
116
|
+
pause(1000)
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## See also #seealso
|
|
121
|
+
|
|
122
|
+
[fy](/reference/sprites/sprite/fy),
|
|
123
|
+
[ax](/reference/sprites/sprite/ax)
|
|
@@ -58,6 +58,8 @@ sprites.onOverlap(0, 0, function (sprite, otherSprite) {})
|
|
|
58
58
|
* [**vy- velocity y**](/reference/sprites/sprite/vy)
|
|
59
59
|
* [**ax - acceleration x**](/reference/sprites/sprite/ax)
|
|
60
60
|
* [**ay - acceleration y**](/reference/sprites/sprite/ay)
|
|
61
|
+
* [**fx - friction x**](/reference/sprites/sprite/fx)
|
|
62
|
+
* [**fy - friction y**](/reference/sprites/sprite/fy)
|
|
61
63
|
|
|
62
64
|
### Image and Attributes
|
|
63
65
|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
//% icon="\uf075"
|
|
2
|
+
//% color="#f59c16"
|
|
3
|
+
//% block="Text to Speech"
|
|
4
|
+
declare namespace tts {
|
|
5
|
+
//% shim=tts::_speakAsync promise
|
|
6
|
+
function speak(text: string, pitch?: number, rate?: number, volume?: number, language?: string, onStart?: () => void, onBoundary?: (offset: number, nextWord: string, fullText: string) => void): void;
|
|
7
|
+
|
|
8
|
+
//% shim=tts::_getLanguageCode
|
|
9
|
+
function getLanguageCode(): string;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Pauses the current text being spoken. Any calls waiting for the text to finish
|
|
13
|
+
* will not return until the text is either resumed or cancelled.
|
|
14
|
+
*/
|
|
15
|
+
//% shim=tts::_pause
|
|
16
|
+
//% blockId=tts_pause
|
|
17
|
+
//% block="pause speech"
|
|
18
|
+
//% weight=90
|
|
19
|
+
function pause(): void;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Returns true if the text to speech is currently paused
|
|
23
|
+
*/
|
|
24
|
+
//% shim=tts::_isPaused
|
|
25
|
+
//% blockId=tts_isPaused
|
|
26
|
+
//% block="is speech paused"
|
|
27
|
+
//% weight=60
|
|
28
|
+
function isPaused(): boolean;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Resumes the current text being spoken if in the paused state.
|
|
32
|
+
*/
|
|
33
|
+
//% shim=tts::_resume
|
|
34
|
+
//% blockId=tts_resume
|
|
35
|
+
//% block="resume speech"
|
|
36
|
+
//% weight=80
|
|
37
|
+
function resume(): void;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Cancels all text currently being spoken and any that has been queued.
|
|
41
|
+
*/
|
|
42
|
+
//% shim=tts::_cancel
|
|
43
|
+
//% blockId=tts_cancel
|
|
44
|
+
//% block="cancel speech"
|
|
45
|
+
//% weight=70
|
|
46
|
+
function cancel(): void;
|
|
47
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
namespace pxsim.tts {
|
|
2
|
+
export function _getLanguageCode() {
|
|
3
|
+
return window.navigator.language;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function _speakAsync(text: string, pitch?: number, rate?: number, volume?: number, language?: string, onStart?: RefAction, onBoundary?: RefAction): Promise<void> {
|
|
7
|
+
return new Promise<void>((resolve, reject) => {
|
|
8
|
+
const utterance = new SpeechSynthesisUtterance(text);
|
|
9
|
+
utterance.voice = getVoiceForLanguage(language || _getLanguageCode());
|
|
10
|
+
|
|
11
|
+
if (pitch != undefined) utterance.pitch = pitch;
|
|
12
|
+
if (rate != undefined) utterance.rate = rate;
|
|
13
|
+
if (volume != undefined) utterance.volume = volume;
|
|
14
|
+
|
|
15
|
+
utterance.onend = () => resolve();
|
|
16
|
+
utterance.onerror = reject;
|
|
17
|
+
|
|
18
|
+
if (onStart) {
|
|
19
|
+
utterance.onstart = () => runtime.runFiberAsync(onStart);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (onBoundary) {
|
|
23
|
+
utterance.onboundary = event => {
|
|
24
|
+
const offset = event.charIndex;
|
|
25
|
+
const nextWord = text.substring(offset).split(/\s/).shift();
|
|
26
|
+
|
|
27
|
+
runtime.runFiberAsync(onBoundary, offset, nextWord, text);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
speechSynthesis.speak(utterance);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function _pause() {
|
|
36
|
+
speechSynthesis.pause();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function _isPaused(): boolean {
|
|
40
|
+
return speechSynthesis.paused;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function _resume() {
|
|
44
|
+
speechSynthesis.resume();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function _cancel() {
|
|
48
|
+
speechSynthesis.cancel();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function getVoiceForLanguage(language: string): SpeechSynthesisVoice {
|
|
52
|
+
language = language.toLowerCase();
|
|
53
|
+
const generalCode = language.substring(0, 2);
|
|
54
|
+
|
|
55
|
+
let bestMatch: SpeechSynthesisVoice;
|
|
56
|
+
let bestNonlocalMatch: SpeechSynthesisVoice;
|
|
57
|
+
|
|
58
|
+
for (const voice of speechSynthesis.getVoices()) {
|
|
59
|
+
const current = voice.lang.toLowerCase();
|
|
60
|
+
if (current === language) {
|
|
61
|
+
if (voice.localService) return voice;
|
|
62
|
+
else bestNonlocalMatch = voice;
|
|
63
|
+
}
|
|
64
|
+
else if (current.substring(0, 2) === generalCode) {
|
|
65
|
+
if (!bestMatch && voice.localService) bestMatch = voice;
|
|
66
|
+
if (!bestNonlocalMatch && !voice.localService) bestNonlocalMatch = voice
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return bestMatch || bestNonlocalMatch || (language !== "en-us" ? getVoiceForLanguage("en-US") : undefined);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
namespace tts {
|
|
2
|
+
class TextToSpeechState {
|
|
3
|
+
boundaryListeners: ((offset: number, nextWord: string, fullText: string) => void)[];
|
|
4
|
+
|
|
5
|
+
constructor() {
|
|
6
|
+
this.boundaryListeners = [];
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
let state: TextToSpeechState;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Runs code each time a word or sentence boundary is reached in text being spoken
|
|
14
|
+
*/
|
|
15
|
+
//% blockId=tts_onWordSpoken
|
|
16
|
+
//% block="on word spoken from $fullText at $offset with $nextWord"
|
|
17
|
+
//% draggableParameters="reporter"
|
|
18
|
+
//% weight=10
|
|
19
|
+
export function onWordSpoken(handler: (offset: number, nextWord: string, fullText: string) => void) {
|
|
20
|
+
getState().boundaryListeners.push(handler);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Speak some text using the computer's text to speech voice and pause until the speaking has finished.
|
|
25
|
+
* If some text is already being spoken, this text will be queued until the other text finishes.
|
|
26
|
+
*
|
|
27
|
+
* @param text The text to speak
|
|
28
|
+
* @param volume The volume to speak at
|
|
29
|
+
* @param pitch A pitch modifier for moving the pitch of text up or down
|
|
30
|
+
* @param rate The rate at which the text will be spoken; higher is faster
|
|
31
|
+
* @param language The ISO language code for the text to be spoken; defaults to the system language
|
|
32
|
+
*/
|
|
33
|
+
//% blockId=tts_speakText
|
|
34
|
+
//% block="speak $text||with volume $volume pitch $pitch rate $rate language $language"
|
|
35
|
+
//% inlineInputMode=inline
|
|
36
|
+
//% volume.min=0
|
|
37
|
+
//% volume.max=255
|
|
38
|
+
//% volume.defl=128
|
|
39
|
+
//% pitch.min=0
|
|
40
|
+
//% pitch.max=255
|
|
41
|
+
//% pitch.defl=128
|
|
42
|
+
//% rate.min=0
|
|
43
|
+
//% rate.max=255
|
|
44
|
+
//% rate.defl=25
|
|
45
|
+
//% weight=100
|
|
46
|
+
export function speakText(text: string, volume = 128, pitch = 128, rate = 25, language?: string) {
|
|
47
|
+
// Ranges from 0 to 1
|
|
48
|
+
volume = Math.map(Math.clamp(0, 255, volume), 0, 255, 0, 1);
|
|
49
|
+
// Ranges from 0 to 2
|
|
50
|
+
pitch = Math.map(Math.clamp(0, 255, pitch), 0, 255, 0, 2);;
|
|
51
|
+
// Ranges from 0.1 to 10
|
|
52
|
+
rate = Math.map(Math.clamp(0, 255, rate), 0, 255, 0.1, 10);
|
|
53
|
+
|
|
54
|
+
tts.speak(text, pitch, rate, volume, language, undefined, onBoundary);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function onBoundary(offset: number, nextWord: string, fullText: string) {
|
|
58
|
+
for (const handler of getState().boundaryListeners) {
|
|
59
|
+
control.runInParallel(() => handler(offset, nextWord, fullText))
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function getState() {
|
|
64
|
+
if (!state) {
|
|
65
|
+
state = new TextToSpeechState();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return state;
|
|
69
|
+
}
|
|
70
|
+
}
|