0
\$\begingroup\$

I am drawing a line in XNA which I want to never end. I also have a tool that moves forward in X-direction and a camera which is centered at this tool. However, when I reach the end of the viewport the lines are not drawn anymore. Here are some pictures to illustrate my problem:

enter image description here

At the start the line goes across the whole screen, but as my tool moves forward, we reach the end of the line.

Here are the method which draws the lines:

        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;
    }
}

Here are the draw method in Game. The dots are my lines:

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);
}

Here's the next vector-method, It just finds me a new point where the line should be drawn with a new X-coordinate between 100 and 200 pixels and a random Y-coordinate between the old vector Y-coordinate and the height of the viewport:

        Vector2 nextVector (Vector2 vector)
    {
        return new Vector2 (vector.X + r.Next(100, 200), r.Next ((int)(vector.Y - 100), viewport.Height));
    }

Can anyone point me in the right direction here? I'm guessing it has to do with the viewport.width, but I'm not quite sure how to solve it. Thank you for reading!

\$\endgroup\$
  • 1
    \$\begingroup\$ If you want to draw a line that doesn't end on screen, you need to continue drawing new lines when the edge of your viewport reaches the line's end (off screen). Is this not your code or something? You don't seem to be sure how it even works. Since we don't know how the nextVector method works, we can't tell you why your line drawing stops. I suggest you explore the code a bit more and learn how it actually works. \$\endgroup\$ – MichaelHouse Aug 13 '14 at 13:48
  • \$\begingroup\$ That's exactly what I want to do, but I don't understand why my program stops drawing lines when it reaches the end off the screen, even tough I try to expand the viewport.Width. \$\endgroup\$ – user2236165 Aug 13 '14 at 14:08
  • \$\begingroup\$ @Andrzej Setting Viewport.Width changes the width of the viewport, not the length of your line. I'm confused. \$\endgroup\$ – Anko Aug 13 '14 at 15:37
  • \$\begingroup\$ Valid point @Anko. But I thought that my NextVector method would just keep generate new vectors that would keep getting drawn independent of the end of the screen. \$\endgroup\$ – user2236165 Aug 13 '14 at 16:22
1
\$\begingroup\$

If you want to continue to draw a line off screen, you need to continually update your code with a point that's off screen.

This means that your nextVector method should take the current position of the camera, plus half the screen width plus some buffer amount.

Then, whenever your camera moves the buffer amount in the x direction, you update the next vector. In this way, your line will always be just ahead of the camera's view port. Making the line appear to be endless.

\$\endgroup\$
0
\$\begingroup\$

I read this and thought it would be a fun exercise this morning, so I decided to write this for fun.

The implementation is pretty simple, keep adding lines at the end of each other until the last line is outside of the viewable area.

The following code will draw a line infinitely going right. As an added optimization, the lines on the left side of the screen are deleted as you pass them. You could easily make it retain the lines that were there previously, or also create lines going left as well. I will leave these exercises to you.

Take a look at the following Line class, which will define a single line on screen:

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);
    }

}

I wrote the implementation inside of a game class, since I was speedcoding. You can see the Game class below:

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);
    }
}

I've also included the Camera class for your convenience:

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);
        }
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.