在 Windows 窗体中实现 gameloop [关闭]

     2023-03-10     265

关键词:

【中文标题】在 Windows 窗体中实现 gameloop [关闭]【英文标题】:Implementing gameloop in Windows Forms [closed] 【发布时间】:2013-10-21 17:20:15 【问题描述】:

对于这个游戏的常见问题,我很抱歉,但我不知道在哪里以及如何在我的游戏中实现游戏循环。我希望游戏循环能够像这样工作:

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();

尝试对班级进行此操作,是的,它再次生成了敌人,但动画出现了错误,我可以看到敌人从一个位置跳到另一个位置。 谢谢你的帮助。

【问题讨论】:

请添加更多详细信息 我希望游戏每次杀死敌人时都会生成敌人。 这是一个巨大的长代码,没有人会像思考一样阅读它。请更新您的问题,以获得更多答案。清理不必要的代码或方法体 我添加了整个代码,但问题是在哪里实现第一部分,即游戏循环,在 Windows 窗体中。 游戏循环需要一种截然不同的方式来编写代码。你必须扔掉所有东西,从头开始。没关系,0.2 版是相当不可避免的。 【参考方案1】:

我的建议是像 Form_Load 这样的函数(或者 main 函数,如果你熟悉将它集成到 Windows 窗体应用程序)中实现游戏循环,但添加对 Application.DoEvents 的调用在循环内部,以确保窗口仍然响应移动和调整大小以及单击按钮等事件。除此之外,您可能需要澄清当前解决方案遇到的问题,以获得更完整、更详细的答案。

【讨论】:

【参考方案2】:

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

线程管理、线程安全和编组的主题留给你研究。

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

【讨论】:

不需要仅仅为了一个游戏循环就引入多线程的所有复杂性吗?只要循环包含Application.DoEvents() 并以合理的帧速率运行(因此 DoEvents 经常发生),一切都应该在单个线程上轻松运行。这就是由 Scrolling Game Development Kit 2 (sgdk2.sf.net) 创建的游戏的运作方式。 @BlueMonkMN 当然没有我建议的“需要”去做。但是,依赖 DoEvents 的架构有时被认为是不好的做法,因为它使 UI 的响应能力依赖于每次 DoEVents 调用之间的每一段代码,以 保证快速。话虽如此,我鼓励您将您的建议作为答案发布,因为我认为考虑到权衡,它同样有效。实现起来确实会简单得多。 我试图这样做,但问题是它会产生更多的敌人从一个敌人跳到另一个敌人。我用它添加了第三部分代码。

怎样在c#中实现父窗体向子窗体传值和子窗体向父窗体传值

...tem.Data;usingSystem.Drawing;usingSystem.Linq;usingSystem.Text;usingSystem.Windows.For 查看详情

如何在access2007的窗体中实现点击按钮打开另一个窗体???

...打开要操作的数据库,在左侧导航窗格中,右击要使用的窗体,在弹出菜单中选择“设计视图”。2、确定“使用控件向导”按钮处于选中状态,然后单击选中“控件”组中的“按钮”控件,在窗体中的适当位置单击鼠标左键。3... 查看详情

在 Windows 窗体设计器中加载窗体时出现“找不到类型”错误

】在Windows窗体设计器中加载窗体时出现“找不到类型”错误【英文标题】:"Couldnotfindtype"errorloadingaformintheWindowsFormsDesigner【发布时间】:2010-09-0518:38:29【问题描述】:我有一个.NET2.0Windows窗体应用程序,它大量使用了ListV... 查看详情

如何在 Windows 服务中实现啥都不做 ExecuteAsync?

】如何在Windows服务中实现啥都不做ExecuteAsync?【英文标题】:HowtoImplementDonothingExecuteAsyncinWindowsService?如何在Windows服务中实现什么都不做ExecuteAsync?【发布时间】:2022-01-1711:28:50【问题描述】:我正在实现一个Windows服务,我不... 查看详情

winform开发中实现控件随窗体大小的改变而自动适应其改变

...体边缘的距离不变,到锚定边缘的距离始终保持在“Windows窗体设计器”中定位该控件时所定义的距离。需要注意的是,某些控件(如ComboBox控件)有高度限制,将控件锚定到其 查看详情

winform开发中实现控件随窗体大小的改变而自动适应其改变

...体边缘的距离不变,到锚定边缘的距离始终保持在“Windows窗体设计器”中定位该控件时所定义的距离。需要注意的是,某些控件(如ComboBox控件)有高度限制,将控件锚定到其 查看详情

如何在windows服务中实现互斥锁

】如何在windows服务中实现互斥锁【英文标题】:Howtoimplementmutexinwindowsservice【发布时间】:2020-05-2910:53:52【问题描述】:您好,我是线程主题的新手,我需要在我的Windows服务中添加一个Mutex,因为每当我运行它时,它会一遍又一... 查看详情

在 windows phone 中实现谷歌游戏服务

】在windowsphone中实现谷歌游戏服务【英文标题】:implementgooglegamesservicesinwindowsphone【发布时间】:2015-02-0816:14:38【问题描述】:我在Play商店上传了一款安卓游戏。我做了一个windows8和windowsphone8版本一样的。我需要实现在android版... 查看详情

如何在 Windows 10 UWP 中实现图表控件

】如何在Windows10UWP中实现图表控件【英文标题】:howtoimplementchartcontrolinWindows10UWP【发布时间】:2015-11-2701:55:15【问题描述】:我需要实现线性图。Windows10UWP有图表控件吗?有什么建议吗?谢谢【问题讨论】:我在大约6个月前研... 查看详情

delphi中实现mdi子窗体(转)

...口管理功能,同屏观看多个网页的内容   ①多文档窗体(MDI) MDI窗体是一种具有主子结构的窗体体系,微软的Word便是其中的一个典型例子。MDI体系中至少需要两种窗体,只能将其中之一设置为主窗体,其余窗体全部... 查看详情

如何在 Windows Store 应用程序中实现家长控制?

】如何在WindowsStore应用程序中实现家长控制?【英文标题】:HowtoimplementparentalcontrolinWindowsStoreapplication?【发布时间】:2014-12-2522:30:20【问题描述】:我正在将教育游戏移植到Windows应用商店。游戏从网站下载关卡。我不认为他们... 查看详情

在 Windows Phone 7.5 Mango 中实现闹钟

】在WindowsPhone7.5Mango中实现闹钟【英文标题】:ImplementalarmclockinWindowsPhone7.5Mango【发布时间】:2011-08-1012:17:18【问题描述】:我想在windowsphone7mango创建闹钟,为此我想使用PeriodicTask有没有办法将预定间隔从30分钟缩短到每分钟?或... 查看详情

在 Windows 桌面应用程序中实现帮助功能的最佳方法 - 限制应用知识库以授权访问

】在Windows桌面应用程序中实现帮助功能的最佳方法-限制应用知识库以授权访问【英文标题】:BestapproachtoimplementHelpfeatureinWindowsDesktopApplication-RestricttheAppknowledgebasetoauthorizeaccess【发布时间】:2020-12-1216:49:52【问题描述】:在Window... 查看详情

在windows中实现flume日志收集

一、flume的简介任何一个系统在运行的时候都会产生大量的日志信息,我们需要对这些日志进行分析,在分析日志之前,我们需要将分散在生产系统中的日志收集起来。Flume就是这样的日志采集系统。  1.主要有三个... 查看详情

如何使用 jabber net 在 c# Windows 应用程序中实现文件传输

】如何使用jabbernet在c#Windows应用程序中实现文件传输【英文标题】:HowtoimplementFiletransferinc#Windowsappusingjabbernet【发布时间】:2019-08-0611:08:04【问题描述】:我正在使用jabbernet和ejabberd开发一个聊天应用程序。我完成了与xmpp的一对... 查看详情

在windows10应用程序中实现树视图(代码片段)

我创建了一个通用Windows应用程序,可以从Chrome中读取“收藏夹”并将其显示为树状视图。收藏夹是从Chrome浏览器的书签文件中获取的,但是实现Windows10的树视图结构是我遇到问题的地方。我找到的所有样本通常用于Windows8.1,默... 查看详情

在我的 .NET Windows 窗体上实现从 Chrome 拖放

】在我的.NETWindows窗体上实现从Chrome拖放【英文标题】:Implementingdrag-dropfromChromeonmy.NETWindowsform【发布时间】:2011-09-0119:50:05【问题描述】:GoogleChrome有一个方便的功能,我可以单击下载链接并将其拖到Windows资源管理器窗口中,... 查看详情

winform窗体——datagridview控件及通过此控件中实现增删改查

DataGridView:显示数据表,通过此控件中可以实现连接数据库,实现数据的增删改查一、后台数据绑定:    List<xxx>list=newList<xxx>();    dataGridView1.DataSource=list;    &nbs 查看详情