群集モデリングのパーティクルシステム(2)

2014年4月7日( クラウドモデリングのパーティクルシステム)から会話を続けます。



この部分に追加します:

  1. 遅いキャラクター(これらは大きな矢印になります)
  2. 遅い矢印の周りに速く曲がる
  3. 爆発(体の散乱あり)




コードの記述スタイルに関する短いコメント(最初の部分の読者向け):





遅いキャラクター


MainWaylines_2.setupEmitterForMonsterArrows()メソッドを作成します。 これは、実際には以前のMainWaylines_1.setupEmitter()の コピー アンド ペーストです 。 古いコメントを削除し、変更がある場合にのみ残しました。



protected function setupEmitterForMonsterArrows():void { var emitter:Emitter2D = new Emitter2D(); //   -   1     emitter.counter = new Steady(1); var wayline:Wayline = _waylines[0]; emitter.addInitializer( new Position( new LineZone( new Point(wayline.x - wayline.radius*Math.cos(wayline.rotation), wayline.y - wayline.radius*Math.sin(wayline.rotation)), new Point(wayline.x + wayline.radius*Math.cos(wayline.rotation), wayline.y + wayline.radius*Math.sin(wayline.rotation)) ) ) ); // ,        //    emitter.addInitializer( new ImageClass( Arrow, [10] ) ); emitter.addAction( new DeathZone( new RectangleZone( -30, -30, stage.stageWidth+60, stage.stageHeight + 60 ), true ) ); emitter.addAction( new Move() ); emitter.addAction( new RotateToDirection() ); //      ,      , //        action // emitter.addAction( new MinimumDistance( 7, 600 ) ); //    emitter.addAction( new ActionResistance(.1)); emitter.addAction( new FollowWaylines(_waylines) ); var renderer:DisplayObjectRenderer = new DisplayObjectRenderer(); addChild( renderer ); renderer.addEmitter( emitter ); //   emitterWaylinesForMonsterArrows = emitter; emitterWaylinesForMonsterArrows.start(); }
      
      







MainWaylines_2.setup()を展開して実行します



 override protected function setup(e:Event=null):void { super.setup(); //        setupEmitterForMonsterArrows(); }
      
      







このような画像を取得します。 大きな矢印は小さな矢印と結合します-並行して存在します







遅い矢印の周りに速く曲がる


小さなものが大きな矢印を迂回するためには、それらにコマンドを与える必要があります。 MainWaylines_2.setup()に行を追加します。Antigravitiesは、パーティクルシステムライブラリのもう1つの標準アクションです(クールライブラリですよね?)。



 override protected function setup(e:Event=null):void { super.setup(); //        setupEmitterForMonsterArrows(); //   action   "  " //  (!)   ,      -       emitterWaylines.addAction( new Antigravities(emitterWaylinesForMonsterArrows, -400000) ); }
      
      







結果はこの図のようになり始めます。 小さな矢印は既に大きな矢印を包み込んでいますが、すでに多くの矢印が背後に蓄積しています。 これらの交通渋滞は見苦しい。







これは、次の「競合」によるものです。 反重力により、大きな矢印の周りに小さな矢印が曲がります。 FollowWaylines同時にそれらを前方に駆動します-各矢印はパスの垂線上の特定のポイントに向かう傾向があります、覚えていますか? 小さい矢印は、途中でノードポイントに近づきすぎているため、大きい矢印を時間内に丸めるだけの時間はありません。 解決策の1つ(そして、私にとって最も簡単なようです)は、パスセグメントの長さ(ルートノード間の距離)を増やすことです。



MainWaylines_2.setupWaylines()を1行に書き換えます



 override protected function setupWaylines():void { _waylines = []; var w:Number = stage.stageWidth; var h:Number = stage.stageHeight; var points:Array = [new Point(-9,h*.4), new Point(w*.3,h*.4), new Point(w*.5,h*.1), new Point(w*.8,h*.1), new Point(w*.8,h*.9), new Point(w*.5, h*.9), new Point(w*.3, h*.8), new Point(-40, h*.8)]; var fitline:FitLine = new FitLine(points); var path:Path = new Path(fitline.fitPoints); /* *   .  40,  25 * *   ,    ,           * ,   ,         */ var step:Number = path.length / 25; var strength:Number = 100; for(var i:int=0; i<path.length; i+=step) { var segmentLength:int = 60;//*Math.random()+10; var pathpoint:PathPoint = path.getPathPoint(i); var wayline:Wayline = new Wayline(pathpoint.x, pathpoint.y, segmentLength, pathpoint.rotation-Math.PI/2, strength); _waylines.push(wayline); } }
      
      







それでも、大きな矢印は小さな矢印よりもはるかに小さい(60倍)ため、狭いフェアウェイに沿って発射することができ(大きな矢印の場合はEMITTERの幅を小さくします)、小さな矢印がエッジからより自由にバイパスできるようにします。



MainWaylines_2.setupEmitterForMonsterArrows()を編集して、エミッターのLineZoneを20(各側に10ピクセル減らします



 emitter.addInitializer( new Position( new LineZone( new Point(wayline.x - (wayline.radius-10)*Math.cos(wayline.rotation), wayline.y - (wayline.radius-10)*Math.sin(wayline.rotation)), new Point(wayline.x + (wayline.radius-10)*Math.cos(wayline.rotation), wayline.y + (wayline.radius-10)*Math.sin(wayline.rotation)) ) ) );
      
      







今、大きな矢印の後ろの渋滞はずっと小さくなっています







爆発(体の散乱あり)




新しいエミッタを作成します-ボディの散乱のアニメーション用



 protected function setupEmitterForExplosion():void { var emitter:Emitter2D = new Emitter2D(); //    -    emitter.addAction( new Move() ); //      ,       -     emitter.addAction( new SpeedLimit(40)); //      -  emitter.addAction( new Friction(40) ); //    -   (      ) emitter.addAction( new DeathZone( new RectangleZone( -30, -10, stage.stageWidth+40, stage.stageHeight + 20 ), true ) ); //   var renderer:DisplayObjectRenderer = new DisplayObjectRenderer(); addChild( renderer ); renderer.addEmitter( emitter ); //   emitterExplosion = emitter; emitterExplosion.start(); }
      
      







MainWaylines_2.setup()で MouseEvent.MOUSE_DOWNをサブスクライブします -これらのイベントで爆発を生成します



 stage.addEventListener(MouseEvent.MOUSE_DOWN, handleMouseDown);
      
      







すぐに爆発(e)と呼ばないのはなぜですか ? そこで、爆発自体のアニメーションを追加して、結果を生成できます。



 private function handleMouseDown(e:MouseEvent):void { explosion(e); }
      
      







今爆発自体



 private function explosion(e:MouseEvent):void { if(emitterWaylines == null){ return; } if(emitterExplosion == null){ return; } //   var explRadius:int = 30; //      // (        ,   dot-     ) var particleOrigin:Particle2D; var particleClone:Particle2D; var particlePoint:Point = new Point(); //    ... var explPoint:Point = new Point(e.stageX, e.stageY); //     var particles:Array = emitterWaylines.particlesArray; var length:int = particles.length; //      for(var p:int=0; p<length; p++) { particleOrigin = particles[p]; particlePoint.x = particleOrigin.x; particlePoint.y = particleOrigin.y; // ,        if(Point.distance(explPoint, particlePoint) < explRadius) { /* *  ,    -         *       -    */ particleClone = particleOrigin.clone(emitterExplosion.particleFactory) as Particle2D; particleClone.angVelocity = -5 + Math.random() * 10; /* *    Arrow ( ) -    ActionScript  ,      * !      , *         emitterWaylines   * -       renderer.removeChild() * *    .        . *      ( , )   , *       ( -      ) */ particleClone.image = new Arrow(4, 0xff0000); //       emitterExplosion.addParticle(particleClone); //      particleOrigin.isDead = true; } } /* *  action    * *   , ,   -     , *    ,         (.     ). * *    -     :       * *  ,        ,    ... *   -     */ var explosion:Explosion = new Explosion(10000, explPoint.x, explPoint.y, 100); emitterExplosion.addAction(explosion); /* *          -        *       Emitter2D.update(.2) -      */ //         emitterExplosion.update(0.2); //  action Explosion -     emitterExplosion.removeAction(explosion); }
      
      







始めます。 数回クリックすると、次の図が表示されます。赤いものは制御不能に蓄積しますが、ストリームに戻す必要があります。







必要な変更の本質は簡単です-一定時間後、粒子を前のストリームに「戻す」必要があります。

1.最初に、 MainWaylines_2.setupEmitterForExplosion()に変更を加えます。

 protected function setupEmitterForExplosion():void { var emitter:Emitter2D = new Emitter2D(); ... //  action  "" .   ,  . // .    ,       emitterExplosion.addAction( new Age() ); ... //   "   ",      ""  emitterExplosion.addEventListener(ParticleEvent.PARTICLE_DEAD, handleParticleDeadFromEmitterExplosion); }
      
      







2.変更をMainWaylines_2.explosion()に追加します



 private function explosion(e:MouseEvent):void { ... //      for(var p:int=0; p<length; p++) { ... // ,        if(Point.distance(explPoint, particlePoint) < explRadius) { particleClone = particleOrigin.clone(emitterExplosion.particleFactory) as Particle2D; particleClone.angVelocity = -5 + Math.random() * 10; /* * action Age()   ,     *        ,  "" *           */ particleClone.lifetime = 3; particleClone.age = 0; ... } } ... }
      
      







始めます。 受け取ります。







結果:

  1. 2種類のユニット:小と大
  2. 小さいユニットは大きく回ります
  3. 爆発は小さなユニットに影響を与えます(破片にして、戦車には影響しません-大きな矢印)
  4. 小さなものが「カンタス」から回復した後、再び一般的な流れに戻ります




明らかな短所

  1. 非叙事詩の高速シューティングゲーム
  2. fps




パラグラフ1の問題を解決する場合。 エミッターの設定を引き続き使用できます(そして、パーティクルシステムを使用する私の現在の方法は最も完璧ではありません)。次に、ポイント2( FPS )についてはどうでしょうか。 最適化の可能性はありますか? 結局のところ、あなたはまだ通常のグラフィックス、たくさんのゲームコードを固定する必要があります...



最適化の可能性があると思います

  1. 現在のスケールでの小さな矢印間の衝突の禁止-実際は純粋に-ユニットの数を2〜5倍増やすことができ、結果の混乱には何も表示されません(フィールドへの投影がトップダウンでない場合、しかし、等尺性?)。 また、「完全な混乱」はありません-小さな矢印は、忘れずに、個別に指定されたルートに沿って移動するためです(それぞれが接線に対する垂線に対して相対的な位置を持っています)。 相互衝突を防ぐアクションMinimumDistanceを無効にしてみてください-大きな違いに気付かないでしょう(大きなものを追い越す場合のみ)。 また、パフォーマンスが大幅に向上します(アクションコードを見て、計算の数を確認できます)。
  2. 「ネイティブ」レンダリングをオフにしただけで、FPSはすぐに1.5倍以上成長しました(そしてStarlingの場合)。





ここで、一般的なアプローチの複雑さについて説明します-パーティクルシステムでの作業。

エミッターの山、それらの設定、それらの間での粒子の移動など、複雑すぎないように願っています...

実際、 データ指向のアプローチでは、数百のパーティクルの動作のロジック全体が正確にエミッター内にあります。 そして現在、そのうちの3つだけです(大小のシューティングゲームのエミッターは通常双子の兄弟です)。

まだエミッターは、ルート(爆風の敗北)に続く状態( State )として表すことができます。 そして、エミッタ間での粒子の「移動」は、状態間の遷移にすぎません。



コードはgoogle codeで入手できます 。 クラスMainWaylines_2



PS:次のパートでは、シューターの死を追加します(結局、爆発を殺します)

エミッターの設定をいじってみます-壮大なものが欲しいです。



PPS:質問。 アニメーション化された3Dキャラクターからスプライトシートを作成する簡単な方法を学びたいです。 私が自分で見ているように:

  1. アニメキャラクターがいます
  2. 特定のソフトウェア製品でおよそ次のパラメーターを設定したい:

    • サイズ
    • カメラアングル
    • フレーム数
  3. 出力- スプライトシート
どちらを見るか教えてくれませんか? たぶん、そのようなWORKINGテクニックの詳細な説明がありますか?

事前に感謝します。



PPPS: MainWaylines_2.explosion()メソッドのコードに2行追加:爆発前に粒子速度ベクトルをリセットします-より自然に見えます



 protected function explosion(e:MouseEvent):void { ... particleClone.velX = 0; particleClone.velY = 0; ... }
      
      








All Articles