- Home /
Is there a way to override a function in each instance of the same script?
Hey guys. Here's the situation:
My game will have various objects, like signs, NPCs, doors, etc... All of these objects will be tagged with the "Interactive" tag and have the "InteractiveObject" script. This script has the "Act()" function. The player is in first person camera, and interacts with these objects by using raycast to check if the player is looking at any "Interactive" object. If the player is looking at any of them and clicks with the mouse button, the function "Act()" of the raycasthit "InterativeObject" script will be called.
However, each "Interactive" tagged object should have that same "InteractiveObject" script for my code to work, but the Act() of the object's script should be different. A sign Act() would be different of the door Act(), for exemple. Here's the code that runs the object's Act() function:
if(Physics.Raycast(raycast, out hit) && hit.collider.tag == "Interactive" && Input.GetButtonDown("Mouse 1")){
InteractiveObject function = (InteractiveObject)hit.collider.GetComponent(typeof(InteractiveObject));
function.Act();
}
So, is there a way that all of the "Interactive" tagged objects can have the same script "InteractiveObject" but with a diferent behavior to the Act() function in each instance of the script? Is that even possible, or am I approaching the problem the wrong way? If that's the case, can you guys point in the right direction? =/
Thanks for the attention.
Off the top of my head, I would say it's not. I would just have each object have the InteractiveObject script and another script that is specific to the object which has the unique Act() function.
But that could be lots of scripts...
Or you could keep the Act() function on the InteractiveObject script, but it contains all the Act functions for every InteractiveObject. This could be done by using a switch and passing the interactiveObject's name as a parameter. That way there's one script for all your interactiveObjects. In the example above, you would just call function.Act(hit.name), and then the switch inside Act() would find that object name, and run it's portion of the Act().
Hope that helps a bit. Good Luck.
You are describing the number 1 feature of object oriented program$$anonymous$$g. Are you familiar with it? C# is best for it, but you can have some degraded functionality of it in js too.
Yes, i am familiar with object oriented, and i am using C# in Unity. It's just that i am used to working on editors like Eclipse and NetBeans where's the code is all in one project and you create your instances in the code, while Unity is all about separated scripts attached to objects that can already be instancied in the Scene View, so when it comes to acess other functions or objects from one script to another i get a little confused. xD~
Answer by simonmc · Apr 16, 2012 at 09:14 AM
you can extend InteractiveObject for each different objet you like, and override the Act function.
To do this, you will first need to add the virtual
keyword to the method signature of your InteractiveObject class.
Then for each different type of interactive object, define a new class than extends InteractiveObject, and overrides the Act() method.
For example, your door Act might look something like:
public class InteractiveDoor : InteractiveObject {
public override void Act() {
// your specific door functionality
}
}
This way, you can then attach the InteractiveDoor, or InteractiveSign or whatever to each object, and have its specific Act() functionality while keeping whatever other functionality exists in the InteractiveObject sript. (BTW you would not attach the InteractiveObject script to your gameobjects, only the child InteractiveDoor or InteractiveSign script.
However, if there is no common functionality that exists in the InteractiveObject script, then it may be simpler just to have different scripts for each object with an Act() method and use gameObject.SendMessage("Act");
to fire off the functionality.
Answer by zz74b · Apr 16, 2012 at 09:22 AM
You could use Reflection:
var obj = hit.collider.GetComponent(typeof(InteractiveObject));
var fn = obj.GetType().GetMethod("Act", BindingFlags.Public | BindingFlags.Instance);
var fnParams = new object[]{ "FirstParam", 10, true, etc... };
if (fn != null)
{
fn.Invoke(obj, fnParams );
}
This will invoke 'Act' on any object returned by the GetComponent method. Hence it could run on any object returned by GetComponent.
Note: This is pretty much what Unity will be doing internally when you use the SendMessage() method - But this may be slightly more efficient [Disclaimer: I don't know!]
Edit: Just to clarify - You could use this if you don't want to use inheritance / overriding as suggested above (probably your best bet...) For example you could call a differently named method based on the actual type of the object that GetComponent returns.
Answer by lucasandradz-2 · Apr 16, 2012 at 03:48 PM
Thanks for all your answers. I have never seen the SendMessage() method before, i am still new to Unity, sounds interesting... And I have though about the all act() in one and check by the name of the hit wich act() should be called, i just didn't know if that was the best sotulion. It's a valid option i will look into though.
I am a little busy at the moment, but now that i have a clearer vision of what can be done, I will try your sugestions and see which runs best for me when I can. Thanks a lot guys. :D