2012年6月25日月曜日

爆裂くまさん

ゲームをするのに忙しくて更新をさぼってました! hidesukeです。
 さて、6月の頭に @mikito0521 が新作を9leapにアップロードしていました。
 その名も『爆裂くまさん』です。

  Osaki.jsの時間中に、みんなで遊んだのですが、部屋のアチラコチラからレバガチャの音が聞こえてきてジワジワ来る一時を楽しめました。 

よろしければ遊んでみてください。
 enjoy!

2012年5月5日土曜日

[Metal Bear Solid] enchant.js でまずは動くものを

enchant.js を使っていち早くゲームらしきものを作るという目的で Metal Bear Solid なる完全に名前先行のゲームを作成しました。



すべてのソースコードは jsdo.it に記載しております。
(大変申し訳ありませんが、chrome で正常に動きません。safari、スマホ実機なら動きます。次回からはこの点注意して作成します。)











まずは本ブログにも記載しております、タップした位置に熊が移動するというプログラムを活用しました。

参照: 2. タップした方向に向かって、クマが進むようにしましょう



当たり死亡判定つきの針群


Metal Gear Solid のように隠れるだけではなく、隠れている壁にも当たり死亡判定をつけたらどうかと思いましたので、そこのところを実装しました。明らかに当たってはダメそうな針の画像を使用しました。








背景(マップ)は下記のように実装できますし、壁としての当たり判定をつける記述方法もあるようですが、当たった後に死亡させるためには、針はマップとしてではなく、Sprite として作成しました。


背景はタイル図柄で埋めました。

    var map = new Map(game.blockSize, game.blockSize);
    map.image = game.assets['./images/map0.gif'];
    map.loadData([
      [  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5],
      [  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5],

                         (中略)

      [  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5],
      [  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5]
    ]);
    game.rootScene.addChild(map);


針画像は同じものをいくつも作るのでクラス化しました。

var objs = new Array(1);

  var ObjectA = Class.create(Sprite, {
    initialize: function(x, y, n){
      Sprite.call(this, 16, 16);
      this.image = game.assets['./images/map0.gif'];
      this.frame = 16;
      this.moveTo(x, y);
      objs[n] = this;
      game.rootScene.addChild(this);
    },
  });



ObjectA という見事にダメな例の代表みたいな名前が付いておりますが、下記のように、x 座標、y 座標、objs で呼び出すための番号を引数として渡すことで、配置と for 文を利用した当たり判定をつけることができました。


var obj00 = new ObjectA(0, 50, 0);



      for(i = 0; i < objs.length; i++){
        if(this.within(objs[i], 16) == true){
            this.isDead = true;
            break;
        }
      }





敵キャラ見つかり判定 


左右に移動している敵キャラ(girl)に熊が見つかった際に死亡する記述です。





熊と敵キャラが同じ直線上に存在した場合に、爆発画像(bomb)が熊の上に乗っかることで熊の死亡を表しています。
爆発画像は死亡時以外は画面外に置いておき、熊死亡 or 敵キャラ死亡時にリサイクルできるようにしています。

ユーザから見た場合、はじめはなぜ熊が死亡しているかがいまいち直観的でないように実装してしまったため、次回から改善したいと思います。


    var girlEnterFrameFunc = function(){
      
      if(this.x <= 0){
        this.movex = 1;
      }else if(this.x >= 203){
        this.movex = -1;
      }
      if(this.x > 16 && this.x < 64){
        if(bear.x > 16 && bear.x < 64){
          bear.isDead = true;
          bomb.moveTo(bear.x + 8, bear.y + 8);
        }
      }else if(this.x > 96 && this.x < 144){
        if(bear.x > 96 && bear.x < 144){
          bear.isDead = true;
          bomb.moveTo(bear.x + 8, bear.y + 8);
        }
      }else if(this.x > 176){
        if(bear.x > 176){
          bear.isDead = true;
          bomb.moveTo(bear.x + 8, bear.y + 8);
        }
      }
      
      
      
      this.x += this.movex * this.speed;
    };
    
    girl.addEventListener("enterframe", girlEnterFrameFunc);






クリア演出


ゴールには明らかに取るといいことありそうな宝箱の画像を使用しました。






クリア後におめでたい感じを出すために、エヴァの最終回風演出をするんだ!と先に意気込んで決めていましたが、時間差でおめでとうコメントを出すのに苦戦しました。






まずは、針と同様におめでとうクラスを作成し、x 座標、y 座標、Array に入れるための番号、セリフを引数としました。

var Omedeto = Class.create(Label, {
  initialize: function(x, y, n, word){
    Label.call(this, word);
    this.moveTo(x, y);
    omes[n] = this;
  },
});



次に、1 回の実行ごとにセリフを画面に表示させる function を実装。

var omeCount = 0;
var omes = new Array(1);
function omedeto(){
  
  if(omeCount == omes.length){
    clearInterval(omeInterval); 
  }else{
    game.rootScene.addChild(omes[omeCount]);
  }
  
  omeCount++;
}




最後に、1 秒に 1 回上記を実行するように実装。

    var ending = function(){
      
      
      var clearLabel = new Label("CLEAR!");
      clearLabel.font = "50px cursive";
      clearLabel.moveTo(30, 100);
      game.rootScene.addChild(clearLabel);
      
      
      var ome00 = new Omedeto(30, 250, 0, "おめでとう");
      var ome01 = new Omedeto(60, 220, 1, "めでたいな");
      var ome02 = new Omedeto(140, 260, 2, "おめでとさーん");
      var ome03 = new Omedeto(160, 230, 3, "クエックエッ");
      
      
      function startInterval(){
        omeInterval = setInterval("omedeto()", 1000);
      }
      startInterval();
      
    };







なんとかゲームの形をしたものができました。

その他、死亡後に画面タップでゲームリセットできるようにしました。リセット時に敵キャラの位置が毎回デフォルト位置に戻っているよりも熊だけがデフォルト位置に戻っていることにより、毎回同じスタートにならないようになっております。


次回作へ向けて 

  •  説明のいらない直観的ゲーム作りを徹底
  • chrome、safari で正常動作するか確認しながら実装
  • 実は熊の左右の向きが頑健なプログラムではないため、そこを改良
  • 面白いゲーム作り 

友人にスマホでプレイしてもらったところ、画面をタップしっぱなしにすることでそこに熊が付いてくると判断したようです。

今回の実装では、タップし直すことによる熊の再移動はありますが、タップしっぱなしによる熊の再移動は実装していなかったため、直観的動きにするためには、やはりタップしっぱなし対応が必要かと思いました。


Metal Bear Solid 2 をご期待ください。

2012年4月22日日曜日

enchant.js meetup 東京 vol.2 で LTしてきてた

enchant.js meet up 東京 vol.2 でLTをしてきました!



聴衆をマッハで置いてけぼりな感じのLTをしてきたので、自分のブログに解説を書きました。きっと、更に凄い勢いでいろんな人を置いてけぼりにするはずです。(コードをかけばいくらかマシなんでしょうがその元気はない……)

enchant.js meetup 東京 vol.2でLTしてきた。 - 名称未定ドキュメント"Que"

他にもたくさん面白い話を聞けたので、機会があればまとめたいなーとおもいます。

とりあえず、gl.enchant.jsやばい。MMDを読み込んでIKまで実装してあるってのをみて鼻血が止まらなくなるかとおもった。

2012年4月17日火曜日

jsdo.it で avatar.enchant.js を使うには


enchant.js にはキャラや背景を手軽に使うための仕組みである
avatar.enchant.js というものがあります。

どんなものかというのはこのへんを見てもらえると分かるかと思います。
http://wise9.jp/archives/7060 とか
http://osakijs.blogspot.jp/2012/04/avaterenchatjs.html とか(ステマ)

こんなに便利な avatar.enchant.js ですが、現在 jsdo.it の Majjor Library にはありません。
(遠からず入るかと思いますが)

でも使いたいよーという紳士淑女の方々がいらっしゃると思いますので
こうすると使えるよ!というのが今回の記事の趣旨です。いざ本題へ。

1. まず avatar.enchant.js を用意します
  1.1 Start coding して JavaScript タブに avatar.enchant.js のコードをまるっと貼り付けます
      (https://github.com/shi3z/enchant.js の plugins 以下にあります)



  1.2 背景やモンスター画像を使いたい人は Files に画像を追加しておきましょう
      (https://github.com/shi3z/enchant.js の images 以下にあります)














  1.3 保存します

2. 上記で作成した avatar.enchant.js を使います
  2.1 Start coding して Add Library で enchant.js を追加します

















  2.2 Add Library で avatar.enchant.js を追加します(「1.」で作成したもの)

















  2.3 enchant.js のコードをもりもり書きます









(」・ω・)」うー!(/・ω・)/にゃー!

2012年4月11日水曜日

ターミナルプレクサーのお話(1)

依頼があってから寝かせすぎた感のあるターミナルマルチプレクサのお話です。

マルチプレクサってなに?って人は一回Linux系にターミナルログインしてscreen って打ってからC-a c って打ってみたらいいとおもう。

一般的によくあるたーみなるまるちぷれくさ についてデス
今のところ僕が知る限りではこれぐらいあります

  • GNU screen
  • tscreen
  • tmux
  • byobu
個人的に大枠でくくると

1)GNU Screen tscreen byoubu
2)tmux

の2グループにわけられる。いや分けたと思った。
違いはScreenの拡張 か、個別の機能があるかってちがいです。

screen自体が「古い」って言われるのはたぶん枯れきって開発がほぼ終了してんじゃね?ってぐらい(実は別の人がかいはつを続けているっぽいですが)それに比べるとtmuxの方が更新頻度が高いからなんじゃないかなーと思っています。

んなわけでScreen系とtmux系の違いはどこーってなるとこんな感じかな?とおもっとります

Screen
・ RH・Debian系なら大抵標準で入っている   <<( 重要)
・ 便利なscriptがいろんな人によってすでにそろっている。
・ tscreen やbyoubuといった拡張派生系のものがあって移行も比較的すんなりScriptもそのまま使えたりする。
・ 慣れてる人が多い(w
・ メモリくうよ・・・マジで

tmux
・標準設定のままでもそれなりに使えるステータスバー
・各ショートカットがコマンドベース
・縦分割機能搭載(僕がtmuxを知る事になった要因・・・でも最も使ってない機能)
・たまに混乱する「ペイン」って概念
・まぁ概念としてはScreen互換なんだけど・・・・・
・コピー&ペースト用のバッファを複数保持できる(これがでかい)
・sessionが複数もてて、しかも任意に切り替えが出来る(割と重要)

なかんじです。
今更ってかんじの情報ですね。

で、個人的な見解ですが、僕はLinux系のOS運用をする事が多いので基本はGNU screenつかってます。
これなら、自分の作業アカウントに「.screenrc」入れれば環境そのまま使えますので。
同じ問題でscreenscriptもあまり使わないようにしてます。

じゃぁtmuxは? って話なんですがこれは常時使用しているWSの方で使っています。
理由は、メモリの使用量の問題と上記の
「・sessionが複数もてて、しかも任意に切り替えが出来る(割と重要)」
これです。

この辺は次回もっと書いて良いよって言われたら書きます。
昼飯のあいまに書いたので今回こんなところで。

2012年4月10日火曜日

avater.enchat.jsでいろいろ遊んでみた

avater.enchant.jsがいい感じ

avater.enchant.jsがかなりイケてます。
簡単にキャラクタが表示できるというのは、絵心のないプログラマにはまさに福音!
これで「絵がかけないからゲームつくれない」なんてちょっと意味のわからない言い訳が聞けなくなりますね!

さて、このavater.enchant.js、好きなキャラメイクができるのもさることながら、デフォルトで何種類かの動きを備えています。

  • stop
  • run
  • attack
  • special
  • damage
  • dead
  • demo
それぞれ、使いたいタイミングで player.action = "damage" とか指定してあげると













こんな風にダメージうけてくれるわけです。キャワイイ!

じゃぁ、なんか作りたいよね?


さて、こんな横向きで、走ったり攻撃したりするキャラクタがいるんだから、横スクロールシューティングゲームを作りたくなるのがゲーム屋の心情というやつですよね!
というわけで、とりあえず女の子が剣を降ると、弾がでるってのを作りましょうか。
クリックしたタイミングで、弾を出すようにしてみましょう。














あ、あれー? コレじゃない感……。
こう、刀を抜いた時にズバーっと弾がでてほしいじゃないですか。
なのに、あれ?

コード読んでみる


avater.enchant.jsのコードを見てみると、attackの時のアニメーションのコマは

"attack": [ 0,2,9,10,11,5,0,0,0,-1], 
てな具合の定義がしてあります。
この配列の順序で画像を切り替えてアニメーションされるのですが、配列の先頭の0というのは、stopの時と同じ画像なんですね。

これ、配列4番目とか5番目とかその辺りで弾がでてくれたらカッコイイきがします。
なので、そのように書いてしまいましょう。JavaScriptの自由自在っぷりが発揮されます。

まず、そのキャラクタが今何のアクションをしているかはplayer.actionで取得できます。
よって、以下のようなコードで、攻撃アクション中かどうかをしることができます。

var player = new Avater("2:2:1:2076:21310:2206");

if(player.action === "attack") {
  // 攻撃中の処理をここに書く
}

これで取得できます!
さて、つぎは攻撃中のアニメーションの4コマ目あたりで弾を出したいなぁ……と思います。
また、avater.enchant.jsのコードを読むと、actionの指定がある場合、毎フレームごとにanimFrameという値を1増加させて、animPatternという配列に従って画像の表示を変えているようです。
つまり、animFrameの値 = action開始時からのフレーム数ということがわかります。
というわけで、以下のようなコードを書きました。

if(player.action === "attack"){
  if(player.animFrame === 4){
     game.rootScene.addChild(new Bullet());
  }  
}

これで、attack動作中で、4コマ目のときにBullet(弾)を表示するというコードが完成しました!
じゃぁ、動かしてみましょう!

ああ、いいですね! ばっちりです。最高です! 捏造したかのような思い通りのスクリーンショットも取れました!

まとめ

avater.enchant.js のコードを読めば、大抵のことができる。


コード読んでてハマったとこ

var w = ~~(image.width/4);

このコードが何やってるかわからなかったんですね。このチルダチルダ
いろいろ読んでいくつか解説しているページを見つけました。

なるほど。Math.floor使わないという方法があるのか。
いろいろありますなぁ〜。

ソースコードを読むのはとても勉強になりますね><

2012年4月3日火曜日

これも開発環境

Osaki.jsはenchant.jsでゲームを作ったり、遊んだりするクラブ活動です。
みんなでノートパソコンを持ち寄って、わいわいやってるんですが、すげーマシンでコード書いてる猛者がいました



どうです、こいつ!
こいつ、シャープ製 WILLCOM D4 ですよ!
こいつでコードかいてjsdo.itに貼りつけてデモしていました!



初回は、本体のキーボードでちまちま打ってたんですが、さすがに辛かったらしく、第2回はキーボードマウス、ディスプレイケーブル持参という徹底っぷり。
すごく……かっこいいです。

しかし、それより、このエンターブレインのロゴがついたキーボードはどこで手に入れたんだ……。

enchant.js(+Safari)でrotateと移動を一緒にやる方法

昨日のOsaki.jsの終わって、自席に戻ったときに@pinori さんに
Spriteを回転させながら移動ってできない? 
と聞かれました。
つまり、コードにしたらこんな感じ

var img = new Sprite(16, 16);
img.image = someImage;

game.rootScene.addEventListener(Event.ENTER_FRAME, function(){ 
    img.y += 5;
    img.scaleY += 1;
    img.rotate(30);
  }
});

imgというSpriteを毎フレーム毎にy方向に動かしながら、活縦にびよーんと伸ばしながら、かつ30°づつ回転させるというコードです。
コレが動かない……。

で、今日(4/3)は大風、大雨で会社が半ドンとなったので家でこの原因究明しようと思い、



とつぶやくと、

UEIの清水さんから直接ご回答いただきました! 本当に便利な世の中です! ありがとうございました!




バグなら仕方ないんですが、やはりSafariで確認することが多いMac使い。ここはSafariでも動くようにしておきたい。
というわけで、動くようにしました。

回避方法は、twitterでもつぶやいているように、偶数フレームではローテート、奇数フレームでは移動するという動作を交互に実行するようにしました。

コードはこんな感じ。


  var img = new Sprite(16, 16);
  var dScaleY = 1,
      dRotate = 30,
      dy = 3;

  game.rootScene.addEventListener(Event.ENTER_FRAME, function(){
    if(game.frame % 2 === 0) {
      console.log("hoge"); 
      if(img.y > game.height || img.y < 0) {
        dy *= -1;
      }
      img.y += dy;
    } else {
      if (img.scaleY > 10 || img.scaleY < -10) {
        dScaleY *= -1;
      }
      img.scaleY += dScaleY;
      img.rotate(dRotate);
    }
  });

うん、説明と逆だね! 偶数フレームで移動、奇数フレームで回転&拡縮を行なっています。
jsdo.itにサンプル上げたんでそちらもどうぞ


Osaki.jsは勉強になるね!(棒

でもできるゲームを早く公開できたらいいなーと思います。
昨日は、入社3年目ボーイがつくった Metal Bear Solidがスペランカーばりの難易度でゲラゲラわらえてよかったw

2012年4月2日月曜日

Osaki.js#2 で enchant.jsでClass作る方法をお話しします。

今日の Osaki.js はデモ会なんですが、enchant.js でClassを作る方法を軽く解説しようとおもいます。

あくまで、軽く。
軽いジャブ程度に。
資料はenchant.jsのクラス継承とJavaScriptのクラス継承のちょっとした違いを参考にしました

2012年3月28日水曜日

Osaki.js #1 を終えて。実装とゲーム性について。

Osaki.js 第一回目は @hidesuke によるハンズオンでした。
(当日スライドは前回ブログをご参照ください)

提示された課題は3点ありました。

  1. クマが画面の端についたら、折り返すようにしてみましょう
  2. タップした方向に向かって、クマが進むようにしましょう
  3. なんかゲームっぽくしてみましょう

ハンズオンのあと1時間ぐらいを使って、1と2まではさっくりと実装できました。

私(@inuwarumono)の書いたものがこれ
動作サンプル
ソースコード(github)

書いたものを振り返ってみようと思います。ちなみに僕はPerl/Shellスクリプトを少々書くぐらいで、JavaScriptをほとんど書いたことがありません。かなり基本的なことまで記載しますので、冗長に感じられる方はすみませんが少しご辛抱下さい。

1. クマが画面の端についたら、折り返すようにしてみましょう

くまの移動は、毎フレームごとに呼ばれる関数の中で、bear.x, bear.y を変更することで実装することに、というところまではテンプレートにかかれているとおりです。(テンプレートでは単純に this.x += 3; するだけ)

その増分を、bearオブジェクトのプロパティとして定義してあげることにしました。

bear.dx = 2;    // くま移動量のX成分初期値
bear.dy = 1;    // くま移動量のY成分初期値
bear.move = 2;  // 1フレームあたりの移動距離

X軸方向に +2 (=右に2移動), Y軸方向に +1 (=下に1移動) というのが初期値です。 X軸,Y軸の移動量を制御することで、くまの移動方向をコントロールします。

壁で折り返すには、いわゆる「あたり判定」を書けば良いですね。

if (this.x > game.width - bear.width || this.x < 0) {
  this.dx *= -1;        // くま移動のX成分反転
  this.scaleX *= -1;    // くま画像のX軸反転
};
if (this.y > game.height - bear.height || this.y < 0) {
  this.dy *= -1;        // くま移動のY成分反転
};

条件式の部分はX軸,Y軸とも「くまが画面の端から出そうになったら」という意味ですね。
(普通 this.x < 0 を先に書く気がするけど気にすんな。)

条件にマッチした時にやっている事は、くまの移動量の±反転で、右に2移動していたものを、左に2移動するように変更する、ということです。
昔アルカノイドというブロックくずしのゲームがありましたが、あのゲームでは反転時に微妙に方向が変わるようにランダムな要素を混入させていましたね。それを書こうとすると、±判定に加えて、ランダム要素を追加すると…と、これは余談。

次に行きましょう。

くまの移動は、1フレーム毎に bear.x, bear.y の値を操作していて

// くま移動
this.x += bear.move * this.dx;
this.y += bear.move * this.dy;

ここで bear.moveは一回の移動距離で、要するにスピードですね。
(ちなみに this とか bear とか使い分けがうまく出来てないのは僕が初心者だからです。)
増分に、スピード要素を掛け算したものを、this(=bear).x に足しています。

ちなみに、X += 1; というのは、X = X + 1; と同義で、他にも掛け算ならば X *= 2; のように書けます。
この書き方は、JavaScript に限らずその他たいていの言語でも同様なので、慣れておきましょう。
(+=, -=, *= はわりと書くことがあるけど /= とは書いたことないです。%=とも書けるけど、これも書いたことない。)

2. タップした方向に向かって、クマが進むようにしましょう

いきなり書いたコードをはります。

this.rootScene.addEventListener(Event.TOUCH_START, function(e){
  // クリック位置がくまの中心にくるように位置の差を取る
  var _dx = (e.x - bear.width / 2 ) - bear.x;
  var _dy = (e.y - bear.height / 2 )- bear.y;
  // 1フレームあたりの移動距離がbear.moveになるように
  var _dd = Math.sqrt(_dx * _dx + _dy * _dy);
  bear.dx = bear.move / _dd * _dx;
  bear.dy = bear.move / _dd * _dy;
  // X成分の正負をそのままに値を1にしてscaleX設定に使う
  bear.scaleX = bear.dx / Math.abs(bear.dx);
});

_dx, _dy は、その場限りの変数なので、_で始まる変数を書いてみました。これは何流かは良くわかりませんが、僕はこうやって書くことが多いです。

三平方の定理を使って、タップ位置と、クマの現在位置の距離を _dd に取り、X,Yそれぞれの必要移動距離に一回の移動距離との比率(bear.move / _dd)を掛け算しています。
こうすることで、X,Y方向の一回の移動距離が、結果として bear.move になるように調整しているわけです。

また、bear.scaleX は右方向移動(dxがプラスの場合)には 1 を、左方向移動(dxがマイナスの場合)には -1 を入れたいので、絶対値で割り算をすることで結果が 1 または -1 になるように細工しています。
これは簡潔にうまく書けたなー、と満足。

3. なんかゲームっぽくしてみましょう

ここまでのコードで、反転もうまく出来たし、クマはタップした方向にちゃんと動いてくれました。なので、結果は満たしたと言えますね。

しかしこれを、「ゲームっぽくする」というと話はまったく別でした。

ゲームを作るために、実装が先にあってはゲームになりません。というのも、単純な移動といっても実装方法はいくつかあって

  • どっちにどれだけ動くか(僕の実装)
  • どこに向かって動くか(僕の実装では表現できていない)

こんな違いがあります。

たとえばシューティングゲームの自機をクリックしたとこに移動させるようなコードを書こうとすると、僕の書いたコードではたいへん問題があります(移動量しか見てないから)。

「オブジェクトを動かす」なんていう単純な実装一つにしても、実装手段がゲーム性に密接に関連している事に気がついた次第です。

動かすにはどうしたら良いかではなくて、どう動かしたいかを先に考えること、これがゲームを作るということなんでしょう。これには企画者の気持ちがないと作れませんね。ゲーム作りが楽しいのはこういうところに起因していそうです。

次回のOsaki.jsでは、「実際にゲームを作ってみましょう」という予定になっています。
先にどんなゲームを作ろうかアイディアを練ってから参加しようと思います。

2012年3月24日土曜日

Osaki.js #1 enchant.jsハンズオン資料

3月26日に行われる、Osaki.js #1 enchant.js ハンズオンの資料です。


Osakijs01
View more presentations from hidesuke.

超初心者向けで、丁寧すぎる感じに作りました。
ハンズオンで使うテンプレートはここからDLできます

Happy Programing!

2012年3月7日水曜日

Osaki.jsはじめました

Osaki.jsは大崎あたりの某社の有志があつまって、enchant.jsとかでまったりゲームをつくる同好会です。

作品ができあがってきたらこのブログでどんどん発表したいとおもいます。
乞うご期待!