📜 ⬆️ ⬇️

XNA Draw or write a particle system. Part I

And again, hello habravchanam!

Just a few days ago, I started a series of articles on how to create cool games using the XNA Framework, I don’t have my studio, so we’ll confine ourselves to 2D games.

This time, we'll take a closer look at Draw and write our first particle system.

What topics will be covered in this article:
')
In the second part I will tell:

As always, first the theory, then - the patties code.

SpriteBatch.Begin () method



On how to draw, we discussed in the last article. Let's now take a closer look at these methods:

spriteBatch.Begin ()


spriteBatch.Begin(SpriteSortMode, BlendState, SamplerState, DepthStencilState, RasterizerState, Effect, Matrix); 


This is how we start drawing something on the screen, this is the last method overload, so here we will look at everything.

SpriteSortMode - a way to sort sprites. Nothing interesting.

BlendState includes:

Additive - Setting for “additive blend”. Blends one sprite with another using alpha channel sprites.


AlphaBlend - Setup for alpha blend. Applies one sprite to another using the alpha channel of the sprites.


NonPremultiplied - Setting for “blending with non-premultipled alpha”, Superimposes one sprite on another, using Draw'a color alpha.


Opaque - Set up for "opaque blend", Superimposes one sprite on another, as if "overwriting" it.


SamplerState includes:
AnisotropicClamp - Contains the default state for anisotropic filtering and TextureUV - Clamp
AnisotropicWrap - Contains the default state for anisotropic filtering and TextureUV - Wrap
...

Roughly speaking, Clamp - stretches the texture, and Wrap its tile (repeats).

Use a 55x20 texture and stretch it (Clamp) five times, the differences Anisotropic / Linear, Point :

Anisotropic / Linear :


Point :


DepthStencilState - again sorting, we do not need.
RasterizerState - for 2D, we don’t really need it.
Effect - the shader (effect) that will process the drawn object.
Matrix - object transformation matrix (for example, using it you can realize a 2D camera)

Consider a method that is included between Begin and End.

SpriteBatch.Draw () method



 spriteBatch.Draw(Texture2D texture, Vector2D position, Rectangle sourceDest, Color color, float angle, Vector2D origin, Vector2D scale, SpriteEffects effects, float layerDepth); 


texture - the texture itself, which we will draw.

position - position on the screen (world, if there is a transformation matrix, in other words: “camera”).

sourceDest - a rectangle from a texture (which part of the texture we will draw, if all, then new Rectangle (0, 0, width_texture, height_texture) )

color - the color of the object.

angle - the angle of rotation.

origin is the so-called offset or “center of mass” texture. In other words, it shifts the center of the texture by NxM pixels.

scale - texture sizes in X and Y

effects - various texture display effects, for example: you can draw its mirror image.

layerDepth - the depth of the layer.

The parameters of the main functions that are responsible for drawing - sorted out.

Particle system



We write a simple system of particles, in our case it is a trail (trail, trail, tail), which will remain from the movement of the mouse.

Next is the code.

Create a new Particle class, this will be our single particle (smoke, spark, money ), listing with comments:

 using System; using System.Collections.Generic; using System.Linq; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Media; using System.Diagnostics; namespace ParticleSystem { public class Particle { public Texture2D Texture { get; set; } //    public Vector2 Position { get; set; } //   public Vector2 Velocity { get; set; } //   public float Angle { get; set; } //    public float AngularVelocity { get; set; } //   public Vector4 Color { get; set; } //   public float Size { get; set; } //  public float SizeVel { get; set; } //    public float AlphaVel { get; set; } //    public int TTL { get; set; } //    public Particle(Texture2D texture, Vector2 position, Vector2 velocity, float angle, float angularVelocity, Vector4 color, float size, int ttl, float sizeVel, float alphaVel) //  { Texture = texture; Position = position; Velocity = velocity; Angle = angle; Color = color; AngularVelocity = angularVelocity; Size = size; SizeVel = sizeVel; AlphaVel = alphaVel; TTL = ttl; } public void Update() //   { TTL--; //    //       Position += Velocity; Angle += AngularVelocity; Size += SizeVel; Color = new Vector4(Color.X, Color.Y, Color.Z, Color.W - AlphaVel); //  . ,    Vector4,    Color,  : Color.R/G/B   Byte ( 0x00  0xFF),     ,  float  Vector4 } public void Draw(SpriteBatch spriteBatch) { Rectangle sourceRectangle = new Rectangle(0, 0, Texture.Width, Texture.Height); //   :  Vector2 origin = new Vector2(Texture.Width / 2, Texture.Height / 2); //  spriteBatch.Draw(Texture, Position, sourceRectangle, new Color(Color), Angle, origin, Size, SpriteEffects.None, 0); //   } } } 


Now, we need to create a class that will manage all the particles in the game, let's call it ParticleController, listing with comments:

 using System; using System.Collections.Generic; using System.Linq; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Media; using System.Diagnostics; namespace ParticleSystem { class ParticleController { public List<Particle> particles; private Texture2D dot; //   private Texture2D smoke; //   private Random random; public ParticleController() { this.particles = new List<Particle>(); random = new Random(); } public void LoadContent(ContentManager Manager) { dot = Manager.Load<Texture2D>("spark"); smoke = Manager.Load<Texture2D>("smoke"); } public void EngineRocket(Vector2 position) // ,     { for (int a = 0; a < 2; a++) //  2     { Vector2 velocity = AngleToV2((float)(Math.PI * 2d * random.NextDouble()), 0.6f); float angle = 0; float angleVel = 0; Vector4 color = new Vector4(1f, 1f, 1f, 1f); float size = 1f; int ttl = 40; float sizeVel = 0; float alphaVel = 0; GenerateNewParticle(smoke, position, velocity, angle, angleVel, color, size, ttl, sizeVel, alphaVel); } for (int a = 0; a < 1; a++) //  1    { Vector2 velocity = AngleToV2((float)(Math.PI * 2d * random.NextDouble()), .2f); float angle = 0; float angleVel = 0; Vector4 color = new Vector4(1.0f, 0.5f, 0.5f, 0.5f); float size = 1f; int ttl = 80; float sizeVel = 0; float alphaVel = .01f; GenerateNewParticle(dot, position, velocity, angle, angleVel, color, size, ttl, sizeVel, alphaVel); } for (int a = 0; a < 10; a++) //  10 ,    —     { Vector2 velocity = Vector2.Zero; float angle = 0; float angleVel = 0; Vector4 color = new Vector4(1.0f, 0.5f, 0.5f, 1f); float size = 0.1f + 1.8f * (float)random.NextDouble(); int ttl = 10; float sizeVel = -.05f; float alphaVel = .01f; GenerateNewParticle(smoke, position, velocity, angle, angleVel, color, size, ttl, sizeVel, alphaVel); } } private Particle GenerateNewParticle(Texture2D texture, Vector2 position, Vector2 velocity, float angle, float angularVelocity, Vector4 color, float size, int ttl, float sizeVel, float alphaVel) //    { Particle particle = new Particle(texture, position, velocity, angle, angularVelocity, color, size, ttl, sizeVel, alphaVel); particles.Add(particle); return particle; } public void Update(GameTime gameTime) { for (int particle = 0; particle < particles.Count; particle++) { particles[particle].Update(); if (particles[particle].Size <= 0 || particles[particle].TTL <= 0) //         ,   { particles.RemoveAt(particle); particle--; } } } public void Draw(SpriteBatch spriteBatch) { spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive); //    Addictive for (int index = 0; index < particles.Count; index++) //    { particles[index].Draw(spriteBatch); } spriteBatch.End(); } public Vector2 AngleToV2(float angle, float length) { Vector2 direction = Vector2.Zero; direction.X = (float)Math.Cos(angle) * length; direction.Y = -(float)Math.Sin(angle) * length; return direction; } } } 


And in the main class we write LoadContent, Update, Draw in the appropriate places, at the same time we will add the generation of the particles each update:

 particleController.EngineRocket(new Vector2(Mouse.GetState().X, Mouse.GetState().Y)); 


Run, move the mouse, admire:


As you understand, such a system can be made even more beautiful: add shaders. But let the volume of the article remain adequate. How I can use shaders for my own purposes - I will tell you in the second part of the article.

I attach the source code and demo .

See you again;)

UPD: the second part of the article.

Source: https://habr.com/ru/post/128286/


All Articles