Search Unity

Raycasting and Making Second Object Do Something

Discussion in 'Scripting' started by relic1882, Mar 29, 2015.

  1. relic1882

    relic1882

    Joined:
    Mar 11, 2015
    Posts:
    45
    Although I've been learning a whole lot in the past few weeks, I've yet to figure this out.

    I have my character that's throwing out a raycast only a very short distance away so that when he grabs at the npc, it determines if the npc is within grasp before continuing on to changing animations. My question is, how do I get the npc to receive the data that they have been grabbed so that I can go into their script and change animations, health and stuff.

    Here's my code of the player grabbing at the npc:

    Code (CSharp):
    1.     void Attack()
    2.     {
    3.         if (Input.GetButtonUp("Fire1") && eatVictim == false)
    4.         {
    5.             attacking = true;
    6.             anim.SetBool("isAttacking", true);  //set isAttacking true so animation plays right
    7.  
    8.             //cycles through audio clip for the zombie attack
    9.             if (clipNumber < 1)
    10.             {
    11.                 clipNumber++;
    12.             }
    13.             else clipNumber = 0;
    14.             audio.PlayOneShot(zombieTalk[clipNumber]);  //play currently selected audio clip for attacking
    15.         }
    16.  
    17.         if(attacking)           //determine if currently attacking
    18.         {
    19.             //determines if still attacking within the timeframe of the animation (WaitToAttack)
    20.             //WaitToAttack must be in sync with time it takes to animate the actual attack
    21.             if(AttackTime < WaitToAttack)
    22.             {
    23.                 canMove = false;    //shut off user movement input during attack
    24.                 if (AttackTime < 0.5f) controller.Move(moveDirection * Time.deltaTime * attackSpeedBoost);
    25.                 //print("Time since attack is " + AttackTime);
    26.                 AttackTime += Time.deltaTime;
    27.             }
    28.             if (AttackTime >= WaitToAttack && eatVictim == false)
    29.             {
    30.                 anim.SetBool("isAttacking", false);
    31.                 print("Attack finished");
    32.                 canMove = true;
    33.                 attacking = false;
    34.                 AttackTime = 0f;
    35.             }
    36.             //check to see if InnocentHuman victim is within grab range. If so, begin eating
    37.             Ray ray = new Ray(transform.position, transform.forward);
    38.             RaycastHit hit;
    39.             if (Physics.Raycast(ray, out hit, 0.9f))
    40.             {
    41.                 if (hit.collider.gameObject.tag == "InnocentHuman") //check if innocent human is in grasp
    42.                 {
    43.                     eatVictim = true;
    44.                     rayhits++;
    45.                     print("Raycast Hit Victim " + rayhits + " times");
    46.                 }
    47.             }
    48.             //if InnocentHuman is within range, begin eating animation
    49.             if(eatVictim)
    50.             {
    51.                 anim.SetBool("isEating", true);
    52.                 //still looking into how to sent the "being eaten" info to the other script of the victim
    53.             }
    54.  
    55.         }
    56.  
    57.  
    58.     }
    So how can I proceed to have my other script take in the fact that they are being eaten? After line 49 is when I need to send the info to the npc. Will help explain to me how to do it? Thanks.
     
  2. julienkay

    julienkay

    Joined:
    Nov 12, 2013
    Posts:
    170
    Look up RaycastHit in the documentation. The structure gives you information about the object being hit by the raycast. You should be able to use this to access your script:
    Code (CSharp):
    1. hit.transform.gameObject.GetComponent<YourScript>();
    However, depending on the usecase, a cleaner way to accomplish what you want could be to use events. Your NPCs would basically subscribe to an "eating" event on your players script if they are in close range to the player. Check this link for more info: https://unity3d.com/learn/tutorials/modules/intermediate/scripting/events
     
  3. relic1882

    relic1882

    Joined:
    Mar 11, 2015
    Posts:
    45
    Looks like today's lesson plan is set in stone then. Thanks! :)
     
  4. relic1882

    relic1882

    Joined:
    Mar 11, 2015
    Posts:
    45
    Ok so I'm having a little trouble learning how to get script access for my situation using GetComponent like you say here
    Code (CSharp):
    1. 1.hit.transform.gameObject.GetComponent<YourScript>();
    So how would I use it? With the check I have now after the Raycast I'm checking to make sure there is a victim right in front of the player when the attack sequence starts:
    Code (CSharp):
    1. if (Physics.Raycast(ray, out hit, 0.9f))
    2.             {
    3.                 if (hit.collider.gameObject.tag == "InnocentHuman") //check if innocent human is in grasp
    4.                 {
    5.                     eatVictim = true;
    6.                     rayhits++;
    7.                     print("Raycast Hit Victim " + rayhits + " times");
    8.                 }
    9.             }
    So if the Raycast hits an object tagged as an "InnocentHuman" the animation continues to do what I'm planning with the next if statement:
    Code (CSharp):
    1.             //if InnocentHuman is within range, begin eating animation
    2.             if(eatVictim)
    3.             {
    4.                 anim.SetBool("isEating", true);
    5.             }
    So to get script access to the Innocent human being hit by the raycast, how would I use it to pass on some info that the victim has to run a function to animate and die? I also need it to be universal to multiple instances of InnocentHumans walking around the map. Right now my other script is called "BlondeGirlAI.cs". The function I'm going to write in that script is going to be along the lines of:
    Code (CSharp):
    1.     void GettingEaten()
    2.     {
    3.         if(being eaten)     //has to come from when other script attacks while in range AND facing character
    4.         {
    5.             //immobilize character
    6.             //change animation to being eaten
    7.             //set health to dead
    8.             //change animation to dead
    9.             //turn off character
    10.         }
    11.     }
    I need more help. Maybe I'm way overthinking it but I can't figure out what to do in my circumstance.
     
  5. Korno

    Korno

    Joined:
    Oct 26, 2014
    Posts:
    518
    Code (CSharp):
    1.     if (Physics.Raycast(ray, out hit, 0.9f))
    2.                 {
    3.                     if (hit.collider.gameObject.tag == "InnocentHuman") //check if innocent human is in grasp
    4.                     {
    5.                         eatVictim = true;
    6.                         rayhits++;
    7.                         print("Raycast Hit Victim " + rayhits + " times");
    8.                        // HERE HERE HERE!
    9.                        hit.collider.gameObject.GetComponent<BlondGirlAI>().GettingEaten();
    10.                     }
    11.                 }
    12.  
    Something like that. Make sure GettingEaten is public.

    ALSO, as the poster above said another way is to use events. While in this case it might not be needed, it would allow multiple objects to be notified when the player is eating a human (imagine people nearby reacting and screaming and running away or something)
     
  6. relic1882

    relic1882

    Joined:
    Mar 11, 2015
    Posts:
    45
    So you're saying as long as the function of my other script is
    Code (CSharp):
    1. public void GettingEaten()
    2. {
    3.                 //get eaten and do stuff
    4. }
    5.  
    I can easily call to that script in a different object with hit.collider.gameObject.GetComponent<BlondGirlAI>().GettingEaten();

    Working on it now. Thanks for the help guys!

    I will be looking into events after I get this all in my head. This is my first project. Baby steps, right? :)
     
  7. Korno

    Korno

    Joined:
    Oct 26, 2014
    Posts:
    518
    Yeah gameObject.GetComponent<type>() returns a reference (handle) to the component of "type" belonging to that game object. Its a little complicated to explain how it works under the hood but its a useful feature.

    Be careful though, if the gameObject doesnt have a component of that type attached, it will return null.

    What you are basically saying in that code is: The gameobject that my raytrace hit, please give me your BlondGirlAI component. And then you use that reference to call its GettingEaten method.

    Avoid using GetComponent too often though, don't use it in Update or FixedUpdate every frame if possible as it is an expensive method.
     
  8. relic1882

    relic1882

    Joined:
    Mar 11, 2015
    Posts:
    45
    No problem. I only need it for instances like this where it's a one time shot for the object that is about to die. Then I turn off the navigation for that object. The only thing I have to figure out now to complete this part is completely disabling the object or retagging it to "dead" so that my attacking calls no longer factor in its position. Thanks again!