Learn RxJS
Search…
Catch The Dot Game
By adamlubek
This recipe shows usage of scan operator for state management in simple game

Example Code

Could not load image
Catch the dot

index.ts

1
// RxJS v6+
2
import { fromEvent, interval } from 'rxjs';
3
import { tap, scan, map, switchMap, takeWhile } from 'rxjs/operators';
4
import {
5
dot,
6
updatedDot,
7
setTimerText,
8
resetDotSize,
9
moveDot
10
} from './dom-updater';
11
12
interface State {
13
score: number;
14
intrvl: number;
15
}
16
const makeInterval = (val: State) =>
17
interval(val.intrvl).pipe(
18
map(v => 5 - v),
19
tap(setTimerText)
20
);
21
const gameState: State = { score: 0, intrvl: 500 };
22
const nextState = (acc: State) => ({
23
score: (acc.score += 1),
24
intrvl: acc.score % 3 === 0 ? (acc.intrvl -= 50) : acc.intrvl
25
});
26
const isNotGameOver = intervalValue => intervalValue >= 0;
27
28
const game$ = fromEvent(dot, 'mouseover').pipe(
29
tap(moveDot),
30
scan < Event,
31
State > (nextState, gameState),
32
tap(state => updatedDot(state.score)),
33
switchMap(makeInterval),
34
tap(resetDotSize),
35
takeWhile(isNotGameOver)
36
);
37
38
game$.subscribe(
39
n => {},
40
e => {},
41
() => setTimerText('ouch!')
42
);
Copied!

dom-updater.ts

1
const random = () => Math.random() * 300;
2
const elem = id => document.getElementById(id);
3
const setElementText = (elem, text) => (elem.innerText = text.toString());
4
const timer = elem('timer');
5
const setDotSize = size => {
6
dot.style.height = `${size}px`;
7
dot.style.width = `${size}px`;
8
};
9
10
export const dot = elem('dot');
11
export const updatedDot = score => {
12
if (score % 3 === 0) {
13
dot.style.backgroundColor =
14
'#' + ((Math.random() * 0xffffff) << 0).toString(16);
15
}
16
setElementText(dot, score);
17
};
18
export const setTimerText = text => setElementText(timer, text);
19
export const moveDot = () => {
20
setDotSize(5);
21
dot.style.transform = `translate(${random()}px, ${random()}px)`;
22
};
23
export const resetDotSize = () => setDotSize(30);
Copied!

html

1
<style>
2
#dot {
3
margin-top: 10px;
4
height: 30px;
5
width: 30px;
6
background-color: lightgray;
7
border-radius: 50%;
8
transition: all 0.6s ease-in-out;
9
text-align: center;
10
color: white;
11
}
12
13
#timer {
14
position: absolute;
15
top: 150px;
16
left: 150px;
17
opacity: 0.1;
18
font-size: 60px;
19
}
20
</style>
21
22
<div id="timer"></div>
23
<div id="dot"></div>
Copied!
Last modified 1yr ago