i have this problem when my Sprite rotation origin is fixed at top left corner of window (same with sprite.Draw and sprite.Draw2D)
Either way if i change rotation center it's still at top left. I need sprite to rotate around its Z axis.
Edit:
I have tried this:
hereMatrix pm = Matrix.Translation(_playerPos.X + 8, _playerPos.Y + 8, 0);
sprite.Transform = Matrix.RotationZ(_angle) * pm;
sprite.Draw(playerTexture, textureSize, new Vector3(8, 8, 0), new Vector3(_playerPos.X, _playerPos.Y, 0), Color.White);
But it does not seem to works well...
When you draw it, is it in the correct place?
I believe that the multiplication order is reversed, and that you shouldn't be transforming by the players position in the transform.
// shift centre to (0,0)
sprite.Transform = Matrix.Translation(-textureSize.Width / 2, -textureSize.Height / 2, 0);
// rotate about (0,0)
sprite.Transform *= Matrix.RotationZ(_angle);
sprite.Draw(playerTexture, textureSize, Vector3.Zero,
new Vector3(_playerPos.X, _playerPos.Y, 0), Color.White);
Edit
You could also use the Matrix.Transformation method to get the matrix in one step.
I've got the solution for you, it's a simple method that you can use everytime you want to draw a sprite.
With this method you will be able to rotate the sprite with your desired rotation center.
public void drawSprite(Sprite sprite, Texture texture, Point dimension, Point rotationCenter, float rotationAngle, Point position)
{
sprite.Begin(SpriteFlags.AlphaBlend);
//First draw the sprite in position 0,0 and set your desired rotationCenter (dimension.X and dimension.Y represent the pixel dimension of the texture)
sprite.Draw(texture, new Rectangle(0, 0, dimension.X, dimension.Y), new Vector3(rotationCenter.X, rotationCenter.Y, 0), new Vector3(0, 0, 0), Color.White);
//Then rotate the sprite and then translate it in your desired position
sprite.Transform = Matrix.RotationZ(rotationAngle) * Matrix.Translation(position.X, position.Y, 0);
sprite.End();
}
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 just started making a 2D game using unity and I have a resolution & cam problem.
I have a 2D terrain and i'm trying to fix the left side of the cam to the left side of the terrain. However, when I change the screen resolution to iphone 4 for example, the left side is hidden. I tried this script for the cam but it's not working :
void Awake()
{
Ray ray = Camera.main.ScreenPointToRay(new Vector3(Screen.width/ 2, Screen.height / 2,-10));
Camera.main.orthographicSize = ray.origin.y;
transform.position = new Vector3 (ray.origin.x, ray.origin.y,-10);
}
You want to use Camera.pixelRect (also see Camera.pixelWidth and Camera.pixelHeight).
You're finding the world point located at the center of the screen in world coordinates, changing the camera's viewport size based on that, and then setting the camera's position back to the center of the screen. If you want to anchor the viewport's left edge to say x = 0 (assuming your terrain's left edge is at x = 0) you should find the viewport's xMax, convert it from screen coordinates to world coordinates, and set the camera's x position to that.
void Awake()
{
// Set the camera's orthographic size.
// The camera's pixelWidth, pixelHeight, and pixelRect is relative to it.
Vector3 worldCenter = Camera.main.ScreenToWorldPoint (new Vector3 (Screen.width / 2, Screen.height / 2, -10));
Camera.main.orthographicSize = worldCenter.y;
// Get the viewport's rectangle and calculate the camera's desired position.
// We want to use viewportRect.xMax since we want to move the camera to the right by half of the view width.
Rect viewportRect = Camera.main.pixelRect;
Vector3 cameraPosition = new Vector3 (viewportRect.xMax, 0, 0);
cameraPosition = Camera.main.ScreenToWorldPoint (cameraPosition);
cameraPosition.z = -10;
transform.position = cameraPosition;
}
Some references:
http://docs.unity3d.com/ScriptReference/Camera.html
http://docs.unity3d.com/ScriptReference/Camera-orthographicSize.html
http://forum.unity3d.com/threads/screen-width-vs-camera-pixelwidth.136703/
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);
Vector2 drawPos = (-screenPosition);
drawPos.X *= (float)device.DisplayMode.Width;
drawPos.Y *= (float)device.DisplayMode.Height;
spriteBatch.Draw(
texture,
drawPos,
getRectangle(),
Color.White,
rotation,
getOrigin(),
1.0f / zoom,
SpriteEffects.None,
0);
I have a drawPos essentialy being 0..1 and multiply that with the display width and height. screenposition is obtained by dragging the screen. With other elements, primitives, the position is correct and is exactly being dragged along with the input. However when drawing a sprite the sprite is moving to quickly, faster than the input, giving a sort of parallax effect, not what I want.
I somehow get the feeling I am using the parameters wrong, and spriteBatch.Draw(..) does not need pixelcoordinates..
Width and height is obtained by texture loader.
public Vector2 getOrigin()
{
return new Vector2(width / 2, height / 2);
}
public Rectangle getRectangle()
{
return new Rectangle(
0,
0,
width,
height);
}
Also, I am developing for Windows Phone.
The getRectangle() method is basically useless, you are specifying a source rectangle which is the same size as the texture - use null instead (unless ofcourse you've just simplified your code for us).
How is screenPosition defined? I don't understand why you'd times it by -1. You are also using the screen that the window is on to get width/height with device.DisplayMode which is something you should avoid because this will only work when your window is the same size as the screen.
Try drawing the sprite to Vector2.Zero without an origin, and with the sourceRectangle set to null. Slowly add back in your other parameters and see where the error is occuring. Can't really say much else without more information!
spriteBatch.Draw(
texture,
Vector2.Zero,
null,
Color.White,
0,
Vector2.Zero,
1,
SpriteEffects.None,
1);
This is what I would use to make sure the sprite is actually displaying properly.