【问题标题】:Draw a never-ending line in XNA在 XNA 中画一条永无止境的线
【发布时间】:2014-10-06 17:54:11
【问题描述】:

我在 XNA 中画了一条线,我希望它永远不会结束。我还有一个在 X 方向上向前移动的工具和一个以该工具为中心的相机。但是,当我到达视口的尽头时,不再绘制线条。下面是一些图片来说明我的问题:

一开始,这条线穿过整个屏幕,但随着我的工具向前移动,我们到达了这条线的尽头。

以下是绘制线条的方法:

        private void DrawEvenlySpacedSprites (Texture2D texture, Vector2 point1, Vector2 point2, float increment)
    {
        var distance = Vector2.Distance (point1, point2);    // the distance between two points
        var iterations = (int)(distance / increment);       // how many sprites with be drawn
        var normalizedIncrement = 1.0f / iterations;        // the Lerp method needs values between 0.0 and 1.0
        var amount = 0.0f;

        if (iterations == 0)
            iterations = 1;

        for (int i = 0; i < iterations; i++) {
            var drawPoint = Vector2.Lerp (point1, point2, amount);
            spriteBatch.Draw (texture, drawPoint, Color.White);
            amount += normalizedIncrement;
        }
    }

这里是Game中的draw方法。点是我的线:

protected override void Draw (GameTime gameTime)
    {
        graphics.GraphicsDevice.Clear(Color.Black);
        nyVector = nextVector (gammelVector);
        GraphicsDevice.SetRenderTarget (renderTarget);
        spriteBatch.Begin ();
        DrawEvenlySpacedSprites (dot, gammelVector, nyVector, 0.9F);
        spriteBatch.End ();

        GraphicsDevice.SetRenderTarget (null);
        spriteBatch.Begin (SpriteSortMode.Deferred, BlendState.AlphaBlend, null, null, null, null, camera.transform);
        spriteBatch.Draw (renderTarget, new Vector2 (), Color.White);
        spriteBatch.Draw (tool, new Vector2(toolPos.X - (tool.Width/2), toolPos.Y - (tool.Height/2)), Color.White);
        spriteBatch.End ();

        gammelVector = new Vector2 (nyVector.X, nyVector.Y);
        base.Draw (gameTime);
    }

任何人都可以在这里指出正确的方向吗?我猜它与viewport.width有关,但我不太确定如何解决它。感谢您的阅读!

【问题讨论】:

  • 我注意到您正在使用渲染目标。这可能是您问题的根源。
  • 当我不使用渲染目标时问题仍然存在。我使用 renderTarget 的原因是因为我不希望我的线条在移动时重绘工具时消失。
  • 如果我写这个,我不会跨帧保存屏幕内容,而只会保存行顶点的位置。然后在每一帧中,我会画出可见的部分。你总是可以缓存一些部分,但你可能需要不止一个纹理。顺便说一句,您渲染线条的方法可能很简单,但效率极低。如果您需要更高效的东西,请查看here
  • 完全正确。存储每个线顶点的坐标。找到一个函数,它会使用“一个像素”纹理为你画一条线。

标签: c# xna xamarin.ios


【解决方案1】:

我读了这篇文章,并认为今天早上这将是一个有趣的练习,所以我决定写这篇文章是为了好玩。

实现非常简单,在彼此的末尾不断添加行,直到最后一行超出可视区域。

下面的代码将画一条无限向右的线。作为一项额外的优化,屏幕左侧的线条会在您通过它们时被删除。您可以轻松地使其保留以前存在的线条,或者也可以创建向左的线条。我会把这些练习留给你。

看看下面的Line类,它将在屏幕上定义一条线:

public class Line
{
    Texture2D Texture;
    Color Color;
    public Vector2 PointA;
    public Vector2 PointB;
    float Width;

    public Line(Vector2 pointA, Vector2 pointB, float width, Color color, Texture2D texture)
    {
        Texture = texture;
        PointA = pointA;
        PointB = pointB;
        Width = width;
        Color = color;
    }

    public void Draw(SpriteBatch spritebatch)
    {
        float angle = (float)Math.Atan2(PointB.Y - PointA.Y, PointB.X - PointA.X);
        float length = Vector2.Distance(PointA, PointB);
        spritebatch.Draw(Texture, PointA, null, Color, angle, Vector2.Zero, new Vector2(length, Width), SpriteEffects.None, 0);
    }

}

我在游戏类中编写了实现,因为我是快速编码。您可以在下面看到游戏类

public class Game1 : Microsoft.Xna.Framework.Game
{
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;
    Camera Camera;

    Texture2D LineTexture;
    List<Line> Lines;
    Random Random;

    public Game1()
    {
        graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";
    }

    protected override void Initialize()
    {
        base.Initialize();
    }

    protected override void LoadContent()
    {
        spriteBatch = new SpriteBatch(GraphicsDevice);
        Camera = new Camera(GraphicsDevice.Viewport, 1f);

        LineTexture = new Texture2D(GraphicsDevice, 1, 1);
        LineTexture.SetData<Color>(new Color[] { Color.White });

        Random = new Random();
        Lines = new List<Line>();
    }

    protected override void UnloadContent()
    {
    }


    protected override void Update(GameTime gameTime)
    {
        //handle input
        KeyboardState kbState = Keyboard.GetState();

        if (kbState.IsKeyDown(Keys.Escape))
            this.Exit();

        if (kbState.IsKeyDown(Keys.OemMinus))
            Camera.Zoom -= 0.015f;
        else if (kbState.IsKeyDown(Keys.OemPlus))
            Camera.Zoom += 0.015f;

        if (kbState.IsKeyDown(Keys.Up))
            Camera.Move(new Vector2(0, -30));
        else if (kbState.IsKeyDown(Keys.Down))
            Camera.Move(new Vector2(0, 30));
        if (kbState.IsKeyDown(Keys.Left))
            Camera.Move(new Vector2(-30, 0));
        else if (kbState.IsKeyDown(Keys.Right))
            Camera.Move(new Vector2(30, 0));


        //check if line is still in viewport - if not remove it
        for (int i = 0; i < Lines.Count; i++)
        {
            if (Lines[i].PointB.X < Camera.Viewport.X)
            {
                Lines.RemoveAt(i);
                i--;
            }
        }

        //if there are no lines, create one to get started
        if (Lines.Count == 0)
        {
            Vector2 p1 = new Vector2(Camera.Viewport.X, Random.Next(Camera.Viewport.Y + 50, Camera.Viewport.Height - 100));
            Vector2 p2 = new Vector2(p1.X + Random.Next(5, 20), p1.Y + Random.Next(-5, 5));
            Line line = new Line(p1, p2, 1, Color.Black, LineTexture);
            Lines.Add(line);
        }

        //Check if we need to add some lines to the right of our last list item
        while (Lines[Lines.Count - 1].PointB.X < Camera.Viewport.X + Camera.Viewport.Width)
        {
            Vector2 p1 = new Vector2(Lines[Lines.Count - 1].PointB.X, Lines[Lines.Count - 1].PointB.Y); ;
            Vector2 p2 = new Vector2(p1.X + Random.Next(5, 20), p1.Y + Random.Next(-5, 5));
            Line line = new Line(p1, p2, 1, Color.Black, LineTexture);
            Lines.Add(line);
        }

        base.Update(gameTime);
    }

    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(new Color(30, 90, 150));

        spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, Camera.View);

        foreach (Line line in Lines)
            line.Draw(spriteBatch);

        spriteBatch.End();

        base.Draw(gameTime);
    }
}

为了您的方便,我还添加了 Camera 类

public class Camera
{
    private const float zoomUpperLimit = 1.5f;
    private const float zoomLowerLimit = 0.1f;

    private float _zoom;
    private Vector2 _pos;

    private int ViewportWidth, ViewportHeight;

    #region Properties

    public float Zoom
    {
        get { return _zoom; }
        set
        {
            _zoom = value;
            if (_zoom < zoomLowerLimit)
                _zoom = zoomLowerLimit;
            if (_zoom > zoomUpperLimit)
                _zoom = zoomUpperLimit;
        }
    }

    public Rectangle Viewport 
    {
        get
        {
            int width = (int)((ViewportWidth / _zoom));
            int height = (int)((ViewportHeight / _zoom));
            return new Rectangle((int)(_pos.X - width / 2), (int)(_pos.Y - height / 2), width, height);
        }
    }

    public void Move(Vector2 amount)
    {
        _pos += amount;
    }

    public Vector2 Position
    {
        get { return _pos; }
        set { _pos = value; }
    }

    public Matrix View
    {
        get
        {
            return Matrix.CreateTranslation(new Vector3(-_pos.X, -_pos.Y, 0)) *
                    Matrix.CreateScale(new Vector3(Zoom, Zoom, 1)) *
                    Matrix.CreateTranslation(new Vector3(ViewportWidth * 0.5f, ViewportHeight * 0.5f, 0));
        }
    }

    #endregion

    public Camera(Viewport viewport, float initialZoom)
    {
        _zoom = initialZoom;
        _pos = Vector2.Zero;
        ViewportWidth = viewport.Width;
        ViewportHeight = viewport.Height;
    }

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多