1

I want many GameObjects on the scene to have the Y position "animated" programmatically. I have a class, let's call it "TheGameObject", which doesn't inherit from MonoBehaviour and as such can't have the Update() function that I need to achieve the Y movement of the GameObjects. I decided to try using a delegate but then a problem came up: I can pass only one Transform to the delegate.

Here's the code for the delegate in a static class, let's call it "staticClass", that derives from MonoBehaviour:

public delegate void UpdatingEventHandler(Transform t);
public static event UpdatingEventHandler Updating;

void Update() {
    if(Updating != null)
        Updating(/*Transform that should be passed*/);
}

And this is the code in the "TheGameObject" class:

public GameObject gameObject { get; set; }

private void spawn() {
  GameObject go = new GameObject();
  staticClass.Updating += animateYpos(go.transform);
}

void animateYpos(Transform t) {
  //modify t.position.y
}

Is there a way to pass each respective Transform to the delegate in order to call Updating() in the static class Update() and have all the GameObjects to move respectively? The problem isn't the type of the parameter that is passed but which Transform is passed so that each different Transform will have its own Y position modified.

Cress
  • 434
  • 7
  • 23
  • this is completely wrong dude. in Unity, in ECS, you can't have a component that "doesn't inherit from MonoBehavior". – Fattie Jul 15 '16 at 14:13
  • Possible duplicate of [Convert data type from inherited classes in C#](http://stackoverflow.com/questions/37233186/convert-data-type-from-inherited-classes-in-c-sharp) – Fattie Jul 15 '16 at 14:14
  • How about you tell what is your ultimate goal and we tell you a better solution – Umair M Jul 15 '16 at 14:15
  • "TheGameObjectClass" isn't a component, it's a class that has some specific properties (damage etcetera) and also has a property which is the GameObject that gets spawned. – Cress Jul 15 '16 at 14:15
  • 1
    @JoeBlow you can't have a **Unity** Component that doesn't inherit from MonoBehavior, you can make as many non unity components as you like , you just have to attach them to a Unity component if you want it to be usable by the unity engine – MikeT Jul 15 '16 at 14:25

2 Answers2

3

This is sort of totally wrong.

It's very common for experienced developers to not really understand that Unity is not object oriented, and has utterly no connection to concepts like inheritance.

(Sure, the programming language currently used for writing components in Unity, happens to be OO, but that's largely irrelevant.)

Good news though, the solution is incredibly simple.

All you do in Unity is write behaviors that do what you want.

Essay about it ... https://stackoverflow.com/a/37243035/294884

Try to get this concept: say you have a "robot attack device" in your game.

So, the only thing in Unity scenes is GameObjects. (There is nothing else - at all.)

Your "robot attack device" would have these behaviors. ("Behaviours" meaning components attached to it. Components are MonoBehavior.)

"robot attack device"
• animate Z position
• shoot every ten seconds
• respond to bashes with sound effect

and so on.

Whereas, your "kawaii flower" might have these behaviors

"kawaii flower fixed NPC"
• shoot every 5 seconds
• respond to bashes with sound effect
• rainbow animation

In this case you're asking how to write a "animate Y" behavior.

It's very easy, first note that everything you do in Unity you do with an extension, so it will be like:

public static void ForceY( this Transform tt, float goY )
    {
    Vector3 p = tt.position;
    p.y = goY;
    tt.position = p;
    }

Quick tutorial on extensions: https://stackoverflow.com/a/35629303/294884

And then regarding the trivial component (all components are trivial) to animate Y, it's just something like

public class AlwaysMoveOnYTowards:MonoBehaviour
 {
 [System.NonSerialized] public float targetY;
 void Update()
  {
  float nextY = .. lerp, or whatever, towards targetY;
  transform.ForceY(nexyT);
  }
 }

Note that, of course, you just turn that component on and off as needed. So if the thing is asleep or whatever in your game

thatThing.GetComponent<AlwaysMoveOnYTowards>().enabled = false;

and later true when you want that behavior again.

Recall, all you're doing is making a model for each thing in your game (LaraCroft, dinosaur, kawaiiFlower, bullet .. whatever).

(Recall there are two ways to use models in Unity, either use Unity's prefab system (which some like, some don't) or just have the model sitting off-screen and then Instantiate or use as needs be.)

(Note that a recent confusion in Unity (to choose one) is: until some years ago you had to write your own pooling for things that you had a few of. Those days are long gone, never do pooling now. Just Instantiate. A huge problem with Unity is totally out-of-date example code sitting around.)

Incidentally, here's the same sort of ForceY in the case of the UI system

public static void ForceYness(this RectTransform rt, float newY)
    {
    Vector2 ap = rt.anchoredPosition;
    ap.y = newY;
    rt.anchoredPosition = ap;
    }

Finally if you just want to animate something on Y to somewhere one time, you should get in to the amazing Tweeng which is the crack cocaine of game engineering:

https://stackoverflow.com/a/37228628/294884


A huge problem with Unity is folks often don't realize how simple it is to make games. (There are many classic examples of this: you get 1000s of questions asking how to make a (totally trivial) timer in Unity, where the OP has tied themselves in knots using coroutines. Of course, you simply use Invoke or InvokeRepeating 99% of the time for timers in Unity. Timers are one of the most basic parts of a game engine: of course, obviously Unity threw in a trivial way to do it.)

Here's a "folder" (actually just a pointless empty game object, with these models sitting under it) holding some models in a scene for a game.

enter image description here

Those are some of the enemies in the game. As an engineer I just popped them in there, the game "designer" would come along and set the qualities (so, the potato is fast, the turnip is actually an unkillable boss, the flying head connects to Google Maps or whatever).

Same deal, this is from the "folder" (aside, if you use an empty game object as a, well, folder to just hold things, it's often referred to as a "folder" - it's no less a game object) with some "peeps" ("player projectiles"). Again these are the very models of these things to be used in the game. So obviously these would just be sitting off-screen, as you do with games. Look, here they are, literally just sitting around an "-10" or something outside of the camera frustrum (a good place to remember a Unity "camera" is nothing more than ............. a GameObject with certain components (which Unity already wrote for our convenience) attached.)

enter image description here

(Again: in many cases you may prefer to use prefabs. Unity offers both approaches: prefabs, or "just sitting off-screen". Personally I suggest there is a lot to be said for "just sitting off-screen" at first, as it makes you engineer proper states and so on; you'll inherently have to have a "just waiting" state and so on, which is highly important. I strongly encourage you, at first, to just 'sit your models around off-screen', don't use prefabs at first. Anyway that's another issue.)

enter image description here

Here then are indeed some of those peeps ...

enter image description here

enter image description here

The "game designer" comes along and sets that sort of thing as they see fit. (And of course, adds the profoundly important Components such as, you know, "the renderer", sound effects, and the like).

Note: you may notice above: because "life's like that" in the naming there (it's purely a naming issue, not a deep one) we very un-sensibly went against just what I describe here. So, notice I have a component that should be named, say, "Killableness" or perhaps just "projectileness" or indeed just "power" or "speed". Just because life's like that, I rather unsensibly named it "missile" or "projectile" rather than indeed "flight" or "attackPower". You can see this is very very bad because when I reuse the component "attackPower" (stupidly named here "missile") in the next project, which involves say robotic diggers or something rather than missiles, everyone will scream at me "Dude why is our attack power component, attached to our robotic spiders, called 'missile' instead of 'attack power', WTF?" I'm sure you see what I mean.

Note too, there's a great example there of, while Unity and GameObject have no connection at all to computer science or programming, it's totally normal - if confusing - that in writing components you have to be a master of OO since (as it happens) the current language used by Unity does indeed happen to be an OO language (but do bear in mind they could change to using Lisp or something at any time, and it wouldn't fundamentally affect Unity. As an experienced programmer you will instantly see that (for the components discussed here) I have something like a base class "Flightyness" and then there are subclasses like "ParabolaLikeFlightyness" "StraightlineFlightyness" "BirdFlightyness" "NonColliderBasedFlightyness" "CrowdNetworkDrivenFlightyness" "AIFlightyness" and so on; you can see each have the "general" settings (for Steve the game designer to adjust) and more specific settings (again for Steve to adjust). Some random code fragments that will make perfect sense to you...

public class Enemy:BaseFrite
    {
    public tk2dSpriteAnimator animMain;
    public string usualAnimName;
    [System.NonSerialized] public Enemies boss;
    
    [Header("For this particular enemy class...")]
    public float typeSpeedFactor;
    public int typeStrength;
    public int value;

public class Missile:Projectile
    {
    [Header("For the missile in particular...")]
    public float splashMeasuredInEnemyHeight;
    public int damageSplashMode;

Note the use of [Header ... one of the most important things in Unity!

enter image description here

Note how good the "Header" thing works, especially when you chain down through derives. It's nothing but pleasure working on a big project where everyone works like that, making super-tidy, super-clear Inspector panels for your models sitting off-screen. It's a case of "Unity got it really right".

halfer
  • 19,824
  • 17
  • 99
  • 186
Fattie
  • 27,874
  • 70
  • 431
  • 719
  • So you're suggesting to consider each GameObject like it were a class itself and to use only components scripts like they were methods or properties that belong to that "class"? Am I interpreting correctly? – Cress Jul 15 '16 at 14:44
  • Ah, a `GameObject` is not a class. It's just a "thing". Imagine using Photoshop and you draw a red line, and then a blue line. Unity is an ECS system - like Photoshop. The red line in question is not even .. vaguely related to "classes", "comp sci" or anything else. (Heh!) It's **just a red line**. Let's say, Photoshop had a system where you could actually "attach" `Component` software to "things" on the Photoshop scene. So you and I could write some code that (say) made the red line glow repeatedly, and "attach" that code to the red line. Then in fact ...... – Fattie Jul 15 '16 at 14:48
  • ... ***I have just described Unity!!!*** That IS Unity. Note that the red line in question just has ................. nothing to do with anything. It's not a "class" or .. anything. You might later draw a blue line, or a yellow line, or you may happen to duplicate the red line ten times. (With our without, as it happens, out "glowing behavior" attached to it.) The "red line" has utterly no connection to anything in the universe of CompSci! :) It's just a "thing". – Fattie Jul 15 '16 at 14:50
  • So I would ssy: *"So you're suggesting to consider each GameObject like it were a class itself and to use only components scripts like they were methods or properties that belong to that "class"?"* Not really, because "methods or properties" would be a HUGELY strange way to look at what i describe. In my example, how can the "red line" have "methods or properties"? It's just a freaking "red line in photoshop": it doesn't have any relationship, at all, in any way, to anything in the universe of computer science or programming. That's my essay anyway - over to you! Cheers!!! – Fattie Jul 15 '16 at 14:52
  • I have read your answer and the ones you linked but I'm not sure to have understood completely. Let's say we have a GameObject called "enemy", you're suggesting to add a component for each thing the enemy does, like a component for movement, one for shooting, etc, is that correct? And how would you keep track of its lives, its damage and things like that? If I had to instantiate 2 different enemies programmatically with different lives and damage values for example, thinking about what you said, I should just instantiate the GameObject and then modify those values in its component? – Cress Jul 15 '16 at 15:06
  • "a component for movement, one for shooting, etc, is that correct" right on. "how would you keep track of its lives" **ideally** you'd have a component like "health" or "attack power". you could just drop that right on any thing (you ever do, in any game ever) which has that "concept". – Fattie Jul 15 '16 at 15:13
  • "I should just instantiate the GameObject and then modify those values in its component" **that is one billion percent correct** – Fattie Jul 15 '16 at 15:13
  • I just tried this approach and it looks neat! Much simpler than all that delegate stuff. Even if this isn't the answer to how to pass the respective Transforms to the delegate, this approach solves the problem in an alternative way and makes things easier. Thanks mate! – Cress Jul 15 '16 at 15:49
  • Not at all man, I just like to hear myself type! Thanks for the great Q. I dropped in some sample code and the like – Fattie Jul 15 '16 at 15:51
2

Please conside what Joe said but for passing multiple paramaters to a delegate you can use this iirc :

public delegate void DoStuffToTransform(params Transform[] transform);
Uri Popov
  • 2,127
  • 2
  • 25
  • 43
  • true but you very rarely / never use "delegates" in Unity, since Unity does not have anything even vaguely related, in any way, to OO concepts. this answer is really just "how to write c#". note too that it's inconceivable that you would use delegates in Unity since **UnityEvents** exist. You might as well say "I'm drawing in photoshop. I want to draw a line. Can you help me use delegates to write code to draw a line in Photoshop?" **Newsflash, there's a "draw line" button in Photoshop** :) – Fattie Jul 15 '16 at 14:24
  • 1
    Guy asks how to pass unknown number of params to a delegate I tell him that. The beauty of Unity is that you CAN actually do stuff in a different ways and have it work. For example I have a pretty cool Factory class that is not a monobehaviour and still works great with Unity. – Uri Popov Jul 15 '16 at 14:27
  • For sure Uri, it is a great answer. I am going to send you a bounty! :) But it is very dangerous to send people down the wrong track. UnityEvent ... http://stackoverflow.com/a/36249404/294884. Consider in general terms in the real world. Say we were doing a freelance gig or something on a mainstream million-user game for a big studio. Say we started using "delegate" for something. Like, we'd just be yelled at "W. T. F. get on with the job", i.e. do it normally using UnityEvent. There wouldn't be any room for a big theoretical discussion about language techniques you know man :-) – Fattie Jul 15 '16 at 14:38
  • @UriPopov you wrote here how to pass multiple parameters but I asked how to pass to the delegate **each** different Transform that belongs to **each** respective GameObject. I don't even know if that's possible but that's why I asked. – Cress Jul 15 '16 at 15:53
  • 2
    @Cress you can use GameObject.FindGameObjectsWithTag to get a array of gameObjects with a certain tag and the pass that array to the delegate . – Uri Popov Jul 15 '16 at 16:06
  • You could have the TheGameObject classes registering themselves to the delegate. One delegate can do multi-calls, just use +=. But I would say that when you start needing this kind of pattern, you are heading the wrong way and your class should be made MB. You use non MB for storage and logic, MB for Unity lifecycle, Unity callbacks and Component interaction. – Everts Jul 15 '16 at 16:47
  • @UriPopov I actually like this answer. Based on what the OP asked, I think you got it. The only thing I disagree with your answer is the use of the `param` keyword. He shouldn't use that for this because `param` allocates memory under the hood. Since he's calling that from the `Update()` function and on many GameObjects, there will be a-lot of memory allocation while his animation code is running. Simple passing it as an array should be enough. `public delegate void DoStuffToTransform(Transform[] transform);`. **+1** – Programmer Jul 15 '16 at 21:12
  • 1
    @Programmer i did not know that params does that. Good catch. – Uri Popov Jul 16 '16 at 12:23