Sprite animation error - c#

My animation for a 37*37 resolution sprite is working swell a part from when I have both the left and right arrow key pressed down, two animations appear on top of each other.
Here is my code:
keys = Keyboard.GetState();
if (keys.IsKeyDown(Keys.Right))
{
position = new Vector2(position.X + 1.4f, position.Y);
isRight = true;
isLeft = false;
if (keys.IsKeyDown(Keys.Left))
{
isLeft = true;
isRight = false;
}
}
if (keys.IsKeyDown(Keys.Left))
{
position = new Vector2(position.X - 1.4f, position.Y);
isLeft = true;
isRight = false;
if (keys.IsKeyDown(Keys.Right))
{
isRight = true;
isLeft = false;
}
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
int frame = (int)((gameTime.TotalGameTime.TotalSeconds * 12) % 4);
if (keys.IsKeyDown(Keys.Right))
spriteBatch.Draw(texture, position, new Rectangle(frame * 37, 0, 37, 37), Color.White, 0, Vector2.Zero, 1.0f, SpriteEffects.None, 1.0f);
if (keys.IsKeyDown(Keys.Left))
spriteBatch.Draw(texture, position, new Rectangle(frame * 37, 0, 37, 37), Color.White, 0, Vector2.Zero, 1.0f, SpriteEffects.FlipHorizontally, 1.0f);
if (keys.IsKeyUp(Keys.Left) && keys.IsKeyUp(Keys.Right))
{
if (isRight)
spriteBatch.Draw(texture, position, new Rectangle(0, 0, 37, 37), Color.White, 0, Vector2.Zero, 1.0f, SpriteEffects.None, 1.0f);
if (isLeft)
spriteBatch.Draw(texture, position, new Rectangle(0, 0, 37, 37), Color.White, 0, Vector2.Zero, 1.0f, SpriteEffects.FlipHorizontally, 1.0f);
}
spriteBatch.End();
What am I doing wrong?

You have two animations appearing on top of each other because you have two separate SpriteBatch.Draw calls in your Draw method. When you press both left and right keys, both of IsKeyDown ifs are true, and both draws are executed.
Also, this post is more appropriate in https://gamedev.stackexchange.com/.

Related

Drawing a triangle in MonoGame

I'm trying to draw a green 2D triangle in MonoGame using DrawUserPrimitives, but I can't seem to get it working. Every approach that I have tried results in either vague errors or nothing being drawn.
This is my latest attempt at drawing a triangle, taken almost completely from a resource that I found on the Internet:
protected override void LoadContent()
{
_vertexPositionColors = new[]
{
new VertexPositionColor(new Vector3(0, 0, 1), Color.Green),
new VertexPositionColor(new Vector3(10, 0, 1), Color.Green),
new VertexPositionColor(new Vector3(10, 10, 1), Color.Green)
};
_basicEffect = new BasicEffect(GraphicsDevice);
_basicEffect.World = Matrix.CreateOrthographicOffCenter(
0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height, 0, 0, 1);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
EffectTechnique effectTechnique = _basicEffect.Techniques[0];
EffectPassCollection effectPassCollection = effectTechnique.Passes;
foreach (EffectPass pass in effectPassCollection)
{
pass.Apply();
GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList,
_vertexPositionColors, 0, 1);
}
base.Draw(gameTime);
}
This results in a empty blue screen without any trace of a triangle.

Setting up OpenGL camera

I'm having trouble setting up my camera in 3D space.
Here's my code:
private void SetupViewPort()
{
GL.Viewport(0, 0, glControl1.Width, glControl1.Height);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity();
GL.Ortho(0, 1000,0,1000, 0, 1);
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadIdentity();
Vector3d eyePos = new Vector3d(0, 0, 1);
Vector3d point = new Vector3d(500, 500, 0.01);
Vector3d up = new Vector3d(0, 0 , 1);
Matrix4d mat = Matrix4d.LookAt(eyePos, point, up);
//mat.Invert();
GL.LoadMatrix(ref mat);
}
I'm expecting to see shapes that I've drawn onto the 2D plane. But I get a blank screen every time.
Here's the code where my shapes are drawn:
private void glControl1_Paint(object sender, PaintEventArgs e)
{
if (!loaded)
return;
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.Enable(EnableCap.DepthTest);
GL.DepthMask(true);
GL.ClearDepth(1.0);
GL.Color3(Color.Yellow);
GL.Begin(PrimitiveType.Triangles);
GL.Vertex2(0, 0);
GL.Vertex2(0, 600);
GL.Vertex2(600, 600);
GL.Vertex2(100, 100);
GL.Vertex2(50, 70);
GL.Vertex2(200, 100);
GL.End();
glControl1.SwapBuffers();
}
An orthonormal projection matrix and a lookAt view matrix don't play well together. Since you are drawing 2D just leave the lookAt matrix out and use the identity matrix.

Rendering triangles with OpenTK from VBO

I cannot render triangles for the life of me with a VBO in OpenTK. I am loading my data to the VBO in glControl_Load() event. I get a background screen with no triangles when running. The data is a from a mesh m.OpenGLArrays(out data, out indices) outputs a list of floats and ints. The list of floats for the vertices T1v1, T1v2, T1v3, T2v1, T2v2, T2v3, .... , all three vertices for each triangle back to back.
However given a blank screen with the code when I comment the "intermediate" rendering code everything renders fine....??? What am I doing wrong?
private void glControl_Load(object sender, EventArgs e)
{
loaded = true;
glControl.MouseMove += new MouseEventHandler(glControl_MouseMove);
glControl.MouseWheel += new MouseEventHandler(glControl_MouseWheel);
GL.ClearColor(Color.DarkSlateGray);
GL.Color3(1f, 1f, 1f);
m.OpenGLArrays(out data, out indices);
this.indicesSize = (uint)indices.Length;
GL.GenBuffers(1, out VBOid[0]);
GL.GenBuffers(1, out VBOid[1]);
SetupViewport();
}
private void SetupViewport()
{
if (this.WindowState == FormWindowState.Minimized) return;
glControl.Width = this.Width - 32;
glControl.Height = this.Height - 80;
Frame_label.Location = new System.Drawing.Point(glControl.Width / 2, glControl.Height + 25);
GL.MatrixMode(MatrixMode.Projection);
//GL.LoadIdentity();
GL.Ortho(0, glControl.Width, 0, glControl.Height, -1, 1); // Bottom-left corner pixel has coordinate (0, 0)
GL.Viewport(0, 0, glControl.Width, glControl.Height); // Use all of the glControl painting area
GL.Enable(EnableCap.DepthTest);
GL.BindBuffer(BufferTarget.ArrayBuffer, VBOid[0]);
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(data.Length * sizeof(float)), data, BufferUsageHint.StaticDraw);
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
float aspect_ratio = this.Width / (float)this.Height;
projection = Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4, aspect_ratio, 1, 1024);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadMatrix(ref projection);
}
private void glControl_Paint(object sender, PaintEventArgs e)
{
if (loaded)
{
GL.Clear(ClearBufferMask.ColorBufferBit |
ClearBufferMask.DepthBufferBit |
ClearBufferMask.StencilBufferBit);
modelview = Matrix4.LookAt(0f, 0f, -200f + zoomFactor, 0, 0, 0, 0.0f, 1.0f, 0.0f);
var aspect_ratio = Width / (float)Height;
projection = Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4, aspect_ratio, 1, 512);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadMatrix(ref projection);
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadMatrix(ref modelview);
GL.Rotate(angleY, 1.0f, 0, 0);
GL.Rotate(angleX, 0, 1.0f, 0);
GL.EnableClientState(ArrayCap.VertexArray);
GL.BindBuffer(BufferTarget.ArrayBuffer, VBOid[0]);
GL.Color3(Color.Yellow);
GL.VertexPointer(3, VertexPointerType.Float, Vector3.SizeInBytes, new IntPtr(0));
GL.DrawArrays(PrimitiveType.Triangles, 0, data.Length);
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
GL.DisableClientState(ArrayCap.VertexArray);
//GL.Color3(Color.Yellow);
//GL.PolygonMode(MaterialFace.Front, PolygonMode.Fill);
//GL.Begin(PrimitiveType.Triangles);
//for (int i = 0; i < this.md.mesh.Count; i++)
//{
// GL.Normal3(this.md.mesh[i].normal);
// GL.Vertex3(this.md.mesh[i].vertices[0]);
// GL.Vertex3(this.md.mesh[i].vertices[1]);
// GL.Vertex3(this.md.mesh[i].vertices[2]);
//}
//GL.End();
//GL.EndList();
glControl.SwapBuffers();
Frame_label.Text = "Frame: " + frameNum++;
}
}
If something doesn't seem right, then it probably isn't. I seriously questioned my understanding of opengl and spent hours looking at this. However it was just a simple error of forgetting to iterate a count variable in a for loop to transfer the mesh from one object to another. Each triangle had identical vertices! Always expect the unexpected when it comes to debugging!

How do I flip an image in memory?

I would like to flip an image and create a new Texture2D of that flipped image.
I have done some research and found that this code will create a new Texture2D;
RenderTarget2D newTarget = new RenderTarget2D(GraphicsDevice, partWidth, partHeight)
GraphicsDevice.SetRenderTarget(newTarget);
SpriteBatch.Draw(original, Vector2.Zero, partSourceRectangle, ... )
GraphicsDevice.SetRenderTarget(null);
Texture2D newTexture = (Texture2D)newTarget;
I understand that the newTexture is susceptible to being removed from memory so I am advised that I need to use getData/SetData to create a more permanent texture. Could anyone advise me on the specific syntax to do this?
The next method saves flipped texture to new texture2D:
public Texture2D SaveAsFlippedTexture2D(Texture2D input, bool vertical, bool horizontal)
{
Texture2D flipped = new Texture2D(input.GraphicsDevice, input.Width, input.Height);
Color[] data = new Color[input.Width * input.Height];
Color[] flipped_data = new Color[data.Length];
input.GetData<Color>(data);
for (int x = 0; x < input.Width; x++)
{
for (int y = 0; y < input.Height; y++)
{
int index = 0;
if (horizontal && vertical)
index = input.Width - 1 - x + (input.Height - 1 - y) * input.Width;
else if (horizontal && !vertical)
index = input.Width - 1 - x + y * input.Width;
else if (!horizontal && vertical)
index = x + (input.Height - 1 - y) * input.Width;
else if (!horizontal && !vertical)
index = x + y * input.Width;
flipped_data[x + y * input.Width] = data[index];
}
}
flipped.SetData<Color>(flipped_data);
return flipped;
}
Example:
Load our texture then use the method, pass our texture as parameter to return new flipped texture to another texture. You can load your content inside game Update() method as well.
Texture2D texture;
Texture2D flippedTextureHorizontal;
Texture2D flippedTextureVertical;
Texture2D flippedTextureVerticalHorizontal;
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
texture = Content.Load<Texture2D>("kitty-cat");
flippedTextureHorizontal = SaveAsFlippedTexture2D(texture, false, true);
flippedTextureVertical = SaveAsFlippedTexture2D(texture, true, false);
flippedTextureVerticalHorizontal = SaveAsFlippedTexture2D(texture, true, true);
}
Draw method:
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearWrap, DepthStencilState.None, RasterizerState.CullCounterClockwise);
spriteBatch.Draw(texture, Vector2.Zero, null, Color.White, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0);
spriteBatch.Draw(flippedTextureHorizontal, new Vector2(texture.Width + offset, 0), null, Color.White, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0);
spriteBatch.Draw(flippedTextureVertical, new Vector2(texture.Width * 2 + offset * 2, 0), null, Color.White, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0);
spriteBatch.Draw(flippedTextureVerticalHorizontal, new Vector2(texture.Width * 3 + offset * 3, 0), null, Color.White, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0);
spriteBatch.End();
base.Draw(gameTime);
}
Ouput:
The alghorithm can be found Here as well.
The same result as above can be achieved by using code below for horizontal and vertical flipping at the same time:
But not sure it will be 100% correct
test = new Texture2D(GraphicsDevice, texture.Width, texture.Height);
int size = texture.Width * texture.Height;
Color[] data = new Color[size];
texture.GetData<Color>(data);
Array.Reverse(data, texture.Width, size - texture.Width);
test.SetData<Color>(data);

Messed-up triangles when using VertexPositionColorTexture with BasicEffect

image of the problem
I used Microsoft's BasicEffect tutorial here and the code sample here: go.microsoft.com/fwlink/?LinkId=198921 and got everything to work fine. Next I changed everything to use vertexPositionNormalTexture, added a few small methods to help with the texture, and was able to render a textured cube just fine. I also made the cube spin a bit. Next I wanted to try using vertexPositionNormalTexture. Unfortunately, I got this image instead of a cube. Here's some pieces of my code that contain major modifications.
Draw method
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.SteelBlue);
RasterizerState rasterizerState1 = new RasterizerState();
//backface culling
rasterizerState1.CullMode = CullMode.None;
//turn off texture blurring
graphics.GraphicsDevice.SamplerStates[0] = SamplerState.PointClamp;
graphics.GraphicsDevice.RasterizerState = rasterizerState1;
foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
{
pass.Apply();
graphics.GraphicsDevice.DrawPrimitives(
PrimitiveType.TriangleList,
0,
12
);
}
base.Draw(gameTime);
}
Part of the method that sets up vertices
private void InitializeCube()
{
Vector3 topLeftFront = new Vector3(-1.0f, 1.0f, 1.0f);
Vector3 bottomLeftFront = new Vector3(-1.0f, -1.0f, 1.0f);
Vector3 topRightFront = new Vector3(1.0f, 1.0f, 1.0f);
Vector3 bottomRightFront = new Vector3(1.0f, -1.0f, 1.0f);
Vector3 topLeftBack = new Vector3(-1.0f, 1.0f, -1.0f);
Vector3 topRightBack = new Vector3(1.0f, 1.0f, -1.0f);
Vector3 bottomLeftBack = new Vector3(-1.0f, -1.0f, -1.0f);
Vector3 bottomRightBack = new Vector3(1.0f, -1.0f, -1.0f);
Vector2 textureTopLeft = new Vector2(0.0f, 0.0f);
Vector2 textureTopRight = new Vector2(.25f, 0.0f);
Vector2 textureBottomLeft = new Vector2(0.0f, .25f);
Vector2 textureBottomRight = new Vector2(.25f, .25f);
Color frontColor = new Color(255, 255, 255);
Color backColor = new Color(255, 0, 0);
Color topColor = new Color(0, 255, 0);
Color bottomColor = new Color(0, 0, 255);
Color leftColor = new Color(0, 255, 255);
Color rightColor = new Color(0, 0, 0);
// Front face.
cubeVertices[0] =
new VertexPositionColorTexture(
topLeftFront, frontColor, GetTexPos(2));
cubeVertices[1] =
new VertexPositionColorTexture(
bottomLeftFront, frontColor, GetTexPos(2) + textureBottomLeft);
cubeVertices[2] =
new VertexPositionColorTexture(
topRightFront, frontColor, GetTexPos(2) + textureTopRight);
cubeVertices[3] =
new VertexPositionColorTexture(
bottomLeftFront, frontColor, GetTexPos(2) + textureBottomLeft);
cubeVertices[4] =
new VertexPositionColorTexture(
bottomRightFront, frontColor, GetTexPos(2) + textureBottomRight);
cubeVertices[5] =
new VertexPositionColorTexture(
topRightFront, frontColor, GetTexPos(2) + textureTopRight);
Initializing basicEffect
private void InitializeEffect()
{
basicEffect = new BasicEffect(graphics.GraphicsDevice);
basicEffect.World = worldMatrix;
basicEffect.View = viewMatrix;
basicEffect.Projection = projectionMatrix;
//basicEffect.EnableDefaultLighting
}
LoadContent
protected override void LoadContent()
{
canyonTexture = Content.Load<Texture2D>("CanyonTexture");
textureSheetWidth = canyonTexture.Width / 16;
InitializeTransform();
InitializeEffect();
basicEffect.TextureEnabled = true;
basicEffect.VertexColorEnabled = true;
basicEffect.Texture = canyonTexture;
InitializeCube();
}
Setting up the VertexBuffer
private void CreateVertexBuffer()
{
vertexDeclaration = new VertexDeclaration(new VertexElement[]
{
new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
new VertexElement(12, VertexElementFormat.Color, VertexElementUsage.Color, 0),
new VertexElement(24, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0)
});
vertexBuffer = new VertexBuffer(
graphics.GraphicsDevice,
vertexDeclaration,
number_of_vertices,
BufferUsage.None
);
cubeVertices = new VertexPositionColorTexture[number_of_vertices];
InitializeCube();
vertexBuffer.SetData<VertexPositionColorTexture>(cubeVertices);
graphics.GraphicsDevice.SetVertexBuffer(vertexBuffer);
}
protected override void Initialize()
{
// TODO: Add your initialization logic here
CreateVertexBuffer();
base.Initialize();
}
Basically your vertex declaration is wrong.
A Color is only four bytes wide. So the offset of the texture-coordinate element that follows should be 16, not 24.
However you don't even need to create a vertex declaration for this in XNA 4.0. Simply pass VertexPositionColorTexture.VertexDeclaration or typeof(VertexPositionColorTexture) to the constructor of your VertexBuffer.
There is a blog post here that explains how this all works.

Categories

Resources