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

Example Code

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