I'm pretty new to programming games (this is my 1st program in XNA), and I ran into a problem. I want to make a block engine, and this far I have a chunk, and I can move around it with the camera while random blocks are constantly removed from the chunk. My problem is that every time I'm rebuilding the chunk: clearing the vertexlist than adding the required sides of the cubes to it (I only add sides if the neighbor is inactive), the game freezes up for a short time. My chunk only have 800-1200 triangles this way so it shouldn't really tax the computer (FPS is between 50-60), I guess the rebuilding delays the camera movement. I will post my code, could anybody give me some advice on it? (for example would it help if I would make a separate thread for rebuilding the chunk? )
I won't add the Block class (it has a bool if its active or not), and the Dev_Messages class (FPS and triangle display), but the other 3 classes might be relevant.
Thanks in advance!
namespace Chunk
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
Camera camera;
Dev_Messages dev;
Chunk chunk;
//TESTING
bool animate = true;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
camera = new Camera(this, new Vector3(0, 0, 40), Vector3.Zero, Vector3.Up);
chunk = new Chunk(GraphicsDevice);
dev = new Dev_Messages(this);
Components.Add(camera);
base.Initialize();
}
protected override void LoadContent()
{
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
if (animate == true) chunk.Update(gameTime.ElapsedGameTime.TotalMilliseconds);
if (Keyboard.GetState().IsKeyDown(Keys.D1)) animate = false;
if (Keyboard.GetState().IsKeyDown(Keys.D2)) animate = true;
dev.Update(gameTime);
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
GraphicsDevice.BlendState = BlendState.Opaque;
chunk.Draw(camera);
dev.Draw(chunk.getTriangleCount());
base.Draw(gameTime);
}
}
}
CHUNK CLASS:
namespace Chunk
{
class Chunk
{
private const int DIM_X = 8;
private const int DIM_Y = 8;
private const int DIM_Z = 8;
Block[,,] block = new Block [DIM_X, DIM_Y, DIM_Z];
Random random = new Random();
int rnd1, rnd2, rnd3;
double TIME = 0;
private float R = 1;
private Vector3 POS = new Vector3(0,0,0);
private VertexBuffer vertexbuffer;
private List<VertexPositionColor> vertexlist;
private GraphicsDevice device;
private BasicEffect effect;
public Chunk(GraphicsDevice device_) {
device = device_;
effect = new BasicEffect(device);
vertexlist = new List<VertexPositionColor>();
for (int x = 0; x < DIM_X; x++) {
for (int y = 0; y < DIM_Y; y++) {
for (int z = 0; z < DIM_Z; z++) {
block[x, y, z] = new Block(true);
}
}
}
Build();
}
public int getTriangleCount() {
return vertexbuffer.VertexCount / 3;
}
public void Build() {
Color c1 = new Color(155, 255, 155);
Color c2 = new Color(0, 50, 0);
Color c3 = new Color(0, 150, 0);
for (int x = 0; x < DIM_X; x++) {
for (int y = 0; y < DIM_Y; y++) {
for (int z = 0; z < DIM_Z; z++) {
if (block[x, y, z].IsActive()) {
POS = new Vector3(2 * x + 1, 2 * y + 1, -2 * z - 1);
//FRONT
if ((z > 0) && (block[x, y, z-1].IsActive() == false) || z == 0)
{
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X - R, POS.Y + R, POS.Z + R), c1));
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X + R, POS.Y + R, POS.Z + R), c2));
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X - R, POS.Y - R, POS.Z + R), c2));
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X - R, POS.Y - R, POS.Z + R), c2)); //verts[2]
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X + R, POS.Y + R, POS.Z + R), c2));//verts[1]
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X + R, POS.Y - R, POS.Z + R), c3));
}
//BACK
if ((z < DIM_Z - 1) && (block[x, y, z + 1].IsActive() == false) || z == DIM_Z - 1)
{
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X + R, POS.Y + R, POS.Z - R), c1));
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X - R, POS.Y + R, POS.Z - R), c2));
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X + R, POS.Y - R, POS.Z - R), c2));
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X + R, POS.Y - R, POS.Z - R), c2));
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X - R, POS.Y + R, POS.Z - R), c2));
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X - R, POS.Y - R, POS.Z - R), c3));
}
//TOP
if ((y < DIM_Y-1) && (block[x, y+1, z].IsActive() == false) || y == DIM_Y-1)
{
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X - R, POS.Y + R, POS.Z - R), c3));
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X + R, POS.Y + R, POS.Z - R), c2));
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X - R, POS.Y + R, POS.Z + R), c2));
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X - R, POS.Y + R, POS.Z + R), c2));
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X + R, POS.Y + R, POS.Z - R), c2));
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X + R, POS.Y + R, POS.Z + R), c1));
}
//BOTTOM
if ((y > 0) && (block[x, y - 1, z].IsActive() == false) || y == 0)
{
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X + R, POS.Y - R, POS.Z - R), c1));
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X - R, POS.Y - R, POS.Z - R), c2));
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X + R, POS.Y - R, POS.Z + R), c2));
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X + R, POS.Y - R, POS.Z + R), c2));
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X - R, POS.Y - R, POS.Z - R), c2));
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X - R, POS.Y - R, POS.Z + R), c3));
}
//LEFT
if ((x > 0) && (block[x-1, y, z].IsActive() == false) || x == 0)
{
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X - R, POS.Y + R, POS.Z - R), c1));
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X - R, POS.Y + R, POS.Z + R), c2));
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X - R, POS.Y - R, POS.Z - R), c2));
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X - R, POS.Y - R, POS.Z - R), c2));
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X - R, POS.Y + R, POS.Z + R), c2));
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X - R, POS.Y - R, POS.Z + R), c3));
}
//RIGHT
if ((x < DIM_X-1) && (block[x + 1, y, z].IsActive() == false) || x == DIM_X-1)
{
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X + R, POS.Y + R, POS.Z + R), c1));
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X + R, POS.Y + R, POS.Z - R), c2));
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X + R, POS.Y - R, POS.Z + R), c2));
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X + R, POS.Y - R, POS.Z + R), c2));
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X + R, POS.Y + R, POS.Z - R), c2));
vertexlist.Add(new VertexPositionColor(new Vector3(POS.X + R, POS.Y - R, POS.Z - R), c3));
}
vertexbuffer = new VertexBuffer(device, typeof(VertexPositionColor), vertexlist.Count, BufferUsage.None);
vertexbuffer.SetData(vertexlist.ToArray());
}
}
}
}
}
public void Update(double time) {
TIME += time;
if (TIME > 1000)
{
rnd1 = random.Next(0, DIM_X);
rnd2 = random.Next(0, DIM_Y);
rnd3 = random.Next(0, DIM_Z);
if (block[rnd1, rnd2, rnd3].IsActive() == true)
{
block[rnd1, rnd2, rnd3].setActive(false);
vertexlist.Clear();
TIME = 0;
Build();
}
}
}
public void Draw(Camera camera) {
effect.World = Matrix.Identity;
effect.View = camera.view;
effect.Projection = camera.projection;
effect.VertexColorEnabled = true;
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
{
pass.Apply();
device.SetVertexBuffer(vertexbuffer);
device.DrawPrimitives(PrimitiveType.TriangleList, 0, vertexbuffer.VertexCount / 3);
}
}
}
}
CAMERA CLASS:
namespace Chunk
{
public class Camera : Microsoft.Xna.Framework.GameComponent
{
public Matrix view {get; protected set;}
public Matrix projection {get; protected set;}
public Vector3 cameraPosition { get; protected set;}
MouseState originalMouseState;
Vector3 cameraDirection;
Vector3 cameraUp;
float leftrightRot = 0;
float updownRot = 0;
const float rotationSpeed = 0.003f;
public Camera(Game game, Vector3 pos, Vector3 target, Vector3 up)
: base(game)
{
//Build camera view matrix
cameraPosition = pos;
cameraDirection = target - pos;
cameraDirection.Normalize();
cameraUp = up;
//projection matrix (FOV, Aspect ratio, near/far clipping)
projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4,
(float)Game.Window.ClientBounds.Width / (float)Game.Window.ClientBounds.Height, 1, 300);
}
private void UpdateViewMatrix()
{
Matrix cameraRotation = Matrix.CreateRotationX(updownRot) * Matrix.CreateRotationY(leftrightRot);
Vector3 cameraOriginalTarget = new Vector3(0, 0, -1);
Vector3 cameraRotatedTarget = Vector3.Transform(cameraOriginalTarget, cameraRotation);
Vector3 cameraFinalTarget = cameraPosition + cameraRotatedTarget;
Vector3 cameraOriginalUpVector = new Vector3(0, 1, 0);
Vector3 cameraRotatedUpVector = Vector3.Transform(cameraOriginalUpVector, cameraRotation);
view = Matrix.CreateLookAt(cameraPosition, cameraFinalTarget, cameraRotatedUpVector);
}
public override void Initialize()
{
UpdateViewMatrix();
// Set mouse position and do initial get state
Mouse.SetPosition(Game.Window.ClientBounds.Width / 2, Game.Window.ClientBounds.Height / 2);
originalMouseState = Mouse.GetState();
base.Initialize();
}
public override void Update(GameTime gameTime)
{
Vector3 moveVector = new Vector3(0, 0, 0);
// Move forward/backward
if (Keyboard.GetState( ).IsKeyDown(Keys.W))
moveVector += new Vector3(0, 0, -1);
if (Keyboard.GetState( ).IsKeyDown(Keys.S))
moveVector += new Vector3(0, 0, 1);
// Move side to side
if (Keyboard.GetState( ).IsKeyDown(Keys.A))
moveVector += new Vector3(-1, 0, 0);
if (Keyboard.GetState( ).IsKeyDown(Keys.D))
moveVector += new Vector3(1, 0, 0);
// Ascend / Descend
if (Keyboard.GetState().IsKeyDown(Keys.Space))
cameraPosition += new Vector3(0, 1, 0);
if (Keyboard.GetState().IsKeyDown(Keys.LeftControl))
cameraPosition += new Vector3(0, -1, 0);
float TimeDiff = (float)gameTime.ElapsedGameTime.TotalMilliseconds / 10f;
//Move
AddToCameraPosition(moveVector * TimeDiff);
//Mouse Look
MouseState currentMouseState = Mouse.GetState();
if (currentMouseState != originalMouseState) {
float xDifference = currentMouseState.X - originalMouseState.X;
float yDifference = currentMouseState.Y - originalMouseState.Y;
leftrightRot -= rotationSpeed * xDifference * TimeDiff;
updownRot -= rotationSpeed * yDifference * TimeDiff;
Mouse.SetPosition(Game.Window.ClientBounds.Width / 2, Game.Window.ClientBounds.Height / 2);
}
UpdateViewMatrix();
base.Update(gameTime);
}
private void AddToCameraPosition(Vector3 vectorToAdd) {
Matrix cameraRotation = Matrix.CreateRotationX(updownRot) * Matrix.CreateRotationY(leftrightRot);
Vector3 rotatedVector = Vector3.Transform(vectorToAdd, cameraRotation);
cameraPosition += rotatedVector;
UpdateViewMatrix();
}
}
}
