射线在 XNA/Monogame 中的视线

Line of Sight with Ray in XNA/Monogame

我正在尝试为敌人创建视线方法 class。然而,它总是 returns false,无论玩家离敌人有多近,或者射线是否穿过任何块到达玩家。

public virtual bool PlayerInLOS()
    {
        Vector3 middleOfPlayer = new Vector3(Level.Player.Position.X, Level.Player.Position.Y - Level.Player.BoundingRectangle.Height / 2, 0);
        Vector3 middleOfEnemy = new Vector3(Position.X, Position.Y - localBounds.Height / 2, 0);

        Vector3 direction = middleOfPlayer - middleOfEnemy;
        float distanceToPlayer = Vector3.Distance(middleOfEnemy, middleOfPlayer);

        if (direction != Vector3.Zero)
            direction.Normalize();

        Ray lineOfSight = new Ray(middleOfEnemy, direction);

        float? lineToPlayer = lineOfSight.Intersects(Level.Player.BoundingBox);

        foreach (BoundingBox box in Level.boundingBoxes)
        {
            float? distanceToIntersect = lineOfSight.Intersects(box);

            if (distanceToIntersect == null)
                continue;
            else if (distanceToIntersect < visionLength && distanceToIntersect < distanceToPlayer && distanceToIntersect != null)
                return false; 
        }

        // Never gets to this part because it always returns before it exits the for loop
        if (lineToPlayer < visionLength)
            return true;
        else return false;
    }

有什么想法吗?谢谢

我最终通过实施一个完全不同的解决方案解决了这个问题:沿着敌人和玩家之间的距离检查每个 Vector2。完美运行。

    public bool CanSeePlayer()
    {
        Vector2 middleOfPlayer = new Vector2(Level.Player.Position.X, Level.Player.Position.Y - Level.Player.BoundingRectangle.Height / 2);
        Vector2 middleOfEnemy = new Vector2(Position.X, Position.Y - localBounds.Height / 2);

        Vector2 direction = middleOfPlayer - middleOfEnemy;
        float distanceToPlayer = Vector2.Distance(middleOfEnemy, middleOfPlayer);

        if (visionLength > distanceToPlayer) // If the enemy can see farther than the player's distance,
        {
            if (direction != Vector2.Zero)
            direction.Normalize();

            for (int y = 0; y < Level.tiles.GetLength(1); ++y) // loop through every tile, 
            {
                for (int x = 0; x < Level.tiles.GetLength(0); ++x)
                {
                    if (Level.GetCollision(x, y) != TileCollision.Passable) // and if the block is solid,
                    {
                        Vector2 currentPos = middleOfEnemy;
                        float lengthOfLine = 0.0f;

                        Rectangle tileRect = new Rectangle(x * Tile.Width, y * Tile.Height, Tile.Width, Tile.Height);

                        while (lengthOfLine < distanceToPlayer + 1.0f) // check every point along the line
                        {
                            currentPos += direction;

                            if (tileRect.Contains(currentPos)) // to see if the tile contains it.
                            {
                                return false;
                            }

                            lengthOfLine = Vector2.Distance(middleOfEnemy, currentPos);
                        }
                    }
                }
            }
            // If every tile does not contain a single point along the line from the enemy to the player,
            return true;
        }
        return false;            
    }

如果你需要检查敌人是否在视线范围内,并且在一定距离内你可以试试这个代码。

public static bool InLOS(float AngleDistance, float PositionDistance, Vector2 PositionA, Vector2 PositionB, float AngleB)
{
    float AngleBetween = (float)Math.Atan2((PositionA.Y - PositionB.Y), (PositionA.X - PositionB.X));
    if ((AngleBetween <= (AngleB + (AngleDistance / 2f / 100f))) && (AngleBetween >= (AngleB - (AngleDistance / 2f / 100f))) && (Vector2.Distance(PositionA, PositionB) <= PositionDistance)) return true;
    else return false;
}

学分:https://gamedev.stackexchange.com/questions/26813/xna-2d-line-of-sight-check