正方形、三角形などの形を形成する一連の拡大する弾丸パターンを作成したい膨張星:
正方形、三角形などの形を形成する一連の拡大する弾丸パターンを作成したい膨張星:
回答:
これを行う最も簡単な方法は、最初に形状を設計し、次に粒子の動きを計算することです。この回答では、正方形を作成しますが、これはあらゆる形状に適用されます。
何らかの原点を中心とした相対的な位置として形状を設計することから始めます。
次に、形状がどのように拡張するかを計算する必要があります。これを行うには、origin
からpoint
を差し引くことでからを指すベクトルを計算するだけですorigin
、当社からの位置をpoint
、その後の位置を正規化ベクトルを。vector = normalize(point.x - origin.x, point.y - origin.y)
。
これで、このベクトルを使用して、任意の時点でのポイントの位置を計算できます。を行うことにより、ポイントの次の位置を計算しpoint.position += point.vector * point.velocity
ます。前のポイントを使用した擬似コードの例:
// When you start your program you set these values.
point.position = (-3, 3); // Start position. Can be anything.
point.vector = normalize(-3, 3); // Normalized vector.
point.velocity = 3; // Can be anything.
// You do this calculation every frame.
point.position += point.vector * point.velocity;
// point.vector * point.velocity = (-3, 3)
// point.position is now (-6, 6) since (-3, 3) + (-3, 3) = (-6, 6)
これを行うと、すべてのポイントがフレームごとに3単位で外側に移動します。
ノート
そのため、BulletMLと呼ばれるこのプロジェクトがあります。これは、複雑な粒子/弾丸パターンを作成するためのマークアップ言語です。ほぼ確実にコードを自分の言語に移植する必要がありますが、いくつかの本当に驚くべきことができます。
たとえば、このボスは、Unity3D用のBulletMLの(大幅に変更された)拡張で行われました(そのパターンの作成者はそのビデオをアップロードし、Miseryは正気であり1)。それはその敵の最も難しいバリエーションであり、BulletMLが非常に優れていることを示しています(そして、WallmasterのようなMiseryの他のボスもチェックしてください)。
または、この例を示すことができます。これは、最後のフェデレーションの拡張に取り組んでいるときに書いたパターンで、MODの友好性が低く、単一文字のAZ変数のみを使用するシステムの古いリビジョンを使用しています:
これらのリングを作る緑色の弾丸は、高速で回転する親弾丸から生成されますが、それ自体は動きません。彼らは大規模なダメージを与え、プレーヤーをより長い距離に保ち、より低いダメージの武器に制限し、モバイル防御者がプレーヤーに嫌がらせを行えるようにします(中央の不動の構造が破壊された場合、プレーヤーが勝ちます)。
これらのバブルを作成するXML構文の一部を次に示します。
<bullet_pattern name="Barrier">
$WallShotAngle B=.3 A=90
$WallShotAngle B=.3 A=-90
$WallShotAngle B=.3 A=0
$WallShotAngle B=.375 A=180
</bullet_pattern>
<var name="WallShotAngle">
<bullet angle="[A]" speed="4000" interval_mult=".01" dumbfire="1" shot_type="GravityWavePurple">
<wait time="[B]" />
<change angle="0" speed="1000" time=".0001" />
<spawn>
<bullet_pattern>
<bullet angle="[A]" speed="0" shot_type="CurveBarGreen" damage_mult="8">
<wait time="12" />
<die />
</bullet>
</bullet_pattern>
</spawn>
<die />
</bullet>
</var>
スクリーンショットで紫色の「重力波」ショットの一部を見ることができます。これは、ソース(回転)からバブルの端までほとんど瞬時に移動し、12秒間待機する緑色の「曲線バー」ショットを生成します。スポーン。青と黄色のショットは、はるかに複雑なので省略しました。
拡張のその他のパターン(砲弾)の1つは実際にMiseryによって作成されましたが、私はそれにいくつかの修正を加えました。当初は、長距離に飛び出してから巨大な花火大会に爆発し、大量のダメージを与える低ダメージの貫通ショットです。最大射程はプレイヤーが達成できる範囲よりもはるかに高く、基本的にプレイヤーは短距離で交戦することを余儀なくされました。これは、ショットガン効果により小さな他のタイプのNPCユニットに有利でした(小さなゾーンに多くの弾丸が集まっています)。
BulletMLは、一般的に操作が簡単で、驚くべきことを実行できます。弾丸は方向を変えたり、速度を変えたり、他のパターンを生成したり、早く死んだり、ループ内でコマンドの収集を繰り返したり、遅延を使用したり、弾丸のスプライト画像を変更したり、親を追ったり(追わなかったり)... それに書きます。
あなたが本格的なシュートエムアップゲームをしているなら、私は間違いなくそれをお勧めします。Charanorが答えで説明しているように、座標計算を行って必要な形状を取得する必要がありますが、BulletMLのような弾丸エンジンは柔軟性が非常に高いため、考え出すよりも新しいパターンの設計に多くの時間を費やすことになりますそれらをどのようにコーディングするか。
Charanorが指摘したように、ポイントの配列を使用して形状を定義し、その位置を経時的に更新できます。以下は、ポイントを使用して星型またはカスタムシェイプを実装する方法の実用例です。
package com.mygdx.gtest;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Pixmap.Format;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;
public class Test extends ApplicationAdapter{
public SpriteBatch sb;
private StarShape ss, ssBig;
@Override
public void create() {
sb = new SpriteBatch();
Pixmap pmap = new Pixmap(2, 2,Format.RGBA8888);
pmap.setColor(Color.WHITE);
pmap.fill();
ss = new StarShape(50,50,new Texture(pmap), 10, true);
ssBig = new StarShape(250,250,new Texture(pmap), 50, false);
pmap.dispose();
}
@Override
public void render() {
super.render();
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
ss.update(Gdx.graphics.getDeltaTime());
ssBig.update(Gdx.graphics.getDeltaTime());
sb.begin();
ss.draw(sb);
ssBig.draw(sb);
sb.end();
}
@Override
public void dispose() {
super.dispose();
}
private class StarShape{
public float progress = 1f;
public Texture bulletTex;
public Array<Vector2> points = new Array<Vector2>();
public Vector2 center;
public StarShape(float x, float y, Texture tex, float initialSize, boolean mathWay){
center = new Vector2(x,y);
bulletTex = tex;
if(mathWay){
// define star shape with maths
float alpha = (float)(2 * Math.PI) / 10;
float radius = initialSize;
for(int i = 11; i != 0; i--){
float r = radius*(i % 2 + 1)/2;
float omega = alpha * i;
points.add(
new Vector2(
(float)(r * Math.sin(omega)),
(float)(r * Math.cos(omega))
)
);
}
}else{
// or define star shape manually (better for non geometric shapes etc
//define circle
points.add(new Vector2(-3f,0f));
points.add(new Vector2(-2.8f,1f));
points.add(new Vector2(-2.2f,2.2f));
points.add(new Vector2(-1f,2.8f));
points.add(new Vector2(0f,3f));
points.add(new Vector2(1f,2.8f));
points.add(new Vector2(2.2f,2.2f));
points.add(new Vector2(2.8f,1f));
points.add(new Vector2(3f,0f));
points.add(new Vector2(2.8f,-1f));
points.add(new Vector2(2.2f,-2.2f));
points.add(new Vector2(1f,-2.8f));
points.add(new Vector2(0f,-3f));
points.add(new Vector2(-1f,-2.8f));
points.add(new Vector2(-2.2f,-2.2f));
points.add(new Vector2(-2.8f,-1f));
// mouth
points.add(new Vector2(-2,-1));
points.add(new Vector2(-1,-1));
points.add(new Vector2(0,-1));
points.add(new Vector2(1,-1));
points.add(new Vector2(2,-1));
points.add(new Vector2(-1.5f,-1.1f));
points.add(new Vector2(-1,-2));
points.add(new Vector2(0,-2.2f));
points.add(new Vector2(1,-2));
points.add(new Vector2(1.5f,-1.1f));
points.add(new Vector2(-1.5f,1.5f));
points.add(new Vector2(1.5f,1.5f));
}
}
public void update(float deltaTime){
this.progress+= deltaTime;
}
public void draw(SpriteBatch sb){
Vector2 temp = new Vector2(0,0);
for(Vector2 point: points){
temp.x = (point.x);
temp.y = (point.y);
temp.scl(progress);
sb.draw(bulletTex,temp.x + center.x,temp.y +center.y);
}
}
}
}