$30 off During Our Annual Pro Sale. View Details »

【20220920UV Study : フロントエンドLT会#7】WebAssemblyでブロック崩しを作ってみた話

【20220920UV Study : フロントエンドLT会#7】WebAssemblyでブロック崩しを作ってみた話

UV Study : フロントエンドLT会#7での発表資料です
https://uniquevision.connpass.com/event/257455/

虎の穴ラボ株式会社

September 21, 2022
Tweet

More Decks by 虎の穴ラボ株式会社

Other Decks in Technology

Transcript

  1. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
    WebAssemblyでWebブロック崩
    し作ってみた
    1

    View Slide

  2. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
    アジェンダ
    ● 自己紹介
    ● 動機と話すこと
    ● なぜRust
    ● 作ったもの
    ● Rust
    ● wasm-bindgen
    ● まとめ
    2

    View Slide

  3. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
    自己紹介
    3
    藤原 佳顕(ふじわら よしあき)
    ‣ 虎の穴ラボ
    ‣ Webエンジニア
    ‣ 新規事業担当(Fantia、Creatia)、アーキテクトチーム
    ‣ 前職:独立系ソフトウェア会社、主に
    GISとWeb、ライブラリ開発
    ‣ TypeScript、C#、Ruby on Rails、C++
    ‣ React、Vue、Angular

    入社理由
    ‣ 自分がスキルアップできそうな場所に行きたい
    ‣ オタク系の話ができるところに行きたい
    好きなモノ
    ‣ シューティングゲーム、格闘ゲーム
    ‣ SF小説
    ‣ プログラミング
    自己紹介ページ(藤原)

    View Slide

  4. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
    動機と話すこと
    ● Rust+WebAssemblyでブロック崩し作ってみたので紹介
    ● 話すこと
    ○ Rustの概要
    ○ wasm-bindgenについて
    ○ 書いたソース
    ● 話さないこと
    ○ WebWorkerについて
    ○ JavaScript/TypeScript側の細かいあれこれ
    ○ Rustの細かい文法
    ○ ビルドツールについて
    4

    View Slide

  5. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
    なぜRust
    ● Rust使いたかった(趣味)
    ● 自分→フロントエンド得意ななんでも屋
    ○ React.js、TypeScriptとか好きです
    ● 得意分野を消さないための種まきとして
    WebAssembly
    ● Rustは公式でWebAssemblyのサポートがある
    ○ wasm32-unknown-unknownターゲット
    ● C/C++→Emscripten
    ● Go→バイナリでかい問題
    ● 他
    ○ Blazor、AssemblyScript
    5

    View Slide

  6. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
    作ったもの
    ・MDNのCanvasブロック崩しのRust移植+α (https://yumenosora.co.jp/archives/tora-lab/1575)
    6

    View Slide

  7. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
    作ったもの
    採用サイトからも飛べます (https://yumenosora.co.jp/archives/tora-lab/1575)
    7

    View Slide

  8. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
    Rust
    ● C++の代替を狙う低レイヤ言語
    ● 速度
    ○ (LLVMなので)C/C++と同程度
    ● パラダイム
    ○ マルチパラダイム
    ○ 関数型言語っぽくもオブジェクト指向っぽくも書ける
    ● 難しい?
    ○ コンパイラが優秀なので適当に怒られておけば良いと思います
    ● 言語が出てきた当初からWebAssemblyのサポートを謳っている
    ● WebAssemblyまつわる周辺ツール: wasm-bindgen
    8

    View Slide

  9. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
    wasm-bindgen
    ● wasm-bindgen
    ○ 要するにRust↔JSをやってくれるクレート(ライブラリ)
    ○ Mozilla肝いり
    ● web_sys
    ○ browser APIとのつなぎ込み(DOM含む)
    ● js_sys
    ○ JSとのつなぎ込み
    9

    View Slide

  10. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
    中身(wasm-bindgen)
    10
    #[wasm_bindgen]
    #[derive(Debug, Clone, Copy, Serialize)]
    pub struct Brick {
    x: f64,
    y: f64,
    status: BrickStatus,
    life: u32
    }
    #[wasm_bindgen]
    impl Brick {
    pub fn new(x: f64, y: f64, status: BrickStatus) -> Brick {
    Brick {
    x: x,
    y: y,
    status: status,
    life: 1
    }
    }
    }
    ● wasm_bindgen attributeが付いている部
    分がJS側にエクスポートされる
    ● メソッドも同様にエクスポートできる
    import { Brick } from "mdn-breaking-blocks-wasm";
    const brick = Brick.new(1, 1, 0);
    (Rust側)
    (JavaScript側)

    View Slide

  11. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
    中身(web_sys)
    11
    Web APIのインターフェース定義であるWebIDLままのI/Fが用意されている
    // windowがそもそも存在しない場合は unwrapでpanic
    let _ = web_sys::window().unwrap()
    .alert_with_message("YOU WIN, CONGRATULATIONS!");
    let _ = web_sys::window().unwrap().location().reload();
    // dyn_intoでキャスト→キャスト失敗したら map_errでエラー処理
    let canvas: web_sys::HtmlCanvasElement = canvas
    .dyn_into::()
    .map_err(|_| console::log_1(&JsValue::from_str("CanvasElement is invalid")))
    .unwrap();
    let context = canvas.get_context("2d")
    .unwrap().unwrap()
    .dyn_into::()
    .unwrap();

    View Slide

  12. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
    中身(js_sys)
    12
    JavaScript APIのRustラッパーになる→世界が違うのでうまいこと動くようにされている
    // JavaScript側からコールバックを引数として受け取る
    pub fn draw_with_callback(&mut self, callback: &js_sys::Function) {
    for c in 0..self.bricks.len() {
    for r in 0..self.bricks[c].len() {
    if self.bricks[c][r].get_status() == BrickStatus::Live {
    let brick_x = c as f64 * (BRICK_WIDTH + BRICK_PADDING) + BRICK_OFFSET_LEFT;
    let brick_y = r as f64 * (BRICK_HEIGHT + BRICK_PADDING) + BRICK_OFFSET_TOP;
    self.bricks[c][r].set_x(brick_x);
    self.bricks[c][r].set_y(brick_y);
    let this = JsValue::NULL;
    // JavaScriptと違ってRustではコンパイル時に引数の数と型がわかっている必要がある
    // したがってJSの関数をそのまま呼べない
    (最悪applyを使う)
    let _ = callback.call2(&this, &JsValue::from(brick_x), &JsValue::from(brick_y));
    }
    }
    }
    }

    View Slide

  13. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
    まとめ
    13
    ● wasm-bindgenを使うことで本来は難しい WebAssemblyとJavaScriptの相互運用を行うことができます
    ● Rustは難しいと言われていますが、基本知識 +コンパイラに従うことで書けるようになるきがします
    ● 実は、もう1パターンの実装があります
    ○ 表のレンダリングやゲーム部分 →WebAssembly
    ○ 入れ替わる画像レイヤ部分 →WebWorker
    ○ こちらも機会があれば喋ってみたいと思います
    ● 今日の内容に近い内容はブログにも上げているのでぜひお読みください
    (http://toranoana-lab.hatenablog.com/entry/2019/08/14/190159 )

    View Slide

  14. Copyright (C) 2021 Toranoana Inc. All Rights Reserved.
    まとめ
    14

    View Slide