I'm facing the problem that i wish to destroy a parent object but i couldn't do so.
i wish to destroy User01 while bullet hit any of these child.
My code was as below.
JS:
function OnControllerColliderHit(col:ControllerColliderHit){
if(col.gameObject.tag == "Bullet"){
Destroy(col.transform.parent.gameObject);
}
}
C#:
public class PlayerDoe : MonoBehaviour {
private GameObject par;
// Use this for initialization
void Start () {
par = transform.parent.gameObject;
}
// Update is called once per frame
void Update () {
}
void OnCollisionHit(Collision col){
if (col.gameObject.tag == "Bullet") {
Destroy(par);
}
}
}
I believe you need to use OnCollisionEnter, instead of OnCollisionHit.
There is no OnCollisionHit(). You want to use OnCollisionEnter
void OnCollisionEnter(Collision collision)
{
if(col.gameObject.tag == "Bullet")
Destroy(transform.parent.gameObject);
}
Related
I've written code for destroying the player if it collides with an obstacle. But I get the error
The local function 'OnCollisionEnter' is declared but never used
My Code:
void Update()
{
void OnCollisionEnter(Collision col)
{
if (col.gameObject.tag = "Player")
{
Destroy(col.gameObject);
}
}
}
Your code should look like this:
void Update()
{
}
void OnCollisionEnter(Collision col)
{
if (col.gameObject.tag = "Player")
{
Destroy(col.gameObject);
}
}
You can theoretically define a function in your Update Method, they are called Local Functions.
But you can't do that with Unitys prepgroammed Functions eg. Start(), Update(), OnTriggerEnter(), OnCollisioEnter().
What you need to do instead, is take out your OnCollisionEnter() Function from the locally defined Update scope and instead place it into the MonoBehaviour Scope.
Example:
private void Update() {
}
private void OnCollisionEnter(Collision col) {
// Use CompareTag to get Error Message,
// when the Tag doesn't exist in the Scene
if (col.gameObject.CompareTag("Player")) {
Destroy(col.gameObject);
}
}
Unrelated:
I would also generally advise you to use CompareTag() instead of gameObjec.tag == "". Because CompareTag will throw an Error if there is no such Tag in your Scene and is therefore pretty usefull when you made a typo with the name of the Tag.
this is a pretty long code for a simple function but i can't seem to know how i can shorten it. any advice?
this is a simple script that i created for a beginner project and i placed the script inside the player object with both rigidbody2d and boxcollider2d and yeah it works and all, it toggles both the button gameobjects which is what i was going for in a sense but i wanted it to use only one button. if you can help with this as well i would appreciate it.
//different button objects
public GameObject smithbutton;
public GameObject innbutton;
private void OnTriggerEnter2D(Collider2D col)
{
//debugs which collider player is in
if (col.gameObject.name == "Blacksmith")
{
Debug.Log("This is the Blacksmith");
}
if (col.gameObject.name == "Inn")
{
Debug.Log("This is the Inn");
}
}
private void OnTriggerStay2D(Collider2D col)
{
//once playerobject stays, button will toggle till player leaves
if (col.gameObject.name == "Blacksmith")
{
Debug.Log("still on the Blacksmith's door");
smithbutton.SetActive(true);
}
if (col.gameObject.name == "Inn")
{
Debug.Log("still on the Inn's door");
innbutton.SetActive(true);
}
}
private void OnTriggerExit2D(Collider2D col)
{
//once playerobject exits, button will toggle and disappear
if (col.gameObject.name == "Blacksmith")
{
smithbutton.SetActive(false);
}
if (col.gameObject.name == "Inn")
{
innbutton.SetActive(false);
}
}
There is no much you could do, as the function is quite simple. You could make it better, and still reduce some of the lines. Using tag instead of name will be future proof if you create more Inns or more blacksmiths. Using the collider call a method will let you extend the functionality with ease. I will usually add each of this checks to the Inn and Blacksmiths myself, and they will be looking for the player.
//different button objects
[SerializeField] private GameObject smithbutton;
[SerializeField] private GameObject innbutton;
private void OnTriggerEnter2D(Collider2D col)
{
//debugs which collider player is in
if (col.gameObject.tag == "Blacksmith")
{
ButtonActivationToggle(smithbutton, col);
}
if (col.gameObject.tag == "Inn")
{
ButtonActivationToggle(innbutton, col);
}
}
private void OnTriggerExit2D(Collider2D col)
{
//once playerobject exits, button will toggle and disappear
if (col.gameObject.tag == "Blacksmith")
{
ButtonActivationToggle(smithbutton, col);
}
if (col.gameObject.tag == "Inn")
{
ButtonActivationToggle(innbutton, col);
}
}
public void ButtonActivationToggle(GameObject button, Collider2D collider)
{
bool tmp = false;
tmp = button.activeInHierarchy ? false : true;
button.SetActive(tmp);
if (button.activeInHierarchy)
{
Debug.Log("This is the " + gameObject.collider.tag)
}
}
you dont need the OnTriggerStay, you can do that in OnTriggerEnter and get rid of the Stay function.
public Button mybtn;
bool isBlacksmith; // keep track of where you are (you can later make it an enum if there are more than 2 places and check that)
void Start()
{
//when the button is clicked buttonFunction will be called
mybtn.onClick.AddListener(buttonFunction);
}
private void OnTriggerEnter2D(Collider2D col)
{
if (col.gameObject.name == "Blacksmith")
{
Debug.Log("Entered Blacksmith's door");
mybtn.gameObject.SetActive(true);
isBlacksmith = true;
}
if (col.gameObject.name == "Inn")
{
Debug.Log("Entered Inn's door");
mybtn.gameObject.SetActive(true);
isBlacksmith = false;
}
}
private void OnTriggerExit2D(Collider2D col)
{
//once playerobject exits, button will toggle and disappear
if (col.gameObject.name == "Blacksmith" || col.gameObject.name == "Inn")
{
smithbutton.SetActive(false);
}
}
public void buttonFunction()
{
if (isBlacksmith)
Debug.Log("In Blacksmith");
else
Debug.Log("In Inn");
}
I have wrote a code that semi-works for me. Everything works aside from working animation.
What I'm trying to do is that when Player enters trigger, and if he/she presses E it will perform an animation. (Animation is working fine btw, so it's just code error?).
Here's what I got so far:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class barTrigger : MonoBehaviour {
// press shit to drink text
public GameObject drinkText;
// bottle
public GameObject alcBottle;
// drink animator
public GameObject animatorOjbect;
Animator drinkAmin;
public bool triggerIsOn;
// Use this for initialization
void Start () {
drinkAmin = animatorOjbect.GetComponent<Animator> ();
drinkText.SetActive(false);
alcBottle.SetActive(false);
}
// Update is called once per frame
void Update () {
}
void OnTriggerEnter(Collider other){
triggerIsOn = true;
if (other.gameObject.name == "vThirdPersonController") {
drinkText.SetActive (true);
}
if (triggerIsOn && Input.GetKeyDown (KeyCode.E)) {
drinkAmin.Play ("Dab");
alcBottle.SetActive (true);
}
}
void OnTriggerExit(Collider other){
if (other.gameObject.name == "vThirdPersonController") {
drinkText.SetActive (false);
alcBottle.SetActive (false);
}
}
}
OnTriggerEnter is called once and it will be hard to get press the E button and get Input.GetKeyDown(KeyCode.E) to detect that at the-same time. Checking the E input in the OnTriggerStay function is more appropriate for this but OnTriggerStay does not work sometimes so count it out. Although it's worth knowing that it exist.
Move Input.GetKeyDown(KeyCode.E) to the Update function which is called every frame then set it to true in the OnTriggerEnter function and false in the OnTriggerExit function. Below are the code that should be changed.
void Update()
{
if (triggerIsOn && Input.GetKeyDown(KeyCode.E))
{
Debug.Log("E button pressed");
drinkAmin.Play("Dab");
alcBottle.SetActive(true);
}
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.name == "vThirdPersonController")
{
Debug.Log("Detected vThirdPersonController");
triggerIsOn = true;
drinkText.SetActive(true);
}
}
void OnTriggerExit(Collider other)
{
if (other.gameObject.name == "vThirdPersonController")
{
Debug.Log("Lost vThirdPersonController");
triggerIsOn = false;
drinkText.SetActive(false);
alcBottle.SetActive(false);
}
}
Once you get that working, starting using the CompareTag function instead of gameObject.name as that is more proficient.
My collider object has two child objects, there are camera and collider(is Triggered = true). I need to detect collision child collider and recognize all touched object by this child collider.
gameObject(CapsuleCollider(isTriggered = false), Rigidbody)
gameObject(Camera)
gameObject(CapsuleCollider(isTriggered = true))
I think this is wrong code, but maybe not, at least just for some imagination:
CapsuleCollider legsTrigger;
void Update()
{
legsTrigger= GetComponentInChildren<CapsuleCollider>();
if(legsTrigger.contact...){
Debug.Log("This is : ");
Debug.Log(legsTrigger.gameObject.tag);
}
}
You need to add a monobehaviour to your child. Otherwise you can't detect. If you want to check it from your parent gameobject, on this link there is a really nice solution for it by rsodre. I copied the codes from it and converted from 2D colliders to 3D.
Firstly, create a Bridge script between parent gameobject and childs
public class ColliderBridge : MonoBehaviour
{
ColliderListener _listener;
public void Initialize(ColliderListener l)
{
_listener l;
}
void OnCollisionEnter(Collision collision)
{
_listener.OnCollisionEnter(collision);
}
void OnTriggerEnter(Collider other)
{
_listener.OnTriggerEnter(other);
}
}
Then, add this ColliderBridge script to all childs, and then listen collision events from parent like this(Add ColliderListener script to parent gameobject).
public class ColliderListener : MonoBehaviour
{
void Awake()
{
// Check if Colider is in another GameObject
Collider collider = GetComponentInChildren<Collider>();
if (collider.gameObject != gameObject)
{
ColliderBridge cb = collider.gameObject.AddComponent<ColliderBridge>();
cb.Initialize(this);
}
}
public void OnCollisionEnter(Collision collision)
{
// Do your stuff here
}
public void OnTriggerEnter(Collider other)
{
// Do your stuff here
}
}
First of all, here's the code:
using UnityEngine;
using System.Collections;
namespace UltimateSurvival
{
public class Radiation : MonoBehaviour
{
public GameObject radiationEffect;
public EntityVitals Vitals { get { return m_Vitals; } }
private EntityVitals m_Vitals;
// Use this for initialization
void Start() {
InvokeRepeating ("OnTriggerEnter", 1.5f, 3.5f);
}
// Update is called once per frame
void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "Player")
{
radiationEffect.SetActive(true);
//yield return new WaitForSeconds(5);
var entity = other.GetComponent<EntityEventHandler>();
if(entity)
{
var healthEventData = new HealthEventData(-Random.Range(7.0f, 23.0f));
entity.ChangeHealth.Try(healthEventData);
}
//yield return new WaitForSeconds(5);
}
}
void OnTriggerExit(Collider other)
{
if (other.gameObject.tag == "Player")
{
radiationEffect.SetActive(false);
}
}
}
}
What I'm trying to do is that I want this script to execute OnTriggerEnter every 3.5 seconds. As you can see, I'm using InvokeRepeating but it seems like it doesnt work. I've also tried changing void OnTriggerEnter on IENumerator OntriggerEnter and then yield return new WaitForSeconds(5); - It didn't work either. I'm really confused D: Please help!
It seems you're trying to solve the problem of draining HP from the player if player is inside the area of radiation. This is a solution that will use most of your current code, but is not neccesarily the best code. I'd also like to inform you of OnTriggerStay, which
is called once per frame for every Collider other that is touching the trigger.
and can also be used to solve this problem. I'm going to use your already declared OnTriggerEnter and OnTriggerExit to damage every player inside area every 3.5 seconds.
public GameObject radiationEffect;
public EntityVitals Vitals { get { return m_Vitals; } }
private EntityVitals m_Vitals;
// Declare a list that will contain the players.
List<GameObject> playersInArea = new List<GameObject>();
// Use this for initialization
void Start() {
InvokeRepeating ("DamagePlayers", 1.5f, 3.5f);
}
void DamagePlayers() {
foreach (var player in playersInArea) {
var entity = player.GetComponent<EntityEventHandler>();
if(entity)
{
var healthEventData = new HealthEventData(-Random.Range(7.0f, 23.0f));
entity.ChangeHealth.Try(healthEventData);
}
}
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "Player")
{
playersInArea.Add(other.gameObject);
radiationEffect.SetActive(true);
}
}
void OnTriggerExit(Collider other)
{
if (other.gameObject.tag == "Player")
{
playersInArea.Remove(other.gameObject);
if (playersInArea.Count == 0) {
radiationEffect.SetActive(false);
}
}
}
Something like that should work. If you only have 1 player it should work all the same, but this supports multiple players. Let me know if you have any further issues.
You have problems calling your method using InvokeRepeating because of two reasons:
InvokeRepeating can not be used with method that have parameters: you probably have the Trying to Invoke method: [...] couldn't be called. message in your console.
OnTriggerEnter is a method that is automatically called by Unity when the gameobject's collider is set as Trigger and another collider enters it: as #Hellium said, calling such methods manually is a bad idea (same as calling Start or Update manually: this can happen but really doesn't make sense in most of the scenarios).
Hope this helps,