RxJS 배우기
  • 소개
  • RxJS 배우기
    • 연산자
      • Combination
        • combineAll
        • combineLatest
        • concat
        • concatAll
        • endWith
        • forkJoin
        • merge
        • mergeAll
        • pairwise
        • race
        • startWith
        • withLatestFrom
        • zip
      • Conditional
        • defaultIfEmpty
        • every
        • iif
        • sequenceEqual
      • Creation
        • ajax
        • create
        • defer
        • empty
        • from
        • fromEvent
        • generate
        • interval
        • of
        • range
        • throw
        • timer
      • Error Handling
        • catch / catchError
        • retry
        • retryWhen
      • Multicasting
        • publish
        • multicast
        • share
        • shareReplay
      • Filtering
        • audit
        • auditTime
        • debounce
        • debounceTime
        • distinct
        • distinctUntilChanged
        • distinctUntilKeyChanged
        • filter
        • find
        • first
        • ignoreElements
        • last
        • sample
        • single
        • skip
        • skipUntil
        • skipWhile
        • take
        • takeLast
        • takeUntil
        • takeWhile
        • throttle
        • throttleTime
      • Transformation
        • buffer
        • bufferCount
        • bufferTime
        • bufferToggle
        • bufferWhen
        • concatMap
        • concatMapTo
        • exhaustMap
        • expand
        • groupBy
        • map
        • mapTo
        • mergeMap / flatMap
        • mergeScan
        • partition
        • pluck
        • reduce
        • scan
        • switchMap
        • switchMapTo
        • toArray
        • window
        • windowCount
        • windowTime
        • windowToggle
        • windowWhen
      • Utility
        • tap / do
        • delay
        • delayWhen
        • dematerialize
        • finalize / finally
        • let
        • repeat
        • timeInterval
        • timeout
        • timeoutWith
        • toPromise
      • 전체 목록
    • Subjects
      • AsyncSubject
      • BehaviorSubject
      • ReplaySubject
      • Subject
    • 사용예시
      • Alphabet Invasion Game
      • Battleship Game
      • Breakout Game
      • Car Racing Game
      • Catch The Dot Game
      • Click Ninja Game
      • Flappy Bird Game
      • Game Loop
      • Horizontal Scroll Indicator
      • Http Polling
      • Lockscreen
      • Matrix Digital Rain
      • Memory Game
      • Mine Sweeper Game
      • Platform Jumper Game
      • Progress Bar
      • Save Indicator
      • Smart Counter
      • Space Invaders Game
      • Stop Watch
      • Swipe To Refresh
      • Tank Battle Game
      • Tetris Game
      • Type Ahead
      • Uncover Image Game
    • 개념
      • RxJS 입문서
      • RxJS v5 -> v6 업그레이드
      • 시간 기반의 연산자 비교
      • 연산자 imports의 이해
Powered by GitBook
On this page
  • Example Code
  • index.ts
  • html-renderer.ts
  • Operators Used

Was this helpful?

  1. RxJS 배우기
  2. 사용예시

Flappy Bird Game

PreviousClick Ninja GameNextGame Loop

Last updated 5 years ago

Was this helpful?

By

This recipe demonstrates RxJs implementation of Flappy Bird like game.

Example Code

( )

Flappy Bird

index.ts

// RxJS v6+
import { interval, merge, combineLatest, fromEvent } from 'rxjs';
import { tap, scan, takeWhile } from 'rxjs/operators';
import { paint } from './html-renderer';

const gamePipe = (x, y) => ({ x, y, checked: false });
const gameSize = 10;
const createPipes = y =>
  (random =>
    Array.from(Array(gameSize).keys())
      .map(e => gamePipe(e, y))
      .filter(e => e.x < random || e.x > random + 2))(
    Math.floor(Math.random() * Math.floor(gameSize))
  );

const gamePipes$ = interval(500).pipe(
  scan < any,
  any >
    (acc =>
      (acc.length < 2 ? [...acc, createPipes(gameSize)] : acc)
        .filter(c => c.some(e => e.y > 0))
        .map(cols => cols.map(e => gamePipe(e.x, e.y - 1))),
    [createPipes(gameSize / 2), createPipes(gameSize)])
);

const fly = xPos => (xPos > 0 ? (xPos -= 1) : xPos);
const fall = xPos => (xPos < gameSize - 1 ? (xPos += 1) : gameSize - 1);
const bird$ = merge(interval(300), fromEvent(document, 'keydown')).pipe(
  scan < any,
  any >
    ((xPos, curr) => (curr instanceof KeyboardEvent ? fly(xPos) : fall(xPos)),
    gameSize - 1)
);

const updateGame = (bird, pipes) =>
  (game => (
    pipes.forEach(col => col.forEach(v => (game[v.x][v.y] = 2))),
    (game[bird][0] = 1),
    game
  ))(
    Array(gameSize)
      .fill(0)
      .map(e => Array(gameSize).fill(0))
  );

const valueOnCollisionFor = pipes => ({
  when: predicate =>
    !pipes[0][0].checked && predicate ? ((pipes[0][0].checked = true), 1) : 0
});

combineLatest(bird$, gamePipes$)
  .pipe(
    scan < any,
    any >
      ((state, [bird, pipes]) => ({
        bird: bird,
        pipes: pipes,
        lives:
          state.lives -
          valueOnCollisionFor(pipes).when(
            pipes.some(c => c.some(c => c.y === 0 && c.x === bird))
          ),
        score:
          state.score + valueOnCollisionFor(pipes).when(pipes[0][0].y === 0)
      }),
      { lives: 3, score: 0, bird: 0, pipes: [] }),
    tap(state =>
      paint(updateGame(state.bird, state.pipes), state.lives, state.score)
    ),
    takeWhile(state => state.lives > 0)
  )
  .subscribe();

html-renderer.ts

const createElem = col => {
  const elem = document.createElement('div');
  elem.classList.add('board');
  elem.style.display = 'inline-block';
  elem.style.marginLeft = '10px';
  elem.style.height = '6px';
  elem.style.width = '6px';
  elem.style['background-color'] =
    col === 0
      ? 'white'
      : col === 1
      ? 'cornflowerblue'
      : col === 2
      ? 'gray'
      : 'silver';
  elem.style['border-radius'] = '90%';
  return elem;
};

export const paint = (game: number[][], lives, score) => {
  document.body.innerHTML = `Lives: ${lives}, Score: ${score}`;

  game.forEach(row => {
    const rowContainer = document.createElement('div');
    row.forEach(col => rowContainer.appendChild(createElem(col)));
    document.body.appendChild(rowContainer);
  });
};

Operators Used

combineLatest
fromEvent
interval
merge
scan
takeWhile
tap
adamlubek
StackBlitz