Faire pivoter un bitmap graphique en son centre

Je travaille sur un projet pour l’école, nous devons créer un jeu de base de course en top-down en C # sans utiliser XNA. Tout d’abord, laissez-moi vous dire que tout ce que nous avons appris sur la programmation jusqu’à présent a peu à voir avec l’obtention de quelque chose qui ressemble même de loin à un jeu de course. Cela n’a pas été plus difficile que les tableaux, les boucles, etc. Nous n’avons donc pas appris à utiliser des graphiques ou quoi que ce soit du genre.

Ayant dit tout ce que j’ai le problème suivant.

Nous avons créé un object Graphics, puis nous utilisons DrawImage et un bitmap provenant d’un fichier car.jpg.

graphics = e.Graphics; graphics.RotateTransform(angle); graphics.DrawImage(car, xPos, yPos, car.Width, car.Height); 

Ensuite, nous attendons une touche, par exemple Droite

 case Keys.Right: if (angle != 360) { angle += 10; } else { angle = 0; } this.Refresh(); break; 

Le problème que nous avons est que le pivot de la rotation se trouve dans le coin supérieur gauche. Donc, dès que nous déplacerons la voiture à quelque chose comme (20,25) et que nous commencerons à la faire pivoter, elle utilisera (0,0) comme centre de rotation. Ce que nous voulons réaliser est d’avoir le centre de la rotation au centre de notre voiture.

Nous avons essayé de modifier le centerX et le centerY de RotateTransform mais nous RotateTransform arrivés à la conclusion que cela n’était pas possible avec le bitmap. Nous sums aux sockets avec ce problème depuis plus de 2 jours et nous ne semblons pas pouvoir trouver de solution pour parvenir à ce que nous voulons.

Y at-il quelque chose que nous faisons de mal en créant l’object Graphics, ou existe-t-il une manière totalement différente de changer de centerX et de centerY pour la voiture?

Pour dessiner un Bitmap rotation, vous devez suivre quelques étapes pour préparer l’object Graphics :

  • D’abord vous déplacez son origine sur le milieu de la rotation
  • alors vous faites pivoter de l’angle souhaité
  • Ensuite, vous le déplacez
  • maintenant vous pouvez dessiner le Bitmap
  • enfin vous réinitialisez les Graphics

Cela doit être fait pour chaque bitmap.

Voici les étapes dans le code pour dessiner un Bitmap bmp à la position ( xPos, yPos ):

 float moveX = bmp.Width / 2f + xPos; float moveY = bmp.Height / 2f+ xPosf; e.Graphics.TranslateTransform(moveX , moveY ); e.Graphics.RotateTransform(angle); e.Graphics.TranslateTransform(-moveX , -moveY ); e.Graphics.DrawImage(bmp, xPos, yPos); e.Graphics.ResetTransform(); 

Il y a une complication possible: si votre Bitmap a une résolution dpi différente de celle de l’écran, c’est-à-dire que vous devez d’abord adapter le paramètre dpi la Bitmap !

Pour adapter le Bitmap aux 96dpi habituels, vous pouvez simplement faire une

 bmp.SetResolution(96,96); 

Pour vous préparer aux futurs affichages de type rétine, vous pouvez créer une variable de classe que vous avez définie au démarrage:

 int ScreenDpi = 96; private void Form1_Load(object sender, EventArgs e) { using (Graphics G = this.CreateGraphics()) ScreenDpi = (int)G.DpiX; } 

et l’utiliser après avoir chargé le Bitmap :

 bmp.SetResolution(ScreenDpi , ScreenDpi ); 

Comme d’habitude, la méthode DrawImage utilise le coin supérieur gauche du Bitmap . Vous devrez peut-être utiliser différents Points pour le sharepoint rotation et éventuellement pour la position virtuelle de votre voiture, par exemple au milieu de son devant.

Voici une classe statique qui peindra l’image à l’emplacement souhaité dans la zone souhaitée. Modifiez la valeur rotationangle pour faire pivoter l’image. Et vous pouvez également faire un panoramique et zoomer l’image.

Ajoutez cette classe dans votre projet et appelez les fonctions statiques à partir de Win Form.

 public static class FullImage { public static Image image; public static RectangleF DisplayRect, SourceRect; public static Size ParentBoundry; public static float rotationangle=0; internal static void Paint(Graphics graphics) { if (image == null) return; float hw = DisplayRect.X + DisplayRect.Width / 2f; float hh = DisplayRect.Y + DisplayRect.Height / 2f; System.Drawing.Drawing2D.Masortingx m = graphics.Transform; m.RotateAt(rotationangle, new PointF(hw, hh), System.Drawing.Drawing2D.MasortingxOrder.Append); graphics.Transform = m; graphics.DrawImage(image, new RectangleF(DisplayRect.X, DisplayRect.Y, DisplayRect.Width, DisplayRect.Height), SourceRect, GraphicsUnit.Pixel); graphics.ResetTransform(); } public static void LoadImage(Image img) { image = img; SizeF s = GetResizedSize(image, ParentBoundry); SourceRect = new RectangleF(0, 0, image.Width, image.Height); DisplayRect = new RectangleF(ParentBoundry.Width / 2 - s.Width / 2, ParentBoundry.Height / 2 - s.Height / 2, s.Width, s.Height); } public static Size GetResizedSize(Image ImageToResize, Size size) { int sourceWidth = ImageToResize.Width; int sourceHeight = ImageToResize.Height; float nPercent = 0; float nPercentW = 0; float nPercentH = 0; nPercentW = ((float)size.Width / (float)sourceWidth); nPercentH = ((float)size.Height / (float)sourceHeight); if (nPercentH < nPercentW) nPercent = nPercentH; else nPercent = nPercentW; int destWidth = (int)(sourceWidth * nPercent); int destHeight = (int)(sourceHeight * nPercent); return new Size(destWidth, destHeight); } internal static void MouseWheel(int delta) { if (delta > 0) DisplayRect = ZoomImage(DisplayRect,CurrentMouse, .1f); else DisplayRect = ZoomImage(DisplayRect, CurrentMouse, -.1f); } private RectangleF ZoomImage(RectangleF ImageRectangle, PointF MouseLocation, float ScaleFactor) { /// Original Size and Location SizeF OriginalSize = ImageRectangle.Size; PointF OriginalPoint = ImageRectangle.Location; ///Mouse cursor location -located in width% and height% of totaloriginal image float mouse_widthpercent = System.Math.Abs(OriginalPoint.X - MouseLocation.X) / OriginalSize.Width * 100; float mouse_heightpercent = System.Math.Abs(OriginalPoint.Y - MouseLocation.Y) / OriginalSize.Height * 100; ///Zoomed Image by scalefactor SizeF FinalSize = new SizeF(OriginalSize.Width + OriginalSize.Width * ScaleFactor, OriginalSize.Height + OriginalSize.Height * ScaleFactor); if (FinalSize.Width < 15 || FinalSize.Height < 15) return ImageRectangle; if (FinalSize.Width > 60000 || FinalSize.Height > 60000) return ImageRectangle; /// How much width increases and height increases float widhtincrease = FinalSize.Width - OriginalSize.Width; float heightincrease = FinalSize.Height - OriginalSize.Height; /// Adjusting Image location after zooming the image PointF FinalLocation = new System.Drawing.PointF(OriginalPoint.X - widhtincrease * mouse_widthpercent / 100, OriginalPoint.Y - heightincrease * mouse_heightpercent / 100); ImageRectangle = new RectangleF(FinalLocation.X, FinalLocation.Y, FinalSize.Width, FinalSize.Height); return ImageRectangle; } static bool drag = false; static Point Initial, CurrentMouse; internal static void MouseMove(Point location) { CurrentMouse = location; if (drag) { DisplayRect = new RectangleF(DisplayRect.X + location.X - Initial.X, DisplayRect.Y + location.Y - Initial.Y, DisplayRect.Width, DisplayRect.Height); Initial = location; } } internal static void MouseDown(Point location) { Initial = location; drag = true; } internal static void MouseUp(Point location) { drag = false; } } 

Après avoir ajouté ce code dans votre projet (il est préférable d’append un fichier cs séparé), appelez les fonctions à partir de la classe Win Form (Form1.cs).

 public partial class Form1 : Form { public Form1() { InitializeComponent(); this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true); this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true); this.SetStyle(ControlStyles.ResizeRedraw, true); FullImage.ParentBoundry = new Size(this.Width, this.Height); // Enter the image path FullImage.LoadImage(Image.FromFile(@"D:\a.jpg")); } //Create a paint event private void Form1_Paint(object sender, PaintEventArgs e) { FullImage.Paint(e.Graphics); } private void Form1_MouseDown(object sender, MouseEventArgs e) { Vault.FullImage.MouseDown(e.Location); this.Invalidate(); } private void Form1_MouseMove(object sender, MouseEventArgs e) { Vault.FullImage.MouseMove(e.Location); this.Invalidate(); } private void Form1_MouseUp(object sender, MouseEventArgs e) { Vault.FullImage.MouseUp(e.Location); this.Invalidate(); } protected override void OnMouseWheel(MouseEventArgs e) { Vault.FullImage.MouseWheel(e.Delta); this.Invalidate(); } 

Maintenant, si vous voulez faire pivoter l’image, définissez simplement la valeur comme vous le souhaitez (avec un curseur, un bouton ou ajoutez quelques fonctions supplémentaires pour détecter le mouvement de la souris, puis faire pivoter)

Exemple: ajoutez un bouton et augmentez la valeur de 1 à chaque fois que vous cliquez sur le bouton.

  private void button1_clicked(object sender, EventArgs e) { FullImage.rotationangle++; this.invalidate(); } 

Pour faire pivoter le coin supérieur gauche du centre, vous devez d’abord connaître son angle, puis l’ajuster selon l’angle souhaité et recalculer le nouveau coin supérieur gauche en fonction du nouvel angle:

 var newXPos = (int)(xPos + car.Width / 2.0 + Math.Cos(Math.Atan2(-car.Height / 2, -car.Width / 2) + angle / 180.0 * Math.PI) * -car.Width / 2.0); var newYPos = (int)(yPos + car.Height / 2.0 + Math.Sin(Math.Atan2(-car.Height / 2, -car.Width / 2) + angle / 180.0 * Math.PI) * -car.Height / 2.0); graphics = e.Graphics; graphics.RotateTransform(angle); graphics.DrawImage(car, newXPos, newYPos, car.Width, car.Height);