通过数组操作进行基本图像刷新问题

时间:2013-03-02 01:20:55

标签: c# .net winforms debugging

我正在尝试制作一个简单的平铺游戏引擎并遇到问题。当我不得不重新绘制瓷砖时,我会陷入困境。

        int[,] level = {
                           { 0, 0, 0, 0, 0 ,0 },
                           { 0, 0, 0, 0, 0 ,0 },
                           { 0, 0, 0, 0, 0 ,0 },
                           { 0, 0, 0, 0, 0 ,0 },
                           { 0, 0, 0, 0, 0 ,0 },
                           { 0, 0, 0, 0, 0 ,0 },
                       };

这是我的数组,因此所有值都为0。每个相应的值都链接到一个单独的图块,当您按下按键时,它将打开和关闭。

        //Event Handler (W,A,S,D) is used for movements
    private void panel1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
    {

        .
        .
        .

    }



        //Responsible for movements
    private void tmrMov_Tick(object sender, EventArgs e)
    {


        level[_x, _y] = 0;

        if (_objDirection == Direction.Right)
        {

            if (_x < _boardWidth - 1 && _x >= 0 && _x + 1 < _boardWidth - 1 && _x + 1 >= 0)
                _x += 1;
            else
                _x = _boardWidth - 1;
        }

           .
           .
           .

        level[_x, _y] = _k;

        Invalidate();
    }

这是我的计时器功能,应该“操纵”数组值,因此当程序运行时,可以决定通过键打开/关闭哪个图块。

无论如何,我的问题是刷新涉及'invalidate()'函数调用的图像。虽然,我确实感觉它可以动态改变数组值,但我似乎无法刷新图像以跳转到另一个图块。

以下是我一直在处理的完整项目的链接:http://www.mediafire.com/?g10a0zzt8hru11v

这是我几天前回答的一个类似但不同的问题:Setting up basic game and debugging fundamental problems

提前致谢!

1 个答案:

答案 0 :(得分:0)

所以...我希望你不要对此采取任何冒犯,但我经历了一些事情,并提出了一些建议/修正/评论/等等。

希望这有帮助!如果任何建议的更改需要解释,请告诉我。

所以,让我们从designer.cs文件开始:

// Ahh, here's yer problem: the panel control doesn't raise PreviewKeyDowns - the form does, tho
this.panel1.PreviewKeyDown += 
       new System.Windows.Forms.PreviewKeyDownEventHandler(
           this.panel1_PreviewKeyDown);

    // the form will raise these, so bind the handler to it 
    // (and rename the method)
    this.PreviewKeyDown += 
       new System.Windows.Forms.PreviewKeyDownEventHandler(
           this.Form1_PreviewKeyDown);

啊,一个大问题 - 你的关键事件都没有实际到达你的处理程序。让我们回到代码隐藏的形式。

所以,在构造函数中 - 所有这些都可以:

// arrays of T (T[], int[], etc), come initialized to default(T),
// so none of this is needed.
level[0, 0] = 0;
level[0, 1] = 0;
level[0, 2] = 0;
level[0, 3] = 0;
level[0, 4] = 0;

跳转到Paint处理程序:

// The next two checks have the x and y swapped,
    // meaning the apparent motion will not match what the
    // actual direction should be
//Empty Tile
if (level[y, x] == 0)
{
//Occupied Tile
if (level[y, x] == 1)
{

    // Now the render will mactch properly
//Empty Tile
if (level[x, y] == 0)
{
//Occupied Tile
if (level[x, y] == 1)
{

冠!致Timer.Tick处理程序:

#region Timer function
// doing this could cause flickering
// or flashing if the paint fires while
// we're updating things
level[_x, _y] = 0;

#region Timer function
// instead, keep track temporarily
// what they were - we'll come back to this later on
var oldX = _x;
var oldY = _y;

进一步研究if / else链:

// There's a lot of replication and style choices here that
// will make it harder to debug/troubleshoot 
if (_objDirection == Direction.Right)
{
    if (_x < _boardWidth - 1 && _x >= 0 && _x + 1 < _boardWidth - 1 && _x + 1 >= 0)
        _x += 1;
    else
        _x = _boardWidth - 1;
}
else if (_objDirection == Direction.Left)

让我们看看我们是否可以摆脱一些重复:

// let's figure these out ahead of time
var spaceOnLeft = _x > 0;
var spaceOnRight = _x < _boardWidth - 1;
var spaceOnTop = _y > 0;
var spaceOnBottom = _y < _boardHeight - 1;

// switch is a bit like the if/else construct you had
switch (_objDirection)
{
    case Direction.Up:
        // this means: if(spaceOnTop) y = y-1 else y = height-1
        _y = spaceOnTop ? _y - 1 : _boardHeight - 1;
        break;
    case Direction.Down:
        _y = spaceOnBottom ? _y + 1 : 0;
        break;
    case Direction.Left:
        _x = spaceOnLeft ? _x - 1 : _boardWidth - 1;
        break;
    case Direction.Right:
        _x = spaceOnRight ? _x + 1 : 0;
        break;
}

跳到最后......

// now we'll use the old position to clear...
level[oldX, oldY] = 0;
// then set the new position
level[_x, _y] = _k;

// Since we're only writing on the panel,
// we only need to rerender the panel
panel1.Refresh();

最后一点 - 关键处理程序:

// Hah - artificial difficulty due
// to awkward key choice? Out of curiosity,
// why not Keys.Up, Down, Left, Right?
if (e.KeyCode == Keys.E)
{
    _objDirection = Direction.Left;
}
else if (e.KeyCode == Keys.D)
{
    _objDirection = Direction.Right;
}
else if (e.KeyCode == Keys.W)
{
    _objDirection = Direction.Up;
}
else if (e.KeyCode == Keys.S)
{
    _objDirection = Direction.Down;
}

// same deal here, but with keys
    // Or switch to Up, Down, Left, Right :)
switch (e.KeyCode)
{
    case Keys.E: 
        _objDirection = Direction.Up;
        break;
    case Keys.D:
        _objDirection = Direction.Down;
        break;
    case Keys.W:
        _objDirection = Direction.Left;
        break;
    case Keys.S:
        _objDirection = Direction.Right;
        break;
}

Form1.cs类的完整代码删除:

//Listing all the parameters
public partial class Form1 : Form
{

    #region Declaring Parameters

    enum Direction
    {
        Left, Right, Up, Down
    }

    private int _x;
    private int _y;
    private int _k;
    private Direction _objDirection;
    Random rand = new Random();
    private int _boardWidth;
    private int _boardHeight;
    private int[,] level;

    #endregion

    //Giving values to parameters
    public Form1()
    {
        InitializeComponent();

        #region Initialial values

        _k = 1;
        _boardWidth = 6;
        _boardHeight = 6;
        _x = rand.Next(0, _boardWidth - 1);
        _y = rand.Next(0, _boardHeight - 1);
        _objDirection = Direction.Left;

        //Array that works as a board or platform which we used to distinguish tiles
        level = new int[_boardWidth, _boardHeight];
        #endregion
    }

    //Paint is used for drawing purposes only
    private void panel1_Paint(object sender, PaintEventArgs e)
    {
        /*
               int[,] level = {
                               { 0, 0, 0, 0, 0 ,0 },
                               { 0, 0, 0, 0, 0 ,0 },
                               { 0, 0, 0, 0, 0 ,0 },
                               { 0, 0, 0, 0, 0 ,0 },
                               { 0, 0, 0, 0, 0 ,0 },
                               { 0, 0, 0, 0, 0 ,0 },
                           };
        */
        #region Looping through tiles

        //Initializing first randomly filled tile
        level[_x, _y] = _k;

        for (int y = 0; y < _boardHeight; y++)
        {
            for (int x = 0; x < _boardWidth; x++)
            {
                //Empty Tile
                if (level[x, y] == 0)
                {
                    // Create pen.
                    Pen redPen = new Pen(Color.Red, 1);

                    // Create rectangle.
                    Rectangle redRect = new Rectangle(x * 50, y * 50, 50, 50);

                    // Draw rectangle to screen.
                    e.Graphics.DrawRectangle(redPen, redRect);
                }

                //Occupied Tile
                if (level[x, y] == 1)
                {
                    // Create solid brush.
                    SolidBrush blueBrush = new SolidBrush(Color.Blue);
                    // Create rectangle.
                    Rectangle rect = new Rectangle(x * 50, y * 50, 50, 50);
                    // Fill rectangle to screen.
                    e.Graphics.FillRectangle(blueBrush, rect);
                }
            }
        }
        #endregion
    }

    //Responsible for movements
    private void tmrMov_Tick(object sender, EventArgs e)
    {
        #region Timer function
        // instead, keep track temporarily
        // what they were
        var oldX = _x;
        var oldY = _y;

        // let's figure these out ahead of time
        var spaceOnLeft = _x > 0;
        var spaceOnRight = _x < _boardWidth - 1;
        var spaceOnTop = _y > 0;
        var spaceOnBottom = _y < _boardHeight - 1;

        // switch is a bit like the if/else construct you had
        switch (_objDirection)
        {
            case Direction.Up:
                // this means: if(spaceOnTop) y = y-1 else y = height-1
                _y = spaceOnTop ? _y - 1 : _boardHeight - 1;
                break;
            case Direction.Down:
                _y = spaceOnBottom ? _y + 1 : 0;
                break;
            case Direction.Left:
                _x = spaceOnLeft ? _x - 1 : _boardWidth - 1;
                break;
            case Direction.Right:
                _x = spaceOnRight ? _x + 1 : 0;
                break;
        }

        // now we'll use the old values to clear...
        level[oldX, oldY] = 0;
        // then set the new value
        level[_x, _y] = _k;
        #endregion
        panel1.Refresh();
    }

    //Event Handler (W,A,S,D) is used for movements
    private void Form1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
    {
        #region Controls

        // same deal here, but with keys
        switch (e.KeyCode)
        {
            case Keys.Up:
                e.IsInputKey = true;
                _objDirection = Direction.Up;
                break;
            case Keys.Down:
                e.IsInputKey = true;
                _objDirection = Direction.Down;
                break;
            case Keys.Left:
                e.IsInputKey = true;
                _objDirection = Direction.Left;
                break;
            case Keys.Right:
                e.IsInputKey = true;
                _objDirection = Direction.Right;
                break;
        }
        #endregion
    }
}

干杯!