厚壁二维迷宫中的碰撞检测 [英] Collision detection in a 2D maze with thick walls

查看:37
本文介绍了厚壁二维迷宫中的碰撞检测的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我必须使用 Windows 窗体为学校制作游戏.我的游戏包括一个用户必须通过迷宫.我试图阻止我的用户使用碰撞检测直接穿过墙壁,但由于用于表示墙壁的矩形的不同形状而卡住了.这是游戏的图片.这个问题可能类似于这个,但是随着我的运动,我相信它是完全不同的,因为我没有布置网格系统或图形地图.

I have to make a game with Windows Forms for school. My game consists of a user having to get through a maze. I'm trying to prevent my user from going straight through the walls using collision detection, but am getting stuck because of the varying shape of the rectangles being used to represent walls. Here's an image of the game. This question may be similar to this one, however with my movement I believe that it is quite different, as I don't have a grid system or graphical map laid out.

如您所见,墙壁相当厚.每面墙都由一个 C# Rectangle, 表示,就像我的播放器图像(黄色的小鬼)一样.我知道如何使用 C# 的 IntersectsWith(Rectangle r) 方法确定玩家是否穿过这些墙壁,但我不确定如何使用此信息来处理碰撞并停止玩家根本无法穿过墙壁.

As you can see, the walls are fairly thick. Each wall is represented by a C# Rectangle, as is my Player image (the little yellow ghost). I know how to determine if the player is crossing through these walls using C#'s IntersectsWith(Rectangle r) method, but I'm not exactly sure how to use this information in order to handle the collision and STOP the player from moving through the walls at all.

这是我尝试过的:

这是我的实际移动代码.因为游戏是用WinForm构建的,所以移动是由OnKeyPressedOnKeyUp

This is my actual movement code. Because the game is built in WinForm, the movement is triggered by keyboard events such as OnKeyPressed and OnKeyUp

    public void Move(Direction dir)
    {
        HandleCollision(); // Handle collision while player is trying to move.
        if (dir == Direction.NORTH)
        {                
            this.y -= moveSpeed;
        }
        if (dir == Direction.SOUTH)
        {                
            this.y += moveSpeed;
        }
        if (dir == Direction.EAST)
        {
            this.x += moveSpeed;
        }
        if (dir == Direction.WEST)
        {
            this.x -= moveSpeed;
        }
    }

这是我的碰撞方法,HandleCollision():

    private void HandleCollision()
    {
        // First, check to see if the player is hitting any of the boundaries of the game.
        if (this.x <= 0)
        {
            this.x = 0;
        }
        if (this.x >= 748)
        {
            this.x = 748;
        }
        if (this.y <= 0)
        {
            this.y = 0;
        }
        if (this.y >= 405)
        {
            this.y = 405;
        }           
        // Second, check for wall collision.

        foreach (Rectangle wall in mazeWalls)
        {
            if (playerRectangle.IntersectsWith(wall))
            {
                if (player.X > wall.X) { player.X += wall.Width; }
                else if (player.X < wall.X) { player.X -= wall.Width; }
                else if (player.Y > wall.Y) { player.Y += wall.Height; }
                else if (player.Y < wall.Y) { player.Y -= wall.Height; }                    
            }
        }
    }

现在上面的代码有点有效.然而,因为玩家的坐标加上了墙的宽度/高度,这会在地图上产生一些奇怪的碰撞传送,玩家最终会在那里弹跳.那么,实现可以替换 if (playerRectangle.IntersectsWith(wall)) { 块中的所有代码的碰撞检测系统的最有效方法是什么?

Now this code above kind of works. However, because the player's coordinates are having the wall's width/height added to it, this makes some weird collision teleportation across the map where the player ends up bouncing around. So what would be the most efficient way of going about implementing a collision detection system which can replace all the code within the if (playerRectangle.IntersectsWith(wall)) { block?

推荐答案

在移动中,保存当前位置,执行移动,检查碰撞,如果为真,则恢复旧位置.

In the move, save the current position, perform the move, check for collision, and if true, restore the old position.

为此,HandleCollision 将返回一个布尔值,对于每次成功的测试(成功=检测到碰撞)为 true,如果没有满足任何条件,则在最后返回 false.该方法根本不会修改任何 x 或 y 值.为了体现它的新功能,这个方法应该重命名为CheckCollision.

For this to work, HandleCollision would return a Boolean value, true for each successful test (successful=collision detected), false at the end if no condition was met. The method would not modify any x or y value at all. To reflect its new function, this method should be renamed to CheckCollision.

从你另一个帖子的 gif 来看,你的比赛场地似乎被分成了几个方块,而墙壁和精灵是由多个方块组成的?然后你的移动应该以一格为增量进行,直到达到预期的增量.对于每个方块,必须检查碰撞.

From the gif in your other post it seems that your playing field is divided into squares, and walls and sprite are composed of multiple squares? Then your move should proceed in increments of one square until the intended increment is met. For each square the collision has to be checked.

对于每一步仅检查一次的更高级方法,您需要一些线性数学.碰撞检查将需要当前点 P 和移动的增量 d.您需要检查 P 和 P+d 之间是否有墙被越过.这通常由线性条件中的符号变化表示.对于 P 左边的垂直墙 W,如果 d 指向墙,P.x+d.x-(W.x+W.width) 将为负.用 W.x+W.width<=P.x+s*d.x 确定 s.对于水平墙,您必须在 y 坐标中进行相同的检查.取所有命中对象的最小 s 并将 P+s*d 作为新位置.

For a more advanced method with only one check per move you need some linear mathematics. The collision check will need the current point P and the increment d of the move. You need to check if between P and P+d the wall is crossed. This is usually indicated by a sign change in a linear condition. For a vertical wall W to the left of P, if d points to the wall, P.x+d.x-(W.x+W.width) will be negative. Determine s with W.x+W.width<=P.x+s*d.x. For horizontal walls, you have to do the same check in the y-coordinate. Take the minimal s over all objects hit and P+s*d as the new position.

这篇关于厚壁二维迷宫中的碰撞检测的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆