0

XNA 4.0 で作成しているゲームでパーティクル システムを作成しようとしています。パーティクルは、エミッタが初期化されたワールドでレンダリングされます。問題は、Update() でパーティクルの位置を更新したいのですが、動作しません。パーティクルはレンダリングされますが、位置 0、0、0 の世界の中心でのみです。

各パーティクルは、テクスチャを持つ頂点のグループで構成されます。

誰でも私を助けることができますか?パーティクル エミッタのクラスは次のとおりです。

public class ParticleEmitter : RenderableGameObject
{
    VertexBuffer vertexBuffer;
    VertexDeclaration vertexDeclaration;
    Effect bbEffect;

    VertexPositionTexture[] vertices;

    Texture2D texture;
    int noVertices = 0;

    struct Particle
    {
        public Vector3 position;
    }
    Particle[] particles = new Particle[5];

    public ParticleEmitter(Game1 game)
        : base(game)
    {
        SetupParticles();

        SetupVertices();

        bbEffect = game.Content.Load<Effect>("Effects/Particle");
        texture = game.Content.Load<Texture2D>("Textures/fire");
    }

    private void SetupVertices()
    {
        int vertexIndex = 0;
        vertices = new VertexPositionTexture[particles.Length * 6];

        for (int i = 0; i < particles.Length; ++i)
        {
            vertices[vertexIndex++] = new VertexPositionTexture(particles[i].position, new Vector2(0, 0));
            vertices[vertexIndex++] = new VertexPositionTexture(particles[i].position, new Vector2(1, 0));
            vertices[vertexIndex++] = new VertexPositionTexture(particles[i].position, new Vector2(1, 1));

            vertices[vertexIndex++] = new VertexPositionTexture(particles[i].position, new Vector2(0, 0));
            vertices[vertexIndex++] = new VertexPositionTexture(particles[i].position, new Vector2(1, 1));
            vertices[vertexIndex++] = new VertexPositionTexture(particles[i].position, new Vector2(0, 1));
        }

        noVertices = vertexIndex;

        vertexBuffer = new VertexBuffer(game.GraphicsDevice, typeof(VertexPositionTexture), vertices.Length, BufferUsage.WriteOnly);
        vertexBuffer.SetData(vertices);
        vertexDeclaration = new VertexDeclaration(VertexPositionTexture.VertexDeclaration.GetVertexElements());
    }

    private void SetupParticles()
    {
        for (int i = 0; i < particles.Length; ++i)
        {
            particles[i] = new Particle();
            particles[i].position = Position * i;
        }
    }

    private void UpdateVertices()
    {
        for (int i = 0; i < particles.Length; ++i)
        {
            vertices[i] = new VertexPositionTexture(particles[i].position, new Vector2(0, 0));
            vertices[i] = new VertexPositionTexture(particles[i].position, new Vector2(1, 0));
            vertices[i] = new VertexPositionTexture(particles[i].position, new Vector2(1, 1));

            vertices[i] = new VertexPositionTexture(particles[i].position, new Vector2(0, 0));
            vertices[i] = new VertexPositionTexture(particles[i].position, new Vector2(1, 1));
            vertices[i] = new VertexPositionTexture(particles[i].position, new Vector2(0, 1));
        }

        game.GraphicsDevice.SetVertexBuffer(null);
        vertexBuffer.SetData(vertices);
    }

    private void UpdateParticles()
    {
        for (int i = 0; i < particles.Length; ++i)
        {
            particles[i].position = Position;
        }
    }

    public override void Update(GameTime gameTime)
    {
        UpdateParticles();
        UpdateVertices();

        base.Update(gameTime);
    }

    public override void Draw()
    {
        DrawParticles(game.camera.viewMatrix);
    }

    private void DrawParticles(Matrix currentViewMatrix)
    {
        bbEffect.CurrentTechnique = bbEffect.Techniques["CylBillboard"];
        bbEffect.Parameters["xWorld"].SetValue(Matrix.Identity);
        bbEffect.Parameters["xView"].SetValue(currentViewMatrix);
        bbEffect.Parameters["xProjection"].SetValue(game.camera.projectionMatrix);
        bbEffect.Parameters["xCamPos"].SetValue(game.camera.Position);
        bbEffect.Parameters["xAllowedRotDir"].SetValue(new Vector3(0, 1, 0));
        bbEffect.Parameters["xBillboardTexture"].SetValue(texture);

        foreach (EffectPass pass in bbEffect.CurrentTechnique.Passes)
        {
            game.GraphicsDevice.BlendState = BlendState.AlphaBlend;

            pass.Apply();
            game.GraphicsDevice.SetVertexBuffer(vertexBuffer);
            int noTriangles = noVertices / 3;
            game.GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, noTriangles);
        }
    }
}
4

1 に答える 1

1

この方法では、実際にはパーティクルの位置をまったく変更していません。

private void UpdateParticles()
{
    for (int i = 0; i < particles.Length; ++i)
    {
        particles[i].position = Position;
    }
}

すべてのパーティクルを同じ位置、おそらく原点に設定しています。

おそらくやりたいことは、各パーティクルに速度を追加するようなものです。

struct Particle
{
    public Vector3 position;
    public Vector3 velocity;
}

そして、ランダムな速度で各粒子を初期化します。

// Pass a shared, per-thread instance of Random into this method
private void SetupParticles(Random random)
{
    for (int i = 0; i < particles.Length; ++i)
    {
        particles[i] = new Particle() {
            position = Vector.Zero,
            velocity = new Vector3((float)(random.NextDouble() * 2 - 1),
                                   (float)(random.NextDouble() * 2 - 1),
                                   (float)(random.NextDouble() * 2 - 1))
        };
    }
}

そして、いくつかの物理モデルに従ってそれらを更新します(つまり、時間の経過に伴う重力による速度と加速度)。

Vector3 gravity = new Vector3(0, -9.8f, 0);

private void UpdateParticles(float time)
{
    for (int i = 0; i < particles.Length; ++i)
    {
        particles[i].velocity += gravity * time;
        particles[i].position += particles[i].velocity * time;
    }
}

(注:この回答のすべてのコードは手作業で書かれています-構文エラーなどに注意してください)

于 2013-04-10T09:49:14.077 に答える