在Windows窗体中实现gameloop

问题描述:

对于有关此游戏的常见问题,我很抱歉,但我不知道在哪里以及如何在我的游戏中实现gameloop。我想gameloop这样的工作:在Windows窗体中实现gameloop

Settings(); 
if (startClicked == true) 
{ 
    Spawn(); 
} 
while (enemyKilled == true) 
{ 
    Spawn(); 
} 

这里是我的代码:

public partial class Form1 : Form 
{ 
    public int score1 = 0; 
    public PictureBox enemy = new PictureBox(); 
    public PictureBox missile = new PictureBox(); 
    public int enemyX; 
    public int enemyY; 
    public int missileX; 
    public int missileY; 
    public bool enemyKilled; 
    public bool startClicked; 
    public Form1() 
    { 
     InitializeComponent(); 
     logo.Visible = false; 
     startbutton.Visible = false; 
     spaceship.Visible = false; 
     score.Visible = false; 
     labelEnemyX.Visible = false; 
     labelEnemyY.Visible = false; 
     labelMissileX.Visible = false; 
     labelMissileY.Visible = false; 

    } 

    private void Settings() 
    { 
     logo.Visible = true; 
     startbutton.Visible = true; 
     score.Text = Convert.ToString(score1); 
    } 

    private void Spawn() 
    { 
     enemy.Visible = true; 
     missile.Visible = true; 
     System.Timers.Timer enemyMove = new System.Timers.Timer(); 
     enemyMove.Interval = 100; 
     Random enemyPosition = new Random(); 
     int enemyX = enemyPosition.Next(30, 400); 
     int enemyY = enemy.Location.Y; 
     enemy.Location = new Point(enemyX, 0); 
     enemy.Image = WindowsFormsApplication16.Properties.Resources.Enemy2; 
     enemy.Width = 36; 
     enemy.Height = 29; 
     this.Controls.Add(enemy); 
     enemyMove.Elapsed += (sender, args) => 
      { 
       enemy.Location = new Point(enemyX, enemy.Location.Y + 2); 
       enemyX = enemy.Location.X; 
       enemyY = enemy.Location.Y; 
       labelEnemyX.Text = Convert.ToString(enemyX); 
       labelEnemyY.Text = Convert.ToString(enemyY); 
       if (enemyY <= -10) 
       { 
        enemyKilled = false; 
       } 
      }; enemyMove.Start(); 
    } 

    private void AddScore() 
    { 
     if (enemyKilled == true) 
     { 
      score1++; 
      score.Text = Convert.ToString(score1); 
     } 
    } 

    private void MissileMove() 
    { 
     System.Timers.Timer missileMove = new System.Timers.Timer(); 
     missileMove.Interval = 30; 
     missileMove.Elapsed += (sender, args) => 
      { 
       if (missile.Location.Y >= -30) 
       { 
        missile.Location = new Point(missile.Location.X, missile.Location.Y - 15); 
        missileX = missile.Location.X; 
        missileY = missile.Location.Y; 
        labelMissileX.Text = Convert.ToString(missileX); 
        labelMissileY.Text = Convert.ToString(missileY); 
        int enemyToMissileLocationX = Convert.ToInt32(labelEnemyX.Text); 
        int enemyToMissileLocationY = Convert.ToInt32(labelEnemyY.Text); 
        if ((missileX - enemyToMissileLocationX <= 20 && missileY - enemyToMissileLocationY <= 20 && missileX - enemyToMissileLocationX >= 0 && missileY - enemyToMissileLocationY >= 0) || (enemyToMissileLocationX - missileX <= 20 && enemyToMissileLocationY - missileY <= 20 && enemyToMissileLocationX - missileX >= 0 && enemyToMissileLocationY - missileY >= 0)) 
        { 
         missile.Visible = false; 
         enemy.Visible = false; 
         enemyKilled = true; 
        } 
       } 
      }; missileMove.Start(); 

    } 

    void Form1_Load(object sender, EventArgs e) 
    { 
     Settings(); 
     if (startClicked == true) 
     { 
      Spawn(); 
     } 
     while (enemyKilled == true) 
     { 
      Spawn(); 
     } 
    } 

    private void startbutton_Click(object sender, EventArgs e) 
    { 
     this.startClicked = true; 
     logo.Visible = false; 
     startbutton.Visible = false; 
     spaceship.Visible = true; 
     score.Visible = true; 
     startbutton.Enabled = false; 

    } 

    private void Form1_KeyDown(object sender, KeyEventArgs e) 
    { 
     if (e.KeyCode == Keys.Right) 
     { 
      if (spaceship.Location.X <= 370) 
      { 
       spaceship.Location = new Point(spaceship.Location.X + 10, spaceship.Location.Y); 
      } 
     } 
     if (e.KeyCode == Keys.Left) 
     { 
      if (spaceship.Location.X >= 0) 
      { 
       spaceship.Location = new Point(spaceship.Location.X - 10, spaceship.Location.Y); 
      } 
     } 
     if (e.KeyCode == Keys.Space) 
     { 
      missile.Image = WindowsFormsApplication16.Properties.Resources.Missile; 
      missile.Height = 42; 
      missile.Width = 12; 
      missile.Location = new Point(spaceship.Location.X + 28, spaceship.Location.Y + 15); 
      this.Controls.Add(missile); 
      MissileMove(); 

     } 
    } 
} 

更新:

private void MissileMove() 
    { 
     System.Timers.Timer missileMove = new System.Timers.Timer(); 
     missileMove.Interval = 30; 
     missileMove.Elapsed += (sender, args) => 
      { 
       if (missile.Location.Y >= -30) 
       { 
        missile.Location = new Point(missile.Location.X, missile.Location.Y - 15); 
        missileX = missile.Location.X; 
        missileY = missile.Location.Y; 
        labelMissileX.Text = Convert.ToString(missileX); 
        labelMissileY.Text = Convert.ToString(missileY); 
        int enemyToMissileLocationX = Convert.ToInt32(labelEnemyX.Text); 
        int enemyToMissileLocationY = Convert.ToInt32(labelEnemyY.Text); 
        if ((missileX - enemyToMissileLocationX <= 20 && missileY - enemyToMissileLocationY <= 20 && missileX - enemyToMissileLocationX >= 0 && missileY - enemyToMissileLocationY >= 0) || (enemyToMissileLocationX - missileX <= 20 && enemyToMissileLocationY - missileY <= 20 && enemyToMissileLocationX - missileX >= 0 && enemyToMissileLocationY - missileY >= 0)) 
        { 
         missile.Visible = false; 
         enemy.Visible = false; 
         enemyKilled = true; 
         System.Threading.Thread.Sleep(100); 
         Application.DoEvents(); 
         Spawn(); 
        } 
       } 
      }; missileMove.Start(); 

试图与类要做到这一点,是的,它酿出的敌人再一次,但动画是窃听,我可以看到敌人从一个位置跳到另一个位置。 谢谢你的帮助。

+3

请添加您的questin更多详细信息 – Krekkon

+0

我希望每次杀死敌人时都能产生敌人。 –

+0

这是一个巨大的长码,没有人会认为它是一个想法。 请更新您的问题,以获得更多答案。清理unneccery代码或方法体 – Krekkon

这看起来像一个Windows窗体。因此,我建议你有一个在while循环中运行的后台线程,并处理游戏的所有移动/更新逻辑。复杂的部分将管理Windows窗体线程和游戏线程之间的状态。您需要确保您是按钮点击的事件处理程序等等,这些更新游戏状态以线程安全的方式执行,因为它们将位于GUI线程中。游戏循环线程将需要在GUI上更新状态,这将需要称为marshelling,因为只有GUI线程被允许访问窗体上存在的按钮等控件。

线程主题管理,线程安全和marshelling我会留给你去研究。

这假设它是某种实时游戏,而不是基于回合。如果它是基于回合的,那么你并不需要一个游戏循环。您可以通过使用状态图和纯粹的事件驱动设计来实现相同的目标。

+1

不需要为游戏循环引入多线程的所有复杂性吗?只要循环包含'Application.DoEvents()'并以合理的帧速率运行(所以DoEvents频繁发生),所有内容都应该在单个线程上轻松运行。这就是Scrolling Game Development Kit 2(http://sgdk2.sf.net/)创建的游戏的运作方式。 – BlueMonkMN

+1

@BlueMonkMN我的建议确实没有“需要”去做。但是,依赖于DoEvents的体系结构有时被认为是不好的做法,因为它使UI的响应性依赖于每个DoEVents调用之间的每段代码的**响应性,以保证**速度更快。这就是说,我鼓励你发表你的建议作为答案,因为我认为这是平等的考虑到权衡。这确实会更容易实施。 – AaronLS

+0

我试图做到这一点,但问题是,它产生更多的敌人从一个敌人跳到另一个敌人。我用它添加了第三部分代码。 –

我的建议是实现游戏循环,你必须像函数(或main功能,如果你熟悉集成是为Windows窗体应用程序),但增加了呼叫Application.DoEvents在循环内进行确定窗口仍然响应诸如移动和调整大小以及点击按钮等事件。除此之外,您可能需要澄清您目前使用的解决方案遇到的问题,以获得更全面,更详细的答案。