enchant.jsでゲームを作る 9leap編

トライデントコンピュータ専門学校 ゲームサイエンス学科3年の森です。
私はenchant.jsをJavaScriptの勉強もかねて学んで行こうと思います。

前回のブログに書きましたが、9leapに自作のゲームを投稿しました。
今回は9leapへの投稿の方法や、投稿したゲームの中身について書きます。
ゲームは[ここ](http://9leap.net/games/4105)にあります。

##9leap
まず、9leapへの投稿はソースなどを一まとめしたzipファイルを直接投稿することができます。
特に9leapの機能を使わないのなら。
・ゲームデータのzipファイル
・サムネイル用画像
の二つだけ用意すればOKです。

だがしかし、プラグインの一つである「nineleap.enchant.js」を導入すれば、簡単に9leapの機能が使用できるようになります。
機能としては、「スコア機能」「ゲームスタート, ゲームオーバー画像表示」の二つになります。
今回は使いませんが、これを前提条件としたプラグインに「witter のユーザ情報を取得する[twitter.enchant.js]」「Twitterアカウントを使ってログインしているユーザについて、セーブデータを保存する[memory.enchant.js]があります。

nineleap.enchant.jsの使い方の説明。
index.html内のenchant.jsを読み込んでいるところあたりに
[code language=”html”]
<script type="text/javascript" src="./enchant.js"></script> //enchant.js
<script type="text/javascript" src="./nineleap.enchant.js"></script> //9leap(これを書く)
<script type="text/javascript" src="./main.js"></script> //main
[/code]
と書きます。
さらに、main.jsの方のゲームが終わるところ(ゲームクリアorゲームオーバー)に
[code language=”javascript”]
game.end(score, ‘スコア=’+score +’点’); //表示例:「スコア=80点」
[/code]
と書き加える。

そうすると、ゲーム開始時にゲームスタート画像が表示がされ、game.endが呼ばれた際にゲームオーバー画像を自動で表示されるようになる。
注意:imageフォルダ内に[end.png][start.png]が必要になる

##ゲームの説明
ゲームの説明としては。
車に当たらないように階段まで進み、何階層まで到達できるかな?というゲームです。(死んだ際に居る階層がスコアとして残る)
このゲームに組み込んだ機能としては、自動MAP生成機能がメインでになります。
そもそも自動MAP生成のプログラムを作ってから、どうやってゲームにするか考えた物が、このゲームです。
小さな機能として、車が左手の法則で進みます。

今回は[こちらのサイト](http://d.hatena.ne.jp/yaneurao/20130125)のドルアーガの塔方式を見て自分で同じ方式で作ってみました。(他の自動MAP生成の方法も色々のっているので、興味のある人は見てみては?)

上記のサイトではとても詳しく書かれていますが、自分は簡単に「棒倒しの連続ですればいいんじゃね?」と考え複雑な部分はすべて捨てて考えました。
つまり、1を棒と見たとき
[0,0,0,0,0,0,0]
[0,1,0,1,0,1,0]
[0,0,0,0,0,0,0]
[0,1,0,1,0,1,0]
[0,0,0,0,0,0,0]
と交互に棒があるとして、1の四方上下左右のどこか一方の0を1に置き換える。をすべての棒に行えば良い(カンタン!


[0,1,0,0,0,0,0]
[0,1,1,1,0,1,0]
[0,0,0,1,0,1,0]
[1,1,0,1,1,1,0]
[0,0,0,0,0,0,0]
みたいな感じになる。
注意
①この方式だと外枠がない
②棒の斜めの位置には100%棒が来ない

この考えを元に私が書いたプログラムがこちら
[code language=”javascript”]
var blocks = [
[130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130],
[130, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,130],
[130, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,130],
[130, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,130],
[130, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,130],
[130, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,130],
[130, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,130],
[130, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,130],
[130, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,130],
[130, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,130],

[130, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,130],
[130, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,130],
[130, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,130],
[130, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,130],
[130, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,130],
[130, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,130],
[130, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,130],
[130, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,130],
[130, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,130],
[130, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,130],

[130, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,130],
[130, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,130],
[130, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,130],
[130, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,130],
[130, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,130],
[130, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,130],
[130, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,131, 1,130],
[130, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,130],
[130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130]
];
var flagBlock=true;
for(var i=0; i<29; i++){
for(var j=0; j<31; j++){
if(blocks[i][j] == 131){
while(flagBlock==true){
var rand = Math.floor(Math.random() *10);
if(rand%2==0){
//上下
rand = Math.floor(Math.random() *10);

if(rand%2==0){
//上
if(blocks[i-1][j] != 130){
blocks[i-1][j] = 130;
flagBlock=false;
}
} else {
//下
if(blocks[i+1][j] != 130){
blocks[i+1][j] = 130;
flagBlock=false;
}
}
} else if(rand%2==1){
//左右
rand = Math.floor(Math.random() *10);

if(rand%2==0){
//左
if(blocks[i][j-1] != 130){
blocks[i][j-1] = 130;
flagBlock=false;
}
} else {
//右
if(blocks[i][j+1] != 130){
blocks[i][j+1] = 130;
flagBlock=false;
}
}
}
}
flagBlock=true;
}
}
}
//壁部分を木の画像にする
for(var i=0; i<29; i++){
for(var j=0; j<31; j++){
if(blocks[i][j] == 130){
blocks[i][j] = 131;
}
}
}

//実際にMap生成
var map = new Map(16, 16);
map.image = game.assets["./img/map1.png"];
map.loadData(blocks);
[/code]
ちょっと解説
131とは木の画像を表しており、私のゲームでは木=壁となっています。
1は芝生の画像を表しています
130と指定してある理由は、131を探して四方に~と言う書き方をしているので、一旦131以外の数字で誤魔化しているためです。

こうやってMAPを生成した後。車の配置と、ゴールの配置を行います。
ここで一つ問題が起こります。
スタート位置は左上に固定していますが、ゴール位置はランダムで配置しているため、左上からゴールまで行くためのルートがない可能性が生まれてしまいました。
私はそれを防ぐために、ゴールの配置の後スタートまでに、左上からゴールまで行くためのルートを調べて。
スタートしても良いかどうかをチェックしています。

方法としては、初めに左上をチェックしておき、次からはチェックしてあるマスの四方のマスでチェックしていないマスでかつ木があるマスでもないマスをチェックしていく。これを「ゴールがあるマスにチェックが入るか」「前の状態から1つもチェックが入らなかった」の条件に入るまで繰り返すと言う方法を取っています。

後は、「自キャラが木があるマスに入らない」「自キャラがハートに当たるとHP回復」「自キャラがNPCに当たるとHP減少」「自キャラがゴールのあるマスに入ると初期化してステージ番号と敵を一つ増やす」といった処理をしてゲームができています。

色々試行錯誤しながら作ったのでソースは正直きれいではありませんが、興味のある方は9leapの下のほうに「このゲームをzip形式でダウンロード」という所からダウンロードできます。

enchant.jsでゲームを作る  サンプルプログラム集

トライデントコンピュータ専門学校 ゲームサイエンス学科3年の森です。
私はenchant.jsをJavaScriptの勉強もかねて学んで行こうと思います。

これまで横スクロールアクションゲームもどきを作りましたが。
目移りしてしまい、別のゲームを作成し[9leap]のほうに投稿しました。ゲームは[こちら](http://9leap.net/games/4105)
次のブログでこのゲームの説明をしますが。今回は今まで私がenchant.jsを使って来て身についた知識をサンプルプログラムという形で紹介します。

内容は
01Spriteの表示
02Spriteの移動
03シーンについて
04文字の表示
05キー入力
06クリック&タッチ座標
07Spriteの大きさ&向き
08クラス
09MAP
10あたり判定
で、内容はQiitaに投稿しました。[こちら](http://qiita.com/Yusuke_mori/items/87215c46426f60401c6b)