Como ajusto a origem da rotação para um grupo de sprites?

7

Atualmente, estou agrupando sprites e aplicando uma transformação de rotação no sorteio:

private void UpdateMatrix(ref Vector2 origin, float radians)
{
     Vector3 matrixorigin = new Vector3(origin, 0);
     _rotationMatrix = Matrix.CreateTranslation(-matrixorigin) * Matrix.CreateRotationZ(radians) *  Matrix.CreateTranslation(matrixorigin);
}

Onde a origem é o ponto mais central do meu grupo de sprites. Aplico essa transformação a cada sprite no grupo.

Meu problema é que, quando ajusto o ponto de origem, todo o meu grupo de sprites se reposiciona na tela.

Como diferenciar o ponto de rotação usado na transformação da posição do grupo de sprites? Existe uma maneira melhor de criar essa matriz de transformação?

EDITAR

Aqui está a parte relevante da função Draw ():

Matrix allTransforms = _rotationMatrix * camera.GetTransformation();

spriteBatch.Begin(SpriteSortMode.BackToFront, null, null, null, null, null, allTransforms);

for (int i = 0; i < _map.AllParts.Count; i++)
{
    for (int j = 0; j < _map.AllParts[0].Count; j++)
    {            
       spriteBatch.Draw(_map.AllParts[i][j].Texture, _map.AllParts[i][j].Position, null, Color.White, 0, _map.AllParts[i][j].Origin, 1.0f, SpriteEffects.None, 0f);
    }
}

Isso tudo funciona bem, novamente, o problema é que, quando uma rotação é definida e o ponto de origem é alterado, a posição do grupo de sprites é deslocada na tela.

Estou tentando descobrir uma maneira de ajustar o ponto de origem sem causar uma mudança de posição.

Edição 2 Neste momento, estou procurando soluções alternativas, pois isso não está funcionando. Alguém sabe uma maneira melhor de rotacionar um grupo de sprites no XNA? Preciso de um método que permita modificar o ponto de rotação (origem) sem afetar a posição do grupo de sprites na tela.

EDIT 3 Acho que se eu pudesse redefinir as coordenadas da tela para (0,0) na minha posição de sprite, isso essencialmente me permitiria reposicionar a origem sem movimento. Essencialmente, preciso de uma maneira de definir a posição / rotação atual e começar do zero. Alguém sabe se é possível fazer do meu sprite a nova origem da tela?

ORIGEM EM MOVIMENTO SEM ROTAÇÃO:

Sem rotação

ORIGEM EM MOVIMENTO COM UMA ROTAÇÃO (observe como ela mudou para cima):

Com rotação

jgallant
fonte
Soa como uma pergunta que fiz recentemente: gamedev.stackexchange.com/questions/19297/…
notlesh
Meu problema é que, quando há uma rotação e a origem é modificada, todo o grupo de sprites muda na tela. Como você lida com isso graciosamente?
Jgallant
Podemos ver a área do seu código que chama spitebatch.draw?
usar o seguinte
Quando você diz que a posição do grupo de sprites muda na tela, isso faz com que a origem permaneça na mesma posição da tela? Veja se você pode exibir a origem do ponto com algum marcador visual e comparar capturas de tela.
ChrisC
Se a rotação for 0 - a posição não muda. O problema é que, quando a origem da rotação é alterada, a matriz de rotação acaba mudando a posição do grupo de sprites porque é girada em um local diferente. Isso faz sentido, mas quero evitar esse comportamento completamente.
jgallant

Respostas:

6

Eu tenho isso implementado no meu editor mundial. Posso agrupar sprites e rotacioná-los ou escalá-los como um grupo em torno de uma origem arbitrária (que no meu caso também é o centro do grupo). Eu uso algo como isto:

// Origin should be supplied in World-Space
void RotateGroup(IEnumerable<Sprite> sprites, Vector2 origin, float angle)
{
    Matrix transform =  Matrix.CreateTranslation(-origin.X, -origin.Y, 0f) *
                        Matrix.CreateRotationZ(angle) *
                        Matrix.CreateTranslation(origin.X, origin.Y, 0f);

    foreach(Sprite sprite in sprites)
    {
        sprite.Position = Vector2.Transform(sprite.Position, transform);
        sprite.Rotation += angle;
    }
}

Simplesmente chamo esse método quando quero rotacionar meu grupo como um todo, e o método calcula uma nova posição e rotação para cada sprite, a fim de dar a ilusão de que eles estão mudando como um grupo.

Mais importante ainda, não passo nenhuma matriz especial para a minha função de desenho. Cada sprite ainda tem sua própria posição individual, rotação e origem, independentes de estarem em grupo ou não.

Isso significa que a origem do grupo é conceitual e simplesmente alterar esse valor não atrapalhará seus sprites. O valor é usado apenas ao rotacionar o grupo para especificar onde o pivô deve estar, mas não ao desenhar.

Em resumo, a única matriz que você deve passar para o SpriteBatch.Begin é a sua matriz View, nada mais. Cada sprite deve ser desenhado de acordo com suas propriedades individuais e, se você quiser girá-los como um grupo, brinque com essas propriedades, não com o código do desenho.

David Gouveia
fonte
0

Tente mudar

spriteBatch.Draw(_map.AllParts[i][j].Texture, _map.AllParts[i][j].Position, null, Color.White, 0, _map.AllParts[i][j].Origin, 1.0f, SpriteEffects.None, 0f);

para

spriteBatch.Draw(_map.AllParts[i][j].Texture, _map.AllParts[i][j].Position + _map.AllParts[i][j].Origin, null, Color.White, 0, _map.AllParts[i][j].Origin, 1.0f, SpriteEffects.None, 0f);

O segundo argumento é onde o ponto de origem deve estar localizado; portanto, se você alterar o ponto de origem do padrão 0,0, precisará compensar isso.

ClassicThunder
fonte
A propriedade Origin aqui é a origem do grupo Texture, não do Sprite.
jgallant
0

Espere, você deseja girar todos os sprites de uma só vez. Depois mude a origem para texture.width e texture.height ... e não mude .. apenas altere a rotação real do sprite .. e faça isso para todos os sprites .. e defina a rotação de todos os sprites como uma única variável flutuante .. confie em mim, funciona!

Da_Boom
fonte