Рисование предметов относительно игрока, когда у края карты

У меня есть движок плиток, и все это отлично работает, мой игрок ходит по всему хорошо, я работаю над добавлением предметов, игрок всегда находится в центре экрана, пока он не приблизится к краям мира, затем он начнет подходя близко к краям.

Когда я рисую предметы в мире, они хорошо рисуются, кроме случаев, когда игрок покидает центр (на краю света). Я просто не могу обернуться, как это исправить.

public static void Draw(SpriteBatch spriteBatch, World w, Item i, Player p, Point screenDimensions)
    {
        bool IsOnScreen = true;

        float leftX = p.X - ((screenDimensions.X / 32) / 2);
        float rightX = leftX + (screenDimensions.X / 32);

        float topY = p.Y - ((screenDimensions.Y / 32) / 2);
        float bottomY = topY + (screenDimensions.Y / 32);

        if (i.x < leftX || i.x > rightX || i.y < topY || i.y > bottomY)
            IsOnScreen = false;

        if (IsOnScreen)
            i.animation.Draw(spriteBatch, (int)Math.Floor((i.x - leftX) * 32), (int)Math.Floor((i.y - topY) * 32));
    }

Это довольно понятно, мир передается, чтобы получить размеры (w.worldDimensions.x для ширины и .y для высоты), элемент используется для получения i.x а также i.y (местоположение в игровом мире, а не на экране), игрок для его рисования относительно (содержит .x а также .y для местоположения), а затем Размеры экрана.

1 ответ

Решение

Ну, это не очень понятно для меня. Вы используете класс камеры? Если вы используете класс камеры и используете его для навигации по своему миру, этого никогда не должно произойти.

Вот основной, который я сейчас использую для своего проекта.

class Camera
{
    float zoom;
    public float Rotation { get; private set; }
    public Vector2 Position { get; private set; }
    Matrix transform;

    int velocity = 60;

    UserInput input;

    public float Zoom
    {
        get { return zoom; }
        set { zoom = value; if (zoom < 0.1f) zoom = 0.1f; } // Negative zoom will flip image
    }

    public Camera(UserInput input)
    {
        zoom = 1.0f;
        Rotation = 0f;
        Position = new Vector2(0, 0);
        this.input = input;
    }

    public void MoveCam()
    {
        if (input.IsKeyHold(Keys.Up))
        {
            Position += new Vector2(0, -velocity);
        }
        if (input.IsKeyHold(Keys.Left))
        {
            Position += new Vector2(-velocity, 0);
        }
        if (input.IsKeyHold(Keys.Down))
        {
            Position += new Vector2(0, velocity);
        }
        if (input.IsKeyHold(Keys.Right))
        {
            Position += new Vector2(velocity, 0);
        }

        if (input.IsKeyHold(Keys.OemMinus))
        {
            Zoom -= .01f * Zoom;
        }
        else if (input.IsKeyHold(Keys.OemPlus))
        {
            Zoom += .01f * Zoom;
        }
    }

    public void FollowCam(int xPos, int yPos)
    {
        Position = new Vector2(xPos * TileData.Width, yPos * TileData.Height);
    }


    public Matrix TransformMatrix(GraphicsDevice device)
    {
        transform = Matrix.CreateTranslation(new Vector3(-Position.X, -Position.Y, 0)) *
            Matrix.CreateRotationX(MathHelper.ToRadians(Rotation)) *
            Matrix.CreateRotationY(MathHelper.ToRadians(Rotation)) *
            Matrix.CreateRotationZ(MathHelper.ToRadians(Rotation)) *
            Matrix.CreateScale(new Vector3(zoom, zoom, 0)) *
            Matrix.CreateTranslation(new Vector3(device.Viewport.Width * 0.5f, device.Viewport.Height * 0.5f, 0));
        return transform;
    }
}

Просто создайте экземпляр класса как в main и используйте его в вашем методе draw.

batch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, null, null, null, null, camera.TransformMatrix(graphicsDevice));
batch.End()

Нарисуйте все в своем мире внутри этой спрайтбэтча и используйте новое базовое средство для рисования, чтобы отображать координаты, например, графический интерфейс. Вы можете использовать метод перемещения камеры, чтобы переместить его вручную, и заблокировать, чтобы заблокировать его в любом месте (оно будет обновляться).

Если у вас большие карты, вы можете рендерить только необходимые плитки. Я делаю это так в своем классе карты:

public void Draw(SpriteBatch batch, Vector2 camPosition, float camZoom, GraphicsDevice device)
    {
        float top = (camPosition.Y / TileData.Height) - ((device.Viewport.Height / 2) / TileData.Height + 1) / camZoom;
        float bottom = (camPosition.Y / TileData.Height) + ((device.Viewport.Height / 2) / TileData.Height + 2) / camZoom;
        float left = (camPosition.X / TileData.Width) - ((device.Viewport.Width / 2) / TileData.Width + 1) / camZoom;
        float right = (camPosition.X / TileData.Width) + ((device.Viewport.Width / 2) / TileData.Width + 2) / camZoom;

        for (int y = (int)top; y < (int)bottom; y++)
        {
            for (int x = (int)left; x < (int)right; x++)
            {
                if (y >= 0 && y < map.GetLength(1) && x >= 0 && x < map.GetLength(0))
                {
                    batch.Draw(map[x, y].texture, new Rectangle(x * TileData.Width, y * TileData.Height, TileData.Width, TileData.Height), Color.White);

                }
            }
        }
    }

Здесь сначала я выясняю, какие плитки рисовать с каждого направления. Обратите внимание на camZoom, вы хотите, чтобы при уменьшении масштаба отображалось больше плиток. Затем я использую эти "границы" в своих циклах for, оператор if гарантирует, что я не получаю доступ к плиткам, которые не существуют (за пределами).

Другие вопросы по тегам