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

ゲームを0.5から作ってわかったこと(@KMC春合宿2019)

896e100913296f0473fd2de4a91cafcc?s=47 ikubaku
March 15, 2019

 ゲームを0.5から作ってわかったこと(@KMC春合宿2019)

ゲームの構造をほぼ無から作って学んだ話など

896e100913296f0473fd2de4a91cafcc?s=128

ikubaku

March 15, 2019
Tweet

Transcript

  1. ゲームを 0.5 から作って知ったこと +ブラウザでもラピゲしたい KMC2 回 polaris aka. ikubaku

  2. 2 自己紹介 KMC ID: polaris - またの名を ikubaku - 主にプログラムを書く人

    - ハードウェアもやる - beckey3 を開発中
  3. 3 自己紹介 - Twitter: @ikubaku10 - GitHub: @ikubaku - Web:

    ikbk.net - Mail: hide4d51@gmail.com
  4. 4 近況

  5. 5 近況

  6. 6 近況

  7. 7 細かい近況 - emacs から Unity の入力補完を使ってみた(誰得?) - 緑コーダーに昇進( AtCoder

  8. 8 今日の流れ - 0.5 からゲームを作る - 作って知ったゲームの仕組み - - ゲームフレーム

    - - 当たり判定 - - 幾何と物理現象 - - 入力仮想化 - 去年のラピゲの反省点 - 技術的な視点から - 改良したキットについて
  9. 9 なぜこの話を?( 1 )

  10. 10 なぜこの話を?( 2 )

  11. 11 なぜこの話を?( 2 ) 主にやってたこと - MS Office VBA (だいいっぽ)

    - Windows Form Application (ブラウザをかいた) - ゲーム(開発支援ソフト使用から DirectX 使用までいろいろ) - 組み込み(ちょっとロボカップをやってた、 Arduino とか) - OS (ほんと???) - GPGPU (ほんと???) (アプリ開発、 Web アプリ、 AI についてはほぼ無なので、 やっていきたい)
  12. 12 なぜこの話を?( 2 ) ゲーム開発と OS 周辺で、(特に)様々な学びがあった → どうせなのでゲーム開発の方を講座としてやることにした

  13. 13 なぜこの話を?( 3 ) ラピッドコーディング祭り - 最初はこの話題をするつもりだった - これだけでは少ないのでいろいろ話します

  14. 14 0.5 からゲームを作る - ゲーム開発支援ツール ( Unity Editor, RPG ツクール)を

    使わないゲーム開発、ということにする - ゲームエンジン(の一部)を自分で定義することが多い
  15. 15 変わること - 様々な恩恵がない - 開発支援ツールの使い方は知らなくていける → 自分でエディタを書く文明もある → エディタだけ借りる文明もある(

    Tiled など) 実は学習も兼ねてやる場合は便利だったり( n=1 ) polaris も何度かゲームエンジンの実装を試みてきた
  16. 16 使ってみたもの - DirectX - DX ライブラリ - pygame -

    SDL - Processing → 画像の描画、音の再生、入力装置の状態取得だけ代行して くれる
  17. 17 作って知ったゲームの仕組み - ゲームフレーム - 当たり判定 - 幾何と物理学 - 入力仮想化

  18. 18 ゲームフレーム - 連続的に映像を生成することで動きを見せているものが多い → 動画のように一定間隔で「コマ」を見せる - 自発的に処理を行う - ゲーム全体の流れの実装は無限ループに近くなることが多い

    def main { init(); while(true) { update(); draw(); } exit(0); }
  19. 19 フレームレートと処理落ち - 一定のペースで画面を描画し直したい → 少し待って処理・描画を繰り返す - 以下は WA が生える疑似コード

    const int FPS = 60; def main { init(); while(true) { update(); draw(); wait_ms(1000 / FPS); } return 0; }
  20. 20 なんで? - 処理や描画は無視できる時間で終わらないかもしれない → フレーム時間が変動してしまう! (あえて変動する実装もあります。多分。)

  21. 21 よりよい方法 準備 : 1 フレームにちょうどかけたい時間を f とする 1. 現在時刻

    t を取得する 2. 処理と描画を行う 3. 現在時刻 s を取得する 4. 2 にかかった時間 d = s - t を計算する 5. d > f ならば 1 に戻る(処理落ち) 6. 時間 f – (s – t) だけ待つ 7. 1 に戻る
  22. 22 何が解決できたか? - 処理描画時間が必ずフレーム時間の目標値以内に終わるならば 理想的な動作をする → (条件があるが)フレーム時間を安定させることができた 処理・描画に時間がかかることも考慮に入れるならどうするか?

  23. 23 deltaTime の謎 - 時間がかかることはどうすることもできない - 1 フレームにかかっている時間を直前のフレームなどから得て、 状態をどれだけ変えればよいか決定する →

    目標フレーム時間で実行できるときと結果が同じように見える ( Unity にある deltaTime はこれ) // 加算される値が単位時間あたりのフレーム数に依存する Character.position += 3.0f * dirVector * frameTime; // 最後のフレーム時間に依存する Character.position += 3.0f * dirVector * deltaTime;
  24. 24 当たり判定 - ゲームには欠かせない存在 - 当たり判定を取りたい形にはいろいろある - - その形の組によってアルゴリズムを考える必要がある ここでは

    ... - 点 - 矩形 - 円 の任意の組での当たり判定についてやります (ほかは知らない ... )
  25. 25 「当たっている」とは? 2 つのものが触れ合っている、あるいは重なっている つまり、 2 つの領域が共有するような領域が存在する → これと同値である条件を考えれば良い (ゲーム内のものの外形そのものを領域として用いないほう

    が適切なことがある)
  26. 26 点 vs 点 - p1 == p2 - 自明な例

    - ほぼ使わない
  27. 27 点 vs 円 - 距離を測る ex) 点の座標を p 、円の中心座標を

    c 、円の半径を r として、次の条件 を満たす dist(p, c) <= r
  28. 28 円 vs 円 - 距離を測る(いっしょやんけ!) ex) 円 i(i=0,1) の中心座標を

    c[i] 、円の半径を r[i] として、次の 条件を満たす dist(c[0], c[1]) <= r[0] + r[1] えっ、高校で習った?
  29. 29 矩形 vs 点 - 辺が属する直線で挟み込む ex) 矩形の左上の座標を r0 、右下の座標を

    r1 、点の座標を p とした とき次の条件を満たす( 2 次元、 x 軸方向は右、 y 軸方向は下) r0.x <= p.x <= r1.x かつ r0.y <= p.y <= r1.y
  30. 30 矩形 vs 矩形 - 円 vs 円に近いアプローチで考える ex) 矩形

    i(i=0,1) の中心座標(各辺の垂直二等分線の交点の座標) を c[i] 、幅、高さをそれぞれ w[i] 、 h[i] とするとき、次の条 件を満たす dist(c[0].x, c[1].x) <= w[i] // 側面のめり込み かつ dist(c[0].y, c[1].y) <= h[i] // 上面仮面のめり 込み
  31. 31 矩形 vs 円 - むずい ex) 矩形の中心座標を c 、幅、高さをそれぞれ

    w 、 h 、円の中心座標を d 、半径を r として (I) c-w <= d.x <= c+r なら C-h-r <= d.y <= c+h+r (II) c-h <= d.y <= c+h C-w-r <= d.x <= c+w+r (III) それ以外 矩形の 4 頂点について点 vs 円
  32. 32 幾何 - 角度からその向きのベクトルを作る - 向きのベクトルから角度を得る 円形扇形軌跡の移動、向きや 2 つの位置ベクトルがなす角を 求めたいときに便利

  33. 33 角度からその向きのベクトルを得る - 極座標を使う ex) 角度を θ として Vector b

    = new Vector(cos(θ), sin(θ))
  34. 34 向きのベクトルから角度を得る - 逆正接関数( Tan-1 )をつかう - x == 0

    のときに場合分けする - y の正負で絶対値が大きな角度について判定する (場合分けをまとめた手続きが実装されている場合もある。 atan2 など)
  35. 35 向きのベクトルから角度を得る ex) 向きを表すベクトルを d として、 x 軸に対して時計回りにな す角は次のように求まる -Tan-1(d.y

    / d.x) (d.x > 0) π/2 (d.x == 0 && d.y < 0) -π/2 (d.x == 0 && d.y > 0) Tan-1(d.y / d.x) (d.x < 0)
  36. 36 物理現象 - 使いたいときに使います。たぶん。 - 実はそんなに実装が重くないこともある(当社調べ) - やりたいことによっては運動方程式のとおりに動かさなく ていいこともあるので注意 -

    モデル化大事
  37. 37 運動方程式でモデル化した座標計算 パラメータ : v: 速度(ベクトル) p: 位置(ベクトル) m: 質量(実数)

    計算式 : p.x <= p.x + v.x * deltaTime p.y <= p.y + v.y * deltaTime
  38. 38 力を加える 位置を計算する前に次のように速度を更新する 加える力を f として v.x = v.x +

    f.x/m * deltaTime v.y = v.y + f.y/m * deltaTime 重力も同様
  39. 39 より簡単なモデル化 - 単振動 振幅を A 、周期を T として、 x

    軸に関して単振動するには p.x = Asin(2π * t/T) x 軸について時計回りに θ 傾けると p.x = Acos(θ)sin(2π * t/T) p.y = -Asin(θ)sin(2π * t/T)
  40. 40 パラメータを直接触るとどうなるか - 位置 1 フレームで場所が変わるが、以降のフレームではパラメータ に影響を与えない → テレポートしたようになる -

    速度 そのフレームで力を加える以外の要因として力積を加えてい ることになる
  41. 41 入力の仮想化 入力を仮想的なジョイスティックやボタンに置き換える - (ユーザが)入力のキーアサインを変えたいことがある - 様々な仕様のゲームパッドがある - そもそも仮想コントローラをつけたい場合もある →

    このあたりを吸収する部分とゲーム本体を分離する - 受け方にも気をつけることがある
  42. 42 アナログ入力の処理 - 不感領域を決めると良い(微小な入力も取ってしまうと、 コントローラの性質などによっては予期しない入力が入って しまう) - 生データを積分してなめらかにすると良い(高周波成分い らないでしょ?いらないよね ...

    ??) ← ポテンショメータ などが入っている
  43. 43 Down か Pressed か (I) キーが押されている || 離されていることを調べる場合 キーの現在の状態を取得すれば良い

    (II) キーが押された瞬間 || 話された瞬間を得る場合 直前の状態と現在の状態を比較すれば良い
  44. 44 「現在」はいつなのか 入力の状態は処理を行っている最中に変わってしまうかもしれない - 同フレーム内で入力状態の不整合が生じる → 処理を開始する前に入力状態をすべて決定する必要がある def main {

    init(); while(true) { update_input_state(); // ココ ! update(); draw(); vsync(); } exit(0); }
  45. 45 高速な入力への対応 先程の実装では単位時間あたりのフレーム数の半分だけしか入力の 変化を認識できない 回避策 : 処理と描画の間にほかのスレッドで入力を監視し、変化していれば 次のフレームでイベントを起こす 時刻 入力確認

    入力状態
  46. 46 フレームと非同期に入力を受ける - 先程のように極端な入力を得たいときに便利 - 処理時間中に入力を直接取得する際と同じように、フレー ム中での情報の一貫性や、平行処理における安全性に気をつ ける必要がある ( Processing

    はこれだったので危なかった ... )
  47. 47 入力軸仮想化 - 入力源(ジョイスティック、ボタン)をすべて仮想の 「軸」に置き換えて入力状態を取得するようにする - 仮想軸のゲーム側へのインタフェースは入力源と独立して いる → 入力源を比較的簡単に置き換えることができる

    キーコンフィグや仮想コントローラを使っての入力の実装が 簡単になる
  48. 48 質問タイム

  49. 49 変わること(再掲) - 様々な恩恵がない - 開発支援ツールの使い方は知らなくていける → 自分でエディタを書く文明もある → エディタだけ借りる文明もある(

    Tiled など) 実は学習も兼ねてやる場合は便利だったり( n=1 ) polaris も何度かゲームエンジンの実装を試みて きた
  50. 50 何の成果も !! 得られませんでした !! - 基礎的な機能を設計、実装するだけでたいてい飽きてしまう - バグる -

    重い - 私は実装ゴリラではない - 終了
  51. 51 わかったこと - 全く実用的なものにならなくても、実装することでわかっ てくることがある( OS 自作入門と同じような感じ) - ゲームエンジンを開発するのは極めて難しいミッションの 一つ

    - ここまでやれるんだったら既存のエンジンを改造していき ましょう(真理ではなく私の見解ですが) → 最近のゲーム開発環境は拡張が充実していることが多い (当社比) - 良い子は polaris の真似をしないように
  52. 52 ラピッドコーディング祭り - KMC の新歓期イベントの一つ - 見学者と部員でチームを組み、 6 時間でゲームを作る大炎 上ハッカソン

    とても楽しいイベント - 去年私が担当させていただきました(会場で死んだように 眠っていた人です(は?))
  53. 53 ラピゲの裏側 - 開発キットを毎年用意している - 特に何も導入しなくても動かせるやつが良い - 例年 ruby-sdl2 を利用している

    - Windows と Mac OS X で動いていた - 便利 しかし 2018 年度はそうは行かず ...
  54. 54 事件 https://qiita.com/junkoda/items/78c726b06afe2a9d3930

  55. 55 事件 要は許可されたディレクトリ以外から共有ライブラリをロー ドできなくなった ところが ruby-sdl2 を環境構築無しで使うには ruby のスタンドアロン バイナリがいる

    → こいつはユーザのディレクトリからライブラリを読み込む → 詰んだ ナムサン Apple ゆるすまじ
  56. 56 Processing

  57. 57 Processing - デジタルアート制作などを目的とした、グラフィックス処 理機能付きの開発環境 - Java を使っている - なんとエディタも処理系もデバッガも全部入り

    - Windows 、 macOS 、 Linux に対応 - polaris は結構触ったことがある - 勝利
  58. 58 rapid2018 描画関係と、入力関係のところだけいい感じにラップしたコ ードを書いて、キットを作った 概ね成功

  59. 59 反省点 - ドキュメンテーションが貧弱だった → 公式リファレンスは英語、自作したコードの説明はコメントし かなかった - 引数がすごくたくさんある関数があってむずかった →

    カンマとピリオドを間違えて意味不明なエラーが出るなど → まあ、エディタも悪い - 作ったもののアップロードで少し混乱があった → どこをコピーしたら他の環境でも動くのか?
  60. 60 解決策とか - ドキュメント自動生成(ほんと?) - Prosessing 本もっと導入する - ライブラリ関数の引数をできるだけ短くする -

    やっぱりいい感じのエディタから使えるようにする - 提出や他の環境への移植を簡単にする(パッケージ化と か) - ブラウザで動かせると実はは偉い?
  61. 61 p5.js - Processing API の JavaScript での実装 - ブラウザで動かすことができる

    - 天才 (実は Processing のコードもブラウザで実行することがかつては できたのだが、必要なプログラムがもうメンテナンスされてないの で事実上不可能になってしまっている)
  62. 62 rapidv4 polaris の妄想の残骸がこちらになります https://github.com/kmc-jp/rapidv4 - キットの実装が結構今回した話と絡んでいたりするので気 になる人はぜひコードを読んでみてね - JavaScript

    は結構ハマりどころがあるなーと思って諦めて しまった - polaris はテストをかけ
  63. 63 次年度担当者へ - 健闘を祈る (わからないことはどんどん聞いてね)

  64. 64 おわり Any Questions?