Original Post
This is my first actual project using C# and XNA. I would really appreciate it if people could point out any flaws/hack code so I can learn. It is a simple cellular automaton that is initially randomly seeded, then updated every frame. The part I feel is most hack-ish is where I recreate the texture each frame. It would be great to know a better way. If something isn't clear from the code ask away. *edit* I guess what I really would like to know is, is there a bettere way to draw individual pixels to screen then creating a texture, destroying it and creating a new one. I suppose you could multiple textures and create a buffering system but that still would leave you with remaking alot of textures. Also if anyone knows a performance analyzer for C# that would help also, didn't find anything that looked good when I looked. [Edited by - bmanruler on January 28, 2008 12:03:11 PM]
#region Using Statements
using System;
using System.Collections.Generic;
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.Net;
using Microsoft.Xna.Framework.Storage;
#endregion
namespace CellAuto
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
int screenWidth = 800;
int screenHeight = 600;
int screenSize = 800 * 600;
Texture2D CA;
Color[] caTexture;
Color[] caBuffer;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
caTexture = new Color[screenSize];
caBuffer = new Color[screenSize];
}
public void InitializeCA()
{
Random random = new Random();
Color black = Color.Black;
Color white = Color.White;
// Seed the CA with random values
for (int i = 0; i < screenSize; i++)
{
int RandomBinary = random.Next(2); // generate a random number between 0 and 1
if( 0 == RandomBinary ) // if 0, then add black
{
caTexture = black;
}
else // if 1, then add white
{
caTexture = white;
}
}
// Create the texture
CA = new Texture2D(graphics.GraphicsDevice, screenWidth, screenHeight, 1, TextureUsage.None, SurfaceFormat.Color);
// Set the new data to the texture
CA.SetData<Color>(caTexture);
}
public void GameOfLife()
{
// Update buffer using ruleset
for (int y = 0; y < screenHeight; y++)
{
for (int x = 0; x < screenWidth; x++)
{
caBuffer[y * screenWidth + x] = GameOfLifeRules(x, y);
}
}
// replace original with buffer
for (int i = 0; i < screenSize; i++)
{
caTexture = caBuffer;
}
}
private Color GameOfLifeRules(int X, int Y)
{
// Original game of life rules made image converge too quickly, so this is used.
int temp = LiveNeighborCount(X, Y);
if (0 <= temp && temp <= 2)
{
return Color.Black;
}
if (3 == temp)
{
return Color.White;
}
if (5 == temp)
{
return Color.Black;
}
if (6 <= temp)
{
return Color.White;
}
return caTexture[Y*screenWidth+X];
}
private int LiveNeighborCount(int X, int Y)
{
int retVal = 0;
// Test for bounds
int left = 0,
leftAbove = 0,
above = 0,
rightAbove = 0,
right = 0,
rightBelow = 0,
below = 0,
leftBelow = 0;
// Left
if (X > 0)
{
if (Color.White == caTexture[Y * screenWidth + X - 1])
{
left = 1;
}
}
// Left Above
if (X > 0 && Y > 0)
{
if (Color.White == caTexture[(Y - 1) * screenWidth + X - 1])
{
leftAbove = 1;
}
}
// Above
if (Y > 0)
{
if (Color.White == caTexture[(Y - 1) * screenWidth + X])
{
above = 1;
}
}
// Right Above
if (X+1 < screenWidth && Y > 0)
{
if (Color.White == caTexture[(Y - 1) * screenWidth + X + 1])
{
rightAbove = 1;
}
}
// Right
if (X+1 < screenWidth)
{
if (Color.White == caTexture[Y * screenWidth + X + 1])
{
right = 1;
}
}
// Right Below
if (X+1 < screenWidth && Y+1 < screenHeight)
{
if (Color.White == caTexture[(Y + 1) * screenWidth + X + 1])
{
rightBelow = 1;
}
}
// Below
if (Y + 1 < screenHeight)
{
if (Color.White == caTexture[(Y + 1) * screenWidth + X])
{
below = 1;
}
}
// Left Below
if (X > 0 && Y + 1 < screenHeight)
{
if (Color.White == caTexture[(Y + 1) * screenWidth + X - 1])
{
leftBelow = 1;
}
}
retVal = left + leftAbove + above + rightAbove + right + rightBelow + below + leftBelow;
return retVal;
}
/// <summary>
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base.Initialize will enumerate through any components
/// and initialize them as well.
/// </summary>
protected override void Initialize()
{
// TODO: Add your initialization logic here
InitializeCA();
base.Initialize();
}
/// <summary>
/// LoadContent will be called once per game and is the place to load
/// all of your content.
/// </summary>
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
// TODO: use this.Content to load your game content here
}
/// <summary>
/// UnloadContent will be called once per game and is the place to unload
/// all content.
/// </summary>
protected override void UnloadContent()
{
CA.Dispose();
// TODO: Unload any non ContentManager content here
}
/// <summary>
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input, and playing audio.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
base.Update(gameTime);
}
/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
// This updates the data in the CA so it actually evolves
// Uses the game of life rule
GameOfLife();
// Hack to refresh the texture, discard the previous one and create a new texture with the
// updated buffer
CA.Dispose();
CA = new Texture2D(graphics.GraphicsDevice, screenWidth, screenHeight, 1, TextureUsage.None, SurfaceFormat.Color);
CA.SetData<Color>(caTexture);
// Draw the sprites to screen
spriteBatch.Begin();
spriteBatch.Draw(CA, Vector2.Zero, Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
}
}