Jump to content
  • Advertisement
Sign in to follow this  
slayemin

XNA: having trouble with particles

This topic is 3417 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm trying to create a simple particle engine where each particle has its own state and is owned by a particle generator class. I give each particle its own lifespan and then ask it to change states when it dies. With a state change, it resets its life and changes to a new texture. Ideally, I'd like for each particle to behave independently from other particles. Unfortunately, that's not the case. Currently, when one particle changes states and becomes a new graphic, every particle in my array changes to the new graphic. I'm new to XNA and I don't know what is going on. I suspect that when one particle changes states, it changes the texture on the graphics card and every other instance of a particle uses the new texture. Help! BTW, I think my code might be sloppy and I might be doing some things unnecessarily. If you see anything I can improve, please point it out :) thanks!
class ParticleClump2
    {
        GraphicsDeviceManager graphics;
        ContentManager Content;
        public Random rand;

        private class Particle
        {
            public Effect pointSpritesEffect;
            public VertexPositionColor[] spriteArray;
            public VertexDeclaration vertexPosColDecl;
            int MaxLife, CurrentLife;
            public enum State { Rain = 0, Fire, Smoke };
            public State CurrentState;
            ContentManager cm;

            public void Load(ContentManager Content, GraphicsDeviceManager graphics, Vector3 Pos)
            {
                cm = Content;
                pointSpritesEffect = cm.Load<Effect>("Resources\\Effects\\pointsprites");
                pointSpritesEffect.Parameters["SpriteTexture"].SetValue(
                    cm.Load<Texture2D>("Resources\\Textures\\Glowball"));
                spriteArray = new VertexPositionColor[1];//1 particle in the array
                vertexPosColDecl = new VertexDeclaration(graphics.GraphicsDevice,
                    VertexPositionColor.VertexElements);
                
                for (int i = 0; i < spriteArray.Length; i++)
                {
                    spriteArray.Position = Pos;
                    spriteArray.Color = Color.LimeGreen;//doesn't do anything
                }
                CurrentState = State.Rain;
            }

            public void SetLife(int a)
            {
                MaxLife = a;
                CurrentLife = a;
            }

            public void Update()
            {
                if (CurrentLife-- <= 0)
                {
                    CurrentLife = MaxLife;
                    if (CurrentState == State.Rain)
                    {
                        pointSpritesEffect.Parameters["SpriteTexture"].SetValue(cm.Load<Texture2D>("Resources\\Textures\\FireSprite"));
                        CurrentState = State.Fire;
                        return;
                    }
                    if (CurrentState == State.Fire)
                    {
                        pointSpritesEffect.Parameters["SpriteTexture"].SetValue(cm.Load<Texture2D>("Resources\\Textures\\Smoke"));
                        CurrentState = State.Smoke;
                        return;
                    }
                    if (CurrentState == State.Smoke)
                    {
                        pointSpritesEffect.Parameters["SpriteTexture"].SetValue(cm.Load<Texture2D>("Resources\\Textures\\Glowball"));
                        CurrentState = State.Rain;
                        return;
                    }
                }
            }
            public void Draw(ref Matrix VM, ref Matrix PM, GraphicsDeviceManager graphics)
            {
                graphics.GraphicsDevice.VertexDeclaration = vertexPosColDecl;

                Matrix WVPMatrix = Matrix.Identity * VM * PM;
                pointSpritesEffect.Parameters["WVPMatrix"].SetValue(WVPMatrix);

                pointSpritesEffect.Begin();
                foreach (EffectPass pass in pointSpritesEffect.CurrentTechnique.Passes)
                {
                    pass.Begin();
                    graphics.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.PointList,
                        spriteArray, 0, spriteArray.Length);
                    pass.End();
                }
                pointSpritesEffect.End();
            }
        }
       
        private Particle[] ParticleArray;

        public void Init(ref GraphicsDeviceManager gdm, ContentManager cm)
        {
            graphics = gdm;
            Content = cm;
        }

        public void LoadContent()
        {
            rand = new Random();
            ParticleArray = new Particle[50];   //50 particles in the clump

            //initialize every particle in the array
            for (int a = 0; a < ParticleArray.Length; a++)
            {
                ParticleArray[a] = new Particle();
                Vector3 Pos = new Vector3(rand.Next(100) / 10f, rand.Next(100) / 10f, rand.Next(100) / 10f);
                ParticleArray[a].SetLife(rand.Next(100, 300));

                ParticleArray[a].Load(Content, graphics, Pos);
            }
        }

        public void Update()
        {
            //go through every particle in the array and call its update function
            for (int a = 0; a < ParticleArray.Length; a++)
            {
                ParticleArray[a].Update();
            }
        }

        public void Draw(ref Matrix viewMatrix, ref Matrix projectionMatrix)
        {
            graphics.GraphicsDevice.Clear(Color.Black);

            //set device settings
            graphics.GraphicsDevice.RenderState.PointSpriteEnable = true;
            graphics.GraphicsDevice.RenderState.PointSize = 64.0f;
            graphics.GraphicsDevice.RenderState.AlphaBlendEnable = true;
            graphics.GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha;
            graphics.GraphicsDevice.RenderState.DestinationBlend = Blend.One;
            graphics.GraphicsDevice.RenderState.DepthBufferWriteEnable = false;

            //go through every particle in the clump and call its draw function
            for (int a = 0; a < ParticleArray.Length; a++)
            {
                ParticleArray[a].Draw(ref viewMatrix, ref projectionMatrix, graphics);
            }

            //restore device settings
            graphics.GraphicsDevice.RenderState.PointSpriteEnable = false;
            graphics.GraphicsDevice.RenderState.DepthBufferWriteEnable = true;
            graphics.GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha;
            graphics.GraphicsDevice.RenderState.DestinationBlend = Blend.InverseSourceAlpha;
        }
    }

Share this post


Link to post
Share on other sites
Advertisement
I'm not that familiar with XNA, but my guess would be that you want to do the pointSpritesEffect.Parameters["SpriteTexture"].SetValue() in the Draw() method, and not in the Update() one.

That will probably require storing the texture in the particle object, and adjusting that drawing loop a bit.

Share this post


Link to post
Share on other sites
I think I figured it out. The way I was doing my implementation, I was implementing multiple particle systems within the content manager. The problem is, when I create a new particle effect, I stomp over the parameters of the previous particle effect settings.

After playing around with it, I found that if I create multiple copies of my effect files and define more Effect variables, I can have my particles change state independently of other particles. That's kinda cool but very inefficient.

After doing some research online, I found a sweet tutorial which solves my problem by using Effect.Clone(GraphicsDevice). SO much more simple, but totally unintuitive API call for a noob like me.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!