SlideShare a Scribd company logo
1 of 30
1
〜僕の初めてのリアクティブプログラミング
Reactor を使って
リアクティブに昇龍拳
を繰り出してみた!
quitada
2018/4/26
2
リアクティブプログラミングっ
て何か面白そう!すごそう!で、
何?
リアクティブプログラミングとは?
3
“In computing, reactive programming is an asynchronous
programming paradigm concerned with data streams and
the propagation of change.”
(参考訳)「コンピューター処理において、リアクティ
ブプログラミングは、データストリームとその変更内容
の伝搬を意識した非同期プログラミング方法論の一つで
ある。」
出典:Wikipedia - https://en.wikipedia.org/wiki/Reactive_programming
4
リアクティブプログラミング
のざっくりとした僕の理解
モダンな
ストリーミング
処理関数群
次々やってくる
ストリーミング
データ
なんらかの結果
とか挙動
モダンって何やねん?
5
すぐに思いついたこと
必殺技コマンド
データストリーム
処理関数群
昇龍拳コマンド
データ
ストリーム
しょ〜りゅ〜けん!
ストリートファイターの昇龍拳をモダンに
繰り出せるんじゃね?
P+
だから、モダンって何やね
ん?
ストリートファイターとは?
 1987 年よりカプコン社からリリースされている一連の対戦型格闘ゲーム
シリーズ
 1991 年リリースの二作目、ストリート
ファイター II が爆発的ヒット、各種ビデオ
ゲームプラットフォームにも次々と移植
される(任天堂スーパーファミコンとか)
– 一作目は、大人の事情でファイティング・
ストリートと名前を変えて PC-エンジン
CD-ROM2 に移植されていたりしますが…
6
昇龍拳とは?
 ストリートファイターシリーズのプレイ可能なキャラクターである、リュウ並
びにケンの必殺技の一つ。
 ゲーム中では、以下の操作を素早く行うことにより昇龍拳を繰り出すことがで
きる。対戦相手にヒットすると、比較的大ダメージを与えることができる。
 大ジャンプキックからの、アッパーカットからの昇龍拳といったいわゆるキャ
ンセル技を組み合わせることで対戦をかなり有利に進められる。
7
キャラクターの向いている方向
P+
レバー(パッド)の方向操作 最後にパンチボタン同時押し
8
ということで、リュウさんが昇
龍拳とかを繰り出すだけのアプ
リをリアクティブプログラミン
グして作ってみたので、何か報
告します。
前提とか準備とか(1/3)
 一応、僕は Java ラーなので、JavaFX で作ります。UI は
こんな感じで。
– PC のキーボードからのコマンド入力前提。
– レバーの斜めは方向キー同時押しで対応。
– キーを押すと、UI 上のキー画像が押されたようなアニメーションを
する(ちょっと緑色っぽくなる)。
– 昇龍拳コマンド入力等成功すると、リュウのそれに応じたアニメー
ションが見られるだけのアプリケーション。
– 方向キー↑は “W” キー、←は “A” キー、→ は “S” キー、↓は “Z”、パ
ンチキーは “X” キー、キックキーは “C” とする。
 ついでに、波動拳、竜巻旋風脚や、(必殺技でないけ
ど)中パンチと大キックも実装。
 どうでもいいけど、BGM とか効果音もつけてみる。
9
方向キー
キックキー
リュウさん
(本人)
パンチキー
前提とか準備とか(2/3)
 必殺技コマンド入力の実装アイディア
– javafx.scene.Scene のインスタンスにキーイベントを取得するため以下のリスナーを
付与
▪ キーを押したイベントを取得: Scene#setOnKeyPressed
▪ キーを離したイベントを取得: Scene#setOnKeyReleased
– 取得したキーイベントをバッファしておく。
– 必殺技は最終的にパンチキーかキックキーを押すことで繰り出されるので、当該
キーが押された際にあらかじめバッファしておいたキー入力が各必殺技のコマンド
入力に合致しているか判断して、合致していたら対応する必殺技を繰り出す。
– バッファされたキー入力はアルファベット文字列に変換され、各必殺技に相当する
文字列と比較して入力判定する。キーを押した場合は大文字、キーを離した場合は
小文字とする。例えば昇龍拳と判断されるキー入力文字列は以下(キーを離したと
いうイベントも意識する)。
▪ “SsZzZSX” か “SsZzSZX”
10
前提とか準備とか(3/3)
 リアクティブライブラリーとして、Reactor を使います。
Java だし。最新の v3.1.x 系を使用します
(2018 年 4 月現在)。
 ところで…、Reactor?原子炉?
11
Reactor とは?
 Pivotal 社主導で Project Reactor というオープンソースプロジェクトの下で開発
されている、Reactive Streams 仕様に沿った、JVM 上でノンブロッキングなアプ
リケーションを開発するリアクティブライブラリー。
– https://projectreactor.io/
 バージョンアップするたびに、API がかなり変遷してますが、現在(2018 年 4 月
現在)はコアライブラリーとして、Flux と Mono という Reactive Extensions の実
装が提供されています。
 Spring Framework 5 のリアクティブプログラミング向けフレームワーク(Spring
WebFlux とか)の実装として Reactor が使われています。
 project riff の Java Invoker に Reactor core が含まれているので、サーバーレスな
FaaS 環境でリアクティブに関数実行可能です。
– https://projectriff.io/invokers/java/
12
13
デモ:
とりあえずできあがったアプリ
ケーションがどんなものかデモ
ンストレーションするよ。
【どうでも】キーイベント取得動作で分かったこと【イイネ!】
 いきなり本筋からそれますが…、昇龍拳って、最後にレバー斜め下 + パンチボタンという
同時押しするんで、今回の想定では [→] + [↓] + [P] と、3 キー同時押しになるんですね。
 普通の PC に付属しているキーボードって、ほとんど「2 キーロールオーバー 」というス
ペックで、特殊キーを除いて 2 キーまでしか同時押し認識しないんですね。
 私の PC も例外なく 2 キーロールオーバーだったんで、当初の仕様上、3 キー同時押しを要
求する昇龍拳はだせないんですよね(厳密にいうと、キーのアニメーションがうまく同時
押しを表現できないだけで、マイロジックでは昇龍拳はでるんですけどね)。
 なので、デモアプリを動かすには「N キーロール
オーバー」といったスペックのちょっといい外付け
キーボードを使いましょう。ちなみに僕は、HHKB
Professional BT(無刻印変態仕様)を使っています。
– それでも、PS/2 接続じゃない最近のやつは 6 キーまでしか同時
押し認識しないんですけどね。ま、それで十分ですが。
14
15
比較のため、まずはリアクティ
ブプログラミングなしでアプリ
ケーションを作ってみたよ。
さて、昇龍拳ロジックを見てみ
ましょう。
ノンリアクティブな昇龍拳ロジック
16
mainScene.setOnKeyPressed(new EventHandler<KeyEvent>() { // キー押下時に反応するリスナー付与
public void handle(KeyEvent event) {
String keyEvent = event.getCode().toString(); // キーイベントを文字列に変換
if (keyActionChecker(keyEvent)) { // 方向キーかパンチ・キックキーが押された場合のみ以下実行
commandList.add(keyEvent); // 入力キーバッファ commandList にキー文字列追加
if (keyEvent.equals(PUNCH) || keyEvent.equals(KICK)) { // パンチ・キックキーが押されたら必殺技判定
String cl = readCommand(); // 入力キーバッファの内容を文字列 cl に変換します
if (cl.contains(SYORYU_CL[0])…) { // cl に昇龍拳コマンドが含まれているか?
startAction(3, 17, “shouryuuken.mp3”); // 昇龍拳を繰り出す
} else if (cl.contains(HADOU_CL[0])...) { // cl に波動拳コマンドが含まれているか?
startAction(4, 14, “hadouken.mp3”); // 波動拳を繰り出す
} else if (cl.contains(TATSUMAKI_CL[0])…) { // cl に竜巻旋風脚コマンドが含まれているか?
startAction(5, 27, “tatsumaki_senpukyaku.mp3”); // 竜巻旋風脚を繰り出す
} else if (cl.contains(PUNCH)) { // cl にパンチキーイベントが含まれているか?
startAction(1, 8, “punch.mp3”); // 中パンチを繰り出す
} else {
startAction(2, 15, “kick.mp3”); // 上述のどれにも該当しなかったら、大キックを繰り出す
}
}
}
}
});
mainScene.setOnKeyReleased(new EventHandler<KeyEvent>() { // キー離した時に反応するリスナー付与
public void handle(KeyEvent event) {
String keyEvent = event.getCode().toString(); // キーイベントを文字列に変換
if (keyActionChecker(keyEvent)) { // 方向キーかパンチ・キックキーが離された場合のみ以下実行
commandList.add(keyEvent.toLowerCase()); // commandList にキー文字列を小文字にして追加
}
}
});
入力キーバッファは、異なるリス
ナーインスタンス(キーを押した
場合と話した場合)にまたがって
使用されるので、static な List 型
の変数として定義してあります。
キー押したり離したりするリス
ナーのロジックの記述は、Java 8
以降だとラムダ式使ってもいいん
ですが、ここでは使ってません。
思ったよりも、シンプルでしたが
必殺技判定ロジックの if 文ネスト
の闇がやや深いのと、リスナーの
都合でバッファを共有変数として
持っているのがキモイです。
17
そして、Reactor を使ってリアク
ティブプログラミングした方の
昇龍拳ロジックを見てみましょ
う。
リアクティブな昇龍拳ロジック
18
Flux.create(sink -> { // 複数のデータストリームを扱う Flux を採用。FluxSink でデータをバッファに入れます
mainScene.setOnKeyPressed(keyEvent -> { // キー押下時に反応するリスナーの付与
String pressedKey = keyEvent.getCode().toString(); // キーイベントを文字列に変換
sink.next(pressedKey); // 文字列をバッファに追加
});
mainScene.setOnKeyReleased(keyEvent -> { // キーを離した時に反応するリスナーの付与
String releasedKey = keyEvent.getCode().toString(); // キーイベントを文字列に変換
sink.next(releasedKey.toLowerCase()); // 文字列をバッファに追加(離した時なので小文字に変換)
});
}).filter(keyEvent -> { // 方向キーかパンチ・キックキーが押された場合のみ、バッファに追加
String key = ((String) keyEvent).toUpperCase();
return key.equals(UP) || … || key.equals(KICK);
}).bufferUntil(keyEvent -> { // パンチ・キックキーが押下されるまでデータストリームをバッファする
return ((String) keyEvent).equals(PUNCH) || …);
}).subscribe(commandList -> { // パンチキーかキックキーが押下されたら、必殺技判定ロジック実行
String[] cl = {""};
commandList.forEach(keyEvent -> cl[0] += (String) keyEvent); //入力キーバッファ内容を文字列 cl[0] に変換
if (cl[0].contains(SYORYU_CL[0]) || …) { // cl[0] に昇龍拳コマンドが含まれているか?
startAction(3, 17, “shouryuuken.mp3”); // 昇龍拳を繰り出す
} else if (cl[0].contains(HADOU_CL[0]) || …) { // cl[0] に波動拳コマンドが含まれているか?
startAction(4, 14, “hadouken.mp3”); // 波動拳を繰り出す
} else if (cl[0].contains(TATSUMAKI_CL[0]) ||…) { // cl[0] に竜巻旋風脚コマンドが含まれているか?
startAction(5, 27, “tatsumaki_senpukyaku.mp3”); // 竜巻旋風脚を繰り出す
} else if (cl[0].contains(PUNCH)){ // cl[0] にパンチキーイベントが含まれているか?
startAction(1, 8, “punch.mp3”); // 中パンチを繰り出す
} else {
startAction(2, 15, “kick.mp3”); //上述のどれにも該当しなかったら、大キックを繰り出す
}
});
Reactive Extensions 準拠(?)
の API で各ロジックを
Composable にすっきり記述でき
てうれしいですね!
ノンリアクティブ版ではバラバラ
だったストリームデータをバッ
ファにいれるロジックも、まとめ
て記述できて、バッファ用の共有
変数も特に用意しなくて良いです。
関数を Composable に記述するだ
けで Observable に動きます。
ラムダ式やメソッド参照(ここで
は使ってないですが)、Streams
など積極的に使って、リアクティ
ブストリーマーを目指しましょう
(謎)。
19
ということで、Reactor を使って
リアクティブに昇龍拳を繰り出
してみました!
個人的には、Reactor の他
JavaFX やラムダ式、メソッド参
照、Streams といった Java 技術
の勉強になりましたー。
20
とはいえ、若干の疑問が…
21
• どこがノンブロッキングなの?デ
フォルトでは、ストリームデータ
処理も昇龍拳ロジックもシングル
スレッドで動いているようだけ
ど?もしかして、昇龍拳アプリで
は実感しづらい?
• 僕の理解では、Reactive Streams
仕様的に、バックプレッシャーの
仕組みが必要っぽいけど、
Reactor はどうなってる?
22
リアクティブ界隈用語の僕の理
解をまず整理して、Reactor では
どう実装されているのか検証し
てみますかね…。
リアクティブ界隈用語の僕的理解(1/3)
 「リアクティブプログラミング」のそれは、冒頭に紹介したので、それ
以外のよくでてくる用語の僕的理解を列挙
 Reactive Streams
– リアクティブ宣言を読もう!
▪ https://www.reactivemanifesto.org/ja
– ざっくり言うと、「ノンブロッキングなバックプレッシャーを持つ非同期
ストリーム処理の標準」で、各キーフレーズの僕的理解が以下…
▪ ノンブロッキング:メッセージ受信側における処理の進捗にかかわらず、メッセージ送信
側にはすぐに何らかの応答(失敗、処理中、完了等)が返却される。
▪ バックプレッシャー:メッセージ受信側の処理が追いつかないほど、送信側からメッセー
ジが送られるような過負荷状態を防ぐため、メッセージ受信側が送信側に対してメッセー
ジ送信量を調整するようお願いする仕組み的な。
リアクティブ界隈用語の僕的理解(2/3)
 Reactive Extensions
– Microsoft が最初に提唱した模様
▪ https://msdn.microsoft.com/en-us/library/hh242985(v=vs.103).aspx
– Observable な処理手順で LINQ スタイルのクエリーオペレーターを使った非同期でイ
ベント駆動なプログラムを作成するライブラリー。はて…?
▪ Observable な処理手順:言い換えれば、Pub-Sub の仕組み。メッセージ送信側(Publisher)と受信側
(Subscriber)がいて、送信側から送られてきたメッセージを受信側がうけとってそれに伴う何らかの処理
を行うという形態かと。
▪ LINQ スタイルのクエリーオペレーター:クエリー対象データに対して、ドット演算子で次々と連鎖的につ
なげてクエリーできるやつ。さきほどの、Reactor を使ったサンプルコードの、create とか、filter とか、そ
ういった感じの。LINQ は Microsoft が提供しているものの固有名詞。
– Microsoft からは Rx.Net という名前でモノがでている。まー、要するにリアクティブ
プログラミングを行うライブラリー。
– Reactor は Reactive Extensions の一実装を提供しているといえる。
リアクティブ界隈用語の僕的理解(3/3)
 Reactive Streams と Reactive Extensions の関係性
– 最初は、Reactive Extensions という観点で Microsoft から実装も含めて、.Net な世界
でリアクティブプログラミングを行うライブラリーとしてでてきたようだ。
– その後、他言語にも似たようなライブラリーがでてきたけど、リアクティブプロラ
ミングの解釈がバラバラで、API もバラバラなんで、標準的な要件とか仕様(ノンブ
ロッキングなバックプレッシャーの仕組みが必要!とか)があったらイイネ!とい
うことで、Reactive Streams というイニシアティブが発足、仕様とか API ができたよ
うだ。
– Reactive Streams の仕様とか API ができた後は、Reactive Extensions はそれらをプロ
グラミングしやすいような便利ライブラリーっぽい位置づけになったように見える
(事実、Reactor も途中から API ががらりと変わった)。
– 個人の印象です。印象操作ではないです。
26
ということは、僕のこれまでの
昇龍拳アプリは、Reactor の
Reactive Extensions API を使っ
てプログラミングしたけど、特
に非同期である必要性はないが
Reactive Streams に準拠した
Reactor 実装にそって動かしてみ
たレベル、ということですか
ねー。ぐはー。
27
ということで、「リアクティブ
な昇龍拳ロジック」のノンブ
ロッキングなバックプレッ
シャー版を実装してみたよ!
ノンブロッキングな昇龍拳ロジック
28
Flux.create(sink -> { // 複数のデータストリームを扱う Flux を採用。FluxSink でデータをバッファに入れます
mainScene.setOnKeyPressed(keyEvent -> { // キー押下時に反応するリスナーの付与
String pressedKey = keyEvent.getCode().toString(); // キーイベントを文字列に変換
sink.next(pressedKey); // 文字列をバッファに追加
});
mainScene.setOnKeyReleased(keyEvent -> { // キーを離した時に反応するリスナーの付与
String releasedKey = keyEvent.getCode().toString(); // キーイベントを文字列に変換
sink.next(releasedKey.toLowerCase()); // 文字列をバッファに追加(離した時なので小文字に変換)
});
}).filter(keyEvent -> { // 方向キーかパンチ・キックキーが押された場合のみ、バッファに追加
String key = ((String) keyEvent).toUpperCase();
return key.equals(UP) || … || key.equals(KICK);
}).bufferUntil(keyEvent -> { // パンチ・キックキーが押下されるまでデータストリームをバッファする
return ((String) keyEvent).equals(PUNCH) || …);
}).publishOn(Schedulers.elastic())
.subscribe(commandList -> { // パンチキーかキックキーが押下されたら、必殺技判定ロジック実行
/* 以下、略 */
);
先のコードに、これをくっつけた
だけ。API docs 的には、
subscribeOn の方がそれっぽいけ
ど、動作確認したら publishOn の
方が quitada の思うところのノン
ブロッキング的な動き
(Flux.subscribe 内ロジックと
FluxSink によるストリームデータ
のバッファリングが非同期に行わ
れる、というかストリームデータ
が consume されたら、subscribe
内のロジックが別スレッドでトリ
ガーされて、データストリームの
バッファリング処理は継続しつつ
非同期で subscribe 内ロジックを
実行する)でした。
バックプレシャー付き昇龍拳ロジック
29
Flux flux = Flux.create(sink -> { // FluxSink でデータをバッファに入れます
mainScene.setOnKeyPressed(keyEvent -> { // キー押下時に反応するリスナーの付与(以下、同じなので略)
:
}).publishOn(Schedulers.elastic()); // 先に言及したノンブロッキング的な動作をするためのスケジューラー付与
BaseSubscriber<ArrayList<String>> subscriber = new BaseSubscriber<ArrayList<String>>() {
// バックプレッシャー実装のため、BaseSubscriber を使用
private int onNextAmount = 0; // 受信したデータの個数カウンター
@Override
protected void hookOnSubscribe(Subscription subscription) {
request(2); // サブスクライブ初回にデータストリームより、2 個のデータをリクエスト
}
@Override
protected void hookOnError(Throwable throwable) {
throwable.printStackTrace(); // とりあえず、なんかエラーハンドリング
}
@Override
protected void hookOnComplete() { }
@Override
protected void hookOnNext(ArrayList<String> commandList) {
// パンチキーかキックキーが押下されたら、必殺技判定ロジック実行(同じなので中身省略)
:
// 2 個のデータを消費するたびに、2 個のデータをリクエスト
onNextAmount++;
if (onNextAmount % 2 == 0) {
request(2);
}
}
};
flux.subscribe(subscriber); // サブスクライブ!
ドキュメントに、Subscriber を実
装するため、BaseSubscriber を
使用する例があったので、そのま
ま拝借。Composable に記述しよ
うとしたら、IDE に怒られまくっ
たので、仕方なく切り出してます。
どういう条件で、データストリー
ムからデータリクエストするかは
自分でロジックを考える必要があ
ります。ここでは、データ 2 個消
費して 2 個リクエストするだけの
単純な実装です。当然、リクエス
トしないと、消費されません。
30
ひとまず「リアクティブな昇龍
拳ロジック」を Reactor 使って
実現する試みは、ひとまずこれ
で完了。
さて、次は何に使いましょう
か?Reactive Streams が何に使
えるか使えないかは、あなた次
第。

More Related Content

What's hot

押さえておきたい、PostgreSQL 13 の新機能!! (PostgreSQL Conference Japan 2020講演資料)
押さえておきたい、PostgreSQL 13 の新機能!! (PostgreSQL Conference Japan 2020講演資料)押さえておきたい、PostgreSQL 13 の新機能!! (PostgreSQL Conference Japan 2020講演資料)
押さえておきたい、PostgreSQL 13 の新機能!! (PostgreSQL Conference Japan 2020講演資料)NTT DATA Technology & Innovation
 
ゲームエンジニアのためのデータベース設計
ゲームエンジニアのためのデータベース設計ゲームエンジニアのためのデータベース設計
ゲームエンジニアのためのデータベース設計sairoutine
 
MagicOnion~C#でゲームサーバを開発しよう~
MagicOnion~C#でゲームサーバを開発しよう~MagicOnion~C#でゲームサーバを開発しよう~
MagicOnion~C#でゲームサーバを開発しよう~torisoup
 
stripe-rubyで サブスクリプションを 実装して得た知見
stripe-rubyで サブスクリプションを 実装して得た知見stripe-rubyで サブスクリプションを 実装して得た知見
stripe-rubyで サブスクリプションを 実装して得た知見Isao Ebisujima
 
異次元のグラフデータベースNeo4j
異次元のグラフデータベースNeo4j異次元のグラフデータベースNeo4j
異次元のグラフデータベースNeo4j昌桓 李
 
ドメイン駆動で開発する ラフスケッチから実装まで
ドメイン駆動で開発する ラフスケッチから実装までドメイン駆動で開発する ラフスケッチから実装まで
ドメイン駆動で開発する ラフスケッチから実装まで増田 亨
 
ChatGPTのデータソースにPostgreSQLを使う[詳細版](オープンデベロッパーズカンファレンス2023 発表資料)
ChatGPTのデータソースにPostgreSQLを使う[詳細版](オープンデベロッパーズカンファレンス2023 発表資料)ChatGPTのデータソースにPostgreSQLを使う[詳細版](オープンデベロッパーズカンファレンス2023 発表資料)
ChatGPTのデータソースにPostgreSQLを使う[詳細版](オープンデベロッパーズカンファレンス2023 発表資料)NTT DATA Technology & Innovation
 
イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)Yoshitaka Kawashima
 
ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計Yoshinori Matsunobu
 
オントロジーとは?
オントロジーとは?オントロジーとは?
オントロジーとは?Kouji Kozaki
 
実録Blue-Green Deployment導入記
実録Blue-Green Deployment導入記実録Blue-Green Deployment導入記
実録Blue-Green Deployment導入記Hiroyuki Ohnaka
 
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)Takuto Wada
 
分散システムについて語らせてくれ
分散システムについて語らせてくれ分散システムについて語らせてくれ
分散システムについて語らせてくれKumazaki Hiroki
 
立花氏とのスライドメモ.pptx
立花氏とのスライドメモ.pptx立花氏とのスライドメモ.pptx
立花氏とのスライドメモ.pptxrehacq
 
ソフトウェア開発における『知の高速道路』
ソフトウェア開発における『知の高速道路』ソフトウェア開発における『知の高速道路』
ソフトウェア開発における『知の高速道路』Yoshitaka Kawashima
 
イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)Yoshitaka Kawashima
 

What's hot (20)

押さえておきたい、PostgreSQL 13 の新機能!! (PostgreSQL Conference Japan 2020講演資料)
押さえておきたい、PostgreSQL 13 の新機能!! (PostgreSQL Conference Japan 2020講演資料)押さえておきたい、PostgreSQL 13 の新機能!! (PostgreSQL Conference Japan 2020講演資料)
押さえておきたい、PostgreSQL 13 の新機能!! (PostgreSQL Conference Japan 2020講演資料)
 
ゲームエンジニアのためのデータベース設計
ゲームエンジニアのためのデータベース設計ゲームエンジニアのためのデータベース設計
ゲームエンジニアのためのデータベース設計
 
MagicOnion~C#でゲームサーバを開発しよう~
MagicOnion~C#でゲームサーバを開発しよう~MagicOnion~C#でゲームサーバを開発しよう~
MagicOnion~C#でゲームサーバを開発しよう~
 
stripe-rubyで サブスクリプションを 実装して得た知見
stripe-rubyで サブスクリプションを 実装して得た知見stripe-rubyで サブスクリプションを 実装して得た知見
stripe-rubyで サブスクリプションを 実装して得た知見
 
eBPFを用いたトレーシングについて
eBPFを用いたトレーシングについてeBPFを用いたトレーシングについて
eBPFを用いたトレーシングについて
 
キメるClojure
キメるClojureキメるClojure
キメるClojure
 
各種データベースの特徴とパフォーマンス比較
各種データベースの特徴とパフォーマンス比較各種データベースの特徴とパフォーマンス比較
各種データベースの特徴とパフォーマンス比較
 
異次元のグラフデータベースNeo4j
異次元のグラフデータベースNeo4j異次元のグラフデータベースNeo4j
異次元のグラフデータベースNeo4j
 
ドメイン駆動で開発する ラフスケッチから実装まで
ドメイン駆動で開発する ラフスケッチから実装までドメイン駆動で開発する ラフスケッチから実装まで
ドメイン駆動で開発する ラフスケッチから実装まで
 
ChatGPTのデータソースにPostgreSQLを使う[詳細版](オープンデベロッパーズカンファレンス2023 発表資料)
ChatGPTのデータソースにPostgreSQLを使う[詳細版](オープンデベロッパーズカンファレンス2023 発表資料)ChatGPTのデータソースにPostgreSQLを使う[詳細版](オープンデベロッパーズカンファレンス2023 発表資料)
ChatGPTのデータソースにPostgreSQLを使う[詳細版](オープンデベロッパーズカンファレンス2023 発表資料)
 
イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)イミュータブルデータモデル(入門編)
イミュータブルデータモデル(入門編)
 
ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計
 
オントロジーとは?
オントロジーとは?オントロジーとは?
オントロジーとは?
 
実録Blue-Green Deployment導入記
実録Blue-Green Deployment導入記実録Blue-Green Deployment導入記
実録Blue-Green Deployment導入記
 
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
 
分散システムについて語らせてくれ
分散システムについて語らせてくれ分散システムについて語らせてくれ
分散システムについて語らせてくれ
 
Rest ful api設計入門
Rest ful api設計入門Rest ful api設計入門
Rest ful api設計入門
 
立花氏とのスライドメモ.pptx
立花氏とのスライドメモ.pptx立花氏とのスライドメモ.pptx
立花氏とのスライドメモ.pptx
 
ソフトウェア開発における『知の高速道路』
ソフトウェア開発における『知の高速道路』ソフトウェア開発における『知の高速道路』
ソフトウェア開発における『知の高速道路』
 
イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)
 

Similar to 〜僕の初めてのリアクティブプログラミング Reactor を使ってリアクティブに昇龍拳を繰り出してみた!

【古いスライド】〜僕の初めてのリアクティブプログラミング Reactor を使ってリアクティブに昇龍拳を繰り出してみた!
【古いスライド】〜僕の初めてのリアクティブプログラミング Reactor を使ってリアクティブに昇龍拳を繰り出してみた!【古いスライド】〜僕の初めてのリアクティブプログラミング Reactor を使ってリアクティブに昇龍拳を繰り出してみた!
【古いスライド】〜僕の初めてのリアクティブプログラミング Reactor を使ってリアクティブに昇龍拳を繰り出してみた!Akihiro Kitada
 
Sourcecode Reading Workshop2010
Sourcecode Reading Workshop2010Sourcecode Reading Workshop2010
Sourcecode Reading Workshop2010Hiro Yoshioka
 
ReduxとSwiftの組み合わせ:改訂版
ReduxとSwiftの組み合わせ:改訂版ReduxとSwiftの組み合わせ:改訂版
ReduxとSwiftの組み合わせ:改訂版Fumiya Sakai
 
Apache Auroraの始めかた
Apache Auroraの始めかたApache Auroraの始めかた
Apache Auroraの始めかたMasahito Zembutsu
 
20180613 [TensorFlow分散学習] Horovodによる分散学習の実装方法と解説
20180613 [TensorFlow分散学習] Horovodによる分散学習の実装方法と解説20180613 [TensorFlow分散学習] Horovodによる分散学習の実装方法と解説
20180613 [TensorFlow分散学習] Horovodによる分散学習の実装方法と解説LeapMind Inc
 
Programming camp Codereading
Programming camp CodereadingProgramming camp Codereading
Programming camp CodereadingHiro Yoshioka
 
Ryuの遊び方(pica8も併せてもっと楽しく)(2014/1/23修正版)
Ryuの遊び方(pica8も併せてもっと楽しく)(2014/1/23修正版)Ryuの遊び方(pica8も併せてもっと楽しく)(2014/1/23修正版)
Ryuの遊び方(pica8も併せてもっと楽しく)(2014/1/23修正版)hiroshi oshiba
 
Linuxのユーザーランドをinitから全てまるごとgolangで書く
Linuxのユーザーランドをinitから全てまるごとgolangで書くLinuxのユーザーランドをinitから全てまるごとgolangで書く
Linuxのユーザーランドをinitから全てまるごとgolangで書くTetsuyuki Kobayashi
 
シンプルでシステマチックな Linux 性能分析方法
シンプルでシステマチックな Linux 性能分析方法シンプルでシステマチックな Linux 性能分析方法
シンプルでシステマチックな Linux 性能分析方法Yohei Azekatsu
 
あなたの安心を高速に守る Container-based CI
あなたの安心を高速に守る Container-based CIあなたの安心を高速に守る Container-based CI
あなたの安心を高速に守る Container-based CIWataru MIYAGUNI
 
Fundamentals of Swift & Redux (ReduxとSwiftの組み合わせ)
Fundamentals of Swift & Redux (ReduxとSwiftの組み合わせ)Fundamentals of Swift & Redux (ReduxとSwiftの組み合わせ)
Fundamentals of Swift & Redux (ReduxとSwiftの組み合わせ)Fumiya Sakai
 
ECMAScript6による関数型プログラミング
ECMAScript6による関数型プログラミングECMAScript6による関数型プログラミング
ECMAScript6による関数型プログラミングTanUkkii
 
Java トラブル解析支援ツール HeapStats のご紹介
Java トラブル解析支援ツール HeapStats のご紹介Java トラブル解析支援ツール HeapStats のご紹介
Java トラブル解析支援ツール HeapStats のご紹介Shinya Takebayashi
 
20090124shibuya Trac
20090124shibuya Trac20090124shibuya Trac
20090124shibuya TracKazuya Hirobe
 
アドテク×Scala×パフォーマンスチューニング
アドテク×Scala×パフォーマンスチューニングアドテク×Scala×パフォーマンスチューニング
アドテク×Scala×パフォーマンスチューニングYosuke Mizutani
 
ROMA on JRuby at JRubyKaigi 2010
ROMA on JRuby at JRubyKaigi 2010ROMA on JRuby at JRubyKaigi 2010
ROMA on JRuby at JRubyKaigi 2010Rakuten Group, Inc.
 
イベント駆動プログラミングとI/O多重化
イベント駆動プログラミングとI/O多重化イベント駆動プログラミングとI/O多重化
イベント駆動プログラミングとI/O多重化Gosuke Miyashita
 
debexpo(mentors.d.n)をハックするには
debexpo(mentors.d.n)をハックするにはdebexpo(mentors.d.n)をハックするには
debexpo(mentors.d.n)をハックするにはkenhys
 

Similar to 〜僕の初めてのリアクティブプログラミング Reactor を使ってリアクティブに昇龍拳を繰り出してみた! (20)

【古いスライド】〜僕の初めてのリアクティブプログラミング Reactor を使ってリアクティブに昇龍拳を繰り出してみた!
【古いスライド】〜僕の初めてのリアクティブプログラミング Reactor を使ってリアクティブに昇龍拳を繰り出してみた!【古いスライド】〜僕の初めてのリアクティブプログラミング Reactor を使ってリアクティブに昇龍拳を繰り出してみた!
【古いスライド】〜僕の初めてのリアクティブプログラミング Reactor を使ってリアクティブに昇龍拳を繰り出してみた!
 
Sourcecode Reading Workshop2010
Sourcecode Reading Workshop2010Sourcecode Reading Workshop2010
Sourcecode Reading Workshop2010
 
ReduxとSwiftの組み合わせ:改訂版
ReduxとSwiftの組み合わせ:改訂版ReduxとSwiftの組み合わせ:改訂版
ReduxとSwiftの組み合わせ:改訂版
 
Apache Auroraの始めかた
Apache Auroraの始めかたApache Auroraの始めかた
Apache Auroraの始めかた
 
20180613 [TensorFlow分散学習] Horovodによる分散学習の実装方法と解説
20180613 [TensorFlow分散学習] Horovodによる分散学習の実装方法と解説20180613 [TensorFlow分散学習] Horovodによる分散学習の実装方法と解説
20180613 [TensorFlow分散学習] Horovodによる分散学習の実装方法と解説
 
Programming camp Codereading
Programming camp CodereadingProgramming camp Codereading
Programming camp Codereading
 
Ryuの遊び方(pica8も併せてもっと楽しく)(2014/1/23修正版)
Ryuの遊び方(pica8も併せてもっと楽しく)(2014/1/23修正版)Ryuの遊び方(pica8も併せてもっと楽しく)(2014/1/23修正版)
Ryuの遊び方(pica8も併せてもっと楽しく)(2014/1/23修正版)
 
Linuxのユーザーランドをinitから全てまるごとgolangで書く
Linuxのユーザーランドをinitから全てまるごとgolangで書くLinuxのユーザーランドをinitから全てまるごとgolangで書く
Linuxのユーザーランドをinitから全てまるごとgolangで書く
 
シンプルでシステマチックな Linux 性能分析方法
シンプルでシステマチックな Linux 性能分析方法シンプルでシステマチックな Linux 性能分析方法
シンプルでシステマチックな Linux 性能分析方法
 
あなたの安心を高速に守る Container-based CI
あなたの安心を高速に守る Container-based CIあなたの安心を高速に守る Container-based CI
あなたの安心を高速に守る Container-based CI
 
Fundamentals of Swift & Redux (ReduxとSwiftの組み合わせ)
Fundamentals of Swift & Redux (ReduxとSwiftの組み合わせ)Fundamentals of Swift & Redux (ReduxとSwiftの組み合わせ)
Fundamentals of Swift & Redux (ReduxとSwiftの組み合わせ)
 
ECMAScript6による関数型プログラミング
ECMAScript6による関数型プログラミングECMAScript6による関数型プログラミング
ECMAScript6による関数型プログラミング
 
Introduction of Python
Introduction of PythonIntroduction of Python
Introduction of Python
 
Java トラブル解析支援ツール HeapStats のご紹介
Java トラブル解析支援ツール HeapStats のご紹介Java トラブル解析支援ツール HeapStats のご紹介
Java トラブル解析支援ツール HeapStats のご紹介
 
20090124shibuya Trac
20090124shibuya Trac20090124shibuya Trac
20090124shibuya Trac
 
How To Drink Wsgi
How To Drink WsgiHow To Drink Wsgi
How To Drink Wsgi
 
アドテク×Scala×パフォーマンスチューニング
アドテク×Scala×パフォーマンスチューニングアドテク×Scala×パフォーマンスチューニング
アドテク×Scala×パフォーマンスチューニング
 
ROMA on JRuby at JRubyKaigi 2010
ROMA on JRuby at JRubyKaigi 2010ROMA on JRuby at JRubyKaigi 2010
ROMA on JRuby at JRubyKaigi 2010
 
イベント駆動プログラミングとI/O多重化
イベント駆動プログラミングとI/O多重化イベント駆動プログラミングとI/O多重化
イベント駆動プログラミングとI/O多重化
 
debexpo(mentors.d.n)をハックするには
debexpo(mentors.d.n)をハックするにはdebexpo(mentors.d.n)をハックするには
debexpo(mentors.d.n)をハックするには
 

More from Akihiro Kitada

How to configure the cluster based on Multi-site (WAN) configuration
How to configure the clusterbased on Multi-site (WAN) configurationHow to configure the clusterbased on Multi-site (WAN) configuration
How to configure the cluster based on Multi-site (WAN) configurationAkihiro Kitada
 
Reactive Streams に基づく非同期処理プログラミング 〜 Reactor を使ってみた
Reactive Streams に基づく非同期処理プログラミング 〜 Reactor を使ってみたReactive Streams に基づく非同期処理プログラミング 〜 Reactor を使ってみた
Reactive Streams に基づく非同期処理プログラミング 〜 Reactor を使ってみたAkihiro Kitada
 
【古いスライド】〜僕の初めてのリアクティブプログラミング Reactor を使ってリアクティブに昇龍拳を繰り出してみた!
【古いスライド】〜僕の初めてのリアクティブプログラミング Reactor を使ってリアクティブに昇龍拳を繰り出してみた!【古いスライド】〜僕の初めてのリアクティブプログラミング Reactor を使ってリアクティブに昇龍拳を繰り出してみた!
【古いスライド】〜僕の初めてのリアクティブプログラミング Reactor を使ってリアクティブに昇龍拳を繰り出してみた!Akihiro Kitada
 
Apache Geode の Apache Lucene Integration を試してみた
Apache Geode の Apache Lucene Integration を試してみたApache Geode の Apache Lucene Integration を試してみた
Apache Geode の Apache Lucene Integration を試してみたAkihiro Kitada
 
Apache Calcite の Apache Geode Adapter を弄った
Apache Calcite の Apache Geode Adapter を弄ったApache Calcite の Apache Geode Adapter を弄った
Apache Calcite の Apache Geode Adapter を弄ったAkihiro Kitada
 
Grafana を使った Apache Geode クラスター監視
Grafana を使った Apache Geode クラスター監視Grafana を使った Apache Geode クラスター監視
Grafana を使った Apache Geode クラスター監視Akihiro Kitada
 
〜Apache Geode 入門 Multi-site(WAN)構成による クラスター連携
〜Apache Geode 入門 Multi-site(WAN)構成によるクラスター連携〜Apache Geode 入門 Multi-site(WAN)構成によるクラスター連携
〜Apache Geode 入門 Multi-site(WAN)構成による クラスター連携Akihiro Kitada
 
My first reactive programming - To deliver a deathblow “Shoryuken” with using...
My first reactive programming - To deliver a deathblow “Shoryuken” with using...My first reactive programming - To deliver a deathblow “Shoryuken” with using...
My first reactive programming - To deliver a deathblow “Shoryuken” with using...Akihiro Kitada
 
〜Apache Geode 入門 gfsh によるクラスター構築・管理
〜Apache Geode 入門 gfsh によるクラスター構築・管理〜Apache Geode 入門 gfsh によるクラスター構築・管理
〜Apache Geode 入門 gfsh によるクラスター構築・管理Akihiro Kitada
 
はじめての Cloud Foundry: .NET アプリケーションのはじめ方
はじめての Cloud Foundry: .NET アプリケーションのはじめ方はじめての Cloud Foundry: .NET アプリケーションのはじめ方
はじめての Cloud Foundry: .NET アプリケーションのはじめ方Akihiro Kitada
 
Apache Geode で始める Spring Data Gemfire
Apache Geode で始めるSpring Data GemfireApache Geode で始めるSpring Data Gemfire
Apache Geode で始める Spring Data GemfireAkihiro Kitada
 
Reactor によるデータインジェスチョン
Reactor によるデータインジェスチョンReactor によるデータインジェスチョン
Reactor によるデータインジェスチョンAkihiro Kitada
 

More from Akihiro Kitada (12)

How to configure the cluster based on Multi-site (WAN) configuration
How to configure the clusterbased on Multi-site (WAN) configurationHow to configure the clusterbased on Multi-site (WAN) configuration
How to configure the cluster based on Multi-site (WAN) configuration
 
Reactive Streams に基づく非同期処理プログラミング 〜 Reactor を使ってみた
Reactive Streams に基づく非同期処理プログラミング 〜 Reactor を使ってみたReactive Streams に基づく非同期処理プログラミング 〜 Reactor を使ってみた
Reactive Streams に基づく非同期処理プログラミング 〜 Reactor を使ってみた
 
【古いスライド】〜僕の初めてのリアクティブプログラミング Reactor を使ってリアクティブに昇龍拳を繰り出してみた!
【古いスライド】〜僕の初めてのリアクティブプログラミング Reactor を使ってリアクティブに昇龍拳を繰り出してみた!【古いスライド】〜僕の初めてのリアクティブプログラミング Reactor を使ってリアクティブに昇龍拳を繰り出してみた!
【古いスライド】〜僕の初めてのリアクティブプログラミング Reactor を使ってリアクティブに昇龍拳を繰り出してみた!
 
Apache Geode の Apache Lucene Integration を試してみた
Apache Geode の Apache Lucene Integration を試してみたApache Geode の Apache Lucene Integration を試してみた
Apache Geode の Apache Lucene Integration を試してみた
 
Apache Calcite の Apache Geode Adapter を弄った
Apache Calcite の Apache Geode Adapter を弄ったApache Calcite の Apache Geode Adapter を弄った
Apache Calcite の Apache Geode Adapter を弄った
 
Grafana を使った Apache Geode クラスター監視
Grafana を使った Apache Geode クラスター監視Grafana を使った Apache Geode クラスター監視
Grafana を使った Apache Geode クラスター監視
 
〜Apache Geode 入門 Multi-site(WAN)構成による クラスター連携
〜Apache Geode 入門 Multi-site(WAN)構成によるクラスター連携〜Apache Geode 入門 Multi-site(WAN)構成によるクラスター連携
〜Apache Geode 入門 Multi-site(WAN)構成による クラスター連携
 
My first reactive programming - To deliver a deathblow “Shoryuken” with using...
My first reactive programming - To deliver a deathblow “Shoryuken” with using...My first reactive programming - To deliver a deathblow “Shoryuken” with using...
My first reactive programming - To deliver a deathblow “Shoryuken” with using...
 
〜Apache Geode 入門 gfsh によるクラスター構築・管理
〜Apache Geode 入門 gfsh によるクラスター構築・管理〜Apache Geode 入門 gfsh によるクラスター構築・管理
〜Apache Geode 入門 gfsh によるクラスター構築・管理
 
はじめての Cloud Foundry: .NET アプリケーションのはじめ方
はじめての Cloud Foundry: .NET アプリケーションのはじめ方はじめての Cloud Foundry: .NET アプリケーションのはじめ方
はじめての Cloud Foundry: .NET アプリケーションのはじめ方
 
Apache Geode で始める Spring Data Gemfire
Apache Geode で始めるSpring Data GemfireApache Geode で始めるSpring Data Gemfire
Apache Geode で始める Spring Data Gemfire
 
Reactor によるデータインジェスチョン
Reactor によるデータインジェスチョンReactor によるデータインジェスチョン
Reactor によるデータインジェスチョン
 

〜僕の初めてのリアクティブプログラミング Reactor を使ってリアクティブに昇龍拳を繰り出してみた!

  • 3. リアクティブプログラミングとは? 3 “In computing, reactive programming is an asynchronous programming paradigm concerned with data streams and the propagation of change.” (参考訳)「コンピューター処理において、リアクティ ブプログラミングは、データストリームとその変更内容 の伝搬を意識した非同期プログラミング方法論の一つで ある。」 出典:Wikipedia - https://en.wikipedia.org/wiki/Reactive_programming
  • 6. ストリートファイターとは?  1987 年よりカプコン社からリリースされている一連の対戦型格闘ゲーム シリーズ  1991 年リリースの二作目、ストリート ファイター II が爆発的ヒット、各種ビデオ ゲームプラットフォームにも次々と移植 される(任天堂スーパーファミコンとか) – 一作目は、大人の事情でファイティング・ ストリートと名前を変えて PC-エンジン CD-ROM2 に移植されていたりしますが… 6
  • 7. 昇龍拳とは?  ストリートファイターシリーズのプレイ可能なキャラクターである、リュウ並 びにケンの必殺技の一つ。  ゲーム中では、以下の操作を素早く行うことにより昇龍拳を繰り出すことがで きる。対戦相手にヒットすると、比較的大ダメージを与えることができる。  大ジャンプキックからの、アッパーカットからの昇龍拳といったいわゆるキャ ンセル技を組み合わせることで対戦をかなり有利に進められる。 7 キャラクターの向いている方向 P+ レバー(パッド)の方向操作 最後にパンチボタン同時押し
  • 9. 前提とか準備とか(1/3)  一応、僕は Java ラーなので、JavaFX で作ります。UI は こんな感じで。 – PC のキーボードからのコマンド入力前提。 – レバーの斜めは方向キー同時押しで対応。 – キーを押すと、UI 上のキー画像が押されたようなアニメーションを する(ちょっと緑色っぽくなる)。 – 昇龍拳コマンド入力等成功すると、リュウのそれに応じたアニメー ションが見られるだけのアプリケーション。 – 方向キー↑は “W” キー、←は “A” キー、→ は “S” キー、↓は “Z”、パ ンチキーは “X” キー、キックキーは “C” とする。  ついでに、波動拳、竜巻旋風脚や、(必殺技でないけ ど)中パンチと大キックも実装。  どうでもいいけど、BGM とか効果音もつけてみる。 9 方向キー キックキー リュウさん (本人) パンチキー
  • 10. 前提とか準備とか(2/3)  必殺技コマンド入力の実装アイディア – javafx.scene.Scene のインスタンスにキーイベントを取得するため以下のリスナーを 付与 ▪ キーを押したイベントを取得: Scene#setOnKeyPressed ▪ キーを離したイベントを取得: Scene#setOnKeyReleased – 取得したキーイベントをバッファしておく。 – 必殺技は最終的にパンチキーかキックキーを押すことで繰り出されるので、当該 キーが押された際にあらかじめバッファしておいたキー入力が各必殺技のコマンド 入力に合致しているか判断して、合致していたら対応する必殺技を繰り出す。 – バッファされたキー入力はアルファベット文字列に変換され、各必殺技に相当する 文字列と比較して入力判定する。キーを押した場合は大文字、キーを離した場合は 小文字とする。例えば昇龍拳と判断されるキー入力文字列は以下(キーを離したと いうイベントも意識する)。 ▪ “SsZzZSX” か “SsZzSZX” 10
  • 11. 前提とか準備とか(3/3)  リアクティブライブラリーとして、Reactor を使います。 Java だし。最新の v3.1.x 系を使用します (2018 年 4 月現在)。  ところで…、Reactor?原子炉? 11
  • 12. Reactor とは?  Pivotal 社主導で Project Reactor というオープンソースプロジェクトの下で開発 されている、Reactive Streams 仕様に沿った、JVM 上でノンブロッキングなアプ リケーションを開発するリアクティブライブラリー。 – https://projectreactor.io/  バージョンアップするたびに、API がかなり変遷してますが、現在(2018 年 4 月 現在)はコアライブラリーとして、Flux と Mono という Reactive Extensions の実 装が提供されています。  Spring Framework 5 のリアクティブプログラミング向けフレームワーク(Spring WebFlux とか)の実装として Reactor が使われています。  project riff の Java Invoker に Reactor core が含まれているので、サーバーレスな FaaS 環境でリアクティブに関数実行可能です。 – https://projectriff.io/invokers/java/ 12
  • 14. 【どうでも】キーイベント取得動作で分かったこと【イイネ!】  いきなり本筋からそれますが…、昇龍拳って、最後にレバー斜め下 + パンチボタンという 同時押しするんで、今回の想定では [→] + [↓] + [P] と、3 キー同時押しになるんですね。  普通の PC に付属しているキーボードって、ほとんど「2 キーロールオーバー 」というス ペックで、特殊キーを除いて 2 キーまでしか同時押し認識しないんですね。  私の PC も例外なく 2 キーロールオーバーだったんで、当初の仕様上、3 キー同時押しを要 求する昇龍拳はだせないんですよね(厳密にいうと、キーのアニメーションがうまく同時 押しを表現できないだけで、マイロジックでは昇龍拳はでるんですけどね)。  なので、デモアプリを動かすには「N キーロール オーバー」といったスペックのちょっといい外付け キーボードを使いましょう。ちなみに僕は、HHKB Professional BT(無刻印変態仕様)を使っています。 – それでも、PS/2 接続じゃない最近のやつは 6 キーまでしか同時 押し認識しないんですけどね。ま、それで十分ですが。 14
  • 16. ノンリアクティブな昇龍拳ロジック 16 mainScene.setOnKeyPressed(new EventHandler<KeyEvent>() { // キー押下時に反応するリスナー付与 public void handle(KeyEvent event) { String keyEvent = event.getCode().toString(); // キーイベントを文字列に変換 if (keyActionChecker(keyEvent)) { // 方向キーかパンチ・キックキーが押された場合のみ以下実行 commandList.add(keyEvent); // 入力キーバッファ commandList にキー文字列追加 if (keyEvent.equals(PUNCH) || keyEvent.equals(KICK)) { // パンチ・キックキーが押されたら必殺技判定 String cl = readCommand(); // 入力キーバッファの内容を文字列 cl に変換します if (cl.contains(SYORYU_CL[0])…) { // cl に昇龍拳コマンドが含まれているか? startAction(3, 17, “shouryuuken.mp3”); // 昇龍拳を繰り出す } else if (cl.contains(HADOU_CL[0])...) { // cl に波動拳コマンドが含まれているか? startAction(4, 14, “hadouken.mp3”); // 波動拳を繰り出す } else if (cl.contains(TATSUMAKI_CL[0])…) { // cl に竜巻旋風脚コマンドが含まれているか? startAction(5, 27, “tatsumaki_senpukyaku.mp3”); // 竜巻旋風脚を繰り出す } else if (cl.contains(PUNCH)) { // cl にパンチキーイベントが含まれているか? startAction(1, 8, “punch.mp3”); // 中パンチを繰り出す } else { startAction(2, 15, “kick.mp3”); // 上述のどれにも該当しなかったら、大キックを繰り出す } } } } }); mainScene.setOnKeyReleased(new EventHandler<KeyEvent>() { // キー離した時に反応するリスナー付与 public void handle(KeyEvent event) { String keyEvent = event.getCode().toString(); // キーイベントを文字列に変換 if (keyActionChecker(keyEvent)) { // 方向キーかパンチ・キックキーが離された場合のみ以下実行 commandList.add(keyEvent.toLowerCase()); // commandList にキー文字列を小文字にして追加 } } }); 入力キーバッファは、異なるリス ナーインスタンス(キーを押した 場合と話した場合)にまたがって 使用されるので、static な List 型 の変数として定義してあります。 キー押したり離したりするリス ナーのロジックの記述は、Java 8 以降だとラムダ式使ってもいいん ですが、ここでは使ってません。 思ったよりも、シンプルでしたが 必殺技判定ロジックの if 文ネスト の闇がやや深いのと、リスナーの 都合でバッファを共有変数として 持っているのがキモイです。
  • 18. リアクティブな昇龍拳ロジック 18 Flux.create(sink -> { // 複数のデータストリームを扱う Flux を採用。FluxSink でデータをバッファに入れます mainScene.setOnKeyPressed(keyEvent -> { // キー押下時に反応するリスナーの付与 String pressedKey = keyEvent.getCode().toString(); // キーイベントを文字列に変換 sink.next(pressedKey); // 文字列をバッファに追加 }); mainScene.setOnKeyReleased(keyEvent -> { // キーを離した時に反応するリスナーの付与 String releasedKey = keyEvent.getCode().toString(); // キーイベントを文字列に変換 sink.next(releasedKey.toLowerCase()); // 文字列をバッファに追加(離した時なので小文字に変換) }); }).filter(keyEvent -> { // 方向キーかパンチ・キックキーが押された場合のみ、バッファに追加 String key = ((String) keyEvent).toUpperCase(); return key.equals(UP) || … || key.equals(KICK); }).bufferUntil(keyEvent -> { // パンチ・キックキーが押下されるまでデータストリームをバッファする return ((String) keyEvent).equals(PUNCH) || …); }).subscribe(commandList -> { // パンチキーかキックキーが押下されたら、必殺技判定ロジック実行 String[] cl = {""}; commandList.forEach(keyEvent -> cl[0] += (String) keyEvent); //入力キーバッファ内容を文字列 cl[0] に変換 if (cl[0].contains(SYORYU_CL[0]) || …) { // cl[0] に昇龍拳コマンドが含まれているか? startAction(3, 17, “shouryuuken.mp3”); // 昇龍拳を繰り出す } else if (cl[0].contains(HADOU_CL[0]) || …) { // cl[0] に波動拳コマンドが含まれているか? startAction(4, 14, “hadouken.mp3”); // 波動拳を繰り出す } else if (cl[0].contains(TATSUMAKI_CL[0]) ||…) { // cl[0] に竜巻旋風脚コマンドが含まれているか? startAction(5, 27, “tatsumaki_senpukyaku.mp3”); // 竜巻旋風脚を繰り出す } else if (cl[0].contains(PUNCH)){ // cl[0] にパンチキーイベントが含まれているか? startAction(1, 8, “punch.mp3”); // 中パンチを繰り出す } else { startAction(2, 15, “kick.mp3”); //上述のどれにも該当しなかったら、大キックを繰り出す } }); Reactive Extensions 準拠(?) の API で各ロジックを Composable にすっきり記述でき てうれしいですね! ノンリアクティブ版ではバラバラ だったストリームデータをバッ ファにいれるロジックも、まとめ て記述できて、バッファ用の共有 変数も特に用意しなくて良いです。 関数を Composable に記述するだ けで Observable に動きます。 ラムダ式やメソッド参照(ここで は使ってないですが)、Streams など積極的に使って、リアクティ ブストリーマーを目指しましょう (謎)。
  • 19. 19 ということで、Reactor を使って リアクティブに昇龍拳を繰り出 してみました! 個人的には、Reactor の他 JavaFX やラムダ式、メソッド参 照、Streams といった Java 技術 の勉強になりましたー。
  • 23. リアクティブ界隈用語の僕的理解(1/3)  「リアクティブプログラミング」のそれは、冒頭に紹介したので、それ 以外のよくでてくる用語の僕的理解を列挙  Reactive Streams – リアクティブ宣言を読もう! ▪ https://www.reactivemanifesto.org/ja – ざっくり言うと、「ノンブロッキングなバックプレッシャーを持つ非同期 ストリーム処理の標準」で、各キーフレーズの僕的理解が以下… ▪ ノンブロッキング:メッセージ受信側における処理の進捗にかかわらず、メッセージ送信 側にはすぐに何らかの応答(失敗、処理中、完了等)が返却される。 ▪ バックプレッシャー:メッセージ受信側の処理が追いつかないほど、送信側からメッセー ジが送られるような過負荷状態を防ぐため、メッセージ受信側が送信側に対してメッセー ジ送信量を調整するようお願いする仕組み的な。
  • 24. リアクティブ界隈用語の僕的理解(2/3)  Reactive Extensions – Microsoft が最初に提唱した模様 ▪ https://msdn.microsoft.com/en-us/library/hh242985(v=vs.103).aspx – Observable な処理手順で LINQ スタイルのクエリーオペレーターを使った非同期でイ ベント駆動なプログラムを作成するライブラリー。はて…? ▪ Observable な処理手順:言い換えれば、Pub-Sub の仕組み。メッセージ送信側(Publisher)と受信側 (Subscriber)がいて、送信側から送られてきたメッセージを受信側がうけとってそれに伴う何らかの処理 を行うという形態かと。 ▪ LINQ スタイルのクエリーオペレーター:クエリー対象データに対して、ドット演算子で次々と連鎖的につ なげてクエリーできるやつ。さきほどの、Reactor を使ったサンプルコードの、create とか、filter とか、そ ういった感じの。LINQ は Microsoft が提供しているものの固有名詞。 – Microsoft からは Rx.Net という名前でモノがでている。まー、要するにリアクティブ プログラミングを行うライブラリー。 – Reactor は Reactive Extensions の一実装を提供しているといえる。
  • 25. リアクティブ界隈用語の僕的理解(3/3)  Reactive Streams と Reactive Extensions の関係性 – 最初は、Reactive Extensions という観点で Microsoft から実装も含めて、.Net な世界 でリアクティブプログラミングを行うライブラリーとしてでてきたようだ。 – その後、他言語にも似たようなライブラリーがでてきたけど、リアクティブプロラ ミングの解釈がバラバラで、API もバラバラなんで、標準的な要件とか仕様(ノンブ ロッキングなバックプレッシャーの仕組みが必要!とか)があったらイイネ!とい うことで、Reactive Streams というイニシアティブが発足、仕様とか API ができたよ うだ。 – Reactive Streams の仕様とか API ができた後は、Reactive Extensions はそれらをプロ グラミングしやすいような便利ライブラリーっぽい位置づけになったように見える (事実、Reactor も途中から API ががらりと変わった)。 – 個人の印象です。印象操作ではないです。
  • 26. 26 ということは、僕のこれまでの 昇龍拳アプリは、Reactor の Reactive Extensions API を使っ てプログラミングしたけど、特 に非同期である必要性はないが Reactive Streams に準拠した Reactor 実装にそって動かしてみ たレベル、ということですか ねー。ぐはー。
  • 28. ノンブロッキングな昇龍拳ロジック 28 Flux.create(sink -> { // 複数のデータストリームを扱う Flux を採用。FluxSink でデータをバッファに入れます mainScene.setOnKeyPressed(keyEvent -> { // キー押下時に反応するリスナーの付与 String pressedKey = keyEvent.getCode().toString(); // キーイベントを文字列に変換 sink.next(pressedKey); // 文字列をバッファに追加 }); mainScene.setOnKeyReleased(keyEvent -> { // キーを離した時に反応するリスナーの付与 String releasedKey = keyEvent.getCode().toString(); // キーイベントを文字列に変換 sink.next(releasedKey.toLowerCase()); // 文字列をバッファに追加(離した時なので小文字に変換) }); }).filter(keyEvent -> { // 方向キーかパンチ・キックキーが押された場合のみ、バッファに追加 String key = ((String) keyEvent).toUpperCase(); return key.equals(UP) || … || key.equals(KICK); }).bufferUntil(keyEvent -> { // パンチ・キックキーが押下されるまでデータストリームをバッファする return ((String) keyEvent).equals(PUNCH) || …); }).publishOn(Schedulers.elastic()) .subscribe(commandList -> { // パンチキーかキックキーが押下されたら、必殺技判定ロジック実行 /* 以下、略 */ ); 先のコードに、これをくっつけた だけ。API docs 的には、 subscribeOn の方がそれっぽいけ ど、動作確認したら publishOn の 方が quitada の思うところのノン ブロッキング的な動き (Flux.subscribe 内ロジックと FluxSink によるストリームデータ のバッファリングが非同期に行わ れる、というかストリームデータ が consume されたら、subscribe 内のロジックが別スレッドでトリ ガーされて、データストリームの バッファリング処理は継続しつつ 非同期で subscribe 内ロジックを 実行する)でした。
  • 29. バックプレシャー付き昇龍拳ロジック 29 Flux flux = Flux.create(sink -> { // FluxSink でデータをバッファに入れます mainScene.setOnKeyPressed(keyEvent -> { // キー押下時に反応するリスナーの付与(以下、同じなので略) : }).publishOn(Schedulers.elastic()); // 先に言及したノンブロッキング的な動作をするためのスケジューラー付与 BaseSubscriber<ArrayList<String>> subscriber = new BaseSubscriber<ArrayList<String>>() { // バックプレッシャー実装のため、BaseSubscriber を使用 private int onNextAmount = 0; // 受信したデータの個数カウンター @Override protected void hookOnSubscribe(Subscription subscription) { request(2); // サブスクライブ初回にデータストリームより、2 個のデータをリクエスト } @Override protected void hookOnError(Throwable throwable) { throwable.printStackTrace(); // とりあえず、なんかエラーハンドリング } @Override protected void hookOnComplete() { } @Override protected void hookOnNext(ArrayList<String> commandList) { // パンチキーかキックキーが押下されたら、必殺技判定ロジック実行(同じなので中身省略) : // 2 個のデータを消費するたびに、2 個のデータをリクエスト onNextAmount++; if (onNextAmount % 2 == 0) { request(2); } } }; flux.subscribe(subscriber); // サブスクライブ! ドキュメントに、Subscriber を実 装するため、BaseSubscriber を 使用する例があったので、そのま ま拝借。Composable に記述しよ うとしたら、IDE に怒られまくっ たので、仕方なく切り出してます。 どういう条件で、データストリー ムからデータリクエストするかは 自分でロジックを考える必要があ ります。ここでは、データ 2 個消 費して 2 個リクエストするだけの 単純な実装です。当然、リクエス トしないと、消費されません。