ラベル 9leap の投稿を表示しています。 すべての投稿を表示
ラベル 9leap の投稿を表示しています。 すべての投稿を表示

2011年11月25日金曜日

CoffeeScript×enchant.js、enchant.jsをCoffeeScriptで書く。



enchant.jsをCoffeeScriptで書直しました。


hanachin/enchant.js ? GitHub


enchant.coffeeというファイルがあるはずです。


サンプルはexample/action-coffee/とexample/action-coffee2/以下に入っています。


理由


僕はCoffeeScriptにハマっています。CoffeeScriptは美しいからです。


functionを書かなくていいし、全て式なのでreturnを書かなくていいし、後置でifが書けるし、デフォルト引数もあるし、内包表記が凄く便利だし、?オペレータもかなり便利です。


僕はenchant.jsにもハマっています。enchant.jsは素早くゲームが作れるし、スマートフォンでもサクサク動くし、書いていて楽しいから。


enchant.jsがCoffeeScriptで書けたらいいな… そう思ってた時期にHotRubyからenchant.jsを使う記事を読みました。


wise9 › Ruby on enchant.js / RubyでHTML5ゲームを作ってみる


その中にはこう書かれていました。



ならCoffeeScriptで書けばいいじゃん、という意見もあるだろうけど、ここでは聞かなかったことにする。

僕はCoffeeScriptで書けばいいじゃん、と思った。


思ったからには書かねばならない。情熱が覚めないうちに。


まだまだ全然CoffeeScriptらしく書けてませんが公開します。


ちなみにenchant.coffeeの行数は2295行、元のenchant.jsが2685行なので14.5%、390行程度ソースコードの行数が減りました。


サンプルのアクションゲーム


9leap : enchant.coffeeサンプル by hanachin_ - どこでも遊べる、投稿型ゲームサイト


メソッドをオーバーライドするだけで動作


9leap : enchant.coffeeサンプル2 by hanachin_ - どこでも遊べる、投稿型ゲームサイト


ソースコードはこんな感じ



enchant()

class Bear extends Sprite
constructor: (w, h, image) ->
super 32, 32
@image = Game.instance.assets[image]
@x = 0
@y = 0

enterframe: (e) ->
@x = @x + 1

game = new Game(320, 320)
game.fps = 24
game.preload('chara1.gif')

game.onload = ->
bear = new Bear(32, 32, "chara1.gif")
game.rootScene.addChild(bear)

game.start()


もちろんenterframeだけでなく他のイベントにも対応しています。


実装について


全体的に

不要なfunctionを置換したりインデントを揃えるので時間がかかった。


メソッドのオーバーライドでイベントドリブン

EventTargetクラスのコンストラクタで



constructor: ->
@_listeners = {}
# Eventクラスで定義されたイベント名と
# 同じ名前のメソッドを持っていれば呼び出すようにする
for own prop, ev of enchant.Event
@addEventListener(ev, ((ev) -> ((e) -> @[ev](e) if @[ev]?))(ev))


enchant.Eventクラスの持つイベント名に対して、それぞれイベントリスナを追加しています。


イベントを受信した際に、クラスがそのイベント名と同じ名前のメソッドを持っていれば、それを実行するようになっています。


現状




  • サンプルのゲームが動く

  • メソッドをオーバーライドする形でのイベントドリブンプログラミングが出来る

  • CoffeeScriptのデバッガがないのでデバッグしづらい

  • GitHubにてオープンソースで公開


これから


バグがあれば直しますので@までご報告ください。


なるべくenchant.jsの機能追加等に追従出来るようにしようと考えています。


後は9leapのプラグイン等をCoffeeScriptで書直します。


enchant.coffee自体も整理したいのですが、まずは9leapで実際に使えるようになることを目指します。


質問等


何か質問等ございましたらTwitterで@宛にmentionをください。


もしくは以下のアドレスまで連絡をください。


http://services.nexodyne.com/email/icon/5JhEZ.J3qJ4%3D/LFg9q1s%3D/R01haWw%3D/0/image.png


よろしくお願いします。





2011年10月26日水曜日

enchant PROを使ってゲーム開発してハマったとこ4つとこれからいじりたいとこ



enchant PROを使ったゲーム一番のりです


3Dスロット風ゲームです。


9leapアプリから「ぼか☆すろ」を開いて遊ぶ事が出来ます。


9leap : ぼか☆すろ by hanachin_ - どこでも遊べる、投稿型ゲームサイト


http://dl.dropbox.com/u/3622136/9leap/play.png


このエントリでは開発環境と、アプリ開発中にハマったところ4つと、これからいじりたいとこを書きます。


開発環境について


ソース書くのはMacBook Airで作業しました。


enchant PROを使用した作品の動作確認にはAndroidの実機が必要だと考え、開発用の実機としてICONIA TAB A500を学校から借りました。


しかしICONIA TABではOrientationセンサーと3Dしか動作が確認出来ませんでした。


またCameraはlogcatのログを読む限りでは初期化されてるようですがプレビュー表示が出来ませんでした orz


なので今回は3Dだけを使ったゲームを作ることに決めました。


ハマったところや問題点


※僕の環境(とその時試した状態)ではうまく動かなかったけど、他の人のところでは問題なく動くかもしれません


ゲームのソースは9leap : ぼか☆すろ by hanachin_ - どこでも遊べる、投稿型ゲームサイトから入手出来ます。


1. プラグインの読み込み


enchant('nineleap');


enchant.js初心者なので明示的にプラグインの名前を指定する方法を知らず、プラグインが読み込まれないことがありハマりました。


2. 縦長の画面におけるGameのtouchイベントの発生するエリアとScene3Dの描画エリアの違い


game = new Game(320, 320);


という風にGameクラスのインスタンスを作成しています。


Scene3Dは縦長の画面全体を使って描画されてるっぽいです。


画面全体のうちどこかを触ったときに何かしたいとき



game.rootScene.addEventListener('touchstart', function (e) {
// ...
});


このようにSceneのtouchstartイベントに書くと赤線で囲った範囲しか反応しません。


http://dl.dropbox.com/u/3622136/9leap/touch_area.png


Gameクラスを320x320で初期化しているからだと思います。


ちなみに未解決です。いい方法あったら教えてください。


3. Labelで描画したテキストの残像が消えない


var label = new Label('foobar'); // 1
game.rootScene.addChild(label);
label.text = 'hoge'; // 2
label.text = 'fuga'; // 3


のようなコードで、1で初期化したテキストの描画が2でテキストを再設定した後も消えず、3で再設定すると2は消えるが1は残ったまま、というような事がありました。


9leapにあがっているARサンプルでも同じ現象を確認しました。


なので、それを解消するためにこのようなコードを書きました。



var bg = new Sprite(100, 20);
bg.backgroundColor = '#fff';
game.rootScene.addChild(bg);

var score = 100;
var scoreLabel = new Label('score: ' + score);
var updateScore = function () {
bg.x = 0;

scoreLabel.text = 'score: ' + score;
}
scoreLabel.addEventListener('enterframe', updateScore);
game.rootScene.addChild(scoreLabel);


スコアを毎フレーム再表示する処理です。


スコアを表示するLabelの後ろに背景Spriteを設置しています。


scoreLabel.textを再設定する前にそのSpriteのxを移動させて背景を再描画し、labelのtextの残像を消しています。


4. 箱が明るくならない

箱を明るく表示させたいのに3Dのボックスの明るさのいじり方が分からず暗いままでした。


http://dl.dropbox.com/u/3622136/9leap/play_old.png


結論からいうと箱を自己発光させました。


surface.emission、Surface3Dのemissionというプロパティに値を渡すことで発光させる事が出来ました。



surface.emission = [0.8, 0.8, 0.8, 1.0];


箱を明るく表示させるためには光源の位置を移動させるなどの方法があると思いますがドキュメントにそれらしい事が書いてありませんでした。


このemissionというプロパティもenchant PROのドキュメントには書かれていませんでした。


enchant PROのソースを読むとSurface3Dでまだドキュメントが用意されてないプロパティとして




  • ambient

  • diffuse

  • specular

  • emission

  • shininess


などがありました。


EP_GLという変数を通してAndroid側のOpenGLのオブジェクトをいじっているようです。


なので




  1. emissionなどのプロパティに渡す値はOpenGLの同等の関数に渡す値を渡せばよい

  2. JSで渡すならどうするだろう?


と考え、配列を渡すことで上手く発光させる事が出来ました。


これからenchant PROをいじるなら


EP_はおそらくenchant PROの頭文字を取った接頭辞で、他にもEP_がついてる変数が




  • EP_SENSOR

  • EP_CAMERA

  • EP_ZXING

  • EP_AR

  • EP_MEDIA

  • EP_SOUND


など、いくつかあります。


これらのオブジェクトの持つプロパティについてどうなってるのか、気になります。


for in文を使ってこれらの持つオブジェクトのプロパティやメソッドを調べたいですね。


まとめ


4つほどつまずく事もありましたがAndroidネイティブの機能を手軽に呼び出すことが出来ました。


今後使う人が増えたりドキュメントが充実したり情報が増えるといいなー!





2011年10月16日日曜日

OJAG workshop@Naha Vol.12に参加してゲーム作ってきた!



昨日は日本Androidの会 沖縄支部の勉強会に参加しました。


成果物は9leap : OJAG Naha Hackathon by hanachin_ - どこでも遊べる、投稿型ゲームサイト


今回の勉強会は




  • 9leapの伏見様(@)のお話


    • 今回のために来沖(日帰り)してくださったみたいです。超ありがたいです。

    • enchantと9leapの紹介

    • ライブコーディング



  • enchant.jsを使ったハッカソン!


    • ハックとマラソンを掛け合わせた言葉で皆で集まって開発する感じのイベント

    • 今回は2時間半ちょい黙々とゲーム作成。



  • 懇親会


    • 10時間で21本ゲーム作成の話などなど



  • 懇親会2


    • 居酒屋でMacBookを4台並べながらのアイデアソン




という感じでした。


僕も2時間半ぐらい黙々といじってTouchTheNumbers風のゲームを作成しました。懇親会も楽しかったです。


以下、当日聞いた内容の自分なりのまとめと、ハッカソンで作ったもの、作ってた時の過程を書きます。


9leapについて


9leapという若いプログラマ向けのゲームコンテストサイトがあります。(enchant.jsで作られたゲームが数多く投稿されています)


その9leapのプロジェクトリーダーの伏見様が1時間ほどenchant.jsの紹介とライブコーディングをしてくださいました!(テキストエディタはCotEditorでした)


スライドはまだあがってないようですが内容的には「enchant.js & PRO」第21回 html5とか勉強会 ショートセッションのような感じでした。


enchant.jsについて


enchant.jsはJSでBASICみたいにゲームを短く楽しく書けてしかも軽い、モダンなブラウザがあればどこでもゲームが動く!というすごいものです。


確かに書いてみるとめっちゃ楽でした。1枚の画像にまとめられてる複数の絵を切り出すのがプロパティ指定するだけで出来たり。


ゲームがっつり書いたことない自分でも2時間半で1つゲームが作れました!


こんなに簡単に作れるなんて中身がどうなってるのか気になるので是非enchant.jsソース読みしたい。


あと、ゲームつくり楽しかったのでリトライしてみたくなりました。っていうかリトライしますw


enchant PRO

スマートフォンのカメラ等をenchant.jsから簡単に扱えるらしい。ARも簡単に書けるようでめっちゃ気になる…


ハッカソンで作ったもの


TouchTheNumbers(5x5のますにランダムに配置された1から25までの数字を順番よく押して時間を競うゲーム)を作りました。


先輩のiPod touchでプレイしてハマってしまったのが理由。


動きのあるサンプル見せてもらったのに動きが地味なのもの作ってしまったので後でもっと楽しい感じに書き直そうかと orz


9leapで公開したので以下のリンクからプレイ出来ます!


9leap : OJAG Naha Hackathon by hanachin_ - どこでも遊べる、投稿型ゲームサイト


作ってた時の過程


画像の出し方、移動程度は予習してました。


目標は「必ず完成させて公開する」でした。


私が今受講している週末ものづくり講座の影響です。


ステップ

ステップとしては




  1. 数値を画像に変換


    1. まずは0から9までの変換

    2. それを利用してn桁対応



  2. 数値の入ったますを作る


    1. まずは普通のますを作る

    2. 数値を画像に変換してそのますにのっける



  3. 1から25までの数値の入ったますをランダムに配置

  4. 1から順に押されているかのチェック

  5. 時間の計測

  6. 9leap公開・スコア送信


という感じで進めていきました。


数値の入ったますを作る処理が出来るまででハッカソンの時間の2/3、順に押されてるかのチェックと時間の計測を実装したとこで2時間経過、その後9leap公開、送信ちょっとした修正で30分ぐらいかかりました。


ソース

ソースコードは以下のような感じ。


9leap : OJAG Naha Hackathon by hanachin_ - どこでも遊べる、投稿型ゲームサイトからzipで一式落とせます。



Array.prototype.shuffle = function() {
var i = this.length;
while(i){
var j = Math.floor(Math.random()*i);
var t = this[--i];
this[i] = this[j];
this[j] = t;
}
return this;
}

enchant();

count = 0;

window.onload = function() {
var game = new Game(320, 320);
game.fps = 15;
game.preload('font.png');
game.onload = function() {
function makeBlock(w, h) {
var block = new Sprite(w, h);
block.x = 0;
block.y = 0;
return block;
}
function squareBlock(size) {
var bg = makeBlock(size, size);
return bg;
}
function addBorder(block, size, color) {
var wrap = new Group();
var bg = makeBlock(block.width + size * 2, block.height + size * 2);
bg.x = 0;
bg.y = 0;
bg.backgroundColor = color;
block.x += size;
block.y += size;
wrap.addChild(bg);
wrap.addChild(block);
return wrap
}
function numBlock(n) {
var block = new Group();
block.x = 0;
block.y = 0;
block.width = 44;
block.height = 44;
// 64
var bg = squareBlock(44);
bg.backgroundColor = "#fff";
var bg = addBorder(bg, 2, "#2f4f4f");
block.addChild(bg);

var nums = (""+n).split('').map(function (x) { return parseInt(x); });
for (var i = 0; i < nums.length; i++) {
var sp = numSprite(nums[i]);
sp.x = i * 16 + 8;
sp.y = 16;
block.addChild(sp);
}
return block;
}
function numSprite(n) {
var sp = new Sprite(16, 16);
sp.image = game.assets['font.png'];
sp.x = 0;
sp.y = 0;
sp.frame = n + 16;
return sp;
}

function init() {
// var scene = new Scene();
var scene = game.currentScene;

var nums = [];
for (var i = 1; i <= 25; i++) { nums.push(i); }
nums.shuffle();

for (var i = 0; i < 5; i++) {
for (var j = 0; j < 5; j++) {
var index = (i * 5) + j;
var block = numBlock(nums[index]);
block.x = j * 48;
block.y = i * 48;

var click = (function () {
var n = nums[index];
var b = block;
return function (e) {
var x = e.x;
var y = e.y;
if (b.x < x && x < b.x + 48
&& b.y < y && y < b.y + 48
&& count == n) {
count++;
b.backgroundColor = "black";
var paint = squareBlock(48);
paint.x = b.x;
paint.y = b.y;
paint.backgroundColor = "#fff";
scene.addChild(paint);

if (count == 26) {
var score = Math.floor((start / game.fps) * 10)/10;
game.end(10000 - score, "Your score is " + score);
}
}
}
});
block.addEventListener("touchstart", click());

scene.addChild(block);
}
}

count = 1;

//game.replaceScene(scene);
}

init();

start = 0;

game.rootScene.addEventListener('enterframe', function () {
start++;
});
};
game.start();
};


感想


ハッカソン楽しい。動いたもの公開して人が遊んでくれるとやっぱり嬉しい。


ゲームプログラミングやるとプログラミングが出来るよになるというのも話されていたのでゲームを作りたい。


そして作ったゲームを9leapにドシドシ投稿していきたいです。


刺激を受けた部分としては懇親会でお話されていた10時間で21本というのを聞いて自分も手をもっと早く動かせるようになりたいなぁ、と。


# enchant PROのARやTwitterでやりとりされていたnode.jsでエアホッケーとかすごく楽しそう