Drawing system?

My current attempt at this works if the player doesn’t move his mouse too quickly, but as soon as he starts moving his mouse at an average speed gaps in between pixels appear, which I don’t want.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[System.Serializable]
public class Draw : MonoBehaviour
{
    public GameObject pixel;

    void Update()
    {
       if ( Input.GetKey(KeyCode.Mouse0) )
        {
            Vector3 mousePos = Input.mousePosition;
            mousePos.z = 15;

            Vector3 pos = Camera.main.ScreenToWorldPoint(mousePos);
            Instantiate(pixel, pos, Quaternion.identity);
        }
    }
}

If I just make the pixels bigger it gets rid of the problem, but it also takes away the crisp, smooth look. How can I fix this problem?

You’ll need to keep track of the mouse position from last frame and make sure you draw pixels between the current position and previous position if there’s a gap. I don’t think using a GameObject for each pixel in the line is going to be very scalable/efficient though. Probably better to be writing pixels to a Texture.

2 Likes

Thanks for the advice. I don’t think I can use a texture because I want the blocks the player is drawing to interact with other objects.

Could you give me some advice on how to do what you said, I’m too dumb haha.

I was also wondering if I could somehow make a line renderer a physical object, like have the line interact with other objects. Because it would make this a whole lot easier in my opinion.

Something like this:

public class Draw : MonoBehaviour
{
    public GameObject pixel;
    public float maxDist = 10f;
    private Vector3 oldPos;
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Mouse0))
        {
            Vector3 mousePos = Input.mousePosition;
            mousePos.z = 15;
            Vector3 oldPos = Camera.main.ScreenToWorldPoint(mousePos);
        }
        if (Input.GetKey(KeyCode.Mouse0))
        {
            Vector3 mousePos = Input.mousePosition;
            mousePos.z = 15;
            Vector3 pos = Camera.main.ScreenToWorldPoint(mousePos);
            float d = (pos - oldPos).magnitude;
            int c = Mathf.FloorToInt(d / maxDist);
            for(int i = 0; i <= c; i++)
                Instantiate(pixel, Vector3.Lerp(oldPos, pos, (float)i/c), Quaternion.identity);

            oldPos = pos;
        }
    }
}

Actually when instantiating objects you probably want to do a min distance check as well and not drawing anything unless you moved at least a certain distance. Otherwise you would create a “pixel” every frame as long as you hold down the mouse button. This could be achieved by something like this:

public class Draw : MonoBehaviour
{
    public GameObject pixel;
    public float maxDist = 10f;
    private Vector3 oldPos;
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Mouse0))
        {
            Vector3 mousePos = Input.mousePosition;
            mousePos.z = 15;
            Vector3 oldPos = Camera.main.ScreenToWorldPoint(mousePos);
            Instantiate(pixel, oldPos, Quaternion.identity);
        }
        if (Input.GetKey(KeyCode.Mouse0))
        {
            Vector3 mousePos = Input.mousePosition;
            mousePos.z = 15;
            Vector3 pos = Camera.main.ScreenToWorldPoint(mousePos);
            float d = (pos - oldPos).magnitude;
            int c = Mathf.FloorToInt(d / maxDist);
            if (c > 0)
            {
                for (int i = 1; i <= c; i++)
                    Instantiate(pixel, Vector3.Lerp(oldPos, pos, (float)i / c), Quaternion.identity);
                oldPos = pos;
            }
        }
    }
}

Here we only update oldPos when we actually drew new pixels. So if you keep your mouse still after drawing the last pixel, the distance would be smaller than the minimum required distance and nothing is drawn. As soon as you move further away from the last drawn location we draw a new “pixel”.

Keep in mind if those pixels actually have colliders on them, they should have a rigidbody on them as well (maybe a kinematic one). You also want to place that pixels on a seperate layer and disable collisions within that layer. So the pixels can collide with other things but not with each other.

Finally note that the “visual” drawing does not necessarily match the logical drawing of your pixel objects. Always keep in mind those could be completely seperate concepts. We had a related question on UA. This is the result of my script in action.

1 Like