I have a rectangle with a square at its bottom. I also have code that makes the rectangle rotate around its origin which is at the top of this rectangle. Im trying to make the square at the bottom to always stay at the end of this rectangle even when its rotated. Hers a picture to illustrate my problem:
I see now that it wasn't such a good idea to make the square at the bottom white. So when i rotate the rectangle upwards to the right or upwards to the left, I want the square to keep staying at the end of this rectangle. Maybe there is a simple solution, but my knowledge isn't as good as it should be on this subject. Hope someone could point me in the right direction.
Something like this aught to get you there.
float pendulumAngle;
Vector2 origin;
Vector2 squareTLcorner;//top left corner of square
Vector2 squareOffset;
void Reset()
{
pendulumAngle = 0;
origin = new Vector2(?.?f, ?.?f);// set to whatever you need
squareTLcorner = new Vector2(?.?f, ?.?f); // set to whatever you need
squareOffset = squareTLcorner - origin;
}
void UpdatePendulum(float angleMovedSinceLastFrame)
{
pendulumAngle += angleMovedSinceLastFrame;
}
void UpdateSquarePosition()
{
squareTLcorner = Vector2.Transform(squareOffset, Matrix.CreateRotationZ(pendulumAngle) + origin;
}
void DrawSquare()
{
spriteBatch.Draw(sqTex,squareTLcorner, , ,pendulumAngle, , , , );// overload 6 of 7
}
The easiest way is passing a transformation matrix to the sprite batch.
Rectangle Black = new Rectangle(0,0, 20, 100);
Rectangle White = new Rectangle( Black.Left, Black.Bottom, Black.Width, Black.width);
Vector2 Pivot= new Vector(100,100);
vector2 Origin = new Vector2( 10,10);
Matrix transform = Matrix.CreateTranslation(-Origin.X, -Origin.Y)
* Matrix.CreateRotationZ(angle)
* Matrix.CreateTranslation(Pivot);
SpriteBatch.begin(...., transform)
SpriteBatch.Draw( Texture, Black, Color);
SpriteBatch.Draw( Texture, White, Color);
SpriteBatch.end();
Basically you are working in a different space that is rotated ans translated as you need, realize that Black rectangle location is (0,0).
Code it's not tested but should work as expected. ;)
Related
Normally XNA start drawing sprite from top-left, but I would like to start draw object from bottom-center, how this could be done?
You want to specify a different origin in your SpriteBatch.Draw calls. The default is 0,0 (top-left). Note that the origin is relative to the sprite, not the screen.
So if your sprite is 64x64, you want to use an origin of 32x64 for bottom center.
e.g. using this override (MSDN)
spriteBatch.Draw (
texture,
position,
sourceRectangle,
color,
rotation,
new Vector2(32, 64), // origin
scale,
effects,
layerDepth
)
You can calculate these on the fly if you wish. e.g if you're using the full texture you could specify it as new Vector2(texture.Center.X, texture.Height). Or alternatively you could base it on the sourceRectangle if you're using a sprite sheet.
You need to specify a bunch of other arguments to use these Draw overrides but you can just pass in the defaults. The defaults are:
sourceRectangle: null = full texture
color: Color.White = default color (sprite colors will be used)
rotation: 0f = no rotation
scale: 1f = default scale
efects: SpriteEffects.None = no flipping
layerDepth: 0 = default layer
Lets say you are drawing an image WidthxHeight on position XxY.
spriteBatch.Draw(texture, position, Color.White);
First let's set the bottom of the image to those coordinates by subtracting images height from position's Y coordinate (subtracting because in XNA the Y-axis is inverted, not like in your math class)
spriteBatch.Draw(texture, position + new Vector2(0, -texture.Height), Color.White);
Second, let's set the image to the left by subtracting half of the image's width from position's X coordinate.
spriteBatch.Draw(texture, position + new Vector2(-texture.Width/2, -texture.Height), Color.White);
And there you have it.
Edit: Another thought: you can create new variable called DrawPosition and use that variable when needed, instead of always substracting. That would look something like this:
private Texture2D texture;
public Vector2 position;
public Vector2 DrawPosition
{ get { return position + new Vector2(-texture.Width/2, -texture.Height); } }
public void Draw(SpriteBatch spriteBatch)
{ spriteBatch.Draw(texture, DrawPosition, Color.White); }
Or, if this new variable doesn't make sense to you, create a function that will return the DrawPosition()
public Vector2 DrawPosition()
{ return position + new Vector2(-texture.Width/2, -texture.Height); }
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.
This is my code for drawing the tower:
SpriteBatch.Draw(
GetTowerImage(m.SquareTower),
new Rectangle(m.X * TILE_SIZE, m.Y * TILE_SIZE, TILE_SIZE, TILE_SIZE),
null,
Color.White,
m.SquareTower.Rotation,
new Vector2(TILE_SIZE - 35, TILE_SIZE - 35),
SpriteEffects.None,
(float)0.0);
My code that gets the position of a tower and places it in a position, however when my rotation method takes place and rotates the image
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
(I don't have enough reputation to post images)
I would comment but my reputation is too low... sorry.
By the looks of it I'm pretty positive that your origin is your tower's X and Y position, it really should be something like this:
// AKA the centre of your tower relative to it's Vector2 position
Vector2 origin = new Vector2(towerWidth / 2, towerHeight / 2);
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);
There is a similar question System.Drawing in XNA, but this may be a clearer question and thus one easier to answer.
We're trying to draw lines on the screen in C#. We are using the XNA library. This code
void DrawLine2 (Vector2 point1, Vector2 point2)
{
System.Drawing.Pen pen = new System.Drawing.Pen(System.Drawing.Color.Green, 1);
Point p1 = new Point((int)point1.X, (int)point1.Y), p2 = new Point((int)point2.X, (int) point2.Y);
Graphics.DrawLine (pen, p1, p2);
}
gives the compile-time error that Graphics does not exist.
Perhaps I should be using something in XNA to draw the line rather than in System -- but if so I am not sure what. XNA has a Spritebatch drawing function, but AFAIK you give it a sprite and a center (and a rotation), rather than 2 points.
Try this handy extensions method,
public static void DrawLine(this SpriteBatch spriteBatch, Vector2 begin, Vector2 end, Color color, int width = 1)
{
Rectangle r = new Rectangle((int)begin.X, (int)begin.Y, (int)(end - begin).Length()+width, width);
Vector2 v = Vector2.Normalize(begin - end);
float angle = (float)Math.Acos(Vector2.Dot(v, -Vector2.UnitX));
if (begin.Y > end.Y) angle = MathHelper.TwoPi - angle;
spriteBatch.Draw(1X1 PIXEL TEXTURE, r, null, color, angle, Vector2.Zero, SpriteEffects.None, 0);
}
Spritebatch can be used to draw a line, as Beanish commented you can simply make a one pixel sprite and extend it between two points.
This is a great library for drawing 2D primitives in XNA that uses the technique for drawing lines, as well as other objects like arcs. I use it extensively:
http://sourceforge.net/projects/primitives2d/