LibCanvasを使用してPingPongを作成する方法



良い一日。 このトピックでは、LibCanvasを使用してピンポンを作成する方法を説明します。 トピックの目的はピンポンゲームを作成することではなく、LibCanvasの基本を説明することであるため、最も重要な部分のみを残して大幅に簡略化しました。



そのため、このトピックでは、LibCanvasを使用して(最適化なしで)ピンポンを作成する方法について順を追って説明します。



だから、ピンポン-ボールが打つ2枚のボード。 一般的に、あなたはすべて知っています。 最初に必要なことは、最初のhtmlファイルを作成することです。 それは非常に単純です-唯一のキャンバス要素、AtomJSとLibCanvasへのリンク、およびアプリケーションファイルへのリンク:



<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>LibCanvas :: ping-pong</title> <link href="/styles.css" rel="stylesheet" /> <script src="/lib/atom.js"></script> <script src="/lib/libcanvas.js"></script> </head> <body> <canvas></canvas> <!-- Game engine --> <script src="js/init.js"></script> <script src="js/controller.js"></script> <script src="js/field.js"></script> <script src="js/unit.js"></script> <script src="js/ball.js"></script> </body> </html>
      
      







初期化



すべては初期化ファイルから始まります。



その中で、 LibCanvas.extract



を呼び出して、グローバル名を使用できるようにします。 デフォルトでは、すべてのクラスは名前空間LibCanvas.Shapes.Circle



保存されます。 extract



後、それらは省略形で使用できます: Circle







2番目のステップは、おもちゃの名前空間を宣言することです。 すべてのクラスがそこに保存されます。



最後のステップは、domを起動したときにコントローラーを作成することです。



 LibCanvas.extract(); window.Pong = {}; atom.dom(function () { new Pong.Controller('canvas'); });
      
      







初期化はアプリケーションによって異なる場合がありますが、一般的にはそれらの間で似ています。 私の友人の1人は興味深いアプローチが大好きです。JavaScriptのすべてのロジック(要素の作成とスクリプトの接続を含む)を備えた最小限のHTMLファイルです。 はい、このコードは有効です!



 <!DOCTYPE html> <title>LibCanvas :: ping-pong</title> <script src="js/load.ls"></script>
      
      







コントローラー



次のステップは、コントローラーを作成することです。 その中で、 LibCanvas



オブジェクトとゲーム要素を作成します。 atom.Class



を使用してすべてのゲームクラスを作成しますatom.Class



はコンストラクターです。



 Pong.Controller = atom.Class({ initialize: function (canvas) { this.libcanvas = new LibCanvas(canvas, { preloadImages: { elems : 'im/elems.png' } }) .listenKeyboard([ 'aup', 'adown', 'w', 's' ]) .addEvent('ready', this.start.bind(this)) .start(); }, start: function () { var libcanvas = this.libcanvas; [...] } });
      
      







オブジェクトをコンストラクターに渡して、イメージをプリロードします。 画像がダウンロードされるまで、アプリケーションは起動しません。 これらは、スティックとボールの2つのスプライトです。







LibCanvas



、キーボードを使用し、キー「aup」、「adown」、「w」、「s」のデフォルトアクションを回避する必要があることをLibCanvas



ます。 これにより、便利なコントロールを実装できると同時に、たとえば、ブラウザウィンドウを矢印で移動することもなくなります。



LibCanvasがレンダリングを開始する準備ができたら、コントローラーのstartメソッドを開始します。 後で彼に戻ります。



競技場



私たちと一緒の競技場は、背景、ポイント、いくつかの計算、ユニットの作成を担当します。



 Pong.Field = atom.Class({ Implements: [ Drawable ], width : 800, height: 500, [...] });
      
      







エンティティを作成し、レンダリングのためにlibcanvasに追加します。 キャンバスの巧妙なサイズ変更に注目してください。 これは、オブジェクトにwidthプロパティとheightプロパティがあるためです。



 Pong.Controller = atom.Class({ [...] start: function () { var libcanvas = this.libcanvas; var field = new Pond.Field(); libcanvas.size( field, true ); libcanvas.addElement( field ); [...] } });
      
      







ボール



ボールのロジックは非常にシンプルです-「インパルス」があります-動きの方向と速度。

速度はピクセル/秒で設定されます。 更新のたびに、前回の更新から経過した時間を取得します。これにより、速度が乗算されます。 このため、fpsに関係なく、一定の速度で移動します

ボールが上部または下部の境界に到達すると-ヒットし、反対方向に飛ぶ。

appendToを使用すると、ボールをフィールドに簡単にピン留めできます。 壁の初期位置と説明のためのフィールドのサイズを知ることは重要です。

レンダリングは非常に簡単です。現在の長方形にスプライトの必要な部分を描画するだけです。

オブジェクトの構築中、 libcanvas



プロパティはまだ使用できないため、 libcanvasSet



イベントを待ってからlibcanvasSet



を使用するlibcanvas



ことにlibcanvas







 Pong.Ball = atom.Class({ Implements: [ Drawable ], impulse: null, initialize: function (controller) { this.impulse = new Point( Number.random(325, 375), Number.random(325, 375) ); this.addEvent('libcanvasSet', function () { this.image = this.libcanvas.getImage('elems').sprite( 23, 0, 26, 26 ); }); }, move: function (time) { this.shape.move( this.impulse.clone().mul(time / 1000) ); }, update: function (time) { this.move(time); var from = this.shape.from, to = this.shape.to; //      if ( (this.impulse.y < 0 && from.y < 0) || (this.impulse.y > 0 && to.y > this.field.height) ) this.impulse.y *= -1; }, appendTo: function (field) { this.shape = new Rectangle( 40, field.height / 2, 24, 24 ); this.field = field; return this; }, draw: function () { this.libcanvas.ctx.drawImage(this.image, this.shape); } });
      
      







呼び出しをコントローラーに追加します。 フレームごとにボールの位置を更新する必要があるため、 addFunc



を使用して更新をサブスクライブしaddFunc





 Pong.Controller = atom.Class({ [...] start: function () { [...] ball = new Pong.Ball(); libcanvas [...] .addElement( ball.appendTo( field ) ) .addFunc(function (time) { ball.update( time ); libcanvas.update(); }); } });
      
      







ユニットを作成する



次に必要なのはラケットです。 それらはキーボードを使用して制御されます(左はw、右は上下)。

このクラスは、コントロール、動き、ボールとの接触を担当します。

「速度」プロパティは静的である、つまりプロトタイプに追加されることに注意してください。 変更するのではなく、使用するだけです。

コントロールでは、キャンバスを更新し、 必要なキーのステータスを確認します 。 必要に応じて、オブジェクトを移動します。

図形を目的の速度に移動する興味深い方法は、四角形の移動メソッドを使用してこれを行うことです。

fitToFieldは、要素が許容範囲内にあることを確認し、そうでない場合は、その場所に返します。

drawメソッドでは、Ballと同様に、画像の必要な部分が現在の形状に描画されます。



 Pong.Unit = atom.Class({ Implements: [ Drawable ], size: { width: 20, height: 100, padding: 20 }, speed: new Point( 0, 300 ), score: 0, controls: function (up, down) { this.addEvent('libcanvasSet', function () { var lc = this.libcanvas.addFunc(function (time) { if (lc.getKey(up)) { this.move( -time ); } else if (lc.getKey(down)) { this.move( time ); } }.bind(this)); }); return this; }, appendTo: function (field, number) { var s = this.size; this.field = field; this.number = number; this.shape = new Rectangle({ // field.width, field.height from: [ (number == 2 ? field.width - s.width - s.padding : s.padding), (field.height - s.height) / 2 ], size: s }); return this; }, fitToField: function () { var shape = this.shape; var top = shape.from.y, bottom = shape.to.y - this.field.height; if (top < 0) shape.move(new Point(0, -top)); if (bottom > 0) shape.move(new Point(0, -bottom)); }, move: function (time) { this.shape.move( this.speed.clone().mul( time / 1000 ) ); this.fitToField(); }, draw: function() { this.libcanvas.ctx.drawImage( this.libcanvas.getImage('elems').sprite(0,0,20,100), this.shape ); } });
      
      







フィールド上にユニットを作成し、そこでコントロールと位置を与えます:

 Pong.Field = atom.Class({ [...] createUnits: function (libcanvas) { this.unit = new Pong.Unit() .controls('w', 's') .appendTo( this, 1 ); this.enemy = new Pong.Unit() .controls('aup', 'adown') .appendTo( this, 2 ); libcanvas .addElement( this.unit ) .addElement( this.enemy ); }, [...]
      
      







当然、コントローラーにメソッド呼び出しを追加する必要があります。



 Pong.Controller = atom.Class({ [...], start: function () { [...], field.createUnits( libcanvas ); } });
      
      







オブジェクトの相互作用



次に、ボールを極端なボーダーやプレーヤーと相互作用させる必要があります。 Ballに簡単なメソッドを追加します。

ボールの方向を確認する必要があることに注意してください。そうしないと、ボールがプレーヤーや壁に引っかかることがあります。



 Pong.Ball = atom.Class({ [...] checkCollisions: function () { var coll = this.field.collidesUnits( this ), isOut = this.field.isOut( this.shape ); if ( (( coll < 0 || isOut < 0 ) && this.impulse.x < 0) || (( coll > 0 || isOut > 0 ) && this.impulse.x > 0) ) this.impulse.x *= -1; }, update: function (time) { [...] this.checkCollisions(); }, [...] });
      
      







フィールド内のチェックは非常に簡単です。

ユニットとの衝突チェックをユニットの肩に転送し、方向のみを返します。

右または左の境界線を越えているかどうかを確認することも非常に簡単です。 国境と接触した場合、反対側のプレーヤーのスコアを上げます。



 Pong.Field = atom.Class({ [...] collidesUnits: function (ball) { return this.unit .collides(ball) ? -1 : this.enemy.collides(ball) ? 1 : 0; }, isOut: function (shape) { if (shape.from.x < 0) { this.enemy.score++; return -1; } else if (shape.to.x > this.width) { this.unit.score++; return 1; } return 0; }, [...]
      
      







Unitの内部では、組み込みのRectangle().intersect



Intersectメソッドを使用して、2つの長方形の交差を確認します。

 Pong.Unit = atom.Class({ [...] collides: function (ball) { return ball.shape.intersect(this.shape); }, });
      
      







アカウントの引き出し



最後のステップは、プレーヤーのスコアを表示することです。 これは、 ctx.text



を使用して簡単に実行できます。これにより、CSSにより近いテキストを表示し、インデント、テキストを表示する長方形、およびいくつかの追加機能を指定できます。



 Pong.Field = atom.Class({ [...] drawScore: function (unit, align) { this.libcanvas.ctx.text({ text: unit.score, size: 32, padding: [0, 70], color: 'white', align: align }); return this; }, draw: function () { this .drawScore( this.unit , 'left' ) .drawScore( this.enemy, 'right' ); } });
      
      







おわりに



以上です。 完全なコードとゲームは以下で見つけることができます

libcanvas.github.com/games/pingpong/





トピックのゲームはさらに開発できます。 たとえば、node.jsおよびWebSocket上のサーバーでネットワークゲームを追加します。

または、美しい外観、アニメーションを追加します。 ゲームプレイを改善することもできます-障害物、ボールの異なる反射角を追加します。

これはすべて、LibCanvasを使用して非常に簡単に実行できます。 興味のあるトピックは何ですか? 希望する人がいる場合は、それらについて説明します。



別の質問は、より基本的なことを説明する価値があり、LibCanvasに関するトピックに情報があまりロードされていないか、個々の小さな側面や類似のフルレングスの記事をより狭く、説明することは非常に簡単に知覚されるのか?



Habréに登録していない場合は、時々考えがややこしいと思われるので、コメントや電子メールshocksilien@gmail.comで質問することをtoしないでください。



All Articles