KeyDown事件逐渐减慢/冻结

时间:2015-01-15 00:42:18

标签: c# winforms keydown

我正在尝试在Windows窗体中制作2D滚动游戏;但是,我遇到了一个问题。

游戏在前几分钟运行良好;但是,随着应用程序继续运行,KeyDown响应越来越慢。最终,它达到了按键(移动角色)的程度,完全冻结了应用程序。

但是,如果我没有按任何内容,其他方法/功能将继续顺利运行。

我相信有一些方法可以使用多个线程解决这个问题,但我不知道从哪里开始。我会为KeyDown / KeyUp个事件创建一个单独的帖子吗?如果是这样,怎么样?或者有更简单的选择吗?

游戏的全部代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading; 

namespace Fly_High
{
    public partial class Form1 : Form
    {
    //public variables 
    static bool blnFirstRun = false; 

    //variables for scrolling background
    static Image imgBackground;
    static Image[] imgBackgroundsArray = {GameImages.Gradient1, GameImages.Gradient2, GameImages.Gradient3, GameImages.Gradient4, GameImages.Gradient5, GameImages.Gradient6, GameImages.Gradient7, GameImages.Gradient8, GameImages.Gradient9, GameImages.Gradient10, GameImages.Gradient11};
    static int imageXValue = 0;
    static int imageYValue = 2400;
    static int intScrollSpeed = 5;
    static int intBackgroundCounter = 1; 

    //obstacle scrolling speed array 
    static int[] intObstacleScroll = {3, 1, 5, 2, 4};

    //dimensions of picture 
    static int imgWidth = 0;
    static int imgHeight = 0; 

    //images for spaceship picturebox 
    static Image imgShip = GameImages.alienblaster;
    static Image imgShipLeft = GameImages.alienblasterLeft;
    static Image imgShipRight = GameImages.alienblasterRight;

    //speed variables for ship 
    static int intLeftAndRight = 5;
    static bool blnUp = false;
    static bool blnLeft = false;
    static bool blnRight = false; 

    //square obstacles picturebox array 
    PictureBox[] pcbSquareObstacles = new PictureBox[5];
    Boolean[] blnSquareObstacles = {false, false, false, false, false};
    static int[] intSize1 = {42, 40};
    static int[] intSize2 = {60, 19};
    static int[] intSize3 = {16, 155};
    static int[] intSize4 = {81, 47};
    static int[] intSize5 = {23, 24};
    static int[] intSize6 = {33, 71};
    static int[][] intSizeArray = new int[][] {intSize1, intSize2, intSize3, intSize4, intSize5, intSize6};
    static Color[] colorArray = {Color.Red, Color.Blue, Color.Lime}; 

    //circle score bubbles array 
    PictureBox[] pcbScoreBubbles = new PictureBox[10];
    Boolean[] blnScoreBubbleCollision = {false, false, false, false, false, false, false, false, false, false}; 
    static Size szLeastPoints = new Size (10,10);
    static Size szMediumPoints = new Size (15,15); 
    static Size szMostPoints = new Size (20, 20); 

    //score and life variables 
    static int intHits = 0;
    static int intTmrCounter = 0;
    static int intScore; 

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        //load image from resources 
        imgBackground = GameImages.Gradient1;
        imgWidth = imgBackground.Width;
        imgHeight = imgBackground.Height; 

        //add doublebuffer to form, this prevents flickering
        this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
        this.UpdateStyles();
    }

    private void Form1_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.KeyData == Keys.W) //if user presses w, increase scroll speed of image
        {
            if (blnFirstRun == false)
            {
                //if this is the first time the user presses 'w', display the following messages then start the timer.

                blnFirstRun = true; 

                //display countdown before timer
                lblCountDown.Text = "5";
                lblCountDown.Refresh(); 
                System.Threading.Thread.Sleep(1000);
                lblCountDown.Text = "4";
                lblCountDown.Refresh(); 
                System.Threading.Thread.Sleep(1000);
                lblCountDown.Text = "3";
                lblCountDown.Refresh(); 
                System.Threading.Thread.Sleep(1000);
                lblCountDown.Text = "2";
                lblCountDown.Refresh(); 
                System.Threading.Thread.Sleep(1000);
                lblCountDown.Text = "1";
                lblCountDown.Refresh(); 
                System.Threading.Thread.Sleep(1000);
                lblCountDown.Text = "GO!";
                lblCountDown.Refresh(); 
                System.Threading.Thread.Sleep(500);
                lblCountDown.Visible = false;

                //enable timer
                tmrTick.Enabled = true; 
            }
            //set up boolean to true 
            blnUp = true; 
        }
        else if (e.KeyData == Keys.A) 
        {
            //if user presses 'A', set left scroll boolean to true
            blnLeft = true;    

            //change ship image 
            pcbShip.Image = imgShipLeft; 
        }
        else if (e.KeyData == Keys.D) //if user press d, scroll to the right
        {
            //if user presses 'D', set right scroll bool to true
            blnRight = true;

            //change ship image 
            pcbShip.Image = imgShipRight; 

        }
    }

    private void Form1_Paint(object sender, PaintEventArgs e)
    {
        //draw the image to the form
        e.Graphics.DrawImage(imgBackground, new Rectangle(0, 0, this.Width, this.Height), new Rectangle(imageXValue, imageYValue, this.Width, this.Height), GraphicsUnit.Pixel); 
    }

    private void tmrTick_Tick(object sender, EventArgs e)
    {
        /***************************************
         * Date: 6/1/2014
         * Description: Set up speed variables as well as timer to move along with the scrolling background.
         * Note: Booleans are used in keydown event instead of actual movement to create smooth movement. 
         * The booleans are checked in the timer.
         * Note: Keyup event was used to reset booleans to false.
        ***************************************/

        //check for key down events
        if (blnUp == true)
        {
            //do not allow scroll speed to exceed 7
            if (intScrollSpeed < 8)
            {
                intScrollSpeed += 2;
            }
        }

        //if the ship is not at the left edge, move to the left
        if (pcbShip.Left > -10 && blnLeft == true)
        {
            pcbShip.Left -= intLeftAndRight;
        }

        //if ship is not at right edge, move to the right
        if (pcbShip.Left < this.Width - pcbShip.Width -5 && blnRight == true)
        {
            pcbShip.Left += intLeftAndRight; 
        }

        //scrolling background
        imageYValue -= intScrollSpeed; 

        //create and move obstacles 
        ObstacleSquareMaker();

        //check for collisions 
        ObstacleSquareCollision();

        //move obstacles and check if they go offscreen
        ObstacleOffScreenChecker(); 

        //create bubbles
        ScoreBubbleMaker();

        //check for bubble collisions
        ScoreBubbleCollision(); 

        //move score bubbles and check if they go offscreen
        ScoreBubbleOffScreenChecker(); 

        //check for hits
        LifeChecker(); 

        //check if the background is almost up, if so load next background in array
        if (imageYValue + imgHeight <= this.Height / 4)
        {
            imageYValue = 2600;

            //if counter is larger than array length, reset it
            if (intBackgroundCounter == 10)
            {
                intBackgroundCounter = 1;
            }
            else
            {
                //else, increment counter
                intBackgroundCounter += 1;
            }
            imgBackground = imgBackgroundsArray[intBackgroundCounter];
        }

        //increment score by 10 for every 10 timer ticks
        intTmrCounter += 1; 

        if (intTmrCounter == 10)
        {
            intTmrCounter = 0;
            intScore += 10; 
        }

        //refresh score label
        lblScore.Text = intScore.ToString(); 

        //refresh form
        this.Invalidate();

        //refresh picturebox
        pcbShip.Refresh(); 
    }

    private void Form1_KeyUp(object sender, KeyEventArgs e)
    {
        //check if any of the keys have been let go, if so, set the variables to false
        if (e.KeyData == Keys.W)
        {
            //set w to false and set speed back to normal
            blnUp = false;
            intScrollSpeed = 5; 
        }
        else if (e.KeyData == Keys.A)
        {
            //set a to false
            blnLeft = false; 

            //set ship image to center
            //change ship image 
            pcbShip.Image = imgShip; 
        }
        else if (e.KeyData == Keys.D)
        {
            //set d to false
            blnRight = false;
            //change ship image 
            pcbShip.Image = imgShip; 
        }
    }

    public void ObstacleSquareMaker()
    {
        /***************************************
         * Date: 7/1/2014
         * Description: Created method to randomly generate pictureboxes. Size is determined from a predetermined set. Location is randomized. 
         * Backgrounds and other effects of pictureboxes will also be randomized. 
         * Name is based on position in array. 
        ***************************************/

        //variable declaration 
        Random randGenerator = new Random(); 
        Point pntRandom = new Point();
        int intRandomArrayValue; 

        //randomly generate obstacles
        for (int i = 0; i < pcbSquareObstacles.Length; i++)
        {
            if (pcbSquareObstacles[i] == null)
            {
                //obstacle array
                pcbSquareObstacles[i] = new PictureBox();
                pcbSquareObstacles[i].Name = "pcbObstacle" + i;

                //create new random point
                pntRandom = new Point(randGenerator.Next(3, this.Width - 3), randGenerator.Next(-200, -100));

                //assign location
                pcbSquareObstacles[i].Location = pntRandom;

                //check for overlaps
                OverlapChecker(); 

                //colour
                pcbSquareObstacles[i].BackColor = colorArray[randGenerator.Next(0,3)];

                //get size from size array 
                intRandomArrayValue = randGenerator.Next(0, 6);
                pcbSquareObstacles[i].Size = new Size(intSizeArray[intRandomArrayValue][0], intSizeArray[intRandomArrayValue][1]);

                //add to controls
                this.Controls.Add(pcbSquareObstacles[i]); 

                //reset boolean collision array value
                blnSquareObstacles[i] = false; 
            }
        }
    }

    public void ObstacleOffScreenChecker()
    {
        //move obstacles down
        for (int i = 0; i < pcbSquareObstacles.Length; i++)
        {
            if (pcbSquareObstacles[i] != null)
            {
                pcbSquareObstacles[i].Top += intObstacleScroll[i] + intScrollSpeed;
            }
        }

        //check if the obstacles have gone off screen, if so, set array value to null
        for (int i = 0; i < pcbSquareObstacles.Length; i++)
        {
            if (pcbSquareObstacles[i].Top > this.Height)
            {
                pcbSquareObstacles[i] = null;
            }
        }
    }

    public void ObstacleSquareCollision()
    {
        /***************************************
         * Date: 6/1/2014
         * Description: Collision detection for randomly spawned pictureboxes. 
        ***************************************/
        //check for collision
        for (int i = 0; i < pcbSquareObstacles.Length; i++)
        {
            if (pcbSquareObstacles[i] != null)
            {
                if (pcbSquareObstacles[i].Bounds.IntersectsWith(pcbShip.Bounds) && blnSquareObstacles[i] == false)
                {
                    blnSquareObstacles[i] = true;
                    intHits += 1;
                    lblLives.Size = new Size(115 - ((115 / 5) * intHits), 14); 
                }
            }
        }
    }

    public void OverlapChecker()
    {
        //variable declaration 
        Random randGenerator = new Random();
        Point pntRandom = new Point();

        //loop through obstacles array
        for (int i = 0; i < pcbSquareObstacles.Length - 1; i++)
        {
            //ensure a null error is not raised
            if (pcbSquareObstacles[i] != null && pcbSquareObstacles[i + 1] != null)
            {
                while ((pcbSquareObstacles[i].Bounds.IntersectsWith(pcbSquareObstacles[i + 1].Bounds)))
                {
                    //create new random point
                    pntRandom = new Point(randGenerator.Next(3, this.Width - 3), randGenerator.Next(-200, -100));

                    //assign location
                    pcbSquareObstacles[i].Location = pntRandom;
                }
            }
         }
     }

    public void ScoreBubbleMaker()
    {
        /***************************************
         * Date: 12/1/2014
         * Description: Created a method to continually generate score bubbles.
        ***************************************/

        //variable declaration
        Random randGenerator = new Random();
        Point pntRandom = new Point(); 

        //randomly generate score bubbles
        for (int i = 0; i < pcbScoreBubbles.Length; i++)
        {
            if (pcbScoreBubbles[i] == null)
            {
                //create new picturebox
                pcbScoreBubbles[i] = new PictureBox();
                pcbScoreBubbles[i].Name = "pcbScoreBubble" + i;

                //select size 
                if (randGenerator.Next(0,150) >= 135)
                {
                    //largest size, most points
                    pcbScoreBubbles[i].Size = szMostPoints; 
                }
                else if (randGenerator.Next(0,101) >= 100)
                {
                    //medium points, medium number of points
                    pcbScoreBubbles[i].Size = szMediumPoints; 
                }
                else
                {
                    //smallest size, least number of points
                    pcbScoreBubbles[i].Size = szLeastPoints; 
                }

                //test colour
                pcbScoreBubbles[i].BackColor = Color.Yellow;

                //create new random point
                pntRandom = new Point(randGenerator.Next(3, this.Width - 3), randGenerator.Next(-200, -100));

                //assign location to first point
                pcbScoreBubbles[i].Location = pntRandom;

                //add to controls
                this.Controls.Add(pcbScoreBubbles[i]);

                //reset collision array
                blnScoreBubbleCollision[i] = false; 
            }
        }
    }

    public void ScoreBubbleCollision()
    {
        /***************************************
         * Date: 12/1/2014
         * Description: Collision detection for bubbles. Set picturebox array value to null and increment score based on size.  
        ***************************************/

        //check for collision
        for (int i = 0; i < pcbScoreBubbles.Length; i++)
        {
            if (pcbScoreBubbles[i] != null)
            {
                //check if it hits the ship
                if (pcbScoreBubbles[i].Bounds.IntersectsWith(pcbShip.Bounds) && blnScoreBubbleCollision[i] == false)
                {
                    //set collision variable to true (so it does not occur multiple times)
                    blnScoreBubbleCollision[i] = true; 

                    //increment score based on size of points
                    if (pcbScoreBubbles[i].Size == szLeastPoints)
                    {
                        intScore += 10;
                    }
                    else if (pcbScoreBubbles[i].Size == szMediumPoints)
                    {
                        intScore += 50;
                    }
                    else
                    {
                        intScore += 100;
                    }

                    //make picturebox disappear
                    pcbScoreBubbles[i].Visible = false;
                }
            }
        }
    }

    public void ScoreBubbleOffScreenChecker()
    {
        //move score bubbles
        for (int x = 0; x < pcbScoreBubbles.Length; x++)
        {
            if (pcbScoreBubbles[x] != null)
            {
                pcbScoreBubbles[x].Top += intScrollSpeed;
            }
        }

        //check if score bubbles have gone off screen, if so, set array value to null
        for (int i = 0; i < pcbScoreBubbles.Length; i++)
        {
            if (pcbScoreBubbles[i].Top > this.Height)
            {
                pcbScoreBubbles[i] = null;
            }
        }
    }

    public void LifeChecker()
    {
        /***************************************
         * Date: 7/1/2014
         * Description: Used to determine number of hits and subsequently turn off timer if user collides with objects 5 times. 
        ***************************************/

        //check for collision
        //check for the number of hits 
        if (intHits >= 5)
        {
            tmrTick.Enabled = false; 
        }
    }

    private void exitGameToolStripMenuItem_Click(object sender, EventArgs e)
    {
        //if exit game is clicked, exit entire application
        Application.Exit(); 
    }
}

}

我在按键时将运动变量设置为true,然后在计时器中执行实际运动。

修改 回答B.K:我恐怕我不确定'计时器到期'的意思,但是我会试着解释计时器中发生了什么。

首先,我在KeyDown事件中按下某个键时采用布尔值。然后,我会在计时器的每个刻度上检查这些值,以移动我用于角色的图片框。

计时器的其余部分充满了产生各种障碍等的方法。

就我使用WinForms的原因而言,因为我非常喜欢初学者而且不寻找任何特别复杂的东西。一旦掌握了基础知识,我可以看看XNA;但是,就目前而言,我仍然需要了解很多WinForms

0 个答案:

没有答案