How to delete prefab clones?,Can I delete Trail Renderer prefab clones?
Hello, I am currently creating an app where the user can draw on the screen after pressing a button. I also wanted to have an erase function where once the user is done drawing they can click another button to now erase whatever drawing they have done. I am new to unity and stuck on how I can create this eraser function to delete the drawings. I use a trail rendered to create the drawings and they become clones of a prefab. What do I do to delete these clones? Here is the code for the drawing--
using System.Collections; using System.Collections.Generic; using UnityEngine;
public class Draw : MonoBehaviour {
public GameObject drawPreFab;
GameObject theTrail;
Plane planeObject;
Vector3 startPos;
bool dr = false;
// Start is called before the first frame update
void Start()
{
planeObject = new Plane(Camera.main.transform.forward * -1, this.transform.position);
}
// Update is called once per frame
void Update()
{
dr = ClickExample.testBool;
if (dr == true)
{
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began || Input.GetMouseButtonDown(0))
{
theTrail = (GameObject)Instantiate(drawPreFab, this.transform.position, Quaternion.identity);
Ray mouseRay = Camera.main.ScreenPointToRay(Input.mousePosition);
float _dis;
if (planeObject.Raycast(mouseRay, out _dis))
{
startPos = mouseRay.GetPoint(_dis);
}
}
else if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved || Input.GetMouseButton(0))
{
Ray mouseRay = Camera.main.ScreenPointToRay(Input.mousePosition);
float _dis;
if (planeObject.Raycast(mouseRay, out _dis))
{
theTrail.transform.position = mouseRay.GetPoint(_dis);
}
}
}
}
} ,I am trying to make and app where once a button is pushed you can be able to 'erase' away what has been drawn on the screen. I'm very new to unity and am having trouble removing the prefab clones that are created when drawing on the screen. I am using a Trail renderer to create the prefab clones. Is there anyway to delete these prefab clones when the user clicks/touches over the clones? Here is the code --
using System.Collections; using System.Collections.Generic; using UnityEngine;
public class Draw : MonoBehaviour {
public GameObject drawPreFab;
GameObject theTrail;
Plane planeObject;
Vector3 startPos;
bool dr = false;
// Start is called before the first frame update
void Start()
{
planeObject = new Plane(Camera.main.transform.forward * -1, this.transform.position);
}
// Update is called once per frame
void Update()
{
dr = ClickExample.testBool;
if (dr == true)
{
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began || Input.GetMouseButtonDown(0))
{
theTrail = (GameObject)Instantiate(drawPreFab, this.transform.position, Quaternion.identity);
Ray mouseRay = Camera.main.ScreenPointToRay(Input.mousePosition);
float _dis;
if (planeObject.Raycast(mouseRay, out _dis))
{
startPos = mouseRay.GetPoint(_dis);
}
}
else if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved || Input.GetMouseButton(0))
{
Ray mouseRay = Camera.main.ScreenPointToRay(Input.mousePosition);
float _dis;
if (planeObject.Raycast(mouseRay, out _dis))
{
theTrail.transform.position = mouseRay.GetPoint(_dis);
}
}
}
}
}
Answer by highpockets · Mar 10, 2021 at 07:16 AM
At the moment you are not deleting/destroying anything with this script and you are not caching more than one clone at a time. If you want to just delete the whole drawing with this erase functionality, then I suggest you create a parent then when you instantiate theTrail
objects make them a child of that parent. So when you want to erase, you can just clear the children of the parent:
//when you instantiate, do this
theTrail = Instantiate(trailPrefab, this.transform.position, Quaternion.identity, parentTransform);
//when you delete, do this
void Delete()
{
//Destroy all children
while(parentTransform.childCount > 0)
{
Destroy(parentTransform.GetChild(0).gameObject);
}
}
On the other hand, if you want to erase one trail object at a time, you will have to either check the distance the “eraser” is from the trail objects and if it is within an allowable erase range you delete just that one object or you can add colliders to the trail and send a raycast, but depending on how big the drawing gets, this could be a heavy hit on performance
Thank you @highpockets , I declared a parent transform as follows: Transform parentTransform;
I then invoked the instantiate method as per your comment: theTrail = Instantiate(drawPreFab, this.transform.position, Quaternion.identity, parentTransform);
but when I try to use the deletion method, it seems that it is not working because transform.childCount seems to be returning a value of zero.
Do I have to explicitly create parentTransfrom before invoking the instantiate method (In addition to the current declaration)? If so, what would be the api call for that?
Thank you
Oops, I fixed my code above because I had the loop testing transform.childCount
, not parentTransform.childCount
. I also changed the for loop to a while loop because as you delete the objects the child count gets smaller and thus the for loop would not work the way I had it. Instead just wait while the parentTransform child count is more than 0. You would need to have the parent referenced in the script if that is what you are asking.
[SerializeField] private Transform parentTransform; //Set this in the editor to have access to it throughout the script
Here is a version of your code which includes it:
public GameObject drawPreFab;
GameObject theTrail;
[SerializeField] private Transform parentTransform;
Plane planeObject;
Vector3 startPos;
bool dr = false;
// Start is called before the first frame update
void Start()
{
planeObject = new Plane(Camera.main.transform.forward * -1, this.transform.position);
}
// Update is called once per frame
void Update()
{
dr = ClickExample.testBool;
if (dr == true)
{
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began || Input.GetMouseButtonDown(0))
{
theTrail = (GameObject)Instantiate(drawPreFab, this.transform.position, Quaternion.identity, parentTransform);
Ray mouseRay = Camera.main.ScreenPointToRay(Input.mousePosition);
float _dis;
if (planeObject.Raycast(mouseRay, out _dis))
{
startPos = mouseRay.GetPoint(_dis);
}
}
else if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved || Input.GetMouseButton(0))
{
Ray mouseRay = Camera.main.ScreenPointToRay(Input.mousePosition);
float _dis;
if (planeObject.Raycast(mouseRay, out _dis))
{
theTrail.transform.position = mouseRay.GetPoint(_dis);
}
}
}
public void Delete()
{
while(parentTransform.childCount > 0)
{
Destroy(parentTransform.GetChild(0).gameObject);
}
}
}
THANK YOU SO MUCH IT WORKS NOW! I really appreciate the help from you. In addition to using the SerializeField tag, I also had to set the parent explicitly in the inspector. Once again, thank you so much, you have made my day!
Here is my working code:
using System.Collections; using System.Collections.Generic; using UnityEngine;
public class Draw : MonoBehaviour {
public GameObject drawPreFab;
GameObject theTrail;
Plane planeObject;
Vector3 startPos;
bool dr = false;
[SerializeField] private Transform parentTransform;
// Start is called before the first frame update
void Start()
{
planeObject = new Plane(Camera.main.transform.forward * -1, this.transform.position);
}
// Update is called once per frame
void Update()
{
dr = ClickExample.testBool;
if (dr == true)
{
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began || Input.GetMouseButtonDown(0))
{
theTrail = (GameObject)Instantiate(drawPreFab, this.transform.position, Quaternion.identity, parentTransform);
Debug.Log("theTrail instant");
Ray mouseRay = Camera.main.ScreenPointToRay(Input.mousePosition);
float _dis;
if (planeObject.Raycast(mouseRay, out _dis))
{
startPos = mouseRay.GetPoint(_dis);
}
}
else if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved || Input.GetMouseButton(0))
{
Ray mouseRay = Camera.main.ScreenPointToRay(Input.mousePosition);
float _dis;
if (planeObject.Raycast(mouseRay, out _dis))
{
theTrail.transform.position = mouseRay.GetPoint(_dis);
}
}
} else
{
if(ClickExample.flippedBool == true)
{
ClickExample.flippedBool = false;
Delete();
}
}
}
void Delete()
{
Debug.Log("$$anonymous$$ETE CALLED");
Debug.Log(parentTransform.childCount);
//Destroy all children
for (int i = 0; i < parentTransform.childCount; i++)
{
Destroy(parentTransform.GetChild(i).gameObject);
}
}
}
Answer by ROBLOX_GOD · Aug 17, 2021 at 06:51 AM
@highpockets Have been working on the code, but cannot find a solution. If you are able to see this message, I'm still getting that problem where the first line drawn will be fine, but If I draw a second line, a third one will appear connecting the two. Code is below, once again thanks for all your help!
using System.Collections; using System.Collections.Generic; using UnityEngine;
public class Draw : MonoBehaviour {
public GameObject drawPreFab;
GameObject theTrail;
Plane planeObject;
Vector3 startPos;
bool dr = false;
bool drawObjectCreated = false;
[SerializeField] private Transform parentTransform;
// Start is called before the first frame update
void Start()
{
planeObject = new Plane(Camera.main.transform.forward * -1, this.transform.position);
}
// Update is called once per frame
void Update()
{
dr = ClickExample.testBool;
if (dr == true)
{
if (!drawObjectCreated&&(Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began || Input.GetMouseButtonDown(0)))
{
Debug.Log("theTrail instant");
//theTrail = (GameObject)Instantiate(drawPreFab, startPos, Quaternion.identity, parentTransform);
drawObjectCreated = true;
Ray mouseRay = Camera.main.ScreenPointToRay(Input.mousePosition);
float _dis;
if (planeObject.Raycast(mouseRay, out _dis))
{
theTrail = (GameObject)Instantiate(drawPreFab, this.transform.position, Quaternion.identity,parentTransform);
}
}
else if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved || Input.GetMouseButton(0))
{
Ray mouseRay = Camera.main.ScreenPointToRay(Input.mousePosition);
float _dis;
if (planeObject.Raycast(mouseRay, out _dis))
{
theTrail.transform.position = mouseRay.GetPoint(_dis);
}
Debug.Log("Child count is " + parentTransform.childCount);
}
} else
{
if(ClickClear.flippedBool == true)
{
ClickClear.flippedBool = false;
Delete();
}
}
}
void Delete()
{
Debug.Log("DELETE CALLED");
Debug.Log(parentTransform.childCount);
//Destroy all children
for (int i = 0; i < parentTransform.childCount; i++)
{
Destroy(parentTransform.GetChild(i).gameObject);
}
drawObjectCreated = false;
}
}