• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
1
Question by GrannySmith · Aug 22, 2012 at 01:49 PM · prefabinstances

How to access method of only one instance of prefab?

I'm making an Android App with Augmented Reality. I have a prefab of a 3D Playbutton and when the user touches on it, a specific youtube video shall be opened. On the prefab is the following Javascript attached:

 private var links = new Hashtable();
 
 function Start(){
     links = {
     "FrameMarker0" : "http://www.XXXXXXXXXX.net",
     "FrameMarker6" : "http://www.youtube.com/watch?v=XXXXXXXXXX",
     "FrameMarker7" : "http://www.youtube.com/watch?v=XXXXXXXXXX",
     "FrameMarker8" : "http://www.youtube.com/watch?v=XXXXXXXXXX",
     "FrameMarker9" : "XXXXXXXXXX",
     "FrameMarker12" : "http://www.youtube.com/watch?v=XXXXXXXXXX",
     "FrameMarker14" : "http://www.youtube.com/watch?v=XXXXXXXXXX",
     "FrameMarker15" : "http://www.youtube.com/watch?v=XXXXXXXXXX",
     "FrameMarker16" : "http://www.youtube.com/watch?v=XXXXXXXXXX",
     "FrameMarker17" : "http://www.youtube.com/watch?v=XXXXXXXXXX",
     "FrameMarker18" : "http://www.youtube.com/watch?v=-XXXXXXXXXX"
     };
 }
 
 function Update(){
     for( var i : int; i < Input.touchCount; i++)
     {    
         if(Input.GetTouch(i).phase == TouchPhase.Ended)
         {
             var hit : RaycastHit;
             var ray : Ray = Camera.main.ScreenPointToRay(Input.GetTouch(i).position);
             if (Physics.Raycast(ray, hit, Mathf.Infinity))
             {
                 if(hit.collider.name == gameObject.name)
                 {
                     this.onTouch();
                 }
             }
         }
     }
 }
 
 function onTouch(){
     Application.OpenURL(links[gameObject.transform.parent.name]);
 }

gameObject.transform.parent.name is called because the Playbutton is a child of the marker which is used for the Augmented Reality, but this shouldn't be the problem. The problem is that the method onTouch() will be called for every single instance in the scene. Therefore every youtube video will be opened, of course I only want to open the one video the user clicked on. I know that in such cases I should not call any static variables and so on, but I don't know how to handle methods of instances in this case. Is the Update() method kind of static? If yes how can I handle the touchinput? I know that many similar questions have been asked, but I couldn't find how to cope with methods of a specific instance.

Comment
Add comment · Show 1
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Khada · Aug 22, 2012 at 02:01 PM 0
Share

The update method is NOT static at all. It runs on all objects that you have that scrip attached to. If you don't want that update method to run on more than one object, you need to move its contents into a single, manager style object.

1 Reply

· Add your reply
  • Sort: 
avatar image
1
Best Answer

Answer by lpye · Aug 22, 2012 at 03:55 PM

Hi GrannySmith, (um... what big eyes you have?)

As Khada pointed out, Update is not a static function. It is called on each instance where the script is attached to an object in the scene.

There a few recommendations I would suggest. I am going to assume the script you included is named Playbutton.

First, while it is certainly convenient to attach this code to the Update function of this script because it gives you immediate access to the onTouch() function, it also means that every single instance in the scene is doing the same processing.

Second, and hand in hand with the first point, the Physics.Raycast function you are using provides the HitInfo, which includes the GameObject of the object in question. From that you can go straight to the specific instance you want.

So my suggestions are as follows:

Remove the Update function from your current script, or at least the portions that relate to touch detection and launching of the videos. Obviously if you have removed other bits that are critical to the operation of that script you will want to leave them in. But you don't need to do the raycasting in that Update function.

Create a new script, perhaps named StartVideoOnTouch that looks as follows:

 function Update () {
   for ( var i : int; i < Input.touchCount; i++ ) {
     if ( Input.GetTouch(i).phase == TouchPhase.Ended ) {
       var hit : RaycastHit;
       var ray : Ray = Camera.main.ScreenPointToRay(Input.GetTouch(i).position);
       if ( Physics.Raycast(ray, hit, Mathf.Infinity) ) {
         var play_button : Playbutton = hit.collider.gameObject.GetComponentInChildren(Playbutton);
         if (play_button) {
           play_button.onTouch();
         }
       }
     }
   }
 }

Create an empty GameObject in your scene and attach the StartVideoOnTouch script to it.

What this accomplishes is having only a single Update function doing raycasting, using the HitInfo that comes out of it to check to see if what was touched was the right kind of object and, if it is, calling the onTouch() function on that one specific instance of it.

Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image GrannySmith · Aug 23, 2012 at 07:28 AM 0
Share

Thank you for your input, it did solve my problem. Though there is still a question left: In my initial script I checked whether the name of the hit object equals the name of the gameobject, this script is attached to (at least this is what I think I did). Is it correct that "gameObject" is the reference to the gameobject in the scene which holds this script? If yes then why is a video opened for every playbutton in the scene. The hit object should only contain the gameobject which was actually touched.

avatar image lpye · Aug 23, 2012 at 09:54 AM 0
Share

Your original script was attached to each instance of Playbutton and contains an Update() function. So each update cycle, every Playbutton in the scene was calling its own Update() function.

Within each Update() function being run, a raycast would be cast and checked for a hit. If a hit was found, it would then compare the "name" of the collider's GameObject with that of the GameObject running the Update().

However, the "name" is shared across all instances of the same prefab. So in the designer, if you had changed the name of the prefab to "PlaybuttonPrefab", each instance would have had a gameObject.name value of "PlaybuttonPrefab". So each Playbutton in the scene would have checked for a hit, checked the name of the collider against its own name, and responded accordingly.

Put another way, imagine a group of people all standing on numbered tiles, facing one another. Someone rolls dice and calls out a number, in an attempt to pick whoever is standing on that number. The original Update() function was like having each person look at the number rolled, finding the name of the person standing on that number and comparing it to their own name. If it matches, they are supposed to call out. Unfortunately, every single person playing is named 'John', so every roll of the dice results in every player calling out every single time.

Technically, if you had altered the name of each instantiated prefab so they had unique names, your technique would have worked, although it would have been a little less efficient because every prefab instance would still have been running Update() checking for a hit rather than just one object checking for the hit.

avatar image GrannySmith · Aug 23, 2012 at 11:24 AM 0
Share

Thanks for the input. I understand it much better now and I know what my error was. All the playbuttons are childs of the $$anonymous$$arkers which get tracked by the Augmented reality part and every of those $$anonymous$$arkers is unique with a unique name. Therefore it must have worked if I compared the parents name of every playbutton with the name of the gameObject which got hit by the raycast. something like: if(hit.collider.transform.parent.name == gameObject.name){ doSomething(); }

But your suggested answer is much better because the update is only invoked by one object.

Thanks.

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

9 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

make unique shader for prefab 1 Answer

Calling a function from all instances of a script 1 Answer

Script is reading from prefab instead of instance 1 Answer

One tree being chopped by player all trees get chopped help? 2 Answers

Is it possible to have a prefab of a cube, which has instances with different colours? 2 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges