Attempting to create a Utility class of static functions. Which object references do I need for Unity's built in functions, and where do I put them?
Trying to create a class of static functions, that I can call in a similar fashion to 'Vector3.RotateAround', 'Vector3.Normalize', etc. Here's what I have so far:
using UnityEngine;
public class UtilitySetMono : MonoBehaviour
{
public static void MoveOnKeyboardPress(KeyCode key, Vector3 direction)
{
if (Input.GetKey(key))
{
transform.Translate(direction * Time.deltaTime);
}
}
}
The first part of the 'transform.Translate' function, the word 'transform', is throwing the following error:
An object reference is required for the non-static field method or property 'Component.transform'.
Where should I insert the object reference, and what do I need to type there?
Answer by villevli · Aug 23, 2016 at 09:37 AM
This could be an extension method for the Transform class:
public static void MoveOnKeyboardPress(this Transform transform, KeyCode key, Vector3 direction)
And then you just call it on any transform:
transform.MoveOnKeyboardPress(key, direction);
I'll look into Extension $$anonymous$$ethods. Thanks for the input.
You only need $$anonymous$$onoBehaviour on scripts that are attached as components to a gameobject.
$$anonymous$$eep in $$anonymous$$d that extension method must be defined in a simple public static class.
public static class TransformExtension
{
public static void $$anonymous$$oveOn$$anonymous$$eyboardPress(this Transform transform, $$anonymous$$eyCode key, Vector3 direction)
{
// ...
}
}
Though i don't see much "usefulness" in that method ^^. It's a very specific case which you usually don't have that often. It's very limited since it directly relies on Get$$anonymous$$ey (so no other input method is possible) and directly relies on Time.deltaTime. Also it used transform for movement, so it bypasses physics if a rigidbody is in use.
Utility functions should be as versatile as possible.
But this is a more complicated way of saying the real problem. Regular functions only know about what you tell them inside the parens. $$anonymous$$oveOn$$anonymous$$eyPress would have to be sent a transform, otherwise it doesn't have one. The first step is to change it to $$anonymous$$o$$anonymous$$P(Transform T, $$anonymous$$eyCode ... ). Now it has a transform input, and can use T.Translate.
An improvement (depending) is the extension method trick. Notice how it's still being sent a transform (but in a funny way.)
Everything written inside a standard Unity class in really a member function, which is why you get access to all globals (including transform.) You've been using that magic rule this whole time. The confusion is that you thought you were writing normal functions, but you really weren't. So a real normal utility function is confusing.
Answer by _Yash_ · Aug 23, 2016 at 09:30 AM
You can not access non-static (transform here) inside a static functions. You should use singleton pattern. also you can fix just this function by passing transform to it
using UnityEngine;
public class UtilitySetMono : MonoBehaviour
{
public static void MoveOnKeyboardPress(Transform trans, KeyCode key, Vector3 direction)
{
if (Input.GetKey(key))
{
trans.Translate(direction * Time.deltaTime);
}
}
}
Just to clarify: It does not matter where you are calling the method (unless you are calling from within a method of that object). You just need a reference to an object if you want to call a non-static member function.
That's the thing, if Vector3 doesn't need an object reference in order to use its functions, then how can I write my code in a way that I don't need object references, and so that I can call the function like this:
UtilitySet$$anonymous$$ono.$$anonymous$$oveOn$$anonymous$$eyboardPress(thing1, thing2);
where UtilitySet$$anonymous$$ono is an abstract class?
Vector3 does need a reference.
All non-static member functions get a this pointer implicitly passed as well. Vector3.Normalize() is non-static and is applying the change to the instance you call it on. Without a Vector3 reference, you cannot call Normalize() without parameters.
Vector3 could also have a static method Normalize() but that one would also need a parameter of type Vector3.
Said in a very simple way:
If you have a method that is supposed to work with an object (in your case a transform which is supposed to be moved) it has to somehow know which one to use.
Example:
You have 100 lights that have a method turnOn(). So you could access a specific light and call turnOn() to switch that one on.
Then you have a helper method (student). And you tell him: turnOn(). Of course he will ask "which light?" as he himself is not connected to any of them. So you have to tell him turnOn(light17) or something like that. (After which he will probably ask "now?" but that is another problem)
If I pass 'Transform' as the first parameter, then what should that first parameter be during the function call?
For example:
cmp.usm.$$anonymous$$oveOn$$anonymous$$eyboardPress(new $$anonymous$$eyCode[] { $$anonymous$$eyCode.W, $$anonymous$$eyCode.UpArrow }, dirs.Up);
This is going to throw an error, because it no longer takes two arguments: what should the third (first in the list) be?
this.transform.
Although I prefer @villevli's suggestion of writing an extension method so that this is not necessary.
It worked, definitely a step in the right direction. Thanks!
Although this does present another issue, that being that the first parameter has to be 'this.transform' or just 'transform' on every single call. Is that anything that can be worked around, or am I forced to leave it in?
Answer by Glurth · Aug 23, 2016 at 03:35 PM
I think most of these points have been made in previous answers and comments, just wanted to put them together & summarize. Everyone should feel free to edit this.
public static class ExtensionClassName
{
static public Vector2 RotateAboutPoint(this Vector2 pointToRotate, Vector2 centerPoint, float angle)
{..blah..}
static public Vector2 RotateAboutPoint2(Vector2 pointToRotate, Vector2 centerPoint, float angle)
{..blah..}
static float favoriteAngle=30.0f;
}
Notice the two ways the RotateAboutPoint functions' parameters are defined: the first one has the keyword "this" in front of it. This is no more than a neat syntax trick, which allow this function to be CALLED like so:
pointToRotate.RotateAboutPoint(centerPoint, angle); //Where pointToRotate is a Vector2 variable.
This is functionally exactly the same as NOT using the "this" keyword, and calling the function like so:
ExtensionClassName.RotateAboutPoint2(pointToRoate, centerPoint,angle);
Either way, because these are static functions, you must pass in (or otherwise make accessible) ALL the information needed to compute the return value.
Other ways to make values accessible to static functions, is to store them in static variables. For example the static float favoriteAngle can be read and written by both RotateAboutPoint functions. It can ALSO be access ANYWHERE this class is available with:
ExtensionClassName.favoriteAngle
Limitations: the name of the static class holding these functios must be used, unless the "This" keyword is specified. Alas, the class names Vector2 and Vector3 and similar, are already defined, so we MUST use a unique class name here. this means we CANNOT define, for example, a function called like so: Vector2.RotateAboutPoint(pointToRoate, centerPoint,angle);
Answer by visualbruno · Aug 23, 2016 at 09:56 AM
Hi.
Static function can only access static variables.
Why do you need this function to be static ?
I'm creating a Utility Class of static functions, that I can call directly by doing the following:
UtilitySet$$anonymous$$ono.$$anonymous$$oveOn$$anonymous$$eyboardPress(param1, param2);
without having to declare a reference to UtilitySet$$anonymous$$ono, or having to use GetComponent() or gameObject.AddComponent();
The problem is that with static functions, you need references to $$anonymous$$onoBehaviour/UnityEngine/etc within the function's declaration. I'm fine with that, as long as it means I can call functions directly through the class name, as I would with 'Vector3.$$anonymous$$oveTowards' or 'Vector3.Angle'. The question is, how would I go about doing this?