とある地味なブログ

プログラミングとお絵かきに関する雑記。

ScalaでHTML5なゲームを作る

Scala.jsとEaselJSを使ってブラウザ上で動くゲームを作る。

ゲームエンジン使えば楽勝では?

JavaHTML5なゲームを作るなら、 libgdx が定番ぽい。

だけど、現状、ScalaHTML5なゲームを作るのには対応していないらしい。

これは、libGDXがJavaJavaScriptコンパイルデバッグ実行するのに GWT Project っつうツールを使っているから。

Scala.js + EaselJSを使う

ScalaJavaScriptに変換するやつといえば、 Scala.js

Java中間コードをjsに変換しているらしいので、一部のネイティブコードに依存している処理以外は動く。 ゲーム制作上で躓くのは、Thread.sleep()が使えないところくらいかな?

生のHTML5 Canvasを取り扱うのは(クリックイベントの取得などで)死ねるので、

CreateJS | A suite of JavaScript libraries and tools designed for working with HTML5

を使う。

Scala.jsのHello, World!

Basic tutorial - Scala.js

ここの通りにやれば動くと思う。たぶん。

Scala.js + EaselJSのHello, World!

build.sbtに以下の行を追加する。

libraryDependencies += "com.scalawarrior" %%% "scalajs-createjs" % "0.0.2"
jsDependencies += "org.webjars.bower" % "EaselJS" % "0.8.2" / "lib/easeljs-0.8.2.combined.js"

scalajs-tutorial-fastopt.html<head>内に、以下のタグを追加する。全画面ゲーム用の設定だよ。

    <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no"/>
    <style>
        #game-canvas {
            display: block;
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
        }
    </style>

以下のように<canvas>タグにidを追加する。

<canvas id="game-canvas"></canvas>

src/main/scala/tutorial/webapp/TutorialApp.scalaを以下のように書き換える。

package tutorial.webapp

import com.scalawarrior.scalajs.createjs.{Event, Stage, Text, Ticker}
import org.scalajs.dom

import scala.scalajs.js.JSApp

object TutorialApp extends JSApp {
  def main(): Unit = {
    dom.window.addEventListener("load", (_: dom.Event) => onLoad())
  }

  def onLoad(): Unit = {
    val canvas = dom.document.getElementById("game-canvas").asInstanceOf[dom.html.Canvas]
    val stage = new Stage(canvas)
    val text = new Text("Hello, World!", "16px Arial", "blue")
    stage.addChild(text)

    var x = 10.0

    // 30fpsでゲームのメインループを回す
    Ticker.setFPS(30)
    Ticker.useRAF = true
    Ticker.addEventListener("tick", stage)
    stage.on("tick", { obj: Object =>
      val event = obj.asInstanceOf[Event]

      // 1秒間に10px右に進む
      x += 10 * event.delta / 1000

      text.setTransform(x, 10)

      true
    })
  }

}

これで、ゲームのメインループができたと思う。動かなかったらごめんなさい。

そんなかんじで作ったゲームがこちらにありまうす。 よければ遊んでみてね。