⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pointsprites.cs

📁 《.NET游戏编程入门经典-c#篇》
💻 CS
字号:

using System;
using System.Windows.Forms;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using System.Drawing;


    
	/// <summary>
	/// The Vapor Trail class
	/// </summary>
public class VaporTrail
{
	public struct PointVertex
	{
		public Vector3 v;
		public int color;
		public static readonly VertexFormats Format =   VertexFormats.Position | VertexFormats.Diffuse;
	};

	/// <summary>
	/// Global data for the particles
	/// </summary>
	public struct Particle
	{
		public bool isSpark;     // Sparks are less energetic particles that
		// are generated where/when the main particles
		// hit the ground

		public Vector3 positionVector;       // Current position
		public Vector3 velocityVector;       // Current velocity

		public Vector3 initialPosition;      // Initial position
		public Vector3 initialVelocity;      // Initial velocity
		public float creationTime;     // Time of creation

		public System.Drawing.Color diffuseColor; // Initial diffuse color
		public System.Drawing.Color fadeColor;    // Faded diffuse color
		public float fadeProgression;      // Fade progression
	};

	private float radius = 0.0f;

	private float time = 0.0f;
	private int baseParticle = 0;
	private int flush = 0;
	private int discard = 0;

	private int particles = 0;
	private int particlesLimit = 0;
	private Vector3 m_loc;
	private Vector3 offset;
	private System.Collections.ArrayList particlesList = new System.Collections.ArrayList();
	private System.Collections.ArrayList freeParticles = new System.Collections.ArrayList();

	private System.Random rand = new System.Random();

	public Vector3 EmitterLocation {get { return m_loc; } }
	public Vector3 EmitterOffset { get { return offset; } set { offset = value; } }


	// Geometry
	private VertexBuffer vertexBuffer = null;

	private Texture particleTexture;
	public Texture ParticleTexture { set { particleTexture = value; } }

	private Device device = null;






	/// <summary>
	/// VaporTrail constructor
	/// </summary>
	public VaporTrail(Device device, int flush, int discard, float radius)
	{
		this.device = device;
		if (device != null)
		{
			device.DeviceLost += new System.EventHandler(this.InvalidateDeviceObjects);
			device.Disposing += new System.EventHandler(this.InvalidateDeviceObjects);
			device.DeviceReset += new System.EventHandler(this.RestoreDeviceObjects);
		}
		this.radius        = radius;

		this.baseParticle = discard;
		this.flush        = flush;
		this.discard      = discard;

		particles    = 0;
		particlesLimit = 2048;
		RestoreDeviceObjects(device, null);
	}


        
	public void InvalidateDeviceObjects(object sender, EventArgs e)
	{
		if (vertexBuffer != null)
			vertexBuffer.Dispose();
		vertexBuffer = null;
	}
        
	/// <summary>
	/// Restores the device objects
	/// </summary>
	public void RestoreDeviceObjects(object sender, EventArgs e)
	{

		Device device = (Device)sender;

		// Create a vertex buffer for the particle system.  The size of this buffer
		// does not relate to the number of particles that exist.  Rather, the
		// buffer is used as a communication channel with the device.. we fill in 
		// a bit, and tell the device to draw.  While the device is drawing, we
		// fill in the next bit using NOOVERWRITE.  We continue doing this until 
		// we run out of vertex buffer space, and are forced to DISCARD the buffer
		// and start over at the beginning.

		vertexBuffer = new VertexBuffer(typeof(PointVertex), discard, device,  Usage.Dynamic | Usage.WriteOnly | Usage.Points, PointVertex.Format, Pool.Default);
	}

	public void Explode(int NumParticlesToEmit, Vector3 vPosition)
	{
		// Emit new particles
		int particlesEmit = particles + NumParticlesToEmit;
		while(particles < particlesLimit && particles < particlesEmit)
		{
			Particle particle;

			if (freeParticles.Count > 0)
			{
				particle = (Particle)freeParticles[0];
				freeParticles.RemoveAt(0);
			}
			else
			{
				particle = new Particle();
			}

			// Emit new particle
			float fRand1 = ((float)rand.Next(int.MaxValue)/(float)int.MaxValue) * (float)Math.PI * 2.0f;
			float fRand2 = ((float)rand.Next(int.MaxValue)/(float)int.MaxValue) * (float)Math.PI * 2.0f;

			particle.isSpark = false;

			particle.initialPosition = vPosition + new Vector3(0.0f, radius, 0.0f);

			particle.initialVelocity.X  = (float)Math.Cos(fRand1) * (float)Math.Sin(fRand2) * 100f;
			particle.initialVelocity.Z  = (float)Math.Sin(fRand1) * (float)Math.Sin(fRand2) * 100f;
			particle.initialVelocity.Y  = (float)Math.Cos(fRand2) * 100f;
				

			particle.positionVector = particle.initialPosition;
			particle.velocityVector = particle.initialVelocity;

			particle.diffuseColor = Color.Violet;
			particle.fadeColor    = Color.Black;
			particle.fadeProgression      = 1.0f;
			particle.creationTime     = time;

			particlesList.Add(particle);
			particles++;
		}
	}
  
	/// <summary>
	/// Updates the scene
	/// </summary>
	public void Update(float fSecsPerFrame, int NumParticlesToEmit,
		System.Drawing.Color clrEmitColor,System.Drawing.Color clrFadeColor, float fEmitVel, Vector3 vPosition)
	{
			
		time += fSecsPerFrame;
		//Console.WriteLine(time.ToString());
		//if (time < .1)
		//	return;
		m_loc = vPosition;
		for (int ii = particlesList.Count-1; ii >= 0; ii--)
		{
			Particle p = (Particle)particlesList[ii];
			// Calculate new position
			//float fT = time - p.creationTime;
			float fT = time - p.creationTime;


			p.fadeProgression -= fSecsPerFrame * 0.60f;
				

				
			p.positionVector    = p.initialVelocity * fT + p.initialPosition;
				
			p.velocityVector.Z = 0;


			if (p.fadeProgression < 0.0f)
				p.fadeProgression = 0.0f;

			// Kill old particles
				
			if (p.fadeProgression <= 0.0f)
			{
					

				
				// Kill particle
				freeParticles.Add(p);
				particlesList.RemoveAt(ii);

				if (!p.isSpark)
					particles--;
			}
			else
				particlesList[ii] = p;
		}

		// Emit new particles
		int particlesEmit = particles + NumParticlesToEmit;
		while(particles < particlesLimit && particles < particlesEmit)
		{
			Particle particle;

			if (freeParticles.Count > 0)
			{
				particle = (Particle)freeParticles[0];
				freeParticles.RemoveAt(0);
			}
			else
			{
				particle = new Particle();
			}

			// Emit new particle
			float fRand1 = ((float)rand.Next(int.MaxValue)/(float)int.MaxValue) * (float)Math.PI * 1.0f;
			float fRand2 = ((float)rand.Next(int.MaxValue)/(float)int.MaxValue) * (float)Math.PI * 0.25f;

			particle.isSpark = false;

			particle.initialPosition = vPosition + offset;

			particle.initialVelocity.X  = (float)Math.Cos(fRand1) * (float)Math.Sin(fRand2) * .5f;
			particle.initialVelocity.Y  = (float)Math.Sin(fRand1) * (float)Math.Sin(fRand2) * .5f;
			particle.initialVelocity.Z  = (float)Math.Cos(fRand2);


			particle.positionVector = particle.initialPosition;
			particle.velocityVector = particle.initialVelocity;

			particle.diffuseColor = clrEmitColor;
			particle.fadeColor    = clrFadeColor;
			particle.fadeProgression      = 1.0f;
			particle.creationTime     = time;

			particlesList.Add(particle);
			particles++;
		}
	}

        
        
        
	/// <summary>
	/// Renders the scene
	/// </summary>
	public void Render()
	{
		// Set the render states for using point sprites
		device.RenderState.ZBufferWriteEnable = false;
		device.RenderState.AlphaBlendEnable = true;
		device.RenderState.SourceBlend = Blend.One;
		device.RenderState.DestinationBlend = Blend.One;
		bool lightEnabled = device.RenderState.Lighting;
		device.RenderState.Lighting = false;
		device.SetTexture(0, particleTexture);
		device.Transform.World = Matrix.Identity;

		device.RenderState.PointSpriteEnable = true;
		device.RenderState.PointScaleEnable = true;
		device.RenderState.PointSize = 1.0f;
		device.RenderState.PointScaleA = 0f;
		device.RenderState.PointScaleB = 1.0f;
		device.RenderState.PointScaleC = 1.0f;

		// Set up the vertex buffer to be rendered
		device.SetStreamSource(0, vertexBuffer, 0);
		device.VertexFormat = PointVertex.Format;

		PointVertex[] vertices = null;
		int numParticlesToRender = 0;



		// Lock the vertex buffer.  We fill the vertex buffer in small
		// chunks, using LockFlags.NoOverWrite.  When we are done filling
		// each chunk, we call DrawPrim, and lock the next chunk.  When
		// we run out of space in the vertex buffer, we start over at
		// the beginning, using LockFlags.Discard.

		baseParticle += flush;

		if (baseParticle >= discard)
			baseParticle = 0;

		int count = 0;
		vertices = (PointVertex[])vertexBuffer.Lock(baseParticle * DXHelp.GetTypeSize(typeof(PointVertex)), typeof(PointVertex), (baseParticle != 0) ? LockFlags.NoOverwrite : LockFlags.Discard, flush);
		foreach(Particle p in particlesList)
		{
			Vector3 vPos = p.positionVector;
			Vector3 vVel = p.velocityVector;
			float fLengthSq = vVel.LengthSq();
			uint steps;

			if (fLengthSq < 1.0f)        steps = 2;
			else if (fLengthSq <  4.00f) steps = 3;
			else if (fLengthSq <  9.00f) steps = 4;
			else if (fLengthSq < 12.25f) steps = 5;
			else if (fLengthSq < 16.00f) steps = 6;
			else if (fLengthSq < 20.25f) steps = 7;
			else                          steps = 8;

			vVel *= -0.01f / (float)steps;
			System.Drawing.Color diffuse = ColorOperator.Lerp(p.fadeColor, p.diffuseColor, p.fadeProgression);


			// Render each particle a bunch of times to get a blurring effect
			for (int i = 0; i < steps; i++)
			{
				vertices[count].v     = vPos;
				vertices[count].color = diffuse.ToArgb();
				count++;

				if (++numParticlesToRender == flush)
				{
					// Done filling this chunk of the vertex buffer.  Lets unlock and
					// draw this portion so we can begin filling the next chunk.

					vertexBuffer.Unlock();

					device.DrawPrimitives(PrimitiveType.PointList, baseParticle, numParticlesToRender);

					// Lock the next chunk of the vertex buffer.  If we are at the 
					// end of the vertex buffer, LockFlags.Discard the vertex buffer and start
					// at the beginning.  Otherwise, specify LockFlags.NoOverWrite, so we can
					// continue filling the VB while the previous chunk is drawing.
					baseParticle += flush;

					if (baseParticle >= discard)
						baseParticle = 0;

					vertices = (PointVertex[])vertexBuffer.Lock(baseParticle * DXHelp.GetTypeSize(typeof(PointVertex)), typeof(PointVertex), (baseParticle != 0) ? LockFlags.NoOverwrite : LockFlags.Discard, flush);
					count = 0;

					numParticlesToRender = 0;
				}

				vPos += vVel;
			}
		}

		// Unlock the vertex buffer
		vertexBuffer.Unlock();
		// Render any remaining particles
		if (numParticlesToRender > 0)
			device.DrawPrimitives(PrimitiveType.PointList, baseParticle, numParticlesToRender);

		// Reset render states
		device.RenderState.PointSpriteEnable = false;
		device.RenderState.PointScaleEnable = false;


		device.RenderState.Lighting = lightEnabled;
		device.RenderState.ZBufferWriteEnable = true;
		device.RenderState.AlphaBlendEnable = false;

	}

	public void Dispose()
	{
		if (vertexBuffer != null)
			vertexBuffer.Dispose();
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -