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

ヘブンバーンズレッド × バトル × アドベンチャー 〜WFSのゲーム制作・演出の最大化手法〜

ヘブンバーンズレッド × バトル × アドベンチャー 〜WFSのゲーム制作・演出の最大化手法〜

GREE Tech Conference 2022で発表された資料です。
https://techcon.gree.jp/2022/session/TrackB-2

gree_tech
PRO

October 25, 2022
Tweet

More Decks by gree_tech

Other Decks in Technology

Transcript

  1. 株式会社WFS クライアントエンジニア 市川 ひまわり ヘブンバーンズレッド × バトル × アドベンチャー 〜WFSのゲーム制作・演出の最大化手法〜 株式会社WFS クライアントエンジニア 伊藤 栄治

  2. 市川ひまわり / Himawari Ichikawa 株式会社WFS Unityクライアントエンジニア 2020年新卒入社 主にアドベンチャーパートの開発を担当 自己紹介 ©WFS

  3. 伊藤 栄治 / Eiji Ito 株式会社WFS Unityクライアントエンジニア 2016年新卒入社 主にバトルパートの開発を担当 ©WFS

    自己紹介
  4. • 第一部 ◦ Luaで最上の演出を! 「ヘブンバーンズレッド」におけるアドベンチャー制作エンジンの裏側 • 第二部 ◦ Unity Timelineで作る!

    「ヘブンバーンズレッド」バトルスキルシステム作成事例 構成 ©WFS
  5. Luaで最上の演出を! 「ヘブンバーンズレッド」における アドベンチャー制作エンジンの裏側 市川ひまわり ©WFS

  6. ヘブンバーンズレッドについて ©WFS

  7. 大枠の役務分担(シナリオ/ボイス周り)
 ©WFS ヘブンバーンズレッドとは

  8. ©WFS ADV フィールド バトル ヘブンバーンズレッドの構成要素

  9. ©WFS ADV フィールド バトル ヘブンバーンズレッドの構成要素

  10. ヘブンバーンズレッドにおけるアドベンチャー ©WFS

  11. ヘブンバーンズレッドにおけるアドベンチャー ©WFS 大量のセリフとそれに伴う演出

  12. ヘブンバーンズレッドにおけるアドベンチャー ©WFS 大量のセリフとそれに伴う演出 量産体制を整える必要がある

  13. ヘブンバーンズレッドにおけるアドベンチャー ©WFS Luaを使って作っている • Lua:スクリプト言語の一種 • WFSでは複数タイトルで使用されている

  14. ヘブンバーンズレッドにおけるアドベンチャー ©WFS 演出を組むのは「スクリプター」 • スクリプティングのレベルは様々 • スクリプト初心者の人でも書ける仕組みにする必要がある

  15. アドベンチャー実装の流れ ©WFS

  16. アドベンチャー実装の流れ ©WFS シナリオ納品

  17. アドベンチャー実装の流れ ©WFS  スクリプト  作業 シナリオ納品

  18. アドベンチャー実装の流れ ©WFS テストと 修正  スクリプト  作業 シナリオ納品

  19. アドベンチャー実装の流れ ©WFS テストと 修正  スクリプト  作業 シナリオ納品 シナリオ変換内製ツール 『Tulip』

  20. アドベンチャー実装の流れ ©WFS テストと 修正  スクリプト  作業 シナリオ納品 Layout命令 シナリオ変換内製ツール 『Tulip』

  21. アドベンチャー実装の流れ ©WFS テストと 修正  スクリプト  作業 シナリオ納品 Unity x Luaの

    ホットリロード Layout命令 シナリオ変換内製ツール 『Tulip』
  22. アドベンチャー実装の流れ ©WFS テストと 修正  スクリプト  作業 シナリオ納品 Unity x Luaの

    ホットリロード Layout命令 シナリオ変換内製ツール 『Tulip』
  23. 納品されたテキストファイルをluaにする 納品時の問題 ©WFS テキスト

  24. 納品されたテキストファイルをluaにする 納品時の問題 ©WFS テキスト キャラクター指定 コメント 吹き出しの種類

  25. 納品されたテキストファイルをluaにする • 1行ずつ手動でLua構文に直す必要がある 納品時の問題 ©WFS テキスト キャラクター指定 コメント 吹き出しの種類

  26. 納品されたテキストファイルをluaにする • 1行ずつ手動でLua構文に直す必要がある • 手作業だと正確性が低い 納品時の問題 ©WFS テキスト キャラクター指定 コメント

    吹き出しの種類
  27. 納品されたテキストファイルをluaにする 納品時の問題 ©WFS テキスト ⇒変換ツールを作って自動化!

  28. シナリオ変換内製ツール『Tulip』とは ©WFS • 納品されたシナリオ(.txt)をLuaに変換するためのパーサー

  29. シナリオ変換内製ツール『Tulip』とは ©WFS • 納品されたシナリオ(.txt)をLuaに変換するためのパーサー • 使用言語はPythonとC# • Unityのツールとして作成

  30. シナリオ変換内製ツール『Tulip』とは ©WFS • 納品されたシナリオ(.txt)をLuaに変換するためのパーサー • 使用言語はPythonとC# • Unityのツールとして作成 • シナリオの量産をしやすくする

  31. 簡単なサンプル ©WFS 【茅森】「サンプル」 【和泉】「サンプル2」 納品txtファイル

  32. 簡単なサンプル ©WFS 【茅森】「サンプル」 【和泉】「サンプル2」 納品txtファイル Tulip

  33. 簡単なサンプル ©WFS Adv.talk(“茅森”, [[サンプル]]) Adv.talk(“和泉”, [[サンプル2]]) 出力luaファイル 【茅森】「サンプル」 【和泉】「サンプル2」 納品txtファイル

    Tulip
  34. 実装 ©WFS • テキストファイルを上から順に読んでいく • 特定の文字列を探して変換する • キャラ一覧は事前に読み込んでいる

  35. シナリオ変換内製ツール『Tulip』とは ©WFS 選択肢 3x3選択肢

  36. 3 x 3 選択肢 ©WFS

  37. 3 x 3 選択肢 ©WFS @選択1=SELBTN( 選択肢1-1, 選択肢1-2, 選択肢1-3 )

    @選択2=SELBTN( 選択肢2-1, 選択肢2-2, 選択肢2-3 ) @選択合算=(@選択1*10) + @選択2 switch(@選択合算){ … } 納品txtファイル
  38. 3 x 3 選択肢 ©WFS @選択1=SELBTN( 選択肢1-1, 選択肢1-2, 選択肢1-3 )

    @選択2=SELBTN( 選択肢2-1, 選択肢2-2, 選択肢2-3 ) @選択合算=(@選択1*10) + @選択2 switch(@選択合算){ … } 納品txtファイル local s1, s2 = Adv.doubleQuestion([[]], [[選択 肢1-1|選択肢1-2|選択肢1-3]], [[選択肢2-1|選択肢2-2|選択肢2- 3]]) local s = s1 * 10 + s2 if s == 0 then … 出力luaファイル Tulip
  39. 3 x 3 選択肢 ©WFS @選択1=SELBTN( 選択肢1-1, 選択肢1-2, 選択肢1-3 )

    @選択2=SELBTN( 選択肢2-1, 選択肢2-2, 選択肢2-3 ) @選択合算=(@選択1*10) + @選択2 switch(@選択合算){ … } 納品txtファイル local s1, s2 = Adv.doubleQuestion([[]], [[選択 肢1-1|選択肢1-2|選択肢1-3]], [[選択肢2-1|選択肢2-2|選択肢2- 3]]) local s = s1 * 10 + s2 if s == 0 then … 出力luaファイル Tulip
  40. 3 x 3 選択肢 ©WFS @選択1=SELBTN( 選択肢1-1, 選択肢1-2, 選択肢1-3 )

    @選択2=SELBTN( 選択肢2-1, 選択肢2-2, 選択肢2-3 ) @選択合算=(@選択1*10) + @選択2 switch(@選択合算){ … } 納品txtファイル local s1, s2 = Adv.doubleQuestion([[]], [[選択 肢1-1|選択肢1-2|選択肢1-3]], [[選択肢2-1|選択肢2-2|選択肢2- 3]]) local s = s1 * 10 + s2 if s == 0 then … 出力luaファイル Tulip s1 s2
  41. 3 x 3 選択肢 ©WFS @選択1=SELBTN( 選択肢1-1, 選択肢1-2, 選択肢1-3 )

    @選択2=SELBTN( 選択肢2-1, 選択肢2-2, 選択肢2-3 ) @選択合算=(@選択1*10) + @選択2 switch(@選択合算){ … } 納品txtファイル local s1, s2 = Adv.doubleQuestion([[]], [[選択 肢1-1|選択肢1-2|選択肢1-3]], [[選択肢2-1|選択肢2-2|選択肢2- 3]]) local s = s1 * 10 + s2 if s == 0 then … 出力luaファイル Tulip
  42. 3 x 3 選択肢 ©WFS @選択1=SELBTN( 選択肢1-1, 選択肢1-2, 選択肢1-3 )

    @選択2=SELBTN( 選択肢2-1, 選択肢2-2, 選択肢2-3 ) @選択合算=(@選択1*10) + @選択2 switch(@選択合算){ … } 納品txtファイル local s1, s2 = Adv.doubleQuestion([[]], [[選択 肢1-1|選択肢1-2|選択肢1-3]], [[選択肢2-1|選択肢2-2|選択肢2- 3]]) local s = s1 * 10 + s2 if s == 0 then … 出力luaファイル Tulip z
  43. 3 x 3 選択肢 @選択1=SELBTN( 選択肢1-1, 選択肢1-2, 選択肢1-3 ) @選択2=SELBTN(

    選択肢2-1, 選択肢2-2, 選択肢2-3 ) @選択合算=(@選択1*10) + @選択2 switch(@選択合算){ … } 納品txtファイル local s1, s2 = Adv.doubleQuestion([[]], [[選択 肢1-1|選択肢1-2|選択肢1-3]], [[選択肢2-1|選択肢2-2|選択肢2- 3]]) local s = s1 * 10 + s2 if s == 0 then … 出力luaファイル Tulip
  44. 3 x 3 選択肢 ©WFS @選択1=SELBTN( 選択肢1-1, 選択肢1-2, 選択肢1-3 )

    @選択2=SELBTN( 選択肢2-1, 選択肢2-2, 選択肢2-3 ) @選択合算=(@選択1*10) + @選択2 switch(@選択合算){ … } 納品txtファイル local s1, s2 = Adv.doubleQuestion([[]], [[選択 肢1-1|選択肢1-2|選択肢1-3]], [[選択肢2-1|選択肢2-2|選択肢2- 3]]) local s = s1 * 10 + s2 if s == 0 then … 出力luaファイル Tulip
  45. 3 x 3 選択肢 @選択1=SELBTN( 選択肢1-1, 選択肢1-2, 選択肢1-3 ) @選択2=SELBTN(

    選択肢2-1, 選択肢2-2, 選択肢2-3 ) @選択合算=(@選択1*10) + @選択2 switch(@選択合算){ … } 納品txtファイル local s1, s2 = Adv.doubleQuestion([[]], [[選択 肢1-1|選択肢1-2|選択肢1-3]], [[選択肢2-1|選択肢2-2|選択肢2- 3]]) local s = s1 * 10 + s2 if s == 0 then … 出力luaファイル Tulip
  46. 3 x 3 選択肢の実装 ©WFS • txtファイルを上から順に読み 特定文字列を探して変換 • switch文をif文に書き換える

    @選択1=SELBTN( 選択肢1-1, 選択肢1-2, 選択肢1-3 ) @選択2=SELBTN( 選択肢2-1, 選択肢2-2, 選択肢2-3 ) @選択合算=(@選択1*10) + @選択2 switch(@選択合算){ … } 納品txtファイル
  47. アドベンチャー実装の流れ ©WFS テストと 修正  スクリプト  作業 シナリオ納品 Unity x Luaの

    ホットリロード Layout命令 シナリオ変換内製ツール 『Tulip』
  48. アドベンチャーの抱える問題 ©WFS • 基本構造はアドベンチャー内で共通 ⇒ 同じ命令をたくさん書く必要がある

  49. アドベンチャーの抱える問題 ©WFS • 基本構造はアドベンチャー内で共通 ⇒ 同じ命令をたくさん書く必要がある テンプレート化して 自動で作れるようにしたい

  50. シンプルな演出例 ©WFS 茅森月歌 和泉ユキ

  51. シンプルな演出例 ©WFS

  52. 3つに分けて考える ©WFS レイアウト1 レイアウト2 レイアウト3 キャラクター1人表示 キャラクター2人表示 キャラクター1人表示

  53. シンプルな演出例:レイアウト1 ©WFS

  54. シンプルな演出例:レイアウト1 ©WFS 茅森月歌が フェードイン

  55. シンプルな演出例:レイアウト2 ©WFS

  56. シンプルな演出例:レイアウト2 ©WFS 茅森月歌が 左へスライド

  57. シンプルな演出例:レイアウト2 ©WFS 和泉ユキが フェードイン + 左へスライド

  58. シンプルな演出例:レイアウト2 ©WFS 背景が 少しスライド

  59. シンプルな演出例:レイアウト3 ©WFS

  60. シンプルな演出例:レイアウト3 ©WFS 茅森月歌が 右へスライド

  61. シンプルな演出例:レイアウト3 ©WFS 和泉ユキが フェードアウト + 右へスライド

  62. シンプルな演出例:レイアウト3 ©WFS 背景が 少しスライド

  63. シンプルな演出例から分かること ©WFS 演出にはパターンがある • 表示切り替えはフェード • 立ち位置の変更はスライド

  64. シンプルな演出例から分かること ©WFS 演出にはパターンがある • 表示切り替えはフェード • 立ち位置の変更はスライド キャラクターの表示の演出を 自動化することができそう

  65. Layout命令(内製) ©WFS • 演出を直感的に作ることができる仕組み • 立ち位置の変化から途中経過を補完

  66. Layout命令(内製) ©WFS • 背景をもとにステージを作る Layout.createStage(背景インスタンス)

  67. Layout命令(内製) ©WFS • 背景をもとにステージを作る • ADV立ち絵を表示する Layout.createStage(背景インスタンス) Layout.show(キャラクターインスタンス, ...)

  68. Layout命令で考えてみる ©WFS Layout.show("茅森", "和泉") Layout.show("茅森") Layout.show("茅森") レイアウト1 レイアウト2 レイアウト3

  69. Layout命令で考えてみる ©WFS Layout.show("茅森", "和泉") Layout.show("茅森") Layout.show("茅森") レイアウト1 レイアウト2 レイアウト3 同じ命令でも

    呼び出しタイミングによって 表示演出が変わる!
  70. Layout命令で考えてみる ©WFS -- bgからステージを作る Layout.createStage(bg) -- 茅森表示 Layout.show(RKayamori) Adv.talk(RKayamori, [[1人レイアウト]])

    -- 茅森、和泉表示 Layout.show(RKayamori, YIzumi) Adv.talk(YIzumi, [[2人レイアウト]]) -- 和泉表示 Layout.show(RKayamori) Adv.talk(RKayamori, [[1人レイアウト]])
  71. -- bgからステージを作る Layout.createStage(bg) -- 茅森表示 Layout.show(RKayamori) Adv.talk(RKayamori, [[1人レイアウト]]) -- 茅森、和泉表示

    Layout.show(RKayamori, YIzumi) Adv.talk(YIzumi, [[2人レイアウト]]) -- 和泉表示 Layout.show(RKayamori) Adv.talk(RKayamori, [[1人レイアウト]]) Layout命令で考えてみる ©WFS
  72. -- bgからステージを作る Layout.createStage(bg) -- 茅森表示 Layout.show(RKayamori) Adv.talk(RKayamori, [[1人レイアウト]]) -- 茅森、和泉表示

    Layout.show(RKayamori, YIzumi) Adv.talk(YIzumi, [[2人レイアウト]]) -- 和泉表示 Layout.show(RKayamori) Adv.talk(RKayamori, [[1人レイアウト]]) Layout命令で考えてみる ©WFS
  73. -- bgからステージを作る Layout.createStage(bg) -- 茅森表示 Layout.show(RKayamori) Adv.talk(RKayamori, [[1人レイアウト]]) -- 茅森、和泉表示

    Layout.show(RKayamori, YIzumi) Adv.talk(YIzumi, [[2人レイアウト]]) -- 和泉表示 Layout.show(RKayamori) Adv.talk(RKayamori, [[1人レイアウト]]) Layout命令で考えてみる ©WFS
  74. -- bgからステージを作る Layout.createStage(bg) -- 茅森表示 Layout.show(RKayamori) Adv.talk(RKayamori, [[1人レイアウト]]) -- 茅森、和泉表示

    Layout.show(RKayamori, YIzumi) Adv.talk(YIzumi, [[2人レイアウト]]) -- 和泉表示 Layout.show(RKayamori) Adv.talk(RKayamori, [[1人レイアウト]]) Layout命令で考えてみる ©WFS
  75. Layout命令で考えてみる ©WFS -- bgからステージを作る Layout.createStage(bg) -- 茅森表示 Layout.show(RKayamori) Adv.talk(RKayamori, [[1人レイアウト]])

    -- 茅森、和泉表示 Layout.show(RKayamori, YIzumi) Adv.talk(YIzumi, [[2人レイアウト]]) -- 和泉表示 Layout.show(RKayamori) Adv.talk(RKayamori, [[1人レイアウト]])
  76. シンプルな演出例 ©WFS -- bgからステージを作る Layout.createStage(bg) -- 茅森表示 Layout.show(RKayamori) Adv.talk(RKayamori, [[1人レイアウト]])

    -- 茅森、和泉表示 Layout.show(RKayamori, YIzumi) Adv.talk(YIzumi, [[2人レイアウト]]) -- 和泉表示 Layout.show(RKayamori) Adv.talk(RKayamori, [[1人レイアウト]]) 茅森フェードイン 茅森スライド 和泉フェードイン + スライド 背景 スライド 茅森スライド 和泉フェードアウト + スライド 背景 スライド
  77. 他にもさまざまなLua命令がある ©WFS • ADV • Field • Battle • etc…

  78. アドベンチャー実装の流れ ©WFS テストと 修正  スクリプト  作業 シナリオ納品 Unity x Luaの

    ホットリロード Layout命令 シナリオ変換内製ツール 『Tulip』
  79. 開発サイクル ©WFS 確認 修正 ファイルを Reimport Editor 再生 Editor 止める

  80. 開発サイクル ©WFS 確認 修正 ファイルを Reimport Editor 再生 Editor 止める

  81. 開発サイクル ©WFS 確認 修正 ファイルを Reimport Editor 再生 Editor 止める

  82. 開発サイクル ©WFS 確認 修正 ファイルを Reimport Editor 再生 Editor 止める

  83. 開発サイクル ©WFS 確認 修正 ファイルを Reimport Editor 再生 Editor 止める

  84. 開発サイクル ©WFS 確認 修正 ファイルを Reimport Editor 再生 Editor 止める

  85. 開発サイクル ©WFS 確認 修正 ファイルを Reimport Editor 再生 Editor 止める

  86. 開発サイクル ©WFS 確認 修正 ファイルを Reimport Editor 再生 Editor 止める

  87. Unity x Lua ©WFS ホットリロードが可能 • エディタを再生したまま • Luaスクリプトのリロード

  88. Unity x Lua ©WFS ホットリロードが可能 • エディタを再生したまま • Luaスクリプトのリロード 開発スピードが早い!

  89. ©WFS ホットリロード

  90. まとめ ©WFS

  91. ©WFS • ヘブンバーンズレッドのリッチなアドベンチャーは 様々な工夫を凝らしてできている まとめ

  92. ©WFS • ヘブンバーンズレッドのリッチなアドベンチャーは 様々な工夫を凝らしてできている • UnityとLuaの相性が結構いい ◦ エディタを再生したままホットリロードが可能 ◦ インポート不要

    まとめ
  93. ©WFS • ヘブンバーンズレッドのリッチなアドベンチャーは 様々な工夫を凝らしてできている • UnityとLuaの相性が結構いい ◦ エディタを再生したままホットリロードが可能 ◦ インポート不要

    • アドベンチャーの量産がしやすい まとめ
  94. Unity Timelineで作る! 「ヘブンバーンズレッド」 バトルスキルシステム作成事例 伊藤栄治 ©WFS

  95. 目次 • Unity Timelineとは (ざっくり) • ヘブンバーンズレッドでの利用事例 ◦ Timelineで作るスキル演出 ◦

    Timeline Markerで繋がるシステムと演出 • おまけ: Luaで繋がるバトルとカットシーン • まとめ ©WFS
  96. ©WFS Unity Timelineとは (ざっくり)

  97. • カットシーンなどの映画的なコンテンツを作りやすい機能 ◦ 複数のオブジェクトを同時に管理しやすい Unity Timelineとは (ざっくり) ©WFS

  98. ©WFS ヘブンバーンズレッドでの利用事例

  99. • スキル演出 ヘブンバーンズレッドでの利用事例 ©WFS

  100. • スキル演出 • 敵の攻撃 ©WFS ヘブンバーンズレッドでの利用事例

  101. • スキル演出 • 敵の攻撃 • カットシーン ©WFS ヘブンバーンズレッドでの利用事例

  102. • スキル演出 • 敵の攻撃 • カットシーン • 敵/味方の登場演出 • など

    ©WFS ヘブンバーンズレッドでの利用事例
  103. ©WFS スキルを構成する要素

  104. スキルを構成する要素 ©WFS

  105. ©WFS キャラクターが 飛びかかるモーション スキルを構成する要素

  106. ©WFS ワープエフェクト再生 キャラクターが 飛びかかるモーション スキルを構成する要素

  107. ©WFS ワープエフェクト再生 ボイス再生 キャラクターが 飛びかかるモーション スキルを構成する要素

  108. ©WFS カメラをぐるっと回して敵の方に向ける スキルを構成する要素

  109. ©WFS カメラをぐるっと回して敵の方に向ける この辺りからゆっくり背景を暗くする スキルを構成する要素

  110. ©WFS 別のカメラに切り替えて正面から映す スキルを構成する要素

  111. ©WFS 斬りかかる 効果音を再生 スキルを構成する要素

  112. ©WFS 斬撃のエフェクトを再生 斬りかかる 効果音を再生 スキルを構成する要素

  113. ©WFS 斬撃のエフェクトを再生 ゲージを減らす ダメージを表示 斬りかかる 効果音を再生 スキルを構成する要素

  114. ©WFS 2撃目が命中するタイミングに合わせて.. スキルを構成する要素

  115. ©WFS BREAK! ラベルを表示 スキルを構成する要素

  116. ©WFS BREAK! ラベルを表示 最終ヒット時に与ダメージの 合計値や平均値を表示 スキルを構成する要素

  117. ©WFS BREAK! ラベルを表示 BREAK時や撃破時は ヒットストップを強めにかける 最終ヒット時に与ダメージの 合計値や平均値を表示 スキルを構成する要素

  118. ©WFS Timelineで制御すべきスキルの構成要素

  119. • キャラクターの動き • カメラの動き Timelineで制御すべきスキルの構成要素 ©WFS

  120. • キャラクターの動き • カメラの動き • エフェクト再生 ◦ 再生するタイミングや位置を演出に合わせて調整するため • 効果音/ボイス再生

    ◦ 再生するタイミングを演出に合わせて調整するため Timelineで制御すべきスキルの構成要素 ©WFS
  121. • キャラクターの動き • カメラの動き • エフェクト再生 ◦ 再生するタイミングや位置を演出に合わせて調整するため • 効果音/ボイス再生

    ◦ 再生するタイミングを演出に合わせて調整するため • ヒットタイミング ◦ ダメージ量表示や体力ゲージの変動を演出に組み込むため、 攻撃が命中したタイミングにダメージを反映する必要がある Timelineで制御すべきスキルの構成要素 ©WFS
  122. ©WFS スキルTimelineの実例紹介

  123. ©WFS スキルTimelineの実例紹介

  124. ©WFS スキルTimelineの実例紹介 キャラクター関連

  125. ©WFS スキルTimelineの実例紹介 キャラクター関連 キャラクターの transformやanimatorを 動的にBind(リンク)する

  126. ©WFS スキルTimelineの実例紹介 カメラ関連

  127. ©WFS スキルTimelineの実例紹介 カメラ関連 アクティブトラックを使って 3つのカメラを切り替えている

  128. ©WFS スキルTimelineの実例紹介 カメラ関連 アクティブトラックを使って 3つのカメラを切り替えている

  129. ©WFS スキルTimelineの実例紹介 カメラ関連 アクティブトラックを使って 3つのカメラを切り替えている ココ

  130. ©WFS スキルTimelineの実例紹介 エフェクト関連

  131. ©WFS スキルTimelineの実例紹介 エフェクト関連 各種エフェクトの 再生タイミングを制御

  132. ©WFS スキルTimelineの実例紹介 飛びかかるモーション 1つめのカメラ ワープエフェクト

  133. ©WFS スキルTimelineの実例紹介 着地モーション 2つめのカメラ

  134. ©WFS スキルTimelineの実例紹介 攻撃モーション 3つめのカメラ 斬撃エフェクト

  135. ©WFS スキルTimelineの実例紹介

  136. ©WFS スキルTimelineの実例紹介 ヒット関連 サウンド関連

  137. ©WFS Timeline Markerで繋がる システムと演出

  138. • Marker: Timelineに配置するとその時点で関数呼び出しが行えるもの ◦ 扱い方はAnimation Eventと近い Timeline Markerで繋がるシステムと演出 ©WFS これ

  139. • Marker: Timelineに配置するとその時点で関数呼び出しが行えるもの ◦ 扱い方はAnimation Eventと近い • Markerは自作することができる ◦ 引数の設定も自由に行える

    Timeline Markerで繋がるシステムと演出 ©WFS これ
  140. • Marker: Timelineに配置するとその時点で関数呼び出しが行えるもの ◦ 扱い方はAnimation Eventと近い • Markerは自作することができる ◦ 引数の設定も自由に行える

    Timeline Markerで繋がるシステムと演出 ©WFS 2つめのピンは ボイスマーカー
  141. • Marker: Timelineに配置するとその時点で関数呼び出しが行えるもの ◦ 扱い方はAnimation Eventと近い • Markerは自作することができる ◦ 引数の設定も自由に行える

    Timeline Markerで繋がるシステムと演出 ©WFS 2つめのピンは ボイスマーカー ボイス用の引数
  142. • Marker: Timelineに配置するとその時点で関数呼び出しが行えるもの ◦ 扱い方はAnimation Eventと近い • Markerは自作することができる ◦ 引数の設定も自由に行える

    Timeline Markerで繋がるシステムと演出 ©WFS 3つめのピンは サウンドマーカー 設定項目が異なる
  143. • ヒットマーカー ◦ 攻撃のヒットタイミングを設定するマーカー Timeline Markerで繋がるシステムと演出 ヒットストップ情報 これ

  144. [Serializable, DisplayName("ヒットマーカー")]
 [CustomStyle("HitMarker")]
 public class HitMarker : Marker, INotification, INotificationOptionProvider

    
 {
 public PropertyName id => new PropertyName("Hit");
 
 public bool isHitStop = false;
 public float hitStopSpeed = BattleConstant.DEFAULT_HIT_STOP_SPEED ;
 public float hitStopTime = BattleConstant.DEFAULT_HIT_STOP_TIME ;
 
 public int indexOnTrack { get; set; } // トラック内の同種マーカーのうち何番目か 
 public int countOnTrack { get; set; } // トラック内にいくつ同種のマーカーがあるか 
 public bool isFinal => indexOnTrack == countOnTrack - 1;
 }
 HitMarker.cs Timeline Markerで繋がるシステムと演出
  145. [Serializable, DisplayName("ヒットマーカー")]
 [CustomStyle("HitMarker")]
 public class HitMarker : Marker, INotification, INotificationOptionProvider

    
 {
 public PropertyName id => new PropertyName("Hit");
 
 public bool isHitStop = false;
 public float hitStopSpeed = BattleConstant.DEFAULT_HIT_STOP_SPEED ;
 public float hitStopTime = BattleConstant.DEFAULT_HIT_STOP_TIME ;
 
 public int indexOnTrack { get; set; } // トラック内の同種マーカーのうち何番目か 
 public int countOnTrack { get; set; } // トラック内にいくつ同種のマーカーがあるか 
 public bool isFinal => indexOnTrack == countOnTrack - 1;
 }
 HitMarker.cs Timeline Markerで繋がるシステムと演出 引数で入力する部分
  146. [Serializable, DisplayName("ヒットマーカー")]
 [CustomStyle("HitMarker")]
 public class HitMarker : Marker, INotification, INotificationOptionProvider

    
 {
 public PropertyName id => new PropertyName("Hit");
 
 public bool isHitStop = false;
 public float hitStopSpeed = BattleConstant.DEFAULT_HIT_STOP_SPEED ;
 public float hitStopTime = BattleConstant.DEFAULT_HIT_STOP_TIME ;
 
 public int indexOnTrack { get; set; } // トラック内の同種マーカーのうち何番目か 
 public int countOnTrack { get; set; } // トラック内にいくつ同種のマーカーがあるか 
 public bool isFinal => indexOnTrack == countOnTrack - 1;
 }
 HitMarker.cs Timeline Markerで繋がるシステムと演出 マーカーに 持たせたい変数を定義
  147. public class AttackPlayableTrack : TrackAsset
 {
 public void Awake()
 {


    // トラック内のマーカーに事前情報を渡す
 var hitMarkers = GetMarkers().OfType<HitMarker>().OrderBy(m => m.time).ToList();
 for (var i = 0; i < hitMarkers.Count; i++)
 {
 var marker = hitMarkers[i];
 marker.indexOnTrack = i;
 marker.countOnTrack = hitMarkers.Count;
 }
 }
 }
 
 AttackPlayableTrack.cs Timeline Markerで繋がるシステムと演出
  148. public class AttackPlayableTrack : TrackAsset
 {
 public void Awake()
 {


    // トラック内のマーカーに事前情報を渡す
 var hitMarkers = GetMarkers().OfType<HitMarker>().OrderBy(m => m.time).ToList();
 for (var i = 0; i < hitMarkers.Count; i++)
 {
 var marker = hitMarkers[i];
 marker.indexOnTrack = i;
 marker.countOnTrack = hitMarkers.Count;
 }
 }
 }
 
 AttackPlayableTrack.cs Timeline Markerで繋がるシステムと演出 ヒットマーカーを 集めてきて
  149. public class AttackPlayableTrack : TrackAsset
 {
 public void Awake()
 {


    // トラック内のマーカーに事前情報を渡す
 var hitMarkers = GetMarkers().OfType<HitMarker>().OrderBy(m => m.time).ToList();
 for (var i = 0; i < hitMarkers.Count; i++)
 {
 var marker = hitMarkers[i];
 marker.indexOnTrack = i;
 marker.countOnTrack = hitMarkers.Count;
 }
 }
 }
 
 AttackPlayableTrack.cs Timeline Markerで繋がるシステムと演出 indexとcountを格納
  150. HitReceiver.cs Timeline Markerで繋がるシステムと演出 public class HitReceiver : MonoBehaviour, INotificationReceiver
 {


    public void OnNotify(Playable origin, INotification notification, object context)
 {
 switch (notification)
 {
 case HitMarker marker:
 Hit(null, marker.indexOnTrack, marker.isFinal, marker.isHitStop, marker.hitStopSpeed, marker.hitStopTime);
 return;
 }
 }
 private static void Hit(int hitIndex, bool isFinal, bool isHitStop, float hitStopSpeed, float hitStopTime)
 {
 BattleModule.Instance.actionEntryManager.FireMainHit(hitIndex, isFinal, isHitStop, hitStopSpeed, hitStopTime); 
 }
 }

  151. HitReceiver.cs Timeline Markerで繋がるシステムと演出 public class HitReceiver : MonoBehaviour, INotificationReceiver
 {


    public void OnNotify(Playable origin, INotification notification, object context)
 {
 switch (notification)
 {
 case HitMarker marker:
 Hit(null, marker.indexOnTrack, marker.isFinal, marker.isHitStop, marker.hitStopSpeed, marker.hitStopTime);
 return;
 }
 }
 private static void Hit(int hitIndex, bool isFinal, bool isHitStop, float hitStopSpeed, float hitStopTime)
 {
 BattleModule.Instance.actionEntryManager.FireMainHit(hitIndex, isFinal, isHitStop, hitStopSpeed, hitStopTime); 
 }
 }

  152. HitReceiver.cs Timeline Markerで繋がるシステムと演出 public class HitReceiver : MonoBehaviour, INotificationReceiver
 {


    public void OnNotify(Playable origin, INotification notification, object context)
 {
 switch (notification)
 {
 case HitMarker marker:
 Hit(null, marker.indexOnTrack, marker.isFinal, marker.isHitStop, marker.hitStopSpeed, marker.hitStopTime);
 return;
 }
 }
 private static void Hit(int hitIndex, bool isFinal, bool isHitStop, float hitStopSpeed, float hitStopTime)
 {
 BattleModule.Instance.actionEntryManager.FireMainHit(hitIndex, isFinal, isHitStop, hitStopSpeed, hitStopTime); 
 }
 }

  153. Timeline Markerで繋がるシステムと演出 ©WFS

  154. ©WFS おまけ Luaで繋がるバトルとカットシーン

  155. Luaで繋がるバトルとカットシーン ©WFS

  156. • 今回の例で必要な要件 Luaで繋がるバトルとカットシーン ©WFS

  157. • 今回の例で必要な要件 ◦ 敵がBREAKしたらバトルの進行を一時停止させる Luaで繋がるバトルとカットシーン ©WFS

  158. • 今回の例で必要な要件 ◦ 敵がBREAKしたらバトルの進行を一時停止させる ◦ バトルの状態を残したまま会話パートを再生する Luaで繋がるバトルとカットシーン ©WFS

  159. • 今回の例で必要な要件 ◦ 敵がBREAKしたらバトルの進行を一時停止させる ◦ バトルの状態を残したまま会話パートを再生する ◦ カットシーンを再生する Luaで繋がるバトルとカットシーン ©WFS

  160. • 今回の例で必要な要件 ◦ 敵がBREAKしたらバトルの進行を一時停止させる ◦ バトルの状態を残したまま会話パートを再生する ◦ カットシーンを再生する ▪ と同時にBGMをフェードアウトさせる

    Luaで繋がるバトルとカットシーン ©WFS
  161. Luaで繋がるバトルとカットシーン ©WFS • 今回の例で必要な要件 ◦ 敵がBREAKしたらバトルの進行を一時停止させる ◦ バトルの状態を残したまま会話パートを再生する ◦ カットシーンを再生する

    ▪ と同時にBGMをフェードアウトさせる ◦ カットシーンの特定タイミングで別の戦闘BGMを再生する
  162. • Luaスクリプトは並列で実行してバトルの状態を監視 Luaで繋がるバトルとカットシーン ©WFS

  163. • Luaスクリプトは並列で実行してバトルの状態を監視 • バトルからイベント通知が来たらバトルを一時停止して演出を行う Luaで繋がるバトルとカットシーン ©WFS

  164. • Luaスクリプトは並列で実行してバトルの状態を監視 • バトルからイベント通知が来たらバトルを一時停止して演出を行う • 演出が終わったらバトルを再び再生する Luaで繋がるバトルとカットシーン ©WFS

  165. • Luaスクリプトは並列で実行してバトルの状態を監視 • バトルからイベント通知が来たらバトルを一時停止して演出を行う • 演出が終わったらバトルを再び再生する Luaで繋がるバトルとカットシーン ©WFS バトル
 処理


    Lua Battle 敵がブレイク
 するまで待機

  166. • Luaスクリプトは並列で実行してバトルの状態を監視 • バトルからイベント通知が来たらバトルを一時停止して演出を行う • 演出が終わったらバトルを再び再生する Luaで繋がるバトルとカットシーン ©WFS 敵のブレイクを 通知


    バトルを
 一時停止
 Luaイベント
 終了まで待機
 Lua Battle 敵がブレイク
 するまで待機
 バトル
 処理

  167. • Luaスクリプトは並列で実行してバトルの状態を監視 • バトルからイベント通知が来たらバトルを一時停止して演出を行う • 演出が終わったらバトルを再び再生する Luaで繋がるバトルとカットシーン ©WFS Luaイベント終了まで待機
 ADV


    再生
 カットシーン再 生
 BGM フェード アウト
 Lua Battle
  168. • Luaスクリプトは並列で実行してバトルの状態を監視 • バトルからイベント通知が来たらバトルを一時停止して演出を行う • 演出が終わったらバトルを再び再生する Luaで繋がるバトルとカットシーン ©WFS Luaイベント終了まで待機
 ADV


    再生
 カットシーン再 生
 BGM フェード アウト
 マーカー通知ま で待機
 Lua Battle
  169. • Luaスクリプトは並列で実行してバトルの状態を監視 • バトルからイベント通知が来たらバトルを一時停止して演出を行う • 演出が終わったらバトルを再び再生する Luaで繋がるバトルとカットシーン Luaイベント終了まで待機
 ADV
 再生


    カットシーン再 生
 BGM フェード アウト
 マーカー通知ま で待機
 BGM再生用 マーカー通知
 BGM
 再生
 Lua Battle ©WFS Timeline
  170. • Luaスクリプトは並列で実行してバトルの状態を監視 • バトルからイベント通知が来たらバトルを一時停止して演出を行う • 演出が終わったらバトルを再び再生する Luaで繋がるバトルとカットシーン ©WFS Luaイベント
 終了まで待機


    カットシーン再生終 了まで待機
 Lua Battle 再生終了
 通知
 Timeline
  171. • Luaスクリプトは並列で実行してバトルの状態を監視 • バトルからイベント通知が来たらバトルを一時停止して演出を行う • 演出が終わったらバトルを再び再生する Luaで繋がるバトルとカットシーン ©WFS Luaイベント
 終了まで待機


    カットシーン再生終 了まで待機
 第二形態バトル開 始を通知
 Luaイベント
 終了まで待機
 Luaイベント終了を 通知
 Lua Battle 再生終了
 通知
 Timeline
  172. • Luaスクリプトは並列で実行してバトルの状態を監視 • バトルからイベント通知が来たらバトルを一時停止して演出を行う • 演出が終わったらバトルを再び再生する Luaで繋がるバトルとカットシーン Luaイベント
 終了まで待機
 カットシーン再生終

    了まで待機
 再生終了
 通知
 第二形態バトル開 始を通知
 Luaイベント
 終了まで待機
 Luaイベント終了を 通知
 バトル 再開
 Lua Battle Timeline ©WFS
  173. Luaで繋がるバトルとカットシーン ©WFS

  174. ©WFS まとめ

  175. • ヘブンバーンズレッドではTimelineが様々なシチュエーションで活躍 ◦ スキル、カットシーン、登場演出など まとめ ©WFS

  176. まとめ ©WFS • ヘブンバーンズレッドではTimelineが様々なシチュエーションで活躍 ◦ スキル、カットシーン、登場演出など • Timelineで演出のほぼ全てを制御している ◦ モーション、カメラ、エフェクト、サウンド、ラベル表示など

  177. まとめ ©WFS • ヘブンバーンズレッドではTimelineが様々なシチュエーションで活躍 ◦ スキル、カットシーン、登場演出など • Timelineで演出のほぼ全てを制御している ◦ モーション、カメラ、エフェクト、サウンド、ラベル表示など

    • Markerを活用して演出からシステム処理のタイミングを制御 ◦ 演出側で指定したタイミングでダメージ処理やSE再生などを行う
  178. • ヘブンバーンズレッドではTimelineが様々なシチュエーションで活躍 ◦ スキル、カットシーン、登場演出など • Timelineで演出のほぼ全てを制御している ◦ モーション、カメラ、エフェクト、サウンド、ラベル表示など • Markerを活用して演出からシステム処理のタイミングを制御

    ◦ 演出側で指定したタイミングでダメージ処理やSE再生などを行う • Lua処理を走らせることでバトル中に自在に演出を再生 ◦ 会話パートやカットシーンを指定タイミングで差し込む まとめ ©WFS
  179. 179