物理学を使用したFlashプラットフォームでの別のカジュアルの作成。 パートII

Habraコミュニティにこんにちは。



比較的最近、かなり前に、物理学を使ってFlashプラットフォームで別のカジュアルを作成することに関する記事書きました

この記事では、世界を描き、センサーについて話す方法をお教えします。 残りはカットの下にあります。



これら2つのレッスンから何ができるかは、 ここで見ることができます (音楽をオフにすることはできませんが、システムのサウンドを削除することはできます)



もう一度、最後の「 レッスン 」で何が起こったかを思い出してください。



グラフィックス



今、あなたはゲームで将来のグラフィックス描くために盗む必要がありますが、 このレッスンは主にゲームのプログラミングに関するもので、私がやったことを活用できます。



テクスチャ1:









テクスチャ2:









これは、474x474ピクセルの2つのBMPテクスチャです。

彼らは私たちの世界の基盤として機能します。



テクスチャ2は静的なテクスチャであり、スプライトの形で表示され、常に必要な回転角度で描画されます。



テクスチャ1は、世界を描くためのテクスチャです。beginBitmapFillと変換マトリックスを使用して、世界の四角形で塗りつぶします。 言い換えれば、浸水しないのは、移動の自由と空きスペースです。



必要な設定に従って少し美しく設計すると、次のようになります。











ヒーローボールにシェル画像(スプライト)を与えます。ここで、スケジュールを取ることもお勧めします。





そして、最も退屈な迷路を通過することが完全に退屈ではないように、障害物を作成します:スパイク、火、レーザー。 しかし、以来 記事の量は十分でなければなりません。スパイクのみを考慮しますが、他のすべての基礎を作成します。



ほぞのテクスチャ:





必要なリンクを作成すると、ライブラリは次のようになります。





グラフィックの準備ができました。



センサー





センサーは通常のオブジェクト(静的ボディ、動的ボディ)です。ただし、isSensorフラグがあります。 このチェックボックスは何をしますか? すべてが非常に単純で、そのようなオブジェクトは衝突を「感じ」ますが、isSensorフラグのないオブジェクトの場合、何も起こりません。 固体オブジェクト-センサーを通過するだけで、ContactListenerで衝突イベントをトリガーします。



ContactListenerは、 Box2Dの衝突リスナーです。 たとえば、オブジェクトAとBが世界で衝突すると、Add(ポイント:b2ContactPoint)関数がContactListenerで呼び出され、ポイントには以下が含まれます。衝突に関係するシェープファイル。 グローバル座標系の衝突点。 衝突体。 つまり、これらのイベントを処理できます。



-センサー、リスナー、明確なものは何もありませんが、これはなぜですか?

次に、ヒーローとスパイクの衝突で、ヒーローの死を引き起こし、レベルを再起動するのが論理的です。



理論からビジネスまで、プログラミングに進みます





世界で描くことを学ぶ




プロジェクトのサイズを500x500から600x580に変更します。

デバッグスプライトの描画位置を次のように変更します。



sprite.x = 300; //  600 sprite.y = 290; //  580
      
      







正直なところ、すべてが中心です。



新しい変数を追加します。



 public var game:Sprite; // -   public var level_sprite:Sprite = new Sprite(); // -c   public var viewport:Sprite; // -   (, )
      
      







メインクラスコンストラクターで、ゲームとビューポートを初期化します。



 game = new sprite_game(); game.x = 300; //  game.y = 290; //  game.cacheAsBitmap = true; addChild(game); viewport = new Sprite(); viewport.x = 300; viewport.y = 290; addChild(viewport);
      
      







Flashには、個々のクリップに設定できる特別なオプション「ビットマップとしてキャッシュ」があります。これは、クリップがビットマップイメージとしてメモリのどこかに保存され、ベクターイメージとして変換されなくなることを意味します。 私の実験では、これによりパフォーマンスが向上することが示されていますが、完全な幸福のためには明らかに十分ではありません。



スプライトを回転させるのと同じ場所で、「ギア」の回転をenterFrameListenerに追加します。



 game.rotation = sprite.rotation = rotator;
      
      







私たちはまず、ただ回転する緑のゴミの絵よりも、多かれ少なかれ目を楽しませているものを見ています。



ボールにスプライトを与えます。 createHero関数を探し 、最後に追加します:



 var sprite:Sprite = new sprites_hero(); sprite.width = sprite.height = 16; viewport.addChild(sprite); hero.SetSprite(sprite); //  ,   SetSprite   . //     ,     ,   30 (. ) hero.GetSprite().x = hero.GetPosition().x * 30; hero.GetSprite().y = hero.GetPosition().y * 30; //  hero.GetSprite().rotation = hero.GetAngle() * 180 / Math.PI;
      
      







body.SetSprite-元のbox2Dにはありません。 言い換えれば、これはGetUserDataの類似物です。 しかし、GetUserDataはオブジェクトのタイプ(「ヒーロー」、「ボックス」)に使用されるため、SetSpriteをエンジンに追加しました。 元のBox2Dで作成する場合は、心配しないで、たとえば次のような動的オブジェクトを使用します。body.SetUserData({type: "hero"、sprite:sprite});



表示オブジェクトの位置をフレームごとの数学的計算と同期し、enterFrameListener関数に移動します。具体的には、ヒーローの重力を更新する瞬間に、以下を追加します。



 body.GetSprite().x = body.GetPosition().x * 30; body.GetSprite().y = body.GetPosition().y * 30; body.GetSprite().rotation = body.GetAngle() * 180 / Math.PI;
      
      







スプライトデバッグからAlphaを削除して、何が起こっているのかを区別できるようにします。



 dbgDraw.m_alpha = 0.5; dbgDraw.m_fillAlpha = 0.1;
      
      







始めて、ねじって、すべてがうまくいくことがわかります:











グラフィックに完全に切り替えるためにDebugDrawを削除することは今でも残っていますが、これを行うことができず、壁が描画されないため、これを修正します。

変換行列とテクスチャの変数を作成します。



 public var matrix_texture:Matrix; public var textureal:BitmapData;
      
      







コンストラクターでそれらを初期化します。



 textureal = new texture_gear(); matrix_texture = new Matrix(); matrix_texture.translate(237, 237); //    level_sprite viewport.addChild(level_sprite);
      
      







CreateStaticRect関数に移動して、次のようなものを追加します。



 level_sprite.graphics.beginBitmapFill(textureal, matrix_texture); level_sprite.graphics.drawRect(x - 150, y - 150, w, h); level_sprite.graphics.endFill();
      
      







また、明確にするために、別のStaticRectを(コンストラクターで)追加します。



 CreateStaticRect(150, 140, 30, 30);
      
      







しばらくの間、行にコメントを付けてDebugDrawを無効にします。



 // world.SetDebugDraw(dbgDraw);
      
      







コンパイルし、トレースされた壁を賞賛します。











私たちは自分たちの世界を描き、障害を作り出すことを学びました。

抽象クラスを作成し、障害はそれから継承されます、 障害リスト:



 package { import Box2D.Dynamics.b2World; import flash.display.Sprite; /** * ... * @author forhaxed */ public class Obstacle extends Sprite { public var active:Boolean = true; //      public var angle:int = 0; //   public var viewport:Sprite; //   viewport public var world:b2World; //    // 0 - LEFT, 1 - UP, 2 - RIGHT - 3 - DOWN public function Obstacle(_viewport:Sprite, _world:b2World, x:Number, y:Number, angle:int = 0) { viewport = _viewport; world = _world; } } }
      
      







そして、このクラスの子であるSpike (実際には私たちのスパイク)、リストを作成します:



 package { import Box2D.Collision.Shapes.b2CircleDef; import Box2D.Dynamics.b2Body; import Box2D.Dynamics.b2BodyDef; import Box2D.Dynamics.b2World; import flash.display.Sprite; /** * ... * @author forhaxed */ public class Spike extends Obstacle { public function Spike(_viewport:Sprite, _world:b2World, x:Number, y:Number, angle:int = 0) { super(_viewport, _world, x, y, angle); //   switch(angle) //     { case 0: this.rotation = 90; break; case 1: this.rotation = 180; break; case 2: this.rotation = 270; break; case 3: this.rotation = 0; break; } var body:b2Body; var bodyDef:b2BodyDef; var circleDef:b2CircleDef; var sprite:Sprite; this.x = x; this.y = y; viewport.addChild(this); /* OBSTACLE */ x = x / 30; y = y / 30; var r:Number = 6 / 30; bodyDef = new b2BodyDef(); bodyDef.position.Set(x, y); circleDef = new b2CircleDef(); circleDef.radius = r; circleDef.density = 1; circleDef.friction = 1; circleDef.isSensor = true; //  isSensor  true,        circleDef.restitution = 0.2; body = world.CreateBody(bodyDef); body.SetUserData("spike"); //    spike body.SetSprite(this); //   body.CreateShape(circleDef); body.SetMassFromShapes(); addChild(new saw()); } } }
      
      







3つのスパイクを世界に追加し、メインクラスのコンストラクターに移動して、次のように記述します。



 new Spike(viewport, world, 37, 5, 0); new Spike(viewport, world, 15, 27, 1); new Spike(viewport, world, 15, -17, 3);
      
      







スパイクをコンパイルして賞賛しますが、それらはまだ危険ではないので、それらを危険にします。











b2ContactListenerから継承した新しいGearMazeContactクラスを作成し、そのメソッドをオーバーライドします(はい、AS3ではオーバーライドは非常に重要です)。 リスト:



 package { import Box2D.Dynamics.*; import Box2D.Collision.*; import Box2D.Collision.Shapes.*; import Box2D.Dynamics.Joints.*; import Box2D.Dynamics.Contacts.*; import Box2D.Common.*; import Box2D.Common.Math.*; import flash.display.MovieClip; public class GearMazeContact extends b2ContactListener { public override function Add(point:b2ContactPoint):void { var p1:b2Body = point.shape1.GetBody(); var p2:b2Body = point.shape2.GetBody(); if(p1.GetUserData()=="hero" && p2.GetUserData()=="spike") { if ((p2.GetSprite() as Obstacle).active) { trace("Ha-ha!"); p1.SetUserData("hero_dead"); //     hero_dead,    /* ,         ,    ,     ,    */ } } } } }
      
      







リスナーをワールドに作成し、ワールドを作成してDebugDrawを設定するのと同じ場所でリスナーを接続します。



 var GearListener:GearMazeContact = new GearMazeContact(); world.SetContactListener(GearListener);
      
      







そして、死んだ場合にボールを削除する機能を追加します。これには、ボディ(enterFrameListener)を含む配列を列挙します。



 if (body.GetUserData() == "hero_dead") { if (body.GetSprite() is Sprite) viewport.removeChild(body.GetSprite()); world.DestroyBody(body); }
      
      







ここでは、ゲームプレイをさらにカットし、レーザー、ポータル、のこぎり、 女の子など 、あらゆる種類のグッズを作成できます。



これを使っておもちゃを作りたい場合は、Obstacleを使用して迷路を手続き的に生成するための簡単なアルゴリズムを作成できます。



伝統的に、記事のすべてのコード、デモへのリンク、およびこれらの手順で作成された完成したおもちゃを添付します。



ところで、残念ながらゲームは終了しません:-(

これまでのところ、これは18レベルのある種のアルファです。 コードリファクタリングは私を殺します。私は創造的な人間です。作成、作成、そして再び作成します。 お金は私には興味がない:-)



リンク: ソースコード | デモ | 終了したゲーム



PS良い男datacompboyに感謝します。記事の最初の部分を書いたとき、彼は私にドメインでホスティングを与え、フリーウェアサイトからデモ、ゲーム、ソースコードを与えてくれました。

as3のゲーム開発者についてはまだPSSを書くことができます。喜んでお答えします。



All Articles