Intel XDKでのHTML5ゲーム開発。 パート4.座標系と移動オブジェクト



パート1 » パート2 » パート3 » パート4 » パート5 » パート6 » パート7 //終了)





今日は、Cocos2d-JSで使用される座標系を扱い、画面上でゲームオブジェクトを移動する方法について説明します。







座標系



Cocos2d-JSでは、ゲーム空間内のオブジェクトの位置は座標系を使用して決定されます。 エンジンの各ノードには、その位置を決定するxおよびy座標があります。 数学で学んだものとまったく同じ、正しい直交座標系を使用します。









座標系



目に見えるサイズ



x軸とy軸に沿った最大座標は、可視領域のサイズによって決まります。 Cocos2d-JSは、さまざまな解像度と画面サイズをサポートする「ビュー」または「ビュー」と呼ばれるオブジェクトを提供します。



これは、表示領域のサイズを設定するmain.jsのコード行です。



cc.view.setDesignResolutionSize(480, 800, cc.ResolutionPolicy.SHOW_ALL);
      
      





呼び出されたメソッドの最初の引数は幅、2番目は高さです。 この場合、可視領域のネイティブ解像度は480x800です。 3番目の引数は、画面の解像度とアスペクト比が指定されたパラメーターと異なるデバイスでプログラムを起動したときに、ゲーム空間のサイズを変更するためのルールを設定します。



このエンジンは、プログラムで指定されたパラメーターと画面の特性の不一致の問題を解決するための5つの方法を提供します。 説明は、先ほど確認したコード行の上にあるmain.jsファイルにあります。 デフォルト値のSHOW_ALLを使用します。 このアプローチでは、表示領域のアスペクト比はすべてのディスプレイに保存されますが、画面の空いている部分は黒く塗りつぶされます-黒のバーが競技場の両側に表示されます。



座標空間



各ノードには独自の内部座標空間があります。 ウィンドウと各ノードの両方に、原点がオブジェクトを囲む長方形の左下隅にある座標系があります。





ウィンドウとゲームオブジェクトの起源



ノードの位置を設定することにより、親オブジェクトの座標空間での位置を設定します。 たとえば、上の図に示すように、赤い点(ヘビを扱う)の位置を設定すると、その座標空間(黄色の軸)ではなく、レイヤーの座標系(黒い線で描かれた軸)内で移動します。



角からヘビを引き出します



座標系がわかったので、ヘビの頭を角から引き出して、より適切な場所に配置します。 つまり、ゲームSnakeのバージョンでは、すべてが画面の中央から始まります。



以下に示すようにSnakeLayerレイヤーコードを更新します。 新しいコードは、コメント「以下のコードを追加」の下に追加する必要があります。



 var SnakeLayer = cc.Layer.extend({      snakeHead: null   ctor: function () {             //          /*    */       var winSize = cc.view.getDesignResolutionSize();       /*    */       this._super();             /*    */       this.snakeHead = new SnakePart(asset.SnakeHead_png);             //           /*      */       this.snakeHead.x = winSize.width / 2;       this.snakeHead.y = winSize.height / 2;                     /*       */       this.addChild(this.snakeHead);   }, });
      
      





winSize変数は、ウィンドウのサイズ(幅と高さ)を含むオブジェクトです。 このデータを使用して、x座標がウィンドウの幅の半分に等しく、y座標が高さの半分に等しい位置を蛇の頭に割り当てます。



次に、エミュレーターで発生したことを実行します。







ヘビの頭が画面の中央に移動しました



私たちはヘビに動くことを教えます。



オブジェクトの移動



座標系を理解した後、ノードを画面上で移動するには、そのx座標とy座標を変更する必要があることは明らかです。 やってみましょう。



スネークを移動するには、SnakeLayerレイヤーのコードに次のメソッドを追加します。



 moveSnake: function(dir) { /*  ,    */ var up = 1, down = -1, left = -2, right = 2, step = 20; /*   snakeHead     */ var snakeHead = this.snakeHead; /*       */ var dirMap = {}; dirMap[up] = function() {snakeHead.move(snakeHead.x, snakeHead.y + step);}; dirMap[down] = function() {snakeHead.move(snakeHead.x, snakeHead.y - step);}; dirMap[left] = function() {snakeHead.move(snakeHead.x - step, snakeHead.y);}; dirMap[right] = function() {snakeHead.move(snakeHead.x + step, snakeHead.y);}; /*      */ if (dirMap[dir] !== undefined) { dirMap[dir](); } },
      
      





このメソッドは、呼び出されるたびに一定のハードセットのステップ(可変ステップ)でヘビの頭を動かすという事実に対処します。 この値はゲーム画面の幅と高さを完全に分割するため、ステップとして20を選択しました。 移動の方向を示すために、オブジェクトの座標の望ましい変化を指定する数値を使用します。 ここで、このメソッドを何らかの方法で呼び出す必要があります。



ゲームサイクル



ゲームエンジンには、プログラムをブロックせずに入力イベントを処理し、ゲームロジックを実行し、グラフィックを出力するというタスクを解決する無限ループがあります。 各サイクルパスは、ティックまたはティックと呼ばれます。 定期的に実行されるタイマーと比較できます。



ゲームループの構造を擬似コードで記述すると、次のようになります。



 while (true) { processInput(); runGameLogic(); renderGame(); }
      
      





エンジンがゲームロジックの実行に従事している場合、ゲームオブジェクトのリストを調べ、コードを実行し、その状態を更新します。 たとえば、ゲームに空から落ちるキャラクターがある場合、ゲームは特定のアルゴリズムに基づいて、メジャーごとに位置を更新する必要があります。 SnakeLayerレイヤーをCocos2d-JS更新リストに追加します。



updateメソッドをSnakeLayerコードに追加し、ctorメソッドでscheduleUpdateメソッドを呼び出します。 リスト内の残りのコードは、方位を把握するのに役立つように提供されています。



 var SnakeLayer = cc.Layer.extend({   snakeHead: null,   ctor: function () {       ...       /*   */       this.scheduleUpdate();   },      moveSnake: function(dir) {       ...   },   update: function() {       /* ,   */      var up = 1;      this.moveSnake(up);   },   });
      
      





これで、オブジェクトを作成した後は常に、ゲームループの各サイクルでupdateメソッドが呼び出されます。 ここでエミュレータでプロジェクトを開始すると、ロケットのような蛇の頭が画面の上部の境界線から飛び出します。



走行速度制限



moveSnakeメソッドを呼び出すたびに1ステップだけ移動しますが、ヘビはすぐに画面から飛び出します。 これは、ゲームループが非常に高速に実行されるためです。 上記で示した同様のサイクルのプリミティブスキームとは異なり、実際のゲームサイクルは測定間の時間を追跡します。 この事実を利用して、オブジェクトの位置を更新する方法が目的の速度で機能するようにすることができます。 方法は次のとおりです。



  1. 間隔とカウンターという2つの新しいメンバーをクラスに追加します。



     var SnakeLayer = cc.Layer.extend({   snakeHead: null,   //      interval: 0.25, /* 1/4  */   counter: this.interval,   ctor: function () {...},      moveSnake: function(dir) {...},   update: function(dt) {...},   });
          
          





  2. 更新メソッドのコードを次のコードに置き換えます。



     update: function(dt) {       /* ,   */       var up = 1;       /*        */       if (this.counter < this.interval) {           this.counter += dt;         } else {           this.counter = 0;           this.moveSnake(up);          } },
          
          





更新メソッドの引数は「dt」(デルタ時間、時間変更)になりました。 これは、最後のフレームからの秒数です。 この引数は、ゲームループをこのメソッドに渡します。 クラスの2つの新しいメンバー、intervalとcounterを作成しました。 間隔は、update()の呼び出しの間に経過する必要がある秒数を設定します。 カウンター(カウンター)は、オブジェクトが前回移動してから経過した秒数をカウントするために必要です。 同時に、dtメソッドの引数で利用可能なゲームループからのデータは、カウンターに蓄積されます。



これで、エミュレータでゲームを実行すると、ヘビの移動速度がはるかに遅くなります。



結論



今日のレッスンを要約するには:



これで、次のことができるようになりました。





次回は、蛇の長さを増やし、その動きをより意味のあるものにします。





パート1 » パート2 » パート3 » パート4 » パート5 » パート6 » パート7 //終了)








All Articles