#region File Description
//-----------------------------------------------------------------------------
// ParticleDemo.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion
#region Using Statements
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using SkinnedModel;
#endregion
namespace XnaGraphicsDemo
{
///
/// Demo shows how to use SpriteBatch.
///
class ParticleDemo : MenuComponent
{
const int MaxParticles = 5000;
struct Particle
{
public Vector2 Position;
public Vector2 Velocity;
public float Size;
public float Rotation;
public float Spin;
public Color Color;
}
Particle[] particles = new Particle[MaxParticles];
int firstParticle;
int particleCount;
FloatMenuEntry spawnRate;
float spawnCounter;
Texture2D cat;
Random random = new Random();
///
/// Constructor.
///
public ParticleDemo(DemoGame game)
: base(game)
{
Entries.Add(spawnRate = new FloatMenuEntry() { Text = "spawn rate" });
// This menu option for changing the resolution is currently disabled,
// because the image scaler feature is not yet implemented in the CTP release.
/*
Entries.Add(new ResolutionMenu(game.graphics));
*/
Entries.Add(new MenuEntry
{
Text = "back",
Clicked = delegate
{
// Before we quit back out of this menu, reset back to the default resolution.
if (game.Graphics.PreferredBackBufferWidth != 480)
{
game.Graphics.PreferredBackBufferWidth = 480;
game.Graphics.PreferredBackBufferHeight = 800;
game.Graphics.ApplyChanges();
}
Game.SetActiveMenu(0);
} });
}
///
/// Resets the menu state.
///
public override void Reset()
{
firstParticle = 0;
particleCount = 0;
spawnRate.Value = 0.2f;
base.Reset();
}
///
/// Loads content for this demo.
///
protected override void LoadContent()
{
cat = Game.Content.Load("cat");
}
///
/// Updates the particle system.
///
public override void Update(GameTime gameTime)
{
int i = firstParticle;
for (int j = particleCount; j > 0; j--)
{
// Move a particle.
particles[i].Position += particles[i].Velocity;
particles[i].Rotation += particles[i].Spin;
particles[i].Velocity.Y += 0.1f;
// Retire old particles?
const float borderPadding = 96;
if (i == firstParticle)
{
if ((particles[i].Position.X < -borderPadding) ||
(particles[i].Position.X > 480 + borderPadding) ||
(particles[i].Position.Y < -borderPadding) ||
(particles[i].Position.Y > 800 + borderPadding))
{
if (++firstParticle >= MaxParticles)
firstParticle = 0;
particleCount--;
}
}
if (++i >= MaxParticles)
i = 0;
}
// Spawn new particles?
spawnCounter += spawnRate.Value * 10;
while (spawnCounter > 1)
{
SpawnParticle(null);
spawnCounter--;
}
base.Update(gameTime);
}
///
/// Helper creates a new cat particle.
///
void SpawnParticle(Vector2? position)
{
if (particleCount >= MaxParticles)
return;
int i = firstParticle + particleCount;
if (i >= MaxParticles)
i -= MaxParticles;
particles[i].Position = position ?? new Vector2((float)random.NextDouble() * 480, (float)random.NextDouble() * 800);
particles[i].Velocity = new Vector2((float)random.NextDouble() - 0.5f, (float)random.NextDouble() - 0.5f) * 10f;
particles[i].Size = (float)random.NextDouble() * 0.5f + 0.5f;
particles[i].Rotation = 0;
particles[i].Spin = ((float)random.NextDouble() - 0.5f) * 0.1f;
if (position.HasValue)
{
// Explicitly positioned particles have no tint.
particles[i].Color = Color.White;
}
else
{
// Randomly positioned particles have random tint colors.
byte r = (byte)(128 + random.NextDouble() * 127);
byte g = (byte)(128 + random.NextDouble() * 127);
byte b = (byte)(128 + random.NextDouble() * 127);
particles[i].Color = new Color(r, g, b);
}
particleCount++;
}
///
/// Draws the cat particle system.
///
public override void Draw(GameTime gameTime)
{
DrawTitle("particles", Color.CornflowerBlue, Color.Lerp(Color.Blue, Color.CornflowerBlue, 0.85f));
SpriteBatch.Begin(0, null, null, null, null, null, Game.ScaleMatrix);
Vector2 origin = new Vector2(cat.Width, cat.Height) / 2;
int i = firstParticle + particleCount - 1;
if (i >= MaxParticles)
i -= MaxParticles;
for (int j = 0; j < particleCount; j++)
{
SpriteBatch.Draw(cat, particles[i].Position, null, particles[i].Color, particles[i].Rotation, origin, particles[i].Size, 0, 0);
if (--i < 0)
i = MaxParticles - 1;
}
SpriteBatch.End();
base.Draw(gameTime);
}
///
/// Dragging on the menu background creates new particles.
///
protected override void OnDrag(Vector2 delta)
{
SpawnParticle(LastTouchPoint);
}
///
/// Custom menu entry subclass for cycling through different backbuffer resolutions.
///
class ResolutionMenu : MenuEntry
{
GraphicsDeviceManager graphics;
public ResolutionMenu(GraphicsDeviceManager graphics)
{
this.graphics = graphics;
}
public override string Text
{
get { return string.Format("{0}x{1}", graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight); }
set { }
}
public override void OnClicked()
{
switch (graphics.PreferredBackBufferWidth)
{
case 480:
graphics.PreferredBackBufferWidth = 360;
graphics.PreferredBackBufferHeight = 600;
break;
case 360:
graphics.PreferredBackBufferWidth = 240;
graphics.PreferredBackBufferHeight = 400;
break;
case 240:
graphics.PreferredBackBufferWidth = 480;
graphics.PreferredBackBufferHeight = 800;
break;
}
graphics.ApplyChanges();
base.OnClicked();
}
}
}
}