gl.enchant.jsを試しみた印象

canvas2dをネイティブでゴリゴリ書いちゃうので今までenchant.js使う機会なかったのだけど、gl.enchant.jsは便利そうだったのでenchant.jsにも慣れようと思い使ってみた。
参考にしたのはgl.enchant.js 入門 – ざっくりと作る流れをまとめてみました!! | TM Life だけど、とりあえずキー入力を受けて移動するプレイヤーオブジェクトと、それに追従する三人称カメラまで作った。

見てて難易度が高くみえるけど、何をいじれば何が変化するかを目視で印象つかめば学習が早い。(最近TDDで頑張ってたけど、こういうのは目視しないと全体の印象が掴めない)

基本的にコード中に回転行列とか、オブジェクトのレイヤーを示すであろう謎のバイナリ列がでてきて気持ち悪くみえるのだが、そこは頑張ってスルーして必要になったときに読めばいいのであろう。

三人称カメラ、いまんとこプレイヤーオブジェクトに対する相対座標で、回転はやってないんだけど、回転させるときは入力された向きに対して三角関数で変換してやればいいのかなーってところまでは想像が付く。もうちょっと適当に書いてみたい。

Coffee-Script

で、enchant.jsはenchant.Class.createというメソッドを定義してクラスと継承を実現しているのだけど、constructorというメソッドをnewしたときに呼び出すのはCoffee-Script互換なので、そのままCoffee-Scriptで書けちゃうっていう。上記のコードをOOP書くとこうなった。

main.coffee

enchant()
game = null 

class Player extends Sphere
  constructor : (x,y,z)->
    super()
    [@x,@y,@z] = [x,y,z]
    @phi   = 0
    @theta = 0
    @offsetX = 0
    @offsetY = 0
    @matrix = new mat4.create()
    @mesh.texture = new Texture("../../images/enchant-sphere.png");

  update_position : (input)->
    @phi -= 0.05
    @theta += 0.05 

    @y += 0.1 if input.up
    @y -= 0.1 if input.down
    @x -= 0.1 if input.right
    @x += 0.1 if input.left

    # rotation
    mat4.identity(@matrix)
    mat4.rotateY(@matrix, @theta)
    mat4.rotateX(@matrix, @phi)
    @rotation = @matrix


class ThirdPersonCamera extends Camera3D
  constructor : (@player)->
    super()
    [@x, @y ,@z] = [@player.x,@player.y-90,@player.z-20]
    [@centerX, @centerY ,@centerZ] = [@player.x,@player.y,@player.z]

  update_position : (input)->
    if input.up
      @centerY += 0.1
      # @y -= 0.1
    if input.down
      @centerY -= 0.1
      # @y += 0.1

    if input.right
      @centerX -= 0.1
      @x -= 0.1
    if input.left
      @centerX += 0.1
      @x += 0.1


class MyScene3D extends Scene3D
  constructor : (@root)->
    super()
    @input = @root.input

    light = new DirectionalLight
    light.directionZ =-1
    light.color = [1.0, 1.0, 1.0]
    @setDirectionalLight(light)

    @player = new Player 1,1, -2
    @addChild(@player)

    camera = new ThirdPersonCamera(@player)
    @setCamera(camera)

    @root.addEventListener "enterframe", (e)=>
      @player.update_position(@input)
      camera.update_position(@input)

    for x in [-5..5]
      for y in [-5..5]
        obj = new Cube
        [obj.x , obj.y , obj.z ]  = [x*3,y*3,0]
        @addChild(obj)


class MyGame extends Game
  constructor : ()->
    super(640,640)
    @fps = 30
    scene = new MyScene3D(@)

window.onload = ->
  game = new MyGame
  game.start()

オーバーロードしてsuperで呼んで継承するとだいぶすっきり書ける。ゲームの規模が大きくなるとだいたいクロージャの規模で苦労することになるので、クラスごとに変数持たせたいわけで。
ここまで3時間ぐらい。

あと問題は、僕が3次元の行列計算に関する知識がほとんどないので(2Dアフィン変換がギリギリ)、ベースとなるシステム作った後は、他人が作ったモジュールでゴテゴテ足していくことになるんだろうなー