我尝试在C# winforms中旋转图像,每当我按下键盘时。我试图使用这篇文章https://www.codeproject.com/Articles/58815/C-Image-PictureBox-Rotations和这个答案https://stackoverflow.com/a/26455088/1907765来实现这一点,但是每当我应用变换时,图像就会消失。我不知道该怎么纠正。
图像在运行时从Resource.resx文件加载到PictureBox中。PictureBox位于面板顶部。
在这里列出代码的相关部分:
public partial class Form1 : Form
{
public List<PictureBox> Walls;
public bool MoveUp, MoveDown, MoveLeft, MoveRight;
public bool RotateClockwise, RotateAnticlockwise;
public bool PlayerHasShot;
public bool GameOver = false;
public int PlayerAngle = 0;
public Point PlayerPos = new Point(300, 300);
Bitmap PlayerImage;
// Game defaults
public readonly int BulletSpeed = 20;
public readonly int PlayerSpeed = 5;
public Form1()
{
InitializeComponent();
// <....>
}
private void Form1_Load(object sender, EventArgs e)
{
// Load the player image from bitmap
PbxPlayer.Parent = PnlGameBoard;
Image img = Properties.Resources.tankbase_orig;
PlayerImage = new Bitmap(img);
int dpi = 96;
using (Graphics G = PnlGameBoard.CreateGraphics())
dpi = (int)G.DpiX;
PlayerImage.SetResolution(dpi, dpi);
PbxPlayer.Image = (Bitmap)PlayerImage.Clone();
PbxPlayer.ClientSize = PlayerImage.Size;
}
private void MainTimer_Tick(object sender, EventArgs e)
{
Point newPoint = new Point();
if (MoveUp == true)
{
// Move player up 1 pixel until they've reached 'PlayerSpeed' or collided with something
for (int Y = 1; Y <= PlayerSpeed; Y++)
{
newPoint = new Point(PbxPlayer.Location.X, PbxPlayer.Location.Y - 1);
if (DetectCollision(PbxPlayer, newPoint))
break;
PbxPlayer.Location = newPoint;
}
}
if (MoveLeft == true)
{
// same logic as MoveUp
}
if (MoveDown == true)
{
// same logic as MoveUp
}
if (MoveRight == true)
{
// same logic as MoveUp
}
if (RotateAnticlockwise == true)
{
PlayerAngle -= 2;
if (PlayerAngle < 0)
PlayerAngle = 360;
// Debug label to check the angle is set correctly
LblAngle.Text = PlayerAngle.ToString();
// The amount to move the image by so that it rotates around centre point
PointF offsets = new PointF(PlayerImage.Width / 2f, PlayerImage.Height / 2f);
// Save old image
Image oldImage = PbxPlayer.Image;
// Return new image rotated by an angle of -2 degrees.
PbxPlayer.Image = RotateImage(PbxPlayer.Image, offsets, PbxPlayer.Location, -2);
// Force the picturebox to redraw (I think?)
PbxPlayer.Invalidate();
if (oldImage != null)
oldImage.Dispose();
}
if (RotateClockwise == true)
{
PlayerAngle += 2;
PlayerAngle %= 360;
LblAngle.Text = PlayerAngle.ToString();
PointF offsets = new PointF(PlayerImage.Width / 2f, PlayerImage.Height / 2f);
Image oldImage = PbxPlayer.Image;
PbxPlayer.Image = RotateImage(PbxPlayer.Image, offsets, PbxPlayer.Location, 2);
PbxPlayer.Invalidate();
if (oldImage != null)
oldImage.Dispose();
}
foreach (Control ctl in PnlGameBoard.Controls)
{
if (ctl is PictureBox && (string)ctl.Tag == "bullet")
{
ctl.Left += BulletSpeed;
if (ctl.Left > PnlGameBoard.Width || DetectCollision((PictureBox)ctl, ctl.Location))
{
RemoveBullet((PictureBox)ctl);
}
}
}
}
private void KeyIsDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.W || e.KeyCode == Keys.Up)
MoveUp = true;
if (e.KeyCode == Keys.A || e.KeyCode == Keys.Left)
MoveLeft = true;
if (e.KeyCode == Keys.S || e.KeyCode == Keys.Down)
MoveDown = true;
if (e.KeyCode == Keys.D || e.KeyCode == Keys.Right)
MoveRight = true;
if (e.KeyCode == Keys.Q || e.KeyCode == Keys.Oemcomma)
RotateAnticlockwise = true;
if (e.KeyCode == Keys.E || e.KeyCode == Keys.OemPeriod)
RotateClockwise = true;
if (e.KeyCode == Keys.Space && PlayerHasShot == false)
{
MakeBullet();
PlayerHasShot = true;
}
}
private void KeyIsUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.W || e.KeyCode == Keys.Up)
MoveUp = false;
if (e.KeyCode == Keys.A || e.KeyCode == Keys.Left)
MoveLeft = false;
if (e.KeyCode == Keys.S || e.KeyCode == Keys.Down)
MoveDown = false;
if (e.KeyCode == Keys.D || e.KeyCode == Keys.Right)
MoveRight = false;
if (e.KeyCode == Keys.Q || e.KeyCode == Keys.Oemcomma)
RotateAnticlockwise = false;
if (e.KeyCode == Keys.E || e.KeyCode == Keys.OemPeriod)
RotateClockwise = false;
// Stop repetitive shots
if (PlayerHasShot == true)
PlayerHasShot = false;
if (e.KeyCode == Keys.Enter && GameOver == true)
RestartGame();
}
private void PnlGameBoard_Paint(object sender, PaintEventArgs e)
{
// I feel like I should be doing something else in this event to make the image persist
e.Graphics.DrawImage(PbxPlayer.Image, PbxPlayer.Location);
}
public Bitmap RotateImage(Image image, PointF offset, Point imagePos, int angle)
{
// Credit: https://www.codeproject.com/Articles/58815/C-Image-PictureBox-Rotations
if (image == null)
return null;
Bitmap rotatedBitmap = new Bitmap(image.Width, image.Height);
rotatedBitmap.SetResolution(image.HorizontalResolution, image.VerticalResolution);
using (Graphics G = Graphics.FromImage(rotatedBitmap))
{
G.TranslateTransform(offset.X, offset.Y);
G.RotateTransform(angle);
G.TranslateTransform(-offset.X, -offset.Y);
G.DrawImage(image, new Point(imagePos.X, imagePos.Y));
}
return rotatedBitmap;
}
public void MakeBullet()
{
PictureBox bullet = new PictureBox();
bullet.BackColor = Color.DarkGray;
bullet.BorderStyle = BorderStyle.FixedSingle;
bullet.Height = 5;
bullet.Width = 10;
bullet.Left = PbxPlayer.Left + PbxPlayer.Width;
bullet.Top = PbxPlayer.Top + (PbxPlayer.Height / 2);
bullet.Tag = "bullet";
PnlGameBoard.Controls.Add(bullet);
}
public void RemoveBullet(PictureBox bullet)
{
Controls.Remove(bullet);
bullet.Dispose();
}
/// <summary>
/// Return true if 'pbx' PictureBox intersects with another PictureBox with the 'wall' tag
/// </summary>
/// <param name="pbx">The PictureBox we are checking for a collision</param>
/// <returns></returns>
public bool DetectCollision(PictureBox pbx, Point newPoint)
{
// Create a temporary PictureBox object to check for boundary collision without moving original pbx.
PictureBox newpbx = new PictureBox();
newpbx.Size = new Size(pbx.Width, pbx.Height);
newpbx.Location = new Point(newPoint.X, newPoint.Y);
foreach (var wall in Walls)
{
if (newpbx.Bounds.IntersectsWith(wall.Bounds))
return true;
}
// Release temporary object
newpbx.Dispose();
return false;
}
}
当我启动代码时,图像显示:
然后,如果我按下“Q”,我已经Map到逆时针旋转图像:
如果我试着顺时针旋转它,结果是一样的。
要使旋转后的图像显示在PictureBox中,我缺少什么?
1条答案
按热度按时间dy2hfwbg1#
图像 * 消失 *,因为您在传递给
RotateImage
方法的PbxPlayer.Location
处绘制它。偏移位置时,您正在图像边界或绘图画布之外绘制图像。如果只想围绕中心旋转图像,则位置必须等于
Point.Empty
。说到旋转图像的 * 绘图画布 *。它是
PbxPlayer
,不是PnlGameBoard
。因此,实现后者的Paint
事件在这里是没有意义的,因为您在PictureBox
中显示了旋转,并在定时器的Tick
事件中移动了它,其中设置了PbxPlayer.Location = newPoint;
。因此,您似乎不太可能想要在PnlGameBoard
表面上绘制。注意,不需要以这种方式为每个旋转Angular 持续创建图像。您只需要源映像并将
RotateImage
例程移动到PictureBox.Paint
事件。