首页 文章

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

提问于
浏览
1

这是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 回答

  • 1

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

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

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

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

    假设你的行和列是80Wx60H像素(它们可以是你最喜欢的) . 现在让我们假设您的玩家从0,160开始向东移动 . 而且,根据您的 Map ,当他到达第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
    }
    

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

相关问题