HTML+CSS+JavaScriptでバトルゲーム(のバトルシーン)作ってみた

jsdo.itのSPECKというイベント?第一弾のお題がゲームに関するものだったので、
ゲーム好きとしては何か作っとかないかんやろ!と思ってMooToolsで組んでみたのがこれです。
動作確認はFirefoxとChrome、Safariで。IEでは見れないです。

forked from: GYAOS_sample – jsdo.it – share JavaScript, HTML5 and CSS

目新しい演出はなにもありませんwwwww
参考の動画見てて思ったのは、戦うのがプレイヤーが飼育しているモンスターなら
ボタン押して即行動っていうのは不自然じゃないかしら?ということで
指揮して動かすっていう感覚を作れたらそれでよかったんや…。

目指したのはターン制ではなくリアルタイムバトルなんですけどね、妄想するのと実際組むのとでは難易度が雲泥の差過ぎ。
ゲームプログラマーってすげぇや!と改めて尊敬した次第です。
細かいところまで作るには大分時間が足りなかったけど
HTML+CSS+JavaScriptでバトルゲームは作れるってことが分かったのでよしとします。

続きは中身についてのメモ(MooToolsのマニアックな話)です。

内部は以下のクラスに分かれています。

  • マウスジェスチャー (MoouseGesture)
    クリックされた地点=テンキー5とみなして方角を決め、Canvasにマウスが動いた軌跡を描写する。
  • コンソール (Console:Fx.Morphを継承)
    画面下部に開く窓と各コマンドボタンの作成と制御
  • ダイアログ (Dialog:Fx.CSSを継承)
    上に出てくるメッセージの作成と制御
  • モンスター (Monster:Fx.Morphを継承)
    ステータスとかの設定とゲッター&セッター
  • モーション (Motion)
    敵モンスの動作。敵クラスにだけimplementするつもりで分けたもの
  • サンプルのモンスター (Lion:Monsterを継承)
  • プレイヤー (Player)
    モンスタークラスと同じ。ステータスの実装方法を迷った
  • 戦闘 (Versus)
    やっつけ感漂う残念なクラス。AIの本買っとくんだったと後悔しきり
  • アクション (Action)
    たたかう・にげる・アイテム・モンスター変更などのコマンドに対する動作。
    たたかう・にげる以外はメッセージとログのみ
  • メイン (Gyaos:Action,Versusを実装)
    初期設定・インスタンス作成・エンカウント・勝利・ゲームオーバー

メインの他は全部インスタンスや継承・実装で利用。
モンスターとプレイヤーは異なるステータスのキャラクターをインスタンスで作成。
マウスジェスチャーはシーン変更の都度コマンドを設定し直してます。

Fxクラスの継承と実行

ダイアログではFx.CSSを、モンスターとコンソールではFx.Morphを継承しています。
クラス内部でFxのインスタンスを作成するのと違い、継承した場合はthis.startでエフェクトを実行させることが出来るようになります。

Monsterクラスの抜粋:

var Monster = new Class({
            Extends:Fx.Morph,
            initialize: function(options) {
                this.setOptions(options);
                var element = new Element('img', {'id':'monster','src':this.options.img});
                this.parent(element, options);
           }
});

this.parentは継承元クラスの同名関数を実行するものです。
上記ソースの場合はFx.Morphのinitializeを実行します。(PHPでいうところのparent::__construct() )
Fx.MorphやFx.Tweenは第一引数に対象となる要素の指定が必須ですが、継承先クラスの内部で指定してしまえば必要なくなります。

Fxを継承した場合、クラス内部でのエフェクト実行はthis.start()で可能になります。
FxにはChainも実装されているので複雑なエフェクトの設定も比較的簡単に行えます。

以下は敵モンスターがダメージを受けたときのアニメーションを行うソースです。
モンスター画像の縮小+ダメージテキスト作成 という内容。

//被ダメージ
pain: function(damage) {
     this.setOptions({'duration':100,'transition':'bounce:inOut'});
     var text = new Element('span', {
         'text':damage,
         'class':'damage',
         'morph': {
             'duration':1000,
             'transition':'cubic:out',
             'onComplete':function(){this.element.destroy();}
         }
     });
     text.inject(this.element,'before').morph({'opacity':0, 'top':160});
     this.start({'left':120, 'width':220})
          .chain( function() {
                this.start({'left':110, 'width':240});
          }.bind(this)
     );
    return this;
}

ダメージテキストは要素のプロパティでFx.Morphを設定し、エイリアスのmorph()で実行しています。
morph()やtween()といったエイリアスではchainが出来ません。
モンスター画像のエフェクトはsetOptionsで設定を変更してからstartで実行しています。
setOptionsはinitializeで使う以外にも有効ですが、onCompleteなどのイベントは都度追加で消さない限り蓄積されてしまうので注意が必要です。

イベントの初期化はremoveEventsメソッドで出来ます。

this.removeEvents('complete');

ダメージ算出式

バランスはイマイチですが、ありがちな式だと思います。

攻撃力は攻撃する側のステータスから算出。

Math.floor(((('力' * 0.7) + ('器用さ' * 0.3)) - Math.random()) * 'レベル');

防御力は攻撃される側のステータスから算出。ガードしている場合は1です。

Math.floor('体力'/2 + 'レベル' + ('ガードの有無' * 20 - Math.random()));

ときどきミスったりさせたくなったので、命中率を付け加えました。

 var m = Math.floor(Math.sqrt('攻撃側の器用さ') - '攻撃される側の敏捷'*2)+100;
 return Math.floor(Math.random() * m);

上記3つの関数を元に、最終的な計算は次のようになってます。

var target = ‘攻撃される側’;
var dmg = ‘攻撃力’ – ‘防御力’; //与ダメージ
var hit = ‘命中率’;
if(hit === 0) {//ミス
return {‘dmg’:0, ‘hp’: target.getHp()};
}else if(hit <=10){//凡ヒット dmg = Math.floor(dmg/2 - Math.random()); } var point = target.getHp() - dmg; //攻撃後のHP if(point<=0){//倒してたら0に point = 0; } return {'dmg':dmg, 'hp':point}; [/js]

結果報告

Goldでしたー!いやっふぅー!(*´∀`*)

speck_result

しかしFlashでGoldだったロクがニャーニャー拳が凄すぎて隣に並べられるのは若干辛いものが…w

Leave a Comment.