1

Hello I am trying to make a paint program using XNA and I followed the guide found in here as much as possible: How to create Paint-like app with XNA? And it worked all great so far however there is one issue: the drawn rectangles dont connect together to form a line. I am out of ideas and I would appreciate any help offered. Heres my code below. Please also take a look at the image attached to get a better understanding.

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;

namespace ProfAnas
{
/// <summary>
/// This is the main type for your game.
/// </summary>
public class Game1 : Game
{
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;
    Texture2D canvas;
    Vector2 brushPos;

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

        graphics.PreferredBackBufferWidth = 1920;  // set this value to the desired width of your window
        graphics.PreferredBackBufferHeight = 1080;   // set this value to the desired height of your window
        graphics.ApplyChanges();
    }

    /// <summary>
    /// Allows the game to perform any initialization it needs to before starting to run.
    /// This is where it can query for any required services and load any non-graphic
    /// related content.  Calling base.Initialize will enumerate through any components
    /// and initialize them as well.
    /// </summary>
    protected override void Initialize()
    {
        // TODO: Add your initialization logic here
        base.Initialize();

        Color[] pixel = new Color[1920 * 1080];
        for (int i = 0; i < pixel.Length; i++)
        {
            pixel[i] = Color.White;

        }

        pixel[1919] = Color.Red;

        spriteBatch = new SpriteBatch(GraphicsDevice);
        canvas = new Texture2D(this.GraphicsDevice, 1920, 1080);
        canvas.SetData<Color>(pixel);

    }

    /// <summary>
    /// LoadContent will be called once per game and is the place to load
    /// all of your content.
    /// </summary>
    protected override void LoadContent()
    {
        // Create a new SpriteBatch, which can be used to draw textures.
        spriteBatch = new SpriteBatch(GraphicsDevice);

        // TODO: use this.Content to load your game content here
    }

    /// <summary>
    /// UnloadContent will be called once per game and is the place to unload
    /// game-specific content.
    /// </summary>
    protected override void UnloadContent()
    {
        // TODO: Unload any non ContentManager content here
    }

    /// <summary>
    /// Allows the game to run logic such as updating the world,
    /// checking for collisions, gathering input, and playing audio.
    /// </summary>
    /// <param name="gameTime">Provides a snapshot of timing values.</param>
    protected override void Update(GameTime gameTime)
    {
        MouseState state = Mouse.GetState();

        Color[] pixel = new Color[1920 * 1080];
        canvas.GetData<Color>(pixel);

        if (state.LeftButton == ButtonState.Pressed)
        {
            brushPos.X = state.X;
            brushPos.Y = state.Y;

            double piOn4 = Math.PI / 4;

            int xComponent;
            int yComponent;

            int screenWidth = 1920;
            int screenHeight = 1080;

            int regionXHalfed = (int)Math.Ceiling((10.0 * Math.Cos(piOn4) + 30.0 * Math.Cos(piOn4))/2);
            int regionYHalfed = (int)Math.Ceiling((10.0 * Math.Sin(piOn4) + 30.0 * Math.Sin(piOn4))/2);

            double angle;
            double centerToBoundary;
            double pixelToCenter;
            List<int> boundedPixel = new List<int>();


            for (int row=(state.Y-regionYHalfed); row < (state.Y + regionYHalfed); row++)
            {
                for (int column= (state.X - regionXHalfed); column < (state.X + regionXHalfed); column++)
                {


                    xComponent=column - state.X+1;
                    yComponent=row - state.Y+1;

                    if (xComponent == 0)
                    {
                        pixelToCenter = Math.Sqrt((double)xComponent*xComponent + (double)yComponent*yComponent);

                        if (Math.Abs(pixelToCenter) <= 5*Math.Sqrt(2))
                        {
                            boundedPixel.Add(((row) * screenWidth + column) + 1);
                        }

                        continue;
                    }

                    angle=Math.Atan( (double)yComponent / (double)xComponent);



                    if (angle>= (piOn4 - Math.Atan(1.0/3)) && angle<= (piOn4 + Math.Atan(1.0/3)))
                    {
                        centerToBoundary = 15 / Math.Cos(angle - piOn4);
                        pixelToCenter= xComponent / Math.Cos(angle);

                        if( Math.Abs(pixelToCenter) <= Math.Abs(centerToBoundary))
                        {
                            boundedPixel.Add(((row)* screenWidth + column)+1);
                        }
                    }

                    if (angle >= (piOn4 + Math.Atan(1.0 / 3)) && angle <= Math.PI/2)
                    {
                        centerToBoundary = 5 / Math.Cos(angle + piOn4);
                        pixelToCenter = xComponent / Math.Cos(angle);

                        if (Math.Abs(pixelToCenter) <= Math.Abs(centerToBoundary))
                        {
                            boundedPixel.Add(((row) * screenWidth + column) + 1);
                        }
                    }
                    if (angle >= 0.0 && angle <= (piOn4 - Math.Atan(1.0 / 3)))
                    {
                        centerToBoundary = 5 / Math.Cos(angle + piOn4);
                        pixelToCenter = xComponent / Math.Cos(angle);

                        if (Math.Abs(pixelToCenter) <= Math.Abs(centerToBoundary))
                        {
                            boundedPixel.Add(((row) * screenWidth + column) + 1);
                        }
                    }

                    if (angle >= -Math.PI / 2 && angle <= 0.0)
                    {
                        centerToBoundary = 5 / Math.Cos(angle + piOn4);
                        pixelToCenter = xComponent / Math.Cos(angle);

                        if (Math.Abs(pixelToCenter) <= Math.Abs(centerToBoundary))
                        {
                            boundedPixel.Add(((row) * screenWidth + column) + 1);
                        }
                    }

                }
            }

            foreach (int i in boundedPixel)
            {
                if(i>=0)
                    pixel[i] = Color.Red;

            }
        }

        canvas.SetData<Color>(pixel);

        // TODO: Add your update logic here

        base.Update(gameTime);
    }

    /// <summary>
    /// This is called when the game should draw itself.
    /// </summary>
    /// <param name="gameTime">Provides a snapshot of timing values.</param>
    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.CornflowerBlue);

        // TODO: Add your drawing code here
        spriteBatch.Begin();
        spriteBatch.Draw(canvas, new Vector2(0, 0));
        spriteBatch.End();

        base.Draw(gameTime);
    }
}
}

Thank you :)

Community
  • 1
  • 1
Winneris1
  • 11
  • 3
  • 1
    This is happening because the distance the mouse moves between frames is longer than the width of your "brush." The example you followed simply doesn't account for this situation. You'll have to try something fancier. – adv12 Apr 27 '16 at 18:31

1 Answers1

0

As @adv12 suggested, the Update method of XNA games isn't as fast as the one of MSPaint's, and that's why you'll never have a line if drawing pixel-by-pixel (or in your case rectangle-by-rectangle) if you move your mouse fast across the canvas.

The possible solution is to draw new rectangles when you release left mouse button, between the rectangles that were created when left mouse button was pressed. That will give you twice -1 the rectangles you are currently drawing, and you will have a line, no matter how fast the Update is called.

Monset
  • 648
  • 5
  • 25