IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Développement 2D, 3D et Jeux Discussion :

[XNA 2D] Question sur la rotation


Sujet :

Développement 2D, 3D et Jeux

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 59
    Points : 50
    Points
    50
    Par défaut [XNA 2D] Question sur la rotation
    Bonjour,

    J'ai un petit soucis, pour effectuer la rotation de mon sprite j'utilise ce code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Game.spriteBatch.Begin();
    Game.spriteBatch.Draw(maTexture, new Rectangle(x, y, maTexture.Width, maTexture.Height), null,
                    Color.White, angle, new Vector2(maTexture.Width / 2, maTexture.Height / 2), SpriteEffects.None, 0);
    Game.spriteBatch.End();
    La rotation s'effectue bien en fonction de l'angle (MathHelper.PiOverX,...) mais le sprite lui même est dessiné avec pour origine le vecteur d'origine de la rotation ce qui fausse les valeurs de x et y.

    Est-il normal que ce vecteur influe sur la position du sprite dans la fenetre?

    Merci d'avance

  2. #2
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Points : 4 551
    Points
    4 551
    Par défaut
    Citation Envoyé par suRem Voir le message
    Bonjour,

    J'ai un petit soucis, pour effectuer la rotation de mon sprite j'utilise ce code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Game.spriteBatch.Begin();
    Game.spriteBatch.Draw(maTexture, new Rectangle(x, y, maTexture.Width, maTexture.Height), null,
                    Color.White, angle, new Vector2(maTexture.Width / 2, maTexture.Height / 2), SpriteEffects.None, 0);
    Game.spriteBatch.End();
    La rotation s'effectue bien en fonction de l'angle (MathHelper.PiOverX,...) mais le sprite lui même est dessiné avec pour origine le vecteur d'origine de la rotation ce qui fausse les valeurs de x et y.

    Est-il normal que ce vecteur influe sur la position du sprite dans la fenetre?

    Merci d'avance
    C'est hélas le cas. Le principe est que en spécifiant une origine, tu modifie la façon dont le sprite est dessiné. L'origine n'impacte pas que la rotation, elle impacte aussi les coordonnées de destination du rendu.

    J'ai un peu luté contre ce phénomène lorsque j'ai les entrées correspondantes de mon blog (et hop ! 1 brouzzouf de plus pour le megapubotron...).

    La transformation dépends donc en grande partie de ce que tu considère comme étant le centre de ton sprite (le HotSpot défini ci-dessous). J'ai construit une classe SpriteModifier pour ma librairie, qui contient ce code:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
        public class SpriteModifier
        {
            // ----------------------------------- enumerations
            public enum HotSpot
            {
                LeftCenter,
                CenterCenter,
                RightCenter,
                LeftTop,
                CenterTop,
                RightTop,
                LeftBottom,
                CenterBottom,
                RightBottom
            };
     
            // ----------------------------------- member variables
            private float rotationAngle = 0;
            private HotSpot rotationCenter = HotSpot.CenterCenter;
            private Color tint = Color.White;
            private HotSpot spot = HotSpot.CenterCenter;
            private Vector2 scale = new Vector2(1,1);
            private float depthLayer = 1;
            private float opacity = 1;
            private SpriteEffects effect = SpriteEffects.None;
     
            // ----------------------------------- properties
            public float RotationAngleRadian
            {
                get { return rotationAngle; }
                set { rotationAngle = value; }
            }
     
            public float RotationAngleDegree
            {
                get { return (float)(rotationAngle * 180 / Math.PI); }
                set { rotationAngle = (float)(value * Math.PI / 180); }
            }
     
            public HotSpot RotationCenter
            {
                get { return rotationCenter; }
                set { rotationCenter = value; }
            }
     
            public Color Tint
            {
                get 
                {
                    return new Color(tint.R, tint.G, tint.B, (byte)(tint.A * opacity)); 
                }
                set { tint = value; }
            }
     
            public float Opacity
            {
                get { return opacity; }
                set { opacity = value;  }
            }
     
            public HotSpot Spot
            {
                get { return spot; }
                set { spot = value; }
            }
     
            public Vector2 Scale
            {
                get { return scale; }
                set { scale = value; }
            }
     
            public float DepthLayer
            {
                get { return depthLayer; }
                set { depthLayer = value; }
            }
     
            public SpriteEffects Effect
            {
                get { return effect; }
                set { effect = value; }
            }
     
            // ----------------------------------- functions
            public SpriteModifier()
            {
            }
     
            public SpriteModifier(Color color)
            {
                tint = color;
            }
     
            public SpriteModifier(float angle, HotSpot center)
            {
                rotationAngle = angle;
                rotationCenter = center;
            }
     
            public SpriteModifier(Vector2 s)
            {
                scale = s;
            }
     
            public SpriteModifier(float s)
            {
                scale = new Vector2(s, s);
            }
     
            public SpriteModifier(float angle, HotSpot center, Vector2 s)
            {
                rotationAngle = angle;
                rotationCenter = center;
                scale = s;
            }
     
            public SpriteModifier(HotSpot hs)
            {
                spot = hs;
            }
     
            public SpriteModifier(HotSpot hs, float angle, HotSpot center, Vector2 s)
            {
                rotationAngle = angle;
                rotationCenter = center;
                spot = hs;
                scale = s;
            }
     
            static public Vector2 ComputeHotSpotOffset(HotSpot hotSpot, int baseX, int baseY)
            {
                Vector2 hotSpotOffset = new Vector2(0, 0);
     
                switch (hotSpot)
                {
                    case HotSpot.CenterBottom:
                    case HotSpot.CenterCenter:
                    case HotSpot.CenterTop:
                        hotSpotOffset.X = -baseX / 2;
                        break;
                    case HotSpot.RightBottom:
                    case HotSpot.RightCenter:
                    case HotSpot.RightTop:
                        hotSpotOffset.X = -baseX;
                        break;
                }
                switch (hotSpot)
                {
                    case HotSpot.CenterCenter:
                    case HotSpot.LeftCenter:
                    case HotSpot.RightCenter:
                        hotSpotOffset.Y = -baseY / 2;
                        break;
                    case HotSpot.CenterBottom:
                    case HotSpot.LeftBottom:
                    case HotSpot.RightBottom:
                        hotSpotOffset.Y = -baseY;
                        break;
                }
     
                return hotSpotOffset;
            }
     
            public Vector2 ComputeRotationCenter(Rectangle input)
            {
                if (rotationAngle == 0)
                {
                    return new Vector2(0, 0);
                }
                else
                {
                    Vector2 offset = ComputeHotSpotOffset(rotationCenter, -input.Width, -input.Height);
     
                    return offset;
                }
            }
     
            public Rectangle Transform(Rectangle input)
            {
                input.Width = (int)(input.Width * scale.X);
                input.Height = (int)(input.Height * scale.Y);
     
                Vector2 offset = ComputeHotSpotOffset(spot, input.Width, input.Height);
     
                input.X = (int)(input.X + offset.X);
                input.Y = (int)(input.Y + offset.Y);
     
                return input;
            }
        }
    Pour effectuer le rendu du sprite, j'ai ceci dans ma classe de rendu:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
            protected void DrawInternal(SpriteBatch batch, SpriteModifier modifier, Nullable<Rectangle> srcRect, Rectangle destRect)
            {
                destRect = modifier.Transform(destRect);
                Color tint = modifier.Tint;
     
                float rotAngle = modifier.RotationAngleRadian;
     
                float depthLayer = modifier.DepthLayer;
                Vector2 rotOrigin = modifier.ComputeRotationCenter(destRect);
                Vector2 destPosition = new Vector2(destRect.X, destRect.Y) + rotOrigin;
     
                batch.Draw(sheet, destPosition, srcRect, tint, rotAngle, rotOrigin, modifier.Scale, modifier.Effect, depthLayer);
            }
    Comme tu le vois, en fonction de l'origine (représentée par le HotSpot), je modifie la position de destination.

    Je crois que je couvre tous les cas. Tu peux simplifier le problème en considérant toujours que le centre de la rotation est toujours le centre du sprite (ce qui est somme toute relativement courant).

    Si tu souhaite avoir quelques explications, n'hésite pas à demander sur ce forum (pas en MP, hein, n'est-ce pas ?).
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 59
    Points : 50
    Points
    50
    Par défaut
    Merci beaucoup pour ton explication.

    Etant sur un tout petit jeu 2D je vais me contenter d'ajouter manuellement les coordonnées du centre à la position du sprite dans un premier temps.

    J'imagine que ton code doit se révéler bien pratique dans de plus gros projets, je n'hésiterai pas à m'en inspirer si tu permet .

    Pour l'instant je m'occupe d'un autre problème concernant la gestion de l'odre d'affichage des sprites (un peu comme le post du dessus). Mes sprites sont déssinés dans 2 DrawAbleGameComponents différents (je n'ai pas encore implémenté une classe pour centraliser l'affichage des sprites), et j'aimerai pouvoir définir lequel sera déssiné par dessus l'autre.

    Les 2 sprites étant déssinés dans 2 bloc spriteBatch.Begin() / .End() différents j'imagine que l'attribut depth de Draw() sera inutile, et d'après le dernier post de ton blog il est assez complexe de gérer l'ordre d'appel des DrawAbleGameComponents , la solution est donc soit de centraliser l'affichage des sprites soit de regrouper les 2 Components en un seul ?

    PS : Félicitation pour ton blog

  4. #4
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Points : 4 551
    Points
    4 551
    Par défaut
    Citation Envoyé par suRem Voir le message
    Merci beaucoup pour ton explication.

    Etant sur un tout petit jeu 2D je vais me contenter d'ajouter manuellement les coordonnées du centre à la position du sprite dans un premier temps.

    J'imagine que ton code doit se révéler bien pratique dans de plus gros projets, je n'hésiterai pas à m'en inspirer si tu permet .

    Pour l'instant je m'occupe d'un autre problème concernant la gestion de l'odre d'affichage des sprites (un peu comme le post du dessus). Mes sprites sont déssinés dans 2 DrawAbleGameComponents différents (je n'ai pas encore implémenté une classe pour centraliser l'affichage des sprites), et j'aimerai pouvoir définir lequel sera déssiné par dessus l'autre.

    Les 2 sprites étant déssinés dans 2 bloc spriteBatch.Begin() / .End() différents j'imagine que l'attribut depth de Draw() sera inutile, et d'après le dernier post de ton blog il est assez complexe de gérer l'ordre d'appel des DrawAbleGameComponents , la solution est donc soit de centraliser l'affichage des sprites soit de regrouper les 2 Components en un seul ?

    PS : Félicitation pour ton blog
    C'est vrai que la valeur depthLayer qui est censé spécifier la coordonnée z du polygone affiché n'est pas utilisée si tu passes par deux SpriteBatch différents. Le problème est que le SpriteBatch n'utilise pas le zbuffer pour le rendu (cf ce post de Shawn Hargreaves). Conclusion: tu te dois de gérer l'ordre de dessin par toi même.

    Ceci dit, si tu passes par Game.Components pour gérer ta collection de composants, leur ordre d'utilisation est fixé (via UpdateOrder pendant Game.Update() et via leur DrawOrder pendant Game.Draw()). En spécifiant des valeurs adéquates, tu peux forcer l'affichage d'un sprite avant les autres. La classe Pawn.Model.GameComponentManager que j'ai glissé dans l'archive liée à mon dernier post sur mon blog reprends ce principe, et devrait pouvoir être utilisée de la même manière. Par contre, dès que tu as des DrawOrder identique, tu ne peux plus être sur de l'ordre de dessin - il faut donc faire un peu attention à ce qu'on fait.

    Maintenant, si tu souhaites regrouper tous tes appels à SpriteBatch.Draw() dans un seul batch, fait attention aux "désoptimisations" que tu peux induire.

    Et merci pour les félicitations
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

Discussions similaires

  1. Questions sur la fonction Rotate
    Par emilieGre dans le forum Images
    Réponses: 5
    Dernier message: 16/08/2007, 13h18
  2. Questions sur les rotations
    Par Pragmateek dans le forum DirectX
    Réponses: 7
    Dernier message: 17/07/2007, 01h41
  3. Petit question sur la "Rotation"
    Par AsmBoy dans le forum Algorithmes et structures de données
    Réponses: 1
    Dernier message: 21/01/2006, 18h53
  4. Réponses: 9
    Dernier message: 30/08/2005, 20h18
  5. question sur les message box !
    Par krown dans le forum Langage
    Réponses: 7
    Dernier message: 02/08/2002, 16h11

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo