I am setting up a simple scene with a wall, 3 green bottles, and a target.
When the mouse is clicked on a bottle the bottle is destroyed.
I only know how to do this with 1 bottle, by loading that gameObject manually into a public variable in the Target Controller script. As per screenshot below. This means whenever any bottle gets hit, only that one actually falls.
What I want is, all the bottles in scene (as new ones will be added at run-time) to be added into an array / list. And then when one is shot at, that particular one falls.
How do I do this? I have given my bottles the tag āBottlesā.
I have tried using lists and arrays (though possibly incorrectly) but I canāt get it to access that function for that particular item hit.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class TargetController : MonoBehaviour {
private Camera cam;
private Image player1;
public BottleManager bottles;
// Use this for initialization
void Start () {
cam = GameObject.Find("Main Camera").GetComponent<Camera>();
player1 = GetComponentInChildren<Image> ();
}
// Update is called once per frame
void Update () {
player1.transform.position = Input.mousePosition;
Ray ray = cam.ScreenPointToRay (new Vector3 (Input.mousePosition.x, Input.mousePosition.y, 0));
Debug.DrawLine (ray.origin, ray.direction * 10, Color.red);
RaycastHit hitInfo;
int layerMask = 8;
if (Input.GetMouseButton(0)) {
if (Physics.Raycast (ray, out hitInfo, 300)) {
if (hitInfo.transform.gameObject.layer == layerMask) {
bottles.hit (); // this function just contains the line "rb.AddForce (transform.forward * 100);"
//Destroy (hitInfo.collider.gameObject);
}
}
}
}
}
You could add a tag to the bottle prefab (e.g. āBottleā).
When raycasting, check to see if the collider has the Bottle-tag. If it doesn, destroy it.
Something like this:
float dist = 100; //set to fit project
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if(Physics.Raycast(ray, out hit, dist))
{
if(hit.collider.tag == "Bottle")
{
Destroy(hit.tranform.gameObject);
}
}
With this code attached to e.g. a game manager or any object really, you should be able to shoot away your bottles without them having to be in any kind of list or array, as long as the bottles have the āBottlesā tagā¦
To add a tag, select the prefab. Access the tag dropdown below the name of the game object. If you donāt see a tag that you want to use, add a custom one by clicking āAdd Tagā or something like that. Then simply add a new one to the list in the new menu. Remember to add this new tag to the bottle afterwards, as Unity doesnāt do this automatically after creating a new tag.
If you want to optimize this further, you could also put the bottles on a separate raycast layer, and then only accept collisions from that layer. In this case, itās not required though.
Thatās great thank you! I had something very similar at one stage but did not use .collider after hit so it didnāt work.
This now destroys each bottle I click on.
But how can I pass that bottle identity to my bottles.hit() function? As currently if this is enabled force is still only being applied to the bottle dropped into my public variable (as per first image)
This is why I thought I needed to have all bottles in an array.
Can I detect the rigid body of a raycast collision and apply force to the bottle that way?
setup the bottles.hit() to accept a game object/transform/rigidbody as a parameter. This way, you can pass in what you hit with the raycast and act on it.
move the code from a centralized spot, to a script instance on each bottle. Then, ābottle.hit()ā (or some other name for the method) is a component on the bottle, already knows itself, and you can look it up and call it when hit with the raycast.