[.net] Sprite rendering problems

Started by
8 comments, last by Andy Moogle 18 years, 10 months ago
I'm rendering my sprite with this line: arg_sprite.Draw2D(Tex, Pos, Angle, Pos, Color.White) Pos is the current position of the sprite. When I render it, not matter what pos is equal to, it appears at 0,0 and rotates around it. When I go through it with the debugger, pos is not equal to 0,0 but to what it is supposed to be. If I put the center of rotation on the origin the sprite will appear at pos, and rotate around 0,0. Which is how it is supposed to be. If i set the center of rotation to 50, 50 it still works fine. if i set it to 400,300 (which is in the middle of my form) the sprite just disappears, but if i look at the values using the debugger, they are what they should be. What the hell is going on? The center of rotation is in world coordinates right? Why is this acting so strange? Since I'm already starting a thread, what does Dev.Transform.View = Matrix.OrthoOffCenterLH(0, dp.Width, dp.Height, 0, 1, 10) do? Does it set up the viewport?
Advertisement
Hang on, why have you got Pos in that draw line twice?
One position is the position in the texture, the other is the position on screen.
Anything posted is personal opinion which does not in anyway reflect or represent my employer. Any code and opinion is expressed “as is” and used at your own risk – it does not constitute a legal relationship of any kind.
Quote:Original post by paulecoyote
Hang on, why have you got Pos in that draw line twice?
One position is the position in the texture, the other is the position on screen.

These are the arguments to Draw2D:

Draw2D(
Texture to be drawn,
A point that represent the sprites' rotational center,
Angle of rotation,
Position on screen,
base colour (doesnt really do anything)
)

This is VB.NET with DX9 SDK.
public void Draw2D(
Texture srcTexture,
Point rotationCentre,
float rotationAngle,
Point position,
Color color
);

Your line

arg_sprite.Draw2D(Tex, Pos, Angle, Pos, Color.White)

Uses the same Pos for the rotational centre and the position. The rotational centre should be half width plus half height, that or if you want it from the top corner instead Rectangle.Empty.

The class I'm posting is from a game I'm developing at the moment. It packs lots of different sprites in one texture - the code works well so may be it might be useful to you. Means more then one sprite type and animation frames are kept in the same texture.

A IPositionServer is a way of decoupling the view from the business logic - it just gives x and y.

Anyway it might be useful for you to look at.

[source language="c#"]using System;using Microsoft.DirectX;using Microsoft.DirectX.Direct3D;using System.Drawing;using System.Diagnostics;namespace uk.me.pde.GemWar{	/// <summary>	/// GraphicsSprite.	/// </summary>	public class GraphicsSprite	{		// Information about our sprites		//protected readonly Texture spriteTexture;		protected readonly int numberSpritesRow;// = 6;		protected readonly int numberSpritesCol;// = 8;		protected readonly int numberSprites;		protected readonly int spriteWidth;// = 32;		protected readonly int spriteHeight;// = 32;		protected readonly int textureOffsetX;		protected readonly int textureOffsetY;		protected readonly Vector3 centre = new Vector3(0, 0, 0);				protected int textureColumn = 0;		protected int textureRow = 0;		protected Rectangle drawRectangle = new Rectangle();		protected IPositionServer positionServer;		protected Vector3 drawOffset;		public GraphicsSprite(IPositionServer positionServer, Vector3 drawOffset, int numberSpritesRow, int numberSpritesCol, int spriteWidth, int spriteHeight, int textureOffsetX, int textureOffsetY)		{			this.positionServer = positionServer;			if (null==positionServer)			{				throw new ArgumentNullException("positionServer", "GraphicsSprite requires a position server!");			}			DrawOffset = drawOffset;			this.numberSpritesRow = numberSpritesRow;			this.numberSpritesCol = numberSpritesCol;			this.numberSprites = numberSpritesRow * numberSpritesCol;			this.spriteWidth = spriteWidth;			this.spriteHeight = spriteHeight;			this.textureOffsetX = textureOffsetX;			this.textureOffsetY = textureOffsetY;					}		public IPositionServer PositionServer		{			get			{				return positionServer;			}		}		public Vector3 DrawOffset		{			get			{				return drawOffset;			}			set			{								drawOffset = value;			}		}		/// <summary>		/// Draw this sprite with the current settings		/// </summary>		public virtual void Draw(Sprite sprite, Texture spriteTexture)		{						//Using new seems to inpact every now and again on frames (probably gc)			//sprite.Draw(spriteTexture, new Rectangle(textureColumn * spriteWidth, textureRow * spriteHeight, spriteWidth, spriteHeight), centre, position, Color.White);									//Using set rectangle ref seems to be slightly slower, but no big nasty drop in framerate			SetRectangle(ref drawRectangle, textureOffsetX + (textureColumn * spriteWidth),  textureOffsetY + (textureRow * spriteHeight), spriteWidth, spriteHeight);			sprite.Draw(spriteTexture, drawRectangle, centre, positionServer.Position + drawOffset, Color.White);		}		protected void SetRectangle(ref Rectangle rect, int x, int y, int width, int height)		{			rect.X = x;			rect.Y = y;			rect.Width = width;			rect.Height = height;						//return rect;		}		/// <summary>		/// Updates sprite frame		/// </summary>		/// <param name="elapsedTime"></param>		public void FrameUpdate(float elapsedTime)		{			Vector3 frameMovement = Vector3.Multiply(positionServer.Velocity, elapsedTime);			positionServer.Position.Add(frameMovement);			AnimationUpdate(elapsedTime);		}		/// <summary>		/// Updates the image to be used		/// </summary>		/// <param name="elapsedTime"></param>		protected void AnimationUpdate(float elapsedTime)		{		}		/// <summary>		/// Sprite width		/// </summary>		public int SpriteWidth		{			get			{				return spriteWidth;			}		}		/// <summary>		/// Sprite Height		/// </summary>		public int SpriteHeight		{			get			{				return spriteHeight;			}		}	}}
Anything posted is personal opinion which does not in anyway reflect or represent my employer. Any code and opinion is expressed “as is” and used at your own risk – it does not constitute a legal relationship of any kind.
Quote:Original post by paulecoyote
public void Draw2D(
Texture srcTexture,
Point rotationCentre,
float rotationAngle,
Point position,
Color color
);

Your line

arg_sprite.Draw2D(Tex, Pos, Angle, Pos, Color.White)

Uses the same Pos for the rotational centre ...

*** Source Snippet Removed ***


rotationCentre is in world coordinates though, when I put say, (16,16) in it rotates around point (16,16) on the screen. If i put though the position of the sprite as the rotation center, it shoud rotate around its upper left corner, but for some reason it doesn't work.

I looked into using Draw instead of Draw2D (as you have done) but it does not provide an easy way to rotate the sprite... So I'd rather use draw2d. Though your code is rather interesting, I might incorporate some of your ideas when i get basic rendering to work...

Anybody know why there is this weird behaviour?
Hi seagulls,

the reason is that you have initiated a directX device with the resolution of lets say 800x600. Therefore the middle of the form or panel with the size of 500x500 pixel is the middle of your device (400x300) and not (250x250).

greets,
Oliver Düvel
Qbound]the better choice[
Quote:Original post by Qbound
Hi seagulls,

the reason is that you have initiated a directX device with the resolution of lets say 800x600. Therefore the middle of the form or panel with the size of 500x500 pixel is the middle of your device (400x300) and not (250x250).

greets,
Oliver Düvel

Nope, that's not it. I've done some research now, and it seems the sprite class rotates only around the origin. So I just stopped using the built in rotation, and used some matrix operations to rotate it (translate to origin, rotate, translate back to previous position). It works, great, if anybody is interested I'll post some code.
Quote:Original post by seagulls
Quote:Original post by Qbound
Hi seagulls,

the reason is that you have initiated a directX device with the resolution of lets say 800x600. Therefore the middle of the form or panel with the size of 500x500 pixel is the middle of your device (400x300) and not (250x250).

greets,
Oliver Düvel

Nope, that's not it. I've done some research now, and it seems the sprite class rotates only around the origin. So I just stopped using the built in rotation, and used some matrix operations to rotate it (translate to origin, rotate, translate back to previous position). It works, great, if anybody is interested I'll post some code.



I would really like to see that code. I am having problems getting rotation to work as well. I'm using Draw2D too.
'Everything is rotated around the origin, so the sprite is moved to the origin, rotate then moved back
tmpmatrix = Matrix.Translation(tmp.Pos.X + 16, tmp.Pos.Y + 16, 1) 'the 16 is half the sprite width and length, so it rotates around the middle
SpriteRenderer.Transform = Matrix.Invert(tmpmatrix) * Matrix.RotationZ(tmp.Angle) * tmpmatrix
SpriteRenderer.Draw(tmp.Tex, Drawing.Rectangle.Empty, New Vector3(0, 0, 0), tmp.Pos, Color.White)
Quote:Original post by seagulls
'Everything is rotated around the origin, so the sprite is moved to the origin, rotate then moved back
tmpmatrix = Matrix.Translation(tmp.Pos.X + 16, tmp.Pos.Y + 16, 1) 'the 16 is half the sprite width and length, so it rotates around the middle
SpriteRenderer.Transform = Matrix.Invert(tmpmatrix) * Matrix.RotationZ(tmp.Angle) * tmpmatrix
SpriteRenderer.Draw(tmp.Tex, Drawing.Rectangle.Empty, New Vector3(0, 0, 0), tmp.Pos, Color.White)



Thanks a lot. I'll try it out asap.

This topic is closed to new replies.

Advertisement