2D Windows Form游戏中奇怪的粘性碰撞检测

时间:2013-12-16 02:27:55

标签: c# winforms collision-detection collision

这是question that I posted last night的后续问题。我必须在Windows窗体中为学校写一个游戏,我正在创建一个迷宫游戏,玩家必须在迷宫中通过迷宫才能被杀死。作为一个迷宫游戏,必须使用一些碰撞检测来确保玩家不会简单地穿过墙壁(这将是一个非常无聊的游戏)。我已经实现了一个功能,可以根据我昨晚提出的问题来解决这个问题,但是我得到了一些奇怪的结果。

当玩家触摸墙壁时,游戏会停止,玩家最终会被卡住。玩家不能移动,除非他们按下组合键移动穿过墙壁(我的游戏使用WASD,所以如果我触摸墙壁,我可以按下W + A并穿过墙壁到我的玩家被取消的另一侧)

这是我的碰撞代码:

                // This goes in the main class
                foreach (Rectangle wall in mazeWalls)
                {
                    if (playerRectangle.IntersectsWith(wall))
                    {
                        player.Stop();
                    }
                }   

这是玩家的移动代码:

    public void Move(Direction dir)
    {
        // First, check & save the current position.
        this.lastX = this.x;
        this.lastY = this.y;

        if (dir == Direction.NORTH)
        {
            if (!CheckCollision())
            {
                this.y -= moveSpeed;
            }
            else
            {
                this.y += 1;
            }

        }
        else if (dir == Direction.SOUTH)
        {
            if (!CheckCollision())
            {
                this.y += moveSpeed;
            }
            else
            {
                this.y -= 1;
            }


        }
        else if (dir == Direction.EAST)
        {
            if (!CheckCollision())
            {
                this.x += moveSpeed;
            }
            else
            {
                this.x -= 1;
            }

        }
        else if (dir == Direction.WEST)
        {
            if (!CheckCollision())
            {
                this.x -= moveSpeed;
            }
            else
            {
                this.x += 1;
            }


        }
    }

我的CheckCollision()方法:

    private bool CheckCollision()
    {            
        // First, check to see if the player is hitting any of the boundaries of the game.
        if (this.x <= 0)
        {
            isColliding = true;
        }
        else if (this.x >= 748)
        {
            isColliding = true;
        }
        else if (this.y <= 0)
        {
            isColliding = true;
        }
        else if (this.y >= 405)
        {
            isColliding = true;
        }
        else if (isColliding)
        {
            isColliding = false;
        }
        // Second, check for wall collision.
        return isColliding;
    }

Stop()方法:

    public void Stop()
    {
        this.x = lastX;
        this.y = lastY;            
    }

Here是我上传的一个gif,以便您可以看到播放器与迷宫墙的行为。注意他是如何滑过墙壁并反复卡住的。

我的问题是如何让这个播放器停止粘贴,实际上能够滑动并随墙移动?我尝试了多种碰撞模式,并使用昨晚(非常有帮助)的答案,但他不会停止坚持墙壁!如果您需要任何其他详细信息/信息,请与我们联系。

编辑:输入代码,按照Dan-o的要求:http://pastebin.com/bFpPrq7g

1 个答案:

答案 0 :(得分:1)

游戏设计是一个复杂的主题。有一些很好的文档记录了实现2D迷宫游戏的策略。在这里,大多数人都可以根据你所做的事情提出一般性建议,因为他们知道商业游戏并不是想要在这里做的。无论如何,我会投入两美分。我只在OpenGL中做过这样的事情,而不是使用Windows Forms。

我看到的第一件事就是你的精灵并没有在它的车道中居中。计算最终会使事情变得更容易,因为玩家总是只有4个可能的方向。当对角线也可能时,北,南,东和西并不是那么多。

设计您的游戏板,使您的墙壁和车道宽度相同。使用均匀空格行和列。由于您使用的是固定的电路板尺寸,因此这应该像将宽度和高度除以所需的行数和列数一样简单。

完成此操作后,您将始终根据x和y坐标知道您所在的车道。例如,如果您的列宽度为80像素,并且您的x = 160,那么您就知道自己位于第2列(基于0的数组中为1)。这是你能够将敌人放在棋盘上并能够以编程方式跟踪他们前进方向的唯一方法。此外,你将能够适当地为球道调整你的球员和敌人的大小。

假设你的行和列是80Wx60H像素(它们可以是你最喜欢的)。现在让我们假设您的玩家从0,160开始向东移动。而且,根据您的地图,当他到达第3列(基于零的模型中为2)时,他可以移动北和南。意思是,当他到达160,160。记住,如果x = 0从第1列开始,那么80从第2列开始,依此类推。

暂时忘记碰撞,你可以使用这样的逻辑。

RectangleF playerRectangle = new RectangleF();
int COLUMN_WIDTH = 80;
int ROW_HEIGHT = 60;

if (playerRectangle.IntersectsWith(wall)){
    int column = playerRectangle.X / COLUMN_WIDTH;

    //----------------------------------------------
    // This will return false if the player 
    // is not positioned right at the column. The 
    // result of % will contain decimal digits.
    // playerRectangle.X has to be a float though.
    //----------------------------------------------
    if(column % 1 == 0){
        //--------------------------------------------
        // do this based on your keyboard logic. this 
        // is pseudo-code
        //--------------------------------------------
        if(keys == keys.UP){
            // Move up
        }
        else if(keys == keys.DOWN){
            // Move down
        }
    }
}

您要做的另一件事是在墙上存放方向属性。这样,当你与一个碰撞时,你会知道你的选择是什么。如果碰撞的墙是WallOrientation.NorthSouth,一旦你碰到它,你只能移动北或南。或者,您可以反向朝向它的方向。如果没有按键,你就坐着不动。像这样的事情就可以了。

public enum WallOrientation{
    NorthSouth,
    EastWest
}

此代码均未经过测试。我只是在飞行中写它,所以可能会有错误。我只是想给你一些想法。我希望这个建议可以帮助你解决一些问题。