Why is my sprite drawing to the top left corner when my wizardPos variable clearly puts it at the middle of the screen?
//in load content
wizardPos = new Vector2(graphics.PreferredBackBufferWidth /2, 700);
wizardChar = new Characters.Wizard(this, spriteBatch, wizardPos, wizardWalk1);
//in Draw method
this.spriteBatch.Draw(tempWizard, wizardPos, null, Color.White, 0f, wizardPos, 1f, SpriteEffects.None, 0f);
Try this:
this.spriteBatch.Draw(tempWizard, wizardPos, null, Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0f);
The position of your sprite is actually the position of the origin of your sprite. So when you set the origin to wizardPos, the origin is set relative to the sprite - not the screen. So setting the origin and position to the same value effectively cancel each other out.
The origin will usually be somewhere within the bounds of your sprite since it is used to calculate things like rotation as well
Related
with Monogame I am making a game that draws both graphics and text to the screen, with position modified by a camera matrix. If I set the position of text to the camera position, everything is fine, but when I set sprites to the camera position there is very noticeable jittering as the camera moves. I think this is because graphics are drawn with rectangles which require integer positional values. I guess text has no such requirement though.
How do I get my graphics to follow the camera movement smoothly like the text does?
If it's of use, this is my spriteBatch.Begin() call:
spriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.LinearClamp, null, null, null, camera.GetTransformation(graphics));
And this is my camera transformation:
public Matrix GetTransformation(GraphicsDeviceManager graphicsDevice)
{
Vector3 newVector = new Vector3(-GameInfo.info.cameraPosition.X, -GameInfo.info.cameraPosition.Y, 0);
cameraTransformMatrix = Matrix.CreateTranslation(newVector) *
Matrix.CreateRotationZ(rotation) *
Matrix.CreateScale(new Vector3(zoom, zoom, 1)) *
Matrix.CreateTranslation(new Vector3(GameInfo.info.resolutionWidth * 0.5f, GameInfo.info.resolutionHeight * 0.5f, 0));
return cameraTransformMatrix;
}
Thanks!
I have managed to fix the problem by using a different overload of SpriteBatch.Draw() which doesn't rely on a destination rectangle:
spriteBatch.Draw(texture, position, rSpriteSourceRectangle, Color.White);
For reference, this was my old one:
spriteBatch.Draw(texture, new Rectangle(drawX, drawY, frameWidth, frameHeight), rSpriteSourceRectangle, Color.White);
This code is to draw the tower. Square locations are the top left of the square. TILE_SIZE is simply the dimensions of the square.
SpriteBatch.Draw(TowerImage, new Rectangle(square.X * TILE_SIZE, square.Y * TILE_SIZE, TILE_SIZE, TILE_SIZE), null, Color.White, myTower.Rotation,
new Vector2(TILE_SIZE - 35, TILE_SIZE - 35), SpriteEffects.None, (float)0.0);
This code is how I determine the rotation
public void FaceTarget(Vector2 center, Vector2 enemyCenter)
{
Vector2 direction = center - enemyCenter;
direction.Normalize();
this.Rotation = (float)Math.Atan2(-direction.X, direction.Y);
}
I did this based on:
http://www.riemers.net/eng/Tutorials/XNA/Csharp/Series2D/Rotation.php
http://www.riemers.net/eng/Tutorials/XNA/Csharp/Series2D/Direction_to_Angle.php
The rotation is being really weird, here is how it looks normally:
But when it rotates it goes like this:
Finally when it looks down, it goes complete off path, it's not rotating by its center, but the entire image is moving why is it doing that?
Only the first image is actually the tower in the correct position
It seems like it is rotating of the top left point and I don't know why. Can anyone help?
Apparently, your sprite is taking into consideration as the origin of rotation a Vector2.Zero (or Vector2(0,0)) point. That means the upper left point of the Texture2D file.
I see that you are setting the origin in the Draw method to TILE_SIZE - 35 which makes me wonder, is the tile a square of 70 pixels W/H?
What happens if you replace the substraction with new Vector2(TowerImage.Width / 2, TowerImage.Height / 2)?
I'll leave you an example from this site which explains easily how to rotate an image following the mouse position at all times:
Update method:
MouseState mouse = Mouse.GetState();
mousePosition = new Vector2(mouse.X, mouse.Y);
Vector2 direction = mousePosition - position;
direction.Normalize();
rotation = (float)Math.Atan2(
(double)direction.Y,
(double)direction.X);
Draw method:
spriteBatch.Begin();
spriteBatch.Draw(
rocket,
position,
null,
Color.White,
rotation,
new Vector2(
rocket.Width / 2,
rocket.Height / 2),
1.0f,
SpriteEffects.None,
1.0f);
spriteBatch.End();
Check that in the posted code the rotation angle is calculated slightly different than yours, but the important piece of code is the calculation of the origin point in the Draw method.
I've been trying to fix this problem, but I have no idea. I know before I've asked about origin, but I don't really know how to fix this.
red dot = coordinates x-y
yellow dot = origin used in spritebatch.draw
origin = new vector(img.width/2, img.height/2);
position = new rectangle(400, 200, img.width, img.height);
center_x = position.center.x
center_Y= position.center.y
I noticed that even though I placed the origin when using spritebatch.draw, the positioning is still done from the 0,0 origin instead of the Yellow dot. How can I change this? I noticed it when I check both the center for Y and X on the position rectangle and compared it with the actual coordinates. The center was higher than the coordinates its self. I want it so that the center coordinates are the same from the position's X & Y. Example, I assign 200 for X and 200 fro Y in the position rectangle. When I go check the center of that rectangle, I want it to be 200 on both X and Y. Also, I'm using a rectangle for positioning cause I'm also testing out so collision stuff.
An example would be nice, thanks in advance
You are passing to positioning a rectangle, use a Vector2 to positioning instead:
Vector2 origin = new Vector2(img.Width, img.Height) * 0.5f;
Vector2 pos = new Vector2(400,200) + origin;
spriteBatch.Draw(img, pos, null, Color.White, 0, origin, SpriteEffects.None, 0)
This works for sure.
EDIT:
if you want to work with rectangles be sure that origin is related to the texture size.
Rectangle bounds = new (400,200, img.Width, img.Height);
Vector2 origin = new Vector2(img.Width, img.Height) * 0.5f;
spriteBatch.Draw(img, bounds, null, Color.White, 0, origin, SpriteEffects.None, 0)
This works too.
The position of the yellow dot will be (400,200)
if you don't use origin, the red dot position will be (400,200)
i don't see position on our example of spriteBatch. try using it with all properties.
SpriteBatch.Draw (Texture2D, ImgPosition, ImgRect, ImgColor, ImgRotate, ImgOrigin, Scale, SpriteEffects, Layer)
http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.graphics.spritebatch.draw.aspx
If you're trying to draw a sprite setting its Origin in its center you're doing it right. Your yellow dot is at position (400, 200) and the dot in the screenshot is reasonably in that position, considering the screen dimension of 800x480. But if you want that the upperleft corner of your sprite has that position you need to change your Draw call.
When specifying the Origin, try using Vector2 position instead of Rectangle for the second parameter of Draw to set the positin of your sprite.
Specify Vector2 Position and Origin:
origin = newVector2(img.Width, img.Heigth) / 2;
pos = new Vector2(400, 200) + origin;
spriteBatch.Draw(img, pos, null, Color.White, 0, origin, SpriteEffects.None, 0);
Or use only the position Rectangle:
posRect = new Rectangle(400, 200, img.Width, img.Heigth);
spriteBatch.Draw(img, posRect, Color.White);
Very odd problem, when I try and draw my billboard sprite it always appears as a white block, changing the .draw color property still draws it as white, it also doesn't matter it I use a jpeg, or transparent png.
[EDIT]
So I'm now trying to use a Viewport instead of a basic effect to just get an x and y screen coordinate, I'll fix any scaling issue later, however now the image stays in the exact same spot (on the screen, it doesn't change position based on the camera) and doesn't get any bigger or smaller based on how far away it is
My new billboard rendering function:
public void Draw(Camera camera, GraphicsDevice device, SpriteBatch spriteBatch, Texture2D Texture)
{
Viewport viewport = new Viewport(new Rectangle(0, 0, 800, 480));
Vector3 viewSpaceTextPosition = viewport.Project(this.position, camera.Projection, camera.View, camera.World);
spriteBatch.Begin();
spriteBatch.Draw(Texture, new Vector2(viewSpaceTextPosition.X, viewSpaceTextPosition.Y), null, Color.White, 0, new Vector2(Texture.Bounds.Center.X, Texture.Bounds.Center.Y), this.Scale, SpriteEffects.None, viewSpaceTextPosition.Z);
spriteBatch.End();
device.RasterizerState = RasterizerState.CullCounterClockwise;
device.BlendState = BlendState.Opaque;
device.DepthStencilState = DepthStencilState.Default;
}
So is my use of Viewport wrong or do I just need to use it's information differently in spriteBatch.Draw()?
I think this should do the trick using viewport project... taking two projection points and calculating its distance you get a value affected by depth... so if it's deeper that value will be smaller.
public void Draw(Camera camera, GraphicsDevice device, SpriteBatch spriteBatch, Texture2D Texture)
{
Vector3 pos1= device.Viewport.Project(
this.position,
camera.Projection, camera.View, camera.World);
Vector3 pos2= device.Viewport.Project(
this.position+ Vactor3.UnitY*10,
camera.Projection, camera.View, camera.World);
Vector2 pos = new Vector2(pos1.X, pos1.Y);
Vector2 origin = new Vector2(Texture.Bounds.Center.X, Texture.Bounds.Center.Y);
float Scale = Vector3.Distance(pos1, pos2) * CustomRatio;
spriteBatch.Begin();
spriteBatch.Draw(Texture, pos, null, Color.White, 0,
origin, Scale, SpriteEffects.None, 0);
spriteBatch.End();
device.RasterizerState = RasterizerState.CullCounterClockwise;
device.BlendState = BlendState.Opaque;
device.DepthStencilState = DepthStencilState.Default;
}
In other hand... your previous code seems to be extracted from a source that drinks from this article made by the guy behind Xna that explain how to use basiceffect to draw billboards in 3D with spritebatch...
http://blogs.msdn.com/b/shawnhar/archive/2011/01/12/spritebatch-billboards-in-a-3d-world.aspx
I hope it helps you
Figured it out, you have to enable textures on the effect and then set effect.Texture to the Texture2D you want to use just before calling spriteBatch.Begin() in the draw function
I have a problem with rotating. I know that I can rotate a Texture2D object with the draw method.
My goal is to rotate a texture by 180°. For example, if I make a picture of a human with the camera where the head is at the bottom, I want to be able to rotate it so that the head is at the top again.
Here is the code or the rotation:
spriteBatch.Draw(Texture, Position, null, Color.White, MathHelper.Pi, new Vector2(), 1.0f, SpriteEffects.None, 0f);
The rotation works fine, but I have another problem:
If I add the texture to position 0,0 after rotating it, it's not visible anymore.
How do I rotate or maybe reflect the object, so that the red point will be at the top-left corner again?
http://msdn.microsoft.com/en-us/library/ff433989.aspx
public void Draw (
Texture2D texture,
Vector2 position,
Nullable<Rectangle> sourceRectangle,
Color color,
float rotation,
Vector2 origin,
Vector2 scale,
SpriteEffects effects,
float layerDepth)
//Using:
var origin = new Vector2()
{
X = texture.Width / 2,
Y = texture.Height/ 2
};
spriteBatch.Draw(texture, Vector2.Zero, null, Color.White, MathHelper.Pi, origin, 1f, SpriteEffects.None, 0f)`