あなたの中心的な問題は、中心的なゲーム ループがないことです。これは、「リアルタイム」のイベントとインタラクションを利用するすべてのゲームに不可欠です。ただし、これは通常、初心者のゲーム メーカーが最初に犯す間違いです。以下のいくつかは興味深いかもしれません:
問題の理由
問題は、ミサイルを発射するときに、そのミサイルのタイム ループを作成していることです。これは、ミサイルを継続的に描画します。ただし、ユーザーがキーを押したときにのみゲームの表示をクリアすることもできます。つまり、ミサイルが線として描画されます。このシステムを 1 つのミサイルと 1 人のプレイヤーで機能させることはできますが、より多くの発射体と敵を追加し始めると、ますます多くの問題が発生します。ゲームに単一の更新「ビート」、つまりゲーム ループがある場合は、すべてのエンティティが独自の更新「ビート」を持っており、それを同期する必要があるのではなく、考えてコーディングするのがはるかに簡単です。
これを例えるなら、昔ながらの現実を考えてみてください。実生活では、何かが起こったときに時間が発生し始めるわけではありません (量子力学、時空、ビッグバンを実際に理解し始めない限り!) — 代わりに、時間は常に流れており、新しいエンティティ/オブジェクトが存在することができます。その間交流します。それらのオブジェクトがなくなっても、時間はまだ続きます (ランダムなオブザーバーに基づく理論に同意しない限り)。
ソリューション
更新/再描画に関して、視点を変更する必要があります。世界に存在するオブジェクトの観点から考える必要があり、それぞれの位置または表示を変更するためのビートまたはティックを取得します。そのティックの後、ゲーム画面全体が更新されます...通常は、これらのティックのうち少なくとも 24 回が毎秒発生します (画面上に描画された静的オブジェクトが実際に動いていると人間の目を欺くため)。
したがって、弾丸ごとに新しいインターバルを作成する代わりに、ゲームの再描画全体を制御する単一のグローバル インターバルから開始する必要があります。これを行うにはいくつかの方法がありsetInterval
ます。コードで行ったように使用するのが最も簡単ですが、この方法には欠点があります。これを実現するためのより現代的な方法は、 を使用することwindow.requestAnimationFrame
です。
次に、このループを 1 秒あたり 24 回 (またはそれ以上) 起動すると、ワールドに追加されたすべてのエンティティを処理できます。これは通常、各エンティティを追跡するある種の集中型リストを持つことを意味します。これは完全にあなた次第です。エンティティの配列など、リストを 1 つだけ保持する人もいます。他の人は、そのリストをbullets
、players
、enemies
... などのより説明的な用語に分割します。ゲーム ループがどのように見えるかを示す擬似コードを次に示します。
var display = {/* object that controls your canvas */};
var entities = [];
var entity = {/* object/constructor represents a game entity i.e. player */}
var gameloop = function(){
display.clear();
for( var i=0; i<entities.length; i++ ) {
entities[i].update();
}
};
明らかに、上記には何もありませんentities
。entities
これは、プレーヤーと既にワールドにあるその他のアイテムを含める準備をするために、他のコードが入る場所です。ゲームの進行に合わせてエンティティを追加および削除する追加のコード、つまり弾丸。
entities.push( new entity({
type: 'player',
image: 'ship.png'
}) );
と呼ばれるメソッドをサポートするように各エンティティを設計する必要がありますupdate
。これにより、追加する新しいエンティティが何であれ、ゲーム ループによって自動的にサポートされます。このupdate
メソッドは、そのエンティティ (それが何であれ) を世界中に移動し、必要に応じてエンティティを世界に描画する責任を負う必要がありupdate
ますdraw
。が発生します — これは衝突の計算に役立ちます:
var gameloop = function(){
display.clear();
for( var i=0; i<entities.length; i++ ) {
entities[i].update();
}
for( var i=0; i<entities.length; i++ ) {
entities[i].draw();
}
};
キーボード操作の処理方法
これは、リッスンする重要なイベントが既にあることを考えると、HTML ベースのゲームでは簡単だと思われがちなもう 1 つのトリッキーなことです。ただし、キーの押下をコードの更新に直接リンクするべきではありません...そうしないと、「キーの繰り返し」の発火により奇妙な動きが発生するデモで何が起こるかがわかります。
あなたがすべきことは、あなたがやっているようにキーをリッスンすることですがcontrols
、キーが押された現在の状態でオブジェクト(または同様のもの)を更新します。次に、エンティティupdate
メソッドで、エンティティが応答してそのアクションを実行する必要がある主要な状態をリッスンします。これにより、キーの押下がアクションに合わせて移動し、キーの繰り返しが回避され、物事がゲームの「ビート」内にとどまることを意味します。また、そのキーの押下 (またはキーの組み合わせ) に対する反応をより具体的に制御することもできます。次のコードも例です。
var controls = {};
$(document).on(
'keydown': function(e){
controls[e.keyCode] = true;
},
'keyup': function(e){
delete controls[e.keyCode];
}
);
次に、キーの状態を確認したい時点で、次のように簡単に使用できます。
if ( controls[32] ) {
/// space has been pressed
}
結論
全体として、HTML5 ゲーム チュートリアルを読み、トップ リンクを参照し、ゲームをそのデザインに作り直すことをお勧めします。作業がはるかに簡単になります。