赤宿 = Red Inn

素人の試行錯誤と2Dゲームプログラミング

Current Progress

 妥協案を出したトピックを上げていく。

Processing

ローグライクシステムを乗せるためのシステム。プログラミングでシーケンシャルな挙動を実現するのが難しい。現状のシステムは、まさに苦肉の策。

Engineのゲームループ (Engine = Model, UI = View)

 UIがEngineを持ち、Engne.tick()で時間を進めるという図式。行動の決定やアニメーションの再生などを終えると、UIは再びengine.tick()を呼ぶ。

Actionの観察

望ましい条件:
  • Actionの演出(View)は、Engineのコードを変更せずに差し替えられる。
  • ModelとViewは時間的に同期している。
    (=> リアルタイムでModelを表示したとき、Viewと状況が一致する)
  • ActionのViewの差し替えは簡単。
苦肉の妥協案:
  1. Actionを細切れのmotion()に分け、motionのchainとして表現する。
  2. Engineは1Motion起動ごとにUIに制御を返す。(次motionはラムダ式で保存しておく)
  3. ViewはMotionを再生して、再びengine.tick()を呼ぶ。(次motionが呼ばれる)
  4. View.Actions.XxxがEngine.Actions.Xxxを継承し、各motionをoverrideして演出を作る。
  5. Engineに渡されるActionは、View::ActionFactoryにより生成されたものにする。
  • 演出は差し替え可能
  • 時間的に同期
  • 手間は多い(Factory, chainのための制限など)
参考になりそうな記事:

Actionの演出

 ViewSequenceと名付けたQueueに、演出オブジェクトを作っては載せていく。後は再生するだけ。
 演出オブジェクトには、Tweenを使ってもいい。

Controlling

in OOP

 どうやってゲームを動かすか? オブジェクト指向で解決していく。つまり、オブジェクトを考えることで、結果的に時間的な挙動も実現させる。

 Controlという概念を持ち出す。"制御が働く"ニュアンス。Controlオブジェクトのツリーを作り、アクティブなControlが切り替わることによって、GameModeが切り替わる。コンポーネント指向のステートマシンと言えるかもしれない。ただし考えるのは、ステートではなく制御のコンポーネント。たとえば、RoguelikeModeを考えるよりも、EngineTickControl、PlayerControl、StairControlなどを考える。この方が簡単で、しかも適切だと思う。Mode, Stateと言うと、単位が大きすぎるし、分離の仕方が不適切になりやすかった。

 ViewのコンポーネントであるLogControl、AnimationControlなども加えてみた。この場合、ControlがUI世界に『参加』したような格好となる。

Cradle Framework

 UI.update()はこれの更新をするだけ。

pub class Cradle {
  ctrls: [Control];
  stack: [Control];
  pub update() {
    self.stack.peek().update();
    ...
  pub get<T: Control>() -> T? { self.ctrls.firstOrDefault{ it is T } }
  ...

HUD

LogView : Control

 Engine側で複数のログが一度に書き込まれたとき、一つ一つ順番に描画・演出していきたい。

 書き込みがあった場合、View側のキューにメッセージを保存する。ゲームループからのupdate()時、ログの演出中でなければスタックのトップをpop()し、描画を始める。このUpdatableなオブジェクトを消せると尚良いが……。

Flexibility

Entity非依存

 EngineがSomeFramework.Entityに依存しないようにするには。traitが無いと無理か?

Engine/Modelの境界

 全ローグライクで共通のシステムをEngine、ゲーム固有のシステムをModelとするつもりだったが….どうにも分離できない。

Size/Posで型を分けるか?

 今は両方Vec2自前クラスを使っている。