Получение идеального вращения спрайта в XNA

Я столкнулся с проблемой при обновлении положения пули при повороте стреляющего корабля. В настоящее время код почти работает, за исключением того, что под большинством углов пуля не вылетает оттуда, куда я хочу. Иногда он стреляет немного вверх, чем по центру, где он должен быть, а иногда и вниз. Я почти уверен, что это как-то связано с тригонометрией, но мне трудно найти проблему.

Этот код находится в конструкторе; он устанавливает начальное положение и вращение пули на основе положения корабля (sp.position) и его вращения (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;

Затем в методе обновления я использую следующий код; Я почти уверен, что это работает нормально:

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));
    

Также я должен упомянуть, что мой корабль работал неправильно, когда я его вращал, так как начало координат (центр вращения) было (0,0). Чтобы исправить это, я изменил исходную точку на центр корабля (ширина/2, высота/2), а также добавил эти значения в прямоугольник рисования, чтобы спрайт отрисовывался правильно. Я предполагаю, что это может быть проблемой, и полагаю, что есть лучший способ обойти это. Кстати, игра в 2D.


person Jurgen Camilleri    schedule 17.04.2012    source источник
comment
Не могли бы вы предоставить код, как вы рисуете корабль и пулю? Кстати, наверное, проще, если sp.Position() возвращает центр корабля. Вы можете использовать это непосредственно в spriteBatch.Draw() в качестве позиции при указании соответствующего источника.   -  person Nico Schertler    schedule 17.04.2012
comment
вот так нарисован корабль: spriteBatch.Draw(hero.getTexture(), new Rectangle(hero.getRectangle().X + hero.getTexture().Width/2,hero.getRectangle().Y + hero.getTexture().Height/2, hero.getRectangle().Width,hero.getRectangle().Height),null, Color.White, Controls.rotation, new Vector2(hero.getTexture().Width/2,hero.getTexture().Height/2), SpriteEffects.None, 0F);   -  person Jurgen Camilleri    schedule 17.04.2012
comment
и как нарисованы пули: foreach (Blast b in playerBlasts) { spriteBatch.Draw(b.getTexture(), new Rectangle(b.getRectangle().CollisionRectangle.X + b.getTexture().Width/2,b.getRectangle().Y + b.getTexture().Height/2,b.getRectangle().Width,b.getRectangle().Height), null, Color.White, b.getRectangle().Rotation, new Vector2(b.getTexture().Width / 2, b.getTexture().Height / 2), SpriteEffects.None,0F); }   -  person Jurgen Camilleri    schedule 17.04.2012


Ответы (1)


Проблема в том, что спрайты отрисовываются не в том положении, в котором они должны быть. При вычислении центральной позиции вы предполагаете, что спрайт не вращается. Это вызывает некоторые затруднения. Кроме того, вращение произвольного вектора не так просто, как вы. Вы можете вращать вектор только путем умножения его компонентов на sin/cos, когда он находится на оси x.

Вот как вы можете вращать произвольные векторы:

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;
}

Убедитесь, что угол указан в радианах. При этом вы можете рассчитать правильное положение корабля:

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

Вы можете использовать ту же функцию для определения положения центра пули. Я точно не знаю, куда вы хотите поместить пулю. Я предполагаю, что он находится в центре правого края:

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

Если вам нужна позиция верхнего левого угла маркера, вы можете пойти дальше:

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

Однако, как я уже сказал, вероятно, легче обрабатывать позиции корабля и пуль как центральные позиции. При этом вам потребуется гораздо меньше тригонометрии.

person Nico Schertler    schedule 17.04.2012