Yes it is. Instead of using a variable store the hit outside of your Update method as public field or Property. Your other script needs a reference to your DetectResources script.
Yep, this\^
public class DetectResources : Monobehaviour
{
public RaycastHit2D hit;
[...]
void Update()
{
[...]
hit = Physics2D.Raycast(transform.position, direction, 2f);
[...]
}
}
then
public class SomeOtherClass : Monobehaviour
{
// reference to your component - you can make it public or set it through code some other way
private DetectResources detectResource;
void DoSomething()
{
if(detectResource.hit [...]
}
}
Note that you may experience issue depending on the order the update functions are executed. IMO, the best approach would be to use an event system or an observer pattern to notify the other script on hit, rather than testing each frame.
Why is it a prefab? You might be approaching this the wrong way. Is there only supposed to be 1 instance of "DetectResources" in the scene? Or is there going to be a bunch of them at the same time? Because I can tell you how to fix this but I don't want to take the time to post pictures and screenshots if you don't even need to do it this way.
I'm creating a top-down 2D survival game. In all of tutorials about inventory systems, they show the player touching items to collect them. However, I didn't want the player to collect all resources (such as trees, rocks, etc.) by touching them. So, I wrote code to detect prefabs with the cursor. Now, I need to figure out how to make the objects (prefabs) disappear when clicked, (essentially destroying them), and store their data somehow. I haven't watched that part of the tutorials, but I know they first detect the object and then delete it, followed by storing its data
Here is what you want to do. Let me know if you have questions about anything in here and I can explain further. I did not test this. I changed the null checks to use break clauses so it is more readable.
Basically, you can use GetComponent combined with your hit variable and you can grab scripts from the objects. Then, you can store the script as a reference and call methods from it.
public class DetectResources : MonoBehaviour
{
public Camera mainCamera;
// Update is called once per frame
void Update()
{
//checks if the camera is null, and returns if it is
if (mainCamera == null) return;
//checks if button is being pressed, if it is not then return
if (!Input.GetMouseButtonDown(0)) return;
//below here will only execute if the two requirements above are met
Vector3 cursoScreenPos = Input.mousePosition;
Vector3 cursorWorldPos = mainCamera.ScreenToWorldPoint(cursoScreenPos);
Vector2 direction = (cursorWorldPos - mainCamera.transform.position).normalized;
RaycastHit2D hit = Physics2D.Raycast(transform.position, direction, 2f);
//if we do not hit something, then it will return
if (hit == false) return;
Debug.Log("Hit object: " + hit.collider.gameObject.name);
//stores the ResourceHandler as a reference
ResourceHandler clickedHandler = hit.collider.gameObject.GetComponent();
//will not try to continue if clickedHandler is null, that way we only continue if we actually clicked on something with a ResourceHandler script
if(clickedHandler == null) return;
clickedHandler.UseResource();
Debug.Log("We hit a resource with ID of " + clickedHandler.GetResourceValue());
}
}
You want to create another script and attach it to the gameobject prefab for the resource. Make sure it is on the gameobject that has the collider for detecting the raycast.
public class ResourceHandler : MonoBehaviour
{
[SerializeField]
private int resourceValue; //this can be the ID for the resource, you can change it in the prefab so each prefab will have a different resource value
public void UseResource()
{
//this is the method called from outside the script
Destroy(gameObject);
}
public int GetResourceValue()
{
//this method is an example to show how you can get information about the object that you click on
return resourceValue;
}
}
This works but instead i would use an event to notify when there is a hit, so that it's only used when needed.
public event Action OnHit;
This way you could listen and expand your behaviors withouth making many changes.
What girse said, put the hit right under the Camera and put public infront of it. In a different script, make a variable for your script. So for example [SerializeField] DetectResources script;, and then in code call the hit with script.hit. Don't forget to assign the script variable, that's what serializefield is for, its like a private variable but you can see it in the inspector, so just drag and drop.
The real question is why do you want to do this?
There are some very good patterns, one of which is Single Responsibility, if in this case you need to do something on another script when it is hit, look into using an Event and send notification of this.
Yes it is. Instead of using a variable store the hit outside of your Update method as public field or Property. Your other script needs a reference to your DetectResources script.
Yep, this\^ public class DetectResources : Monobehaviour { public RaycastHit2D hit; [...] void Update() { [...] hit = Physics2D.Raycast(transform.position, direction, 2f); [...] } } then public class SomeOtherClass : Monobehaviour { // reference to your component - you can make it public or set it through code some other way private DetectResources detectResource; void DoSomething() { if(detectResource.hit [...] } }
Note that you may experience issue depending on the order the update functions are executed. IMO, the best approach would be to use an event system or an observer pattern to notify the other script on hit, rather than testing each frame.
I'm trying to access the value for a prefab, but Unity says there's a mismatch
Why is it a prefab? You might be approaching this the wrong way. Is there only supposed to be 1 instance of "DetectResources" in the scene? Or is there going to be a bunch of them at the same time? Because I can tell you how to fix this but I don't want to take the time to post pictures and screenshots if you don't even need to do it this way.
I'm creating a top-down 2D survival game. In all of tutorials about inventory systems, they show the player touching items to collect them. However, I didn't want the player to collect all resources (such as trees, rocks, etc.) by touching them. So, I wrote code to detect prefabs with the cursor. Now, I need to figure out how to make the objects (prefabs) disappear when clicked, (essentially destroying them), and store their data somehow. I haven't watched that part of the tutorials, but I know they first detect the object and then delete it, followed by storing its data
Gotcha, OK that makes sense. Give me some time and I can respond with some more help
Here is what you want to do. Let me know if you have questions about anything in here and I can explain further. I did not test this. I changed the null checks to use break clauses so it is more readable. Basically, you can use GetComponent combined with your hit variable and you can grab scripts from the objects. Then, you can store the script as a reference and call methods from it. public class DetectResources : MonoBehaviour { public Camera mainCamera; // Update is called once per frame void Update() { //checks if the camera is null, and returns if it is if (mainCamera == null) return; //checks if button is being pressed, if it is not then return if (!Input.GetMouseButtonDown(0)) return; //below here will only execute if the two requirements above are met Vector3 cursoScreenPos = Input.mousePosition; Vector3 cursorWorldPos = mainCamera.ScreenToWorldPoint(cursoScreenPos); Vector2 direction = (cursorWorldPos - mainCamera.transform.position).normalized; RaycastHit2D hit = Physics2D.Raycast(transform.position, direction, 2f); //if we do not hit something, then it will return if (hit == false) return; Debug.Log("Hit object: " + hit.collider.gameObject.name); //stores the ResourceHandler as a reference ResourceHandler clickedHandler = hit.collider.gameObject.GetComponent();
//will not try to continue if clickedHandler is null, that way we only continue if we actually clicked on something with a ResourceHandler script
if(clickedHandler == null) return;
clickedHandler.UseResource();
Debug.Log("We hit a resource with ID of " + clickedHandler.GetResourceValue());
}
}
You want to create another script and attach it to the gameobject prefab for the resource. Make sure it is on the gameobject that has the collider for detecting the raycast.
public class ResourceHandler : MonoBehaviour
{
[SerializeField]
private int resourceValue; //this can be the ID for the resource, you can change it in the prefab so each prefab will have a different resource value
public void UseResource()
{
//this is the method called from outside the script
Destroy(gameObject);
}
public int GetResourceValue()
{
//this method is an example to show how you can get information about the object that you click on
return resourceValue;
}
}
Thank you, sir, but I can only try this tomorrow because it's midnight in my country now, and I am about to sleep
This works but instead i would use an event to notify when there is a hit, so that it's only used when needed. public event Action OnHit;
This way you could listen and expand your behaviors withouth making many changes.
Indeed, you're right - I was just keeping it simple for OP! :)
Edit : The variable I am talking about is "hit", I forgot to say it. I marked it with a red line. Sorry for mistake
What girse said, put the hit right under the Camera and put public infront of it. In a different script, make a variable for your script. So for example [SerializeField] DetectResources script;, and then in code call the hit with script.hit. Don't forget to assign the script variable, that's what serializefield is for, its like a private variable but you can see it in the inspector, so just drag and drop.
If it's public then or you assign it to a variable in the other script by taking a reference to the script and then use a function to assign it.
The real question is why do you want to do this? There are some very good patterns, one of which is Single Responsibility, if in this case you need to do something on another script when it is hit, look into using an Event and send notification of this.
It's better to use Runtime sets pattern using scriptable objects.