简体   繁体   中英

Obtaining perfect sprite rotation in XNA

I am encountering an issue when updating a bullet's position when I rotate the ship that shoots it. Currently the code almost works except that at most angles the bullet is not fired from where i want it to. Sometimes it fires slightly upward than the centre where it should be, and sometimes downwards. I'm pretty sure it has something to do with the trigonometry but I'm having a hard time finding the problem.

This code is in the constructor; it sets the bullet's initial position and rotation based on the ship's position ( sp.position ) and its rotation ( Controls.rotation ):

this.backgroundRect = new RotatedRectangle(Rectangle.Empty, Controls.rotation);
//get centre of ship
this.position = new Vector2(sp.getPosition().X + sp.getTexture().Width/2, 
(sp.getPosition().Y + sp.getTexture().Height / 2));

//get blast pos
this.position = new Vector2((float)(this.position.X + (sp.getTexture().Width / 2 * 
Math.Cos(this.backgroundRect.Rotation))), (float)(this.position.Y + 
(sp.getTexture().Width / 2 * Math.Sin(this.backgroundRect.Rotation))));

//get blast pos + texture height / 2
this.position = new Vector2((float)(this.position.X + (this.texture.Height / 2 * 
Math.Cos(this.backgroundRect.Rotation))), (float)(this.position.Y + 
(this.texture.Height / 2 * Math.Sin(this.backgroundRect.Rotation))));
        
this.backgroundRect = new RotatedRectangle(new Rectangle((int)this.position.X, 
(int)this.position.Y, this.texture.Width, this.texture.Height), Controls.rotation);
speed = defSpeed;

Then in the update method I use the following code; I'm pretty sure this is working fine though:

this.position.X = this.position.X + defSpeed * 
(float)Math.Cos(this.getRectangle().Rotation);
this.position.Y = this.position.Y + defSpeed * 
(float)Math.Sin(this.getRectangle().Rotation);
this.getRectangle().CollisionRectangle.X = (int)(position.X + defSpeed * 
(float)Math.Cos(this.getRectangle().Rotation));
this.getRectangle().CollisionRectangle.Y = (int)(position.Y + defSpeed * 
(float)Math.Sin(this.getRectangle().Rotation));
    

Also I should mention that my ship had not been working correctly when I rotated it since the origin (center of rotation) was (0,0). To remedy this I changed the origin to the center of the ship (width/2,height/2) and also added those values to the drawing rectangle so that the sprite would draw correctly. I imagine this could be the problem and suppose there's a better way of going around this. The game is in 2D by the way.

The problem is that the sprites are not drawn on the positions they are supposed to be. When calculating the center position, you assume that the sprite is not rotated. This causes some trouble. Furthermore, rotating an arbitrary vector is not as easy as you did. You can only rotate a vector by multiplying its components with sin/cos when it is on the x-axis.

Here is how you can rotate arbitrary vectors:

Vector2 vecRotate(Vector2 vec, double phi)
{
    double length = vec.Length(); //Save length of vector
    vec.Normalize();
    double alpha = Math.Acos(vec.X); //Angle of vector against x-axis
    if(vec.Y < 0)
        alpha = 2 * Math.PI - alpha
    alpha += phi;
    vec.X = Math.Cos(alpha) * length;
    vec.Y = Math.Sin(alpha) * length;
    return vec;
}

Make sure, the angle is in radians. With that you can calculate the correct position of the ship:

Vector2 ShipCenter = sp.Position() + vecRotate(new Vector2(sp.getTexture().Width/2, sp.getTexture().Height/2), Controls.Rotation);

You can use the same function to determine the position of the bullet's center. I don't exactly know, where you want to place the bullet. I will assume, it is at the center of the right edge:

Vector2 offset = new Vector2(sp.getTexture.Width/2, 0);
this.position = ShipCenter + vecRotate(offset, Controls.Rotation);

If you then need the position of the upper left corner of the bullet, you can go further:

this.position -= vecRotate(new Vector2(this.texture.Width/2, this.texture.Height/2), Controls.Rotation)

However, as I stated, it is probably easier to handle the ship's and bullets' positions as central positions. Doing so, you need far less trigonometry.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM