Monthly archives "5月 2013"

SimCityもどきはEnchantCityと名づけよう

構想一ヶ月前、本格的に着手したのは、ゴールデンウィーク明けなので、はや3週間ぐらいでしょうか。
とりあえず、3割ぐらいはできた。
街に労働者が来て、住居に住み、工場(ダンジョン)に働きに行く。までができた。
といっても、賃金の計上やら、労働者が少ないダンジョンからはモンスターが現れるとかの処理はできてない。
買い物客や学生もできてないけど、これは労働者のアルゴリズムの応用でできるので、あまり問題視してない。
それよりも、問題ありそうなのが、処理が重いことと、建物の破壊と建設を繰り返すと徐々にメモリが増えていくことだ。
ブラウザの対応状況では、
IE: 完全動作
Chrome: BGMがまともに再生されない。(それ以外は動く)
firefox:処理がめちゃくちゃ重い。ボタンの動作がおかしい。
Safari: 読み込みで止まる(オーディオ系のファイルに問題があるみたい)
とIE以外は問題あり。
これから、リファクタリングなどの大改造を施すかも知れないので、とりあえず、現状を中間報告としてアップしておく。
http://9leap.net/games/3339
※前述の通り、問題多々有りなので、動作保証はできません。
※ゲーム内時間で18時になると、労働者が街にやってきて、住居に住みます。そして、翌日6時に工場へ働きに行く。
※道路、住商工の建設&破壊可能。
※なお、BGM、効果音は魔王魂様のサイトから拝借しました。
音楽素材/魔王魂


0

enchant.js Safariでsound.clone()を実行するとメモリリーク

バグっぽいのを見つけたので、enchant.js本家にバグ報告した。
https://github.com/wise9/enchant.js/issues/210

一応、このブログでも報告しておく。
javascirptのメモリ管理を知りたかったので、タクスマネージャーを眺めていたら、とてつもなくメモリ食っていることに気づき、
調べたら、sound.clone()でメモリリークしているっぽい。
効果音鳴らすゲームなら、簡単に100MB、200MBと食っていくので注意。
ただし、Safariでしか発生しないので、ブラウザのバグなのか、enchant.jsのバグなのか微妙なところ。
以下、本家への報告コピペ。

[環境]
OS: Windows7 64bit
ブラウザ:Safari 5.1.7
enchant.js v0.7.0 (v0.6.3でも同様の現象が発生する)

[発生手順]
●手順1
1.サンプルの examples/expert/action/index.html をサファリで実行する
2.Windows タスクマネージャーを実行し、プロセスタブのWebKit2WebProcess.exeに注目
3.サンプルのhtmlに戻りゲームスタート。上キーを押し続けて、ジャンプし続ける
4.タスクマネージャーのWebKit2WebProcess.exeのメモリが4MBぐらいの単位で増え続ける。
5.サンプルのhtmlの上キーを離してジャンプを止めても、メモリが減らない。

●手順2
examples/expert/action/game.js の92行目の
game.assets[‘jump.wav’].clone().play();
の箇所を
game.assets[‘jump.wav’].play();
に変更して、手順1を実行すると、メモリリークの量が減る。(それでもメモリが僅かに増え続けるので他にもメモリリークしているのかも?)

[コメント]
以上のことから、sound.clone()を実行するとメモリリークが発生するものと思われます。
ただし、この現象はSafariでしか発生せず、firefoxやchromeでは問題ありませんでした。


0

enchant.js用プラグイン exntendMapについて解説する

enchantMapEditorでマップ拡張を有効にして吐き出したコードはenchant.js用プラグインexntendMap (ExMap)で読み込む必要がある。

以下がExMapの使い方である。

window.onload = function() {
	var core = new Core(320, 320);
	core.preload('map0.gif');
	core.onload = function() {
		var backgroundMap = new ExMap(16, 16);
		backgroundMap.image = core.assets['map0.gif'];
		backgroundMap.loadData([
		    [39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39],
		    //...マップデータの定義
		    [107,107,107,38,4,22,22,22,22,23,107,107,107,107,107,107,107,107,107,107]
		]);
		backgroundMap.collisionData = [
		    [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
		    //...当り判定の定義
		    [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
		];
		core.rootScene.addChild(backgroundMap);
	}
}

map0
(上の画像がmap0.gif)

このコードでマップデータで定義されたマップが画面に表示される。
ここで疑問なのは、マップデータの39や107などの数字は何を示しているのか?
この数字はマップのチップ番号を示していて、左上を0として右へ16ドット単位で0,1,2,3と連番を振り一番右まで行ったら改行して、さらに2行目3行目・・・と連番を振ったものだ。
だた、読み込んだ画像ファイル(map0.gif)そのものを使っているのではなく、加工を加えた画像を使っている。

		backgroundMap.image = core.assets['map0.gif'];

imageプロパティ内で、加工を加えている。
exmap0
上の画像が加工を加えた結果だ。

この加工のルールは、
元の画像ファイルのうち、左側の縦横96×256をマップのフィールド画像と仮定して、
さらに48×60の単位でフィールドのタイプとして仮定して、
それぞれの他のフィールドとの境界線のバリエーションを生成している。
この加工された画像は縦横サイズ276×512に拡張されている。
よって、チップ番号は0~551までの連番になる。
要は元の画像を元にしたチップ番号ではなく、加工した画像を元にしたチップ番号であることに注意すること。

また、このフィールドのタイプ知ることもできる。

	var type = backgroundMap._typeData[0][0];

上記は座標(0,0)のタイプを取得するコードだ。
最初のマップデータの例では、typeには0が入ってくる。
typeの数字はマップのフィールドのうち、左上から1行目1列目を0、1行目2列目を1、2行目1列目を2・・・4行目2列目を7とした0~7までの数字である。
map0_no


0

enchant.js用マップエディタenchant.js Map EditorをjQuery UIに置き換えてみた

勉強がてら、enchant.jsの公式マップエディタenchantMapEditorjQuery UIに置き換えてみた。

jQuery UI版enchant.js Map Editor
http://9leap.net/games/3338/

機能は公式とほぼ一緒だが、公式はsafariでしか動かなかったが、こちらはIE,chrome,safariで動く。
※firefoxではレイヤーが切り替えられないバグがある。
※上記のフレームをクリックするとMap Editorを操作できるが、フレームが狭すぎてまともに使えないので、こちらから開くことをおススメする。

画面構成を解説します。
[画面]
Create Mapボタン:
起動したらまず最初にこのボタンを押して、横のチップ数、縦のチップ数などを指定してマップを作成する。

Import Mapボタン:
すでに作成済みのMapデータをインポートする。エクスポートと同じ書式のコードから読み込む。

Undo:
アンドゥ(履歴は1回しか覚えていない)

Tool bar:
ドローツール。pen(ペン),fill(塗りつぶし),straight(線),rect(矩形)がある。

selected chip:
パレットから選択したチップを表示

eraser chip:
消しゴムチップ

palette:
マップに配置したいチップをクリックして選択する。選択したチップはselected chipに表示される。

Export Mapボタン:
作成したマップのコードを表示する。ユーザーはこのコードをコピーして自分のプログラミングにペーストして反映させる。

Add Layerボタン:
マップのレイヤーを追加する。
※現在レイヤー追加は未対応。UIは実装したが、内部処理を実装していない。

collision detectionタブ:
当り判定を配置するレイヤー

Layer 0タブ:
チップを配置するレイヤー(ベースとなるフィールドを配置)

Layer 1タブ:
チップを配置するレイヤー(フィールドの上に建つ建物などを配置)

enchant-stage:
マップにチップを配置する。Create Mapボタンで作られる。

使い方を順を追って解説します。(チュートリアル)
enchantMapEditor01
1.まずenchantMapEditorを開いたら、
Create Mapボタンを押して、マップ作成ダイアログを開きます。

enchantMapEditor02
2.マップ作成ダイアログを開いたら、
Number of chips for width: マップの幅のチップ数(チップのサイズは16ドット固定ですのでマップの幅はチップ数*16になります。デフォルトでは20個になっています。これは20*16=320でマップ幅は320ドットになります。)
Number of chips for height: マップの高さのチップ数(チップのサイズは16ドット固定です。デフォルトでは20個になっている)
Image: マップの画像ファイルの種類を指定します。RPG用と2Dスクロール用が用意されています。RPGを指定するとhtmlファイルを同じディレクトリにあるmap0.gifを読み込み、2Dスクロールを指定するとmap1.gifを読み込みます。画像ファイルは置き換えることも可能ですが、256×256のサイズを想定しています。
Enable MAP EXTENTION:マップ拡張と言う機能を有効するか指定します。マップ拡張とはRPGのフィールドマップを作成する場合に、海岸線や森と平原の境目を自動補間する機能です。主にRPG(map0.gif)用の機能になりますので、2Dスクロールの場合はチェックを外してください。
以上を設定して、Create a new mapボタンを押してください。

enchantMapEditor03
3.マップ作成ダイアログの設定にしたがって、パレットにマップ画像ファイルが読み込まれ、enchant-stageに指定したサイズのマップが作られます。

enchantMapEditor04
4.paletteのどこかをクリックすると、描画したいチップを選択できます。この例では草原あたりをクリックします。
マップ拡張を有効にしていると、パレットの左側96×256をそれぞれ48×64を同一のタイプとして認識(例では海、草原、石造物、砂漠、床、森、ダンジョンの床、穴)し、そのタイプを選択したことになります。(例えば、海の海岸線チップは選択できず、海岸線はenchant-stageへ描くときに自動補間され書き込まれる)
マップ拡張を無効にしていると、タイプとして認識せず、選択したチップをそのまま認識します。

enchantMapEditor05
5.ツールバーでペンを選択し、enchant-stage内で適当にドラッグすると選択したチップが描き込まれます。

enchantMapEditor06
6.さらに、ツールバーでfill(塗りつぶし)を選択し、パレットで海タイプを選択し、enchant-stage内の空白部分を適当にクリックすると、空白を海で塗りつぶせます。草原との境界はマップ拡張機能により自動補間されます。

enchantMapEditor07
7.当り判定も設定してみましょう。
ツールをペンに変え、collision detection(当り判定)をクリックし、enchant-stage内の海岸線に沿ってクリックすると、当り判定を設定できます。
当り判定は初期値0になっており、設定した箇所は1が入ります。ゲーム上で当り判定1の場合はプレイヤーがそこを通れないといった処理に使えます。

enchantMapEditor14
8.レイヤーは2つ使えます。
レイヤー0ではフィールドを設定し、レイヤー1では建物を設定するのに適しています。
建物を建ててみましょう。
パレットから建物(この例ではダンジョン)をクリックし、Layer 1をクリックしてレイヤーを切り替え、enchant-stageの草原をクリックすると、建物が建てれます。

enchantMapEditor09
9.ここまで作ったら、作成したマップをエクスポートしてみましょう。
Export Mapボタンを押します。

enchantMapEditor10
10.するとエクスポートダイアログが開きます。

enchantMapEditor11
11.テキスト内をドラッグ&ドロップで選択し、Ctrl+Cでテキストをコピーし、自分のゲームのソースコード内に貼り付けてください。

以上でチュートリアルは終わりですが、その他の機能についても説明しましょう。
enchantMapEditor12
12.インポート機能について説明しましょう。
インポート機能とは、エクスポートでコピーしたマップのソースコードを貼り付けて、再編集するときに使います。
また、現在編集中のマップをソースコードレベルで編集したいときにも使えます。
では、手順を説明します。
Import Mapボタンを押してください。

enchantMapEditor13
13.インポートダイアログが開きます。
テキスト内には、エクスポートで表示されるソースコードを同じソースコードが表示されています。

enchantMapEditor14
14.この例では現在編集中のマップをソースコードレベルで編集してみましょう。
スクリーンショットの赤丸で囲っている部分の数字がマップのレイヤー0のx:0,y:0のチップ番号になります。
これを別のチップ番号に変えてみましょう。(例ではダンジョンのチップ番号を指定している)
変え終わったら、Import a crated mapボタンを押します。

enchantMapEditor15
15.すると、左上x:0,y:0がダンジョンに置き換わっています。

enchantMapEditor16
16.レイヤーの追加について説明します。
ただし、現在レイヤー追加機能は正しく動きませんので、予備知識ぐらいに考えておいてください。
UIとしては機能しているのですが、内部の機能を実装していません。
と言うのも、ほとんどのマップは2レイヤーで収まってしまうと思うので、作る必要が無いかなと思って作ってません。
必要だよと言う方がいたら作りますので、コメント等々いただければと思います。
では、説明します。
まず、Add Layerボタンを押してください。

enchantMapEditor17
17.Layer 2が追加されます。

enchantMapEditor18
18.レイヤーは削除するこも可能です。
Layer 2の隣のバツボタンを押すと削除できます。

enchantMapEditor19
19.Layer 2が削除されました。

以上で、スクリーンショットを使った解説を終了します。

せっかくなので、ファイル構成も解説しておきます。

index.html
公式のmapeditor.htmlをindex.htmlに名前を変更したうえで大幅変更。
公式ではhtmlにはenchant-stageタグとeditタグしか存在せず、その他のタグはjavascriptで生成していたが、こちらはタグ構成をすべてhtmlに書いてある。
jQuery UIのサンプルを参考に書いた。

main.js
公式の同名ファイルから大幅変更。
enchantの初期化とjQuery UIのスクリプトが書いてある。
今回の変更の大半はこのファイルをjQuery UIのスクリプトに置き換える作業になった。

mapeditor.js
公式の同名ファイルから多少変更。
ehchantのcoreの初期化とenchant-stageタグのタッチイベントハンドラが記述してある。
タッチイベント(マウスクリックイベント)でマウス位置が正しく入ってきてなかったり、イベント自体が発生しなかったりなどのバグっぽい動きを修正した。

drawing.js
公式の同名ファイルからほとんど変更なし。
plugins/extendMap.enchant.js を更に拡張してドローツールのpen,fillなどの機能が記述されている。
Export Mapで吐き出す文字列をgame.からcore.に変更したぐらいで、ほとんど変更なし。

enchant.min.js
いわずと知れたehchant.jsの本体。
公式はv0.3と古いバージョンが使われていたが、jQuery UIとの相性が悪くinputタグが動かなかったので、最新版v0.6.3に変更した。

plugins/extendMap.enchant.js
enchant.jsのマップ拡張プラグイン
これもv0.3からv0.6.3へ変更した。

jsディレクトリ
jQueryとjQuery UIの本体が入っている。

css/main.css
スタイルシートまわりを個別ファイルとして新規追加した。
jQuery UIのサンプルを参考に書いた。

css/imagesディレクトリ
ツールバーや消しゴムチップ、アンドゥのアイコンのpngファイルが入っている。
main.cssで参照している。

css/ui-lightnessディレクトリ
jQuery UIの公式スタイルシート。
ui-lightnessというテーマを使っている。

[今後対応したいこと]
1.パレット用の画像ファイルを読み込めるように。
 今は画像固定、画像を変えたければツールをダウンロードして、ローカルで差し替える必要がある。
2.Create Mapをしたあともう一度Createすると、落ちるのを直す。
 今は再度Createしたい場合は、ページを読み直す必要がある
3.firefoxでもレイヤーが切り替わるように。(原因不明、firefoxか、jQuery UIのバグか?)
4.レイヤーの追加・削除の内部処理に対応
5.Import Mapでレイヤーが追加された場合にGUIに反映させる。


2

Map Editorにenchant.js v0.6.3を適用すると正常動作しない問題の解決法

enchant.js用マップエディタenchantMapEditorをjQuery UIに置き換えてみた
http://blog.chat.ac/?p=157
上記の作業中に発生した問題の解決法を備忘録として記す。

enchant.js公式のマップエディタ
https://github.com/wise9/enchantMapEditor
ですが、
これに使われているenchant.js はv0.3と非常に古いバージョンが使われている。
古いバージョンが使われていること自体は問題ないが、
プログラミングの勉強がてらjQuery UIを使ってUIを作り直していたら、
htmlのinputフォームが正常動作しない(inputをクリックしてもアクティブにならない)問題が発生。
原因は良く分からないが、enchant.js v0.6.3を使ったら問題解決した。
しかし、enchant.js v0.6.3を使うと、今度はMap Editorでチップが配置できない(enchant-stageをクリックしてもチップが置かれない)問題が発生。
この問題解決にコードをいじったので、修正箇所を記す。

mapeditor.jsの処理をのぞくと以下の処理を行っていた。
mapeditor.js 116行目

		var editScene = new Scene();
		this.sx = 0;
		this.sy = 0;
		editScene.addEventListener('touchstart', function(e) {

mapeditor.js 163行目

		editScene.addEventListener('touchmove', function(e) {

mapeditor.js 206行目

		game.pushScene(editScene);

このeditSceneはタッチイベントのためだけに作られたシーンのようだ。
これが問題のようで、enchant.js v0.6.3では内部処理が変わったのか、editSceneにはチップがロードされていないのに、editSceneに対してチップを描画しようとして、描画できなくなっていた。
それならば、実際チップを持っているgame.rootSceneにイベントをハンドルすることで解決。
具体的には以下のコードに修正する。
mapeditor.js 116行目

		//var editScene = new Scene();
		this.sx = 0;
		this.sy = 0;
		game.rootScene.addEventListener('touchstart', function(e) {

mapeditor.js 163行目

		game.rootScene.addEventListener('touchmove', function(e) {

mapeditor.js 206行目

		//game.pushScene(editScene);

0