在鼠标坐标处将预制件实例化到画布

时间:2019-04-07 13:25:36

标签: c# unity3d

在我当前正在从事的项目中,我让用户单击一个区域,稍后将其放置在环境中。我想通过在画布上放置简单的标记来可视化它们放置的内容,以便在它们添加和删除点时标记也可以来回移动。

我已经找到了一些有关如何开始的资源,列出了如何将预制件实例化到画布中,但这似乎对我没有用。我觉得这一定与我使用坐标的方式有关,但我不确定。

public GameObject markerPrefab;

然后在另一个函数中

GameObject boatMarker = Instantiate(markerPrefab, Input.mousePosition, Quaternion.identity);
boatMarker.transform.SetParent(GameObject.FindGameObjectWithTag("Canvas").transform, false);

代码运行,并且预制件确实进入了场景,但是它们都出现在画布的右上角,一种在另一种之上。有任何想法我在这里做错了吗?另外,虽然我不想让你们为我编写代码,但对于以后如何删除预制件的特定实例有什么建议吗?

2 个答案:

答案 0 :(得分:2)

我要说的主要问题是您正在使用带有第二个参数false的{​​{3}}

  

如果使用true,则会修改父相对位置,比例和旋转,使对象保持与以前相同的世界空间位置,旋转和比例。

对于您而言,您想要保持相同的世界空间位置。

由于您的画布为Screenspace overlay,因此其宽度和高度(以Unity单位为单位)与显示/窗口像素的宽度和高度完全匹配。因此,当您这样做

GameObject boatMarker = Instantiate(markerPrefab, Input.mousePosition, Quaternion.identity);

已经的对象处于正确的位置。为了直观地看到我只是给它一个立方体,所以您看到它在我单击的位置已经生成了(您看不到该图像,因为它不是Canvas的孩子):

SetParent

如果将那个false参数传递给SetParent会发生什么,那就是它不会保留其当前的世界空间位置,而是保留其当前的localPosition并移至其父对象中的相对位置。由于它是Canvas,而您的预制件也可能也使用RectTransform,因此产生的位置取决于许多因素,例如预制RectTransform的枢轴和锚点设置,例如Canvas Scaler-> Scale Factor

如果您的预制件例如锚定在中心(通常是默认值)上,而您恰好单击窗口的中心,它将显示在右上角。

enter image description here

为什么?

  1. 您单击(windowWidth / 2, WindowHeight / 2)。因此,预制件最初是在此处生成的

  2. 比起false使用SetParent,它可以保持该位置,但是这次相对于Canvas的中心

    =>画布位置的中心是(windowWidth / 2, WindowHeight / 2),因此添加本地预制坐标(windowWidth / 2, WindowHeight / 2)会导致最终位置(WindowWidth, WindowHeight) ==右上角。


因此,您可以通过将预制件固定在左下角来解决此问题

enter image description here

或者不要将false作为参数传递给SetParent

boatMarker.transform.SetParent(_canvas.transform);

您实际上也可以在一个电话中完成

Instantiate(markerPrefab, Input.mousePosition, Quaternion.identity, _canvas.transform);

此外,您不应一次又一次使用FindObjectWidthTag。我宁愿只获取一次,甚至在可能的情况下通过检查器进行引用:

public GameObject markerPrefab;

[SerializeField] private Canvas _canvas;

private void Awake()
{
    // If no canvas is provided get it by tag
    if (!_canvas) _canvas = GameObject.FindGameObjectWithTag("Canvas").GetComponent<Canvas>();
}

// Update is called once per frame
private void Update()
{
    if (Input.GetMouseButtonDown(0))
    {
       Instantiate(markerPrefab, Input.mousePosition, Quaternion.identity, _canvas.transform);
    }
}

enter image description here

答案 1 :(得分:0)

尝试一下:
1-将按钮插入“画布”
2-获取此按钮的Gameobject参考
3-将按钮分配给button变量,将游戏画布分配给代码Canvas变量后,尝试此代码,它将正常工作

    public GameObject refButton;
    public GameObject canvas;
    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            GameObject button = Instantiate(refButton, Input.mousePosition,Quaternion.identity);
            button.transform.SetParent(canvas.transform);
        }
    }