Skip to content

Ikagaka/ikagaka-shell-state

Repository files navigation

ikagaka-shell-state

1スコープのサーフェスのレイヤーのステートマシンです

async function main (){
  const dir = await NarLoader.loadFromURL("/nar/mobilemaster.nar");
  const dic = await cvt(dir.getDirectory("shell/master").asArrayBuffer());
  const shell = await ShellLoader.load(dic); // https://github.com/Ikagaka/ikagaka-shell-loader
  const shellState = new ShellState(shell);
  const scopeId = 0;
  const surfaceId = 0;

  function render(scopeId: number, surfaceId: number, tree: SurfaceRenderingTree): Promise<void>{
    console.info(tree);
    // something canvas rendering
    return Promise.resolve();
  }

  const srfState = shellState.createSurfaceState(scopeId, surfaceId, render);
  
  await sleep(30 * 1000);

  srfState.destructor();
}

API

export declare class ShellState {
    constructor(shell: Shell);
    destructor(): void;
    /**
      * サーフェスのステートマシンを構成して開始します。
      * 描画すべきタイミングで引数に渡した renderer 関数が呼ばれます。
      * tree: SurfaceRenderingTree は現在表示すべきレイヤ状態です。
      * renderer は 渡された引数を元に何らかの方法で何らかの対象に描画します。
      * renderer は 描画の終了を知らせる Promise を返してください。
      */
    createSurfaceState(scopeId: number, surfaceId: number, renderer: (scopeId: number, surfaceId: number, tree: SurfaceRenderingTree) => Promise<void>): SurfaceState;
    /** デバッグ用 collision 領域の表示 */
    showRegion(): void;
    hideRegion(): void;
    /** 着せ替えのオンオフ */
    bind(category: string, parts: string): void;
    bind(scopeId: number, bindgroupId: number): void;
    unbind(category: string, parts: string): void;
    unbind(scopeId: number, bindgroupId: number): void;
}

export declare class SurfaceState {
    /** アニメーションを停止しリソースを開放する */
    destructor(): void;
    /** レイヤを構成して描画関数を呼ぶ */
    render(): Promise<void>;
    /** アニメーション再生タイミングを開始・停止 */
    begin(animId: number): void;
    end(animId: number): void;
    /** 全てのアニメーション再生タイミングを停止 */
    endAll(): void;
    /** アニメーションを再生・停止 */
    play(animId: number): Promise<void>;
    stop(animId: number): void;
    /** アニメーションを一時停止・再開 */
    pause(animId: number): void;
    resume(animId: number): void;
    /** talk アニメーションを再生 */
    talk(): void;
    /** yen-e アニメーションを再生 */
    yenE(): Promise<void>;
}

レンダラ設計の指針

レンダラは \0\1 一体分のサーフェスのレンダリングをします。

SurfaceRenderingTree に含まれるのは element 合成済みのベースサーフェスの Id と、 animation*.pattern によって記述された、その前後に表示されるべきベースサーフェスの Id のツリー構造です。

ベースサーフェスの描画に関しては何も指示を与えません。Serikoがそういう仕様だからです。

以下は仮想的なレンダラ Renderer を使うための疑似コードです。

async function main (){
  const dir = await NarLoader.loadFromURL("/nar/mobilemaster.nar");
  const dic = await cvt(dir.getDirectory("shell/master").asArrayBuffer());
  const shell = await ShellLoader.load(dic); // https://github.com/Ikagaka/ikagaka-shell-loader
  const shellState = new ShellState(shell);

  // シェルディレクトリの静的な情報を元にデータを読み込み
  const renderer = new Renderer(shell);

  // 描画先の Canvas などを指定
  renderer.attach($("#some_canvas")[0]);

  // 必要ならばベースサーフェスのプリロードを行う
  await renderer.preload();

  function render(scopeId: number, surfaceId: number, tree: SurfaceRenderingTree): Promise<void>{
    // 描画すべきリソースが未ロードだった場合非同期で読み込むことができる
    return renderer.render(scope, surface, tree);
  }

  // サーフェスのステートマシンを開始する。必要に応じて render 関数が呼ばれるのでその都度描画する。
  const srfState = shellState.createSurfaceState(scopeId, surfaceId, render);
  
  
  await sleep(30 * 1000);

  srfState.destructor();
}

サーフェスを変更する前に srfState.destructor() を呼んでステートマシンを停止しておく必要があります。 それから createSurfaceState して新しいサーフェスのステートマシンを開始してください。

develop

src/Renderer にレンダラの参考実装が用意してあります。 playground.html で試すことができます。

npm run init
npm run build
npm run test
npm run play