Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Building multiplayer game using Streams (Devoxx UK 2016)

Building multiplayer game using Streams (Devoxx UK 2016)

In this talk you will learn how stream-based programming can be used to implement web frontend and multiplayer backend of the classic game: Snake.

Building dynamic applications using imperative approach tends to create lots of unmaintainable code. Stream-based programming tries to solve this problem by introducing fully declarative way of defining application logic. While using streams, you will focus on WHAT needs to be done, not HOW and WHEN.

The talk is divided into 3 parts. In the first part you will learn how to create a frontend of the Snake web game using streams as building blocks. Then, we will move to the server side and use Scala and Akka Stream library to create backend service that will allow the game to be played by multiple players. In the third part, we will discuss reactive streams and how they make asynchronous communication safe.

Michał Płachta

June 09, 2016
Tweet

More Decks by Michał Płachta

Other Decks in Programming

Transcript

  1. Devoxx UK / 09.06.2016 @miciek Streams? • way of defining

    application logic • focused on data transformations • explicit time dependencies • declarative
  2. Devoxx UK / 09.06.2016 @miciek What’s inside? • how frontend

    web app written in streams looks like • how backend app written using streams looks like • how do Reactive Streams keep our streams safe?
  3. Devoxx UK / 09.06.2016 @miciek Stream operators: map & scan

    stream.map(f) • transforms values from stream using function f • returns a new stream with transformed values stream.scan(init, f) • accumulates values from stream using function f ◦ f(acc,val)=>new_acc • returns a new stream that outputs accumulator value
  4. Devoxx UK / 09.06.2016 @miciek Stream operators: filter stream.filter(p) •

    checks each value from stream against the predicate passed as p • returns a new stream that outputs only values that satisfy condition p Already used: • map(f) • scan(init, f(acc, val))
  5. Devoxx UK / 09.06.2016 @miciek Stream operators: merge stream.merge(stream2) •

    stream is merged with stream2 • returns a new stream that outputs values from both stream and stream2 as they appear Already used: • map(f) • scan(init, f(acc, val)) • filter(p)
  6. Devoxx UK / 09.06.2016 @miciek Stream operators: sampledBy stream.sampledBy(stream2) •

    last value from stream is taken when any value appears in stream2 • returns a new stream that outputs values from stream sampled by values from stream2 Already used: • map(f) • scan(init, f(acc, val)) • filter(p) • merge(stream2)
  7. Devoxx UK / 09.06.2016 @miciek Current implementation • “ticks” •

    “key presses” • “left key presses” • “right key presses” • “left rotations” • “right rotations” • “actions” • “dir changes” • “directions” • “snake head positions” + map, scan, filter, merge & sampledBy 10 streams
  8. Devoxx UK / 09.06.2016 @miciek Stream operators: slidingWindow stream.slidingWindow(n) •

    aggregate last n values • returns a new stream that outputs arrays of last n values from the stream • can be implemented using scan Already used: • map(f) • scan(init, f(acc, val)) • filter(p) • merge(stream2) • sampledBy(stream2)
  9. Devoxx UK / 09.06.2016 @miciek Quiz: Eating a fruit? using

    6 operators • map(f) • scan(init, f(acc, val)) • filter(p) • merge(stream2) • sampledBy(stream2) • slidingWindow(n) & 11 streams • “ticks” • “key presses” • “left key presses” • “right key presses” • “left rotations” • “right rotations” • “actions” • “direction changes” • “directions” • “snake head positions” • “snakes”
  10. Devoxx UK / 09.06.2016 @miciek Snake Server App Requirements •

    client must send snake positions to the server each time it changes • server must generate fruits • server must keep scores • server must broadcast: ◦ positions of all snakes to other players ◦ positions of fruits to all players ◦ current scoreboard to all players
  11. Devoxx UK / 09.06.2016 @miciek Crossing Async Boundary Push Model

    • not safe when Subscriber slower • perfect when Subscriber faster • too slow when Subscriber faster • perfect when Subscriber slower Pull Model
  12. Devoxx UK / 09.06.2016 @miciek Reactive Streams Streams with supply

    & demand • “as fast as possible, but not faster” • consumer wants to pull elements (= demand) • only then publisher can push ◦ it supplies elements until demand is satisfied
  13. Devoxx UK / 09.06.2016 @miciek Reactive Streams API public interface

    Publisher<T> { public void subscribe(Subscriber<? super T> s); } public interface Subscriber<T> { public void onSubscribe(Subscription s); public void onNext(T t); public void onError(Throwable t); public void onComplete(); } public interface Subscription { public void request(long n); public void cancel(); } public interface Processor<T, R> extends Subscriber<T>, Publisher<R> {}
  14. Devoxx UK / 09.06.2016 @miciek Reactive Streams API implementations •

    Project Reactor • Ratpack • Vert.x • Slick • Akka Stream • JDK 9 • Integrations: ◦ Kafka, ◦ Mongo, ◦ Cassandra
  15. Devoxx UK / 09.06.2016 @miciek Akka Stream model Publisher =>

    Source Processor => Flow Subscriber => Sink Our Snake implementation uses Reactive Streams!
  16. Devoxx UK / 09.06.2016 @miciek • NO ◦ frontend is

    pushing every 100ms • Possible solutions: ◦ Reactive Streams web frameworks? ◦ conflate/expand? ◦ buffer between frontend & backend? Is Snake Multiplayer safe?
  17. Devoxx UK / 09.06.2016 @miciek Links Build YOUR OWN Snake

    using Streams - blog post (step-by-step tutorial) michalplachta.com/2016/05/11/reactive-ui-by-example/ Client Side Code github.com/miciek/web-snake-react-bacon Server Side Code github.com/miciek/snake-multiplayer-akka-streams Play with streams and operators! rxmarbles.com/ Akka Streams doc.akka.io/docs/akka/2.4.4/scala/stream/ BaconJS - streams in JavaScript baconjs.github.io/