js_of_ocamlとenchant.js

TypeScriptとenchant.jsの相性悪いという話があったけどjs_of_ocamlも辛い。
enchant.Class.createをうまく扱う方法が思いつかない。

継承使わずに分厚いラッパー用意するほうがいいのかも。

open Js

module Enchant = struct
  let enchant =
    Unsafe.variable "enchant"

  let init modules =
    let ms = jsnew array_empty() in
    modules
    |> Array.iter (fun m ->
      ignore @@ ms##push(string m));
    ignore @@ Unsafe.fun_call (Unsafe.variable "enchant") [|Unsafe.inject ms|];
    ()

  let new_game w h =
    let game = Unsafe.variable "Game" in
    jsnew game (w, h)

  let game_assets game key =
    let g = Obj.magic game in
    Unsafe.get (g##assets) (string key)
end

module E = Enchant

let _ =
  E.init [||];
  Dom_html.window##onload <- Dom_html.handler (fun _ ->
    let game = E.new_game 320 320 in
    game##enemy_speed_ <- 1;
    game##preload(string "chara1.png", string "map0.png");

    let bear_class =
      E.enchant##_Class##create
        (E.enchant##_Sprite,
         Unsafe.obj
           [|
             "initialize", Unsafe.inject @@ wrap_meth_callback (fun this x y ->
               E.enchant##_Sprite##call(this, 32, 32);
               this##x <- x;
               this##y <- y;
               this##image <- E.game_assets game "chara1.png";
               this##frame <- 5;
               game##rootScene##addChild(this)
             )
           |]) in

    let enemy_class =
      E.enchant##_Class##create
        (bear_class,
         Unsafe.obj
           [|
             "initialize", Unsafe.inject @@ wrap_meth_callback (fun this x y ->
               bear_class##call(this, x, y);
               this##addEventListener
                 (string "enterframe",
                  wrap_meth_callback (fun this () ->
                    this##x <- this##x + game##enemy_speed_;
                    let frame = (this##age /. 5.0 |> floor |> int_of_float) mod 4 in
                    this##frame <- [|0; 1; 0; 2 |].(frame) + 5)))
           |]) in

    game##onload <- wrap_callback (fun() ->
      game##rootScene##addEventListener
        (string "enterframe",
         wrap_meth_callback (fun this () ->
           if this##age mod 20 = 0 then
             let _ = jsnew enemy_class (0, Random.int 320) in
             ()
         )));

    game##start ();
    _false
  )