SVGでのレース

画像



はじめに



アーケードjsゲーム。 プロトタイプは、いわゆる「cageの中のレーシング」(一部の子供向け雑誌で見た)でした。 ポイントは、ノートブックのシート上に線が引かれ、プレイヤーがセルを歩き回ることです。 1回の動きで、速度を1つ上げるか、下げることができます。 壁に「衝突」した場合は、この場所から単位速度で続行します。



画像



ゲームコード



ゲームはraphael.jsとplayground.jsを使用して作成され、SVGでグラフィックをレンダリングしました。 私の平均的なラップトップ(CPU 4 x 2.1 GHz)のクロムでは、ゲームは小さなトラックで50 fps、大きなトラックで40 fpsを生成します。



1つのトラックに最大5人のライダー(またはレーサー)が参加します。 対戦相手のレーサーは、このトラックで最高の結果を出している以前のプレイヤーのアクションを繰り返します。 ライザートレーサーをデータベースに登録するには、最後に終了しないようにするだけで十分です。 メニューでは、ライザーの色と、この結果を書き込むことができる名前を選択できます(終了時に結果を表示するため、メインメニューで最適な方法で)。



物理は2次元配列に実装されます。 ライザーに乗る(ハエ?) プレイヤーは、各ターンで速度(3ユニット以上または10ユニット以下)および方向(左または右)を変更できます。 このデータと現在の位置に基づいて、ゲームは現在の動きが終了する場所を確認し、壁の存在または終了について配列をチェックします。 このエンドポイントにあるものに応じて、対応するアルゴリズムの実装が続きます。 トレーサーの作成もこの配列に実装されます(配列のインデックスはデータベースに格納されますが、オフセットの実際のサイズは格納されません)。



トラックの幅は500単位から2000単位までさまざまです。実際のサイズ制限はありませんが、より大きくなると、ブラウザーから出力されるfpsが低くなります。



グラフィックスの場合、SVGは11の子で使用されます。 5(パス)-ライザーの描画用、4(パス)-トラックの描画用、1(円)-壁との衝突のアニメーション用、1(パス)-排気灯用。



画像



データベースは、トレーサーを持つ単一のjsonファイルで表されます。 3つのphpスクリプトが提供します。 マップはjs変数に保存されます。 カード用のJSONを作成することは可能ですが、それらは静的であり、サイズが小さくなっています。



アーケードでは、衝突の音、ライザーの音(プレーヤーの制御下にあるもの、および近づいているときは見知らぬ人の両方)のほか、wallsを吹く音があります。 NFSシリーズでこの効果が本当に気に入ったので、ここで繰り返してみました。 すべてのサウンドはopengameart.orgからダウンロードされます 。 背景は、Let the Games Begin(セクション31-Tech)、またはエイリアンスワンプ(残念ながら、作者は不明です)によって再生されます。



トレース描画



画像



まず、オブジェクトの配列を読み取ります。



{i: size_i, j: size_j, size: indent_in_cell}
      
      





そして、セグメントのチェーンを取得します。セグメントの各要素は次の要素に接続され、最後の要素は最初の要素に接続されます。 そして、私はセグメントの閉じたセットを取得します。



このセグメントのセットから、三角関数を使用して、indent_in_cellによって、平行六面体のセットを取得します(長方形があったはずですが、失敗しました)



画像



次に、すべて同じ三角関数を使用して、配列要素(radiusパラメーターを使用して作成し、最初は単位で埋められている)がいずれかの四角形にあるかどうかを判断します。 はいの場合、この配列要素には値0が割り当てられます。



最後に、すべての長方形を単一のパス要素で描画します。



仕上げには、幅iのオフセットを示します。 このオフセットで、アルゴリズムはゼロ要素の最初のセグメントを検索し、このセグメントから終了点と開始点を取得し、パス要素を使用して描画します。



「ボックス」の値は、型の要素の配列から取得されます



 {i: size_i, j: size_j, width: width_in_cels}
      
      





iとjは左上隅に示され、幅は正方形の合計サイズです。 次に、これらのパラメーターに基づいて、メイン配列が変更されます。 「ボックス」に分類される要素には値3が割り当てられます。次に、配列を通して、すべてのボックスの輪郭を描きます。 もちろん、これらはすべて単一のパス要素で描画されます。



トレーサーを作成して読み取ります。



トレーサーは、次のタイプのオブジェクトの配列です。



 { s: racer.speed, r: racer.root, i: racer.coord.i, j: racer.coord.j, wait: 0, }
      
      





ここで、sはライザーの速度、rootは方向、i、jはライザーが現在のターンで配置されるべき座標、waitは待機時間です。 配列の最後の要素に、トレーサー情報を追加します。



  time: this.timer, human_time: racer.human_time, start_i: racer.start.i, start_j: racer.start.j, road: settings.road, name: racer.name, color: racer.fill,
      
      





ここで、timeはこのライザーがフィニッシュラインに到達したフレームの総数、human_timeはhh形式の時間です:ss、start_i、start_jは開始位置の座標、roadはこのトレーサーが受信されたルートのインデックス、nameは名前ですトレーサー、色-ライザーの色。



各プレイヤーの順番に、オブジェクトは現在のパラメーターで配列に記録されます。 座標、コース、方向、速度を開始します。 速度がゼロの場合、待機パラメーターが増加します。 フレームごとに1回、このパラメーターに1が追加され、速度は次のようになります。

ゼロ以上。



ライザーの開始時に、移動オブジェクトが作成され、待機増分が開始されます(最初は速度がゼロであるため)。次に、移動するたびに、フレームカウンターがゼロになると、移動オブジェクトが配列に書き込まれるか、待機が増分されます。



この配列を読み取るとき、待機値が最初に表示されます。 このパラメーターがゼロよりも大きい場合、このライザーのレンダリングはオフになり、独自のカウンターが無差別になり始めます。 独自のカウンタが待機値と等しい場合、次の移動オブジェクトはさらに見えます。 待機がゼロに等しくないトレーサーオブジェクトは、プレーヤーの制御下にあるライザーの動きと同じ機能によって処理されます。 つまり、移動の速度と方向、いわゆる移動のターゲット(この移動の終点)がオブジェクトから設定され、レンダリングパラメーターを計算してライザーのコースを描くための標準の関数セットが起動されます。



おわりに



その結果、プレイヤー間のネットワークインタラクションの要素を備えた非常に機敏なアーケードゲームを手に入れました。 ブラウザー間の互換性をチェックしませんでした...より正確には、firefoxはスケールを変更するときにひどいfpsを出しましたが、これが何に関連するのかわかりません。 誰かが働かない場合は、クロム、または極端な場合にはクロム。



最初に、私はゆったりと不可解なものを考えました。つまり、セルを数え、次の動きで壁にぶつからないようにすることができるポイントを見つける必要がありました。 そして、細胞がありました。 しかし、50 fpsでレーサーのアウトラインを素晴らしいスピードと滑らかさで実現できることに気付いた後、すべてをやり直し、ターンに沿って論理的なゲームをする代わりに、アーケードを得ました。



ゲームは約3000行のコードと4メガバイトに達しました。



UP 1:クロムがLinux(50fps)で正常に動作する理由を誰かが知っているのに、20しか与えられません。そして、firefoxがviewBox、特にスケーリングを嫌うのはなぜですか? すべてのレンダリングはwindow.requestAnimationFrame()で実行されます



All Articles