我正在尝试创造一个大炮射击射弹的游戏。我想保持滞后,所以我想这样做,以便每次创建一个抛射物时,它都是在一个新的线程中创建的。为此,我使用了以下代码:
Image cubeImage= Image.FromFile("C:\\Users\\Stefan\\Documents\\Visual Studio 2010\\Projects\\Game1\\Game1\\Resources\\CannonCube.png");
PictureBox cannonCube = new PictureBox();
ScreenPanel.Controls.Add(cannonCube);
cannonCube.Image = cubeImage;
cannonCube.SetBounds(cannonCubeInst.X, cannonCubeInst.Y, cubeImage.Width, cubeImage.Height);
cannonCube.BringToFront();
ParameterizedThreadStart pthread = new ParameterizedThreadStart(createShot);
Thread thread = new Thread(pthread);
thread.Start();
cps.Add(cannonCube);
在我尝试在线程中创建对象之前,对象已创建并正常工作。现在,在使用线程之后,它们被创建,但它们不会移动,所以我怀疑我用来计算移动时间的System.Windows.Forms.Timer对象已经停止运行。
这是否意味着我不能在我的theads中使用计时器?
我没有将计时器声明为静态变量,我在构造函数中声明它们:
public CubeProjectile(PictureBox box1, int u, int angle, List<PictureBox> walls)
{
System.Windows.Forms.Timer update;
System.Windows.Forms.Timer wallCheck;
wallList = walls;
u = u / 6;
horizontalSpeed = u * (Math.Cos(angle * (Math.PI / 180)));
verticalSpeed = u * (Math.Sin(angle * (Math.PI / 180)));
box = box1;
update = new Timer();
update.Interval = 29 - u/10;
update.Tick += new EventHandler(Timer_Tick);
update.Start();
wallCheck = new System.Windows.Forms.Timer();
wallCheck.Interval = 5;
wallCheck.Tick += new EventHandler(checkWall);
wallCheck.Start();
}
}
答案 0 :(得分:6)
不,你不能在线程中使用那个Timer。它并不完全像你的程序会崩溃,因为该类基本上是线程不安全的,计时器只是不会勾选,因为你创建的工作线程没有像UI线程那样抽取消息循环。
你几乎可以肯定地解决了错误的问题,首先是你的程序没有使用传统的游戏循环。这些陈述是一个很好的麻烦指标:
update.Interval = 29 - u/10;
//...
wallCheck.Interval = 5;
计时器并不准确。它们只能在时钟中断将处理器从暂停状态唤醒时才会打勾。默认情况下,在Windows上每秒发生64次。或者换句话说,只有15.625,31.250,46.875等的间隔值可以是准确的。您不能使用浮点值,因此您使用15,31,46等。因此,现在游戏的真实更新速度要慢得多,这很容易被误解为滞后问题。
并且您无法保证实际间隔接近于此值,因此您必须测量实际经过的时间来计算新位置。秒表很好,Environment.TickCount也没关系,它具有与计时器相同的分辨率。时钟中断率可以通过btw改变,这在游戏中不常见。你将pinvoke timeBeginPeriod()。不要去那里,15.625毫秒的间隔足以让子弹逼真地飞向人眼。