Search Unity

Question [noob] How to pass a method and property by reference to a function

Discussion in 'HMI & Embedded Systems' started by Ascanio1980, Mar 14, 2021.

  1. Ascanio1980

    Ascanio1980

    Joined:
    Jun 7, 2019
    Posts:
    51
    Hello there,

    I am looking to build an easing class with static methods that I can use to programmatically animate properties of game objects, similarly to what you with do with GSAP in JS/AS3.

    proto code:

    Code (CSharp):
    1. MyEasingClass.animateTo(GameObject.property, FinalValue, MyEasingFunctions.easeOutCubic, Duration);
    I am new to C# and it looks like properties are not referenced in function arguments: values are sent.
    How would I go about this?

    To accelerate development and avoid IDE as much as possible, I would want to use static methods and not have to attach the script as a component to any object. I was thinking about hooking into the target GameObject's Update function to drive a frame-based loop, regardless of whether the duration would be specified in frames or in time (in the second case I'd check the elapsed time between frames, rather that counting how many frames have elapsed).

    Any help on this would be greatly appreciated!
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,752
    Any reason you're not just using DOTWeen or ITween or any one of dozens of other free tweening packages? All this code has been written many times before... I mean if you want the exercise, I'd start by looking at what they did, it's all pretty simple stuff in Unity.

    There is also just the underlying basic Unity animation. It works really really well and you can instantly author more animations right in the editor.
     
  3. Ascanio1980

    Ascanio1980

    Joined:
    Jun 7, 2019
    Posts:
    51
    Hi Kurt-Decker,

    thanks for your reply. Let me respond point by point:
    • I want to exercise and learn, while building my own shelf-stuff to accelerate development.
    • I am also learning Unity as a UI rapid-prototyping tool (not necessarily using Unity's UI framework) for non-gaming apps, essentially as a substitute for Adobe Flash/Animate/AIR, which has been my go-to tool for 20 years, and helped me deliver multi-device hybrid physical-digital UI prototypes with real-time P2P networking while developing graphics and interaction for the Alfa Romeo HMI in the Giulia, using a mix of consumer hardware, prototype OEM hardware and some basic Arduino.
    • The reason why I was so fast and effective with Flash is that I knew the IDE inside out, and over decades I have built my own code framework to solve things like real-time 3D graphics, P2P networking, BT/USB I/O as well as code that turned any MovieClip into a state machine with animated transitions, either driven by code or leveraging the timeline-based visual architecture of the IDE. I could turn around high-fidelity (necessary for incompetent micro-managers) prototypes in a couple hours, against the months (and hundreds of thousands of dollars that the engineering team would be subjected to when asking Tier 1 suppliers).
    Playing with Unity's Animator framework I have decided it is designed for character animation, and is really not nice nor elegant for UI stateful elements with animated transitions. Your content will be scattered across code and graphics and across the dispersed IDE GUI. It's very messy.
    I want to build by own stuff so that with few PreFabs and a code library, I can build high-fidelity interactive UI prototypes with few hundreds of lines of code.
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,752
    Hm, I disagree with that claim. Mecanim's avatar is character-oriented but I'm not talking about that. I'm talking about bog standard Animations. It couldn't be simpler: change this property (or these properties) over time. You can group and control larger-scale stuff (webs of animations) using an Animator. It's all very hierarchal.

    Again I don't agree here. Move related items into a folder. It's pretty standard organization technique in Unity. For instance, I will make a folder for a scene and all assets that go ONLY in that scene go in that folder: textures, animations, materials, models, etc. Common stuff is elsewhere because ... it's common!

    Certainly a valid approach. I think you'll find that most visual effects artists work faster with animations applied to a UI, with some light coding interspersed to control interactive portions.
     
  5. Ascanio1980

    Ascanio1980

    Joined:
    Jun 7, 2019
    Posts:
    51
    Well, I guess opinions are always biased by previous experience. In my case I see Unity as messier and more dispersed compared to what I am used to. I'm not saying its bad, I'm saying it was designed for a different purpose, different context, different workflows, different professional figures.

    I'm sure a lot of my pain is also due to my lack of knowledge about the tool!

    Now, when building UI rapid protos, I define all state machines and content logic elements in code. I then link the code to graphic assets. This way the Information Architecture is all in one place: a set of script files organized in classes. All the graphics assets are Symbols (Prefabs in Unity), which will be instantiated via code.

    My current problem with Animator is that I am finding it convoluted to define animated transitions between states.
    The timelines define animations that happen inside an object's state, defining the duration is also confusing, as timelines are visually generic, while you are working in relative terms (beginning-end, rather than absolute frames), and then define the duration elsewhere.
    Also, I haven't figured a way to fine-tune transition animations between states.

    Default UI transition animations don't follow basic Human Factors and Perceived Quality guidelines, so I absolutely need to customize details, in different ways for intro and outro.
    Just to make an example, default UI Buttons have long outro animations, which is the first thing you cut when trying to improve perceived system responsiveness... especially on embedded automotive hardware where (if you are lucky) you are dealing with a 100-200ms lag to begin with, between user input and GUI response.
     
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,752
    This took me about 21 minutes, based on the date of my previous post.

    It would have taken me hours to code the details of this motion. And now I can trivially add other things to the animation, make it bobble and wobble however, or I can hand it to anyone who can't code and they can go nuts immediately: it's totally WYSIWIG.
     

    Attached Files:

    mopthrow likes this.
  7. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,752
    And with five more minutes I have wiggling and color flashing and rotating and all kinds of stuff.
     

    Attached Files:

    mopthrow likes this.
  8. Ascanio1980

    Ascanio1980

    Joined:
    Jun 7, 2019
    Posts:
    51
    Thanks for that, I will look into it.

    Let me give you an example of what I would build via code and graphic Symbols/Prefabs instantiated programmatically.

    Data-driven multi-page menus and text input for remote-controlled GUI

    Long menus with multiple pages can quickly become a mess when iterating on contents, content organization as well as visual layout. Especially if integrating multi-modal interaction (such as remote knob, proximity sensor and touch-screen at once, which sucks in 99% of implementations... the most successful way is taking from the previous generation Mercedes HMI paradigm that used the added logic element of button groups, so you would have focus highlight for button groups as well as individual buttons, shift group focus by tilting the knob, and shifting button focus by scrolling the knob: this would allow a shallow Info Arch to work effectively with remote controls and touch-screen input at once).
    If you build this via code, the prototypist can change content and content organization within seconds via code. The designer only needs to work on graphics without touching code. In the case of an onscreen keyboard, you'd ask them to comply to a specific labeling system for button instances, and at startup time the code would crawl through graphic elements and link them to logic.

    Data-driven G-force Meter (no user interaction)

    In the G-force Meter that I patented with Alfa Romeo, the circular cursor has a snake trail to show short-term historic values (and allow the pilot to check the performance in the last curve while driving down a straight stretch safely), as well as peak values that show up only when relevant (beyond a certain value), then fade out after a few seconds.

    In both these examples:
    • Code-driven integration accelerates initial build as well as maintenance during design iterations.
    • Some features can only be built by code (such as the G-force history snake)
    • >90% of UI elements are standardized and used over and over. You'd want to have code populate them, rather than manually, but also, you might want to optimize transition animations system-wide, without having to manually go through each and every page, panel, scroll element, menu item and change their animations.
    • You also want to reduce the necessity for spec documentation: if transition animation behaviors are expressed in code, they are human-readable and can be easily versioned and branched (and traced back by looking at the difference in values hardcoded).

    I understand that to build and animate one element the visual IDE can be fast. But when building complex apps and insuring repeatability, traceability and super-fast turnover, I have always seen a code-first approach win. Be it in Adobe Flash with AS3, be it with Sketch/Framer + custom JS, be it with vanilla JS or JS apps built on frameworks such as React.

    Takes a few weeks to build the codebase required to make the process possible (if you know the language, tools and running environment), but after that you fly.
     
  9. Ascanio1980

    Ascanio1980

    Joined:
    Jun 7, 2019
    Posts:
    51
    Another example if the Paginator element in Framer, which is basically a scrollable container with elastic alignment: you drag and "throw", it scrolls and then stops perfectly aligned (not free to stop outside of specific values).

    Another example is generally scrolling a page. There is a huge difference between iOS and Android approach, where Android complies with laws of physics (the duration of scroll depends on the force of throw at mouse-release or end of tap-drag). This results in a poor perception of quality, compared to Apple's design where duration is fixed.
    These minor differences make a HUGE difference in the design of a GUI, and need to be addressed intentionally.

    This you can only do via code, to have full control.
     
  10. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,752
    True... actual quantity-driven interaction can only happen through code.

    I actually hate ALL mobile scrolling controls because none of them move FASTER than your finger. I could care less about momentum honestly... with enough magnification of velocity, you can get through vast amounts of content quickly.

    In fact I even hacked the Unity default UI scrollrect so it becomes usable on large collections:

    https://forum.unity.com/threads/make-scrolling-move-faster-in-scrollrect.375116/#post-2789826

    That's not even using acceleration; if you did a non-linear scale-up it could be even more-controllable and faster to find stuff.
     
  11. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,539
    In GSAP, and most of the JS/AS3 tween libraries you don't pass in properties by ref. You generally pass in a string name for the property.

    This is because both JS/AS3 are interpreted prototypical languages and looking up properties by string name is fairly trivial.

    C# requires reflection to do this. And that is what you'll want to look into doing if you want to do it via string.

    Various tween libraries exist in Unity that behave similar to the JS/AS3 libs. Like itween (which originated in AS3), and hotween. They support strings as well as helper methods like "moveto" which shortcut positions and the sort.

    Dotween is another, the successor to hotween, which foregoes the strings because reflection can be slow and also have some implications when targeting IL2CPP (note that IL2CPP may strip unused properties and the compiler doesn't know a property is used if it's referenced by string). Instead you pass in delegates that perform the setting/getting, which is faster.

    I have even written my own tween library because I wanted to for funsies (I too come from an AS3 background in the long long before times):
    https://github.com/lordofduct/spacepuppy-unity-framework-3.0/tree/master/SPTween

    In the 'dynamic/accessors' folder there you'll see my various "accessors" I use to access properties of objects by name. My engine will prefer one accessor over another depending the property to try to speed things up. Like it uses the 'FastTransformAccessor' when tweening transforms as those are commonly the things you may tween. Another is the FieldAccessor/PropertyAccessor which will 'emit' IL code at runtime to build the code needed to access a field faster than reflection, but requires the mono runtime (no IL2CPP/AOT, noting this was built back when AOT was common). There's also the bog standard BasicMemberAccessor and DynamicMemberAccessor which just use standard reflection.

    Examples of it being used:
    upload_2021-3-14_18-26-21.png

    upload_2021-3-14_18-26-57.png

    upload_2021-3-14_18-27-27.png

    As well as an inspector driven tweener:
    upload_2021-3-14_18-33-30.png

    Pretty much anything UI in this video is using it. Like the inventory spindle and the sort (which is the spindle code you see above).


    Not saying to specifically use any of these. But you can definitely spelunk my github to see how I pulled it off.
     
    Last edited: Mar 14, 2021
  12. Ascanio1980

    Ascanio1980

    Joined:
    Jun 7, 2019
    Posts:
    51
    There is much to hate in all commercial UIs... they are always the fruit of extensive trade-offs.
    When working on embedded systems you also have to keep in mind that the vast majority of weaknesses in the design execution are due to organizational issues (poor managers, bureaucracy, poor structure, poor processes, poor tools, poor supply chain management... it often is an all-round disaster, not kidding!).

    That's why rapid-prototyping is so important. I had countless meeting with c-suite, executive management and middle-management, where topics were discussed on paper (or in front of PowerPoint slides), by people that were not knowledgable (and shouldn't have been dealing with technical decisions in the first place).
    By arriving with my prototypes I would put them straight in the shoes of customers, and force them to make a decision based on the impact on the end user (no knowledge required for that...).
    It made a huge difference. Six month decision making processes cut down to 5 minutes, with much better quality of decisions made.

    For example, the G-force meter was meant to be a carry over of the idiotic implementation used on the 4C (same as what you see on BMW, Audi, Dodge, Ford etc...)... basically borrowed by telemetry (which you look at from the comfort of a chair at the paddock or lab, not while driving!). I had brutal discussions with engineering heads, but they were more concerned with overarching delivery date (the project was super stressed for FCA's standards), so anything they could carry over was gold.

    I went back to the design center, ripped a video from YouTube of some crazy guy shooting a Lotus Elise down the Alps at speeds to high that the video itself would make you anxious. I then created a UI in Flash for me to generate a sudo-datalog animating sliders with keyframes, to generate a feed including speed, engine speed, gear, and 2-axis forces.
    With the sudo-datalog and video at hand, in one afternoon I replicated the behavior of the idiotic previous G-force meter, and designed an improvement. I actually designed it while prototyping... I'd test it on myself, and iterate. I then added another 4 variants by the end of day.

    I then went to the CEO and the chief of engineering, sat them in one of FCA's "Virtual Rooms" (think of private cinemas with 7m wide rear-projection walls), launched the app with fullscreen video of the maniac driving, and my UI overlaid on top of it. First launched the idiotic previous design, and after a few curves asked the CEO "can you tell me what G-force value we reached in the last curve?". "No" he asked. "If you can't do it from the safety of the chair where you as seating, how can you expect our customers to?". "Let me show you an alternative". Switched to my proven UI design with one button (from my tablet which was P2P connected to the computer running the Windows app", without moving from the side of the CEO). It took another 20 seconds for him to say "Yes this works, OK I want it like this in the production by Job 1" (the initial launch).
    The next day I was instructing the engineering team and supplier of the instrument cluster on how to implement it.

    It would have NEVER happened without my rapid prototype, built in Flash, in a few hours from scratch.
     
  13. Ascanio1980

    Ascanio1980

    Joined:
    Jun 7, 2019
    Posts:
    51
    Thanks for the reply! I do remember sending properties as reference arguments, but I might be confusing AS3 with PHP (I haven't coded AS3 in the past 2 years, and haven't coded PHP in the past 13 years).

    I don't like using strings at all: I'm all for strict coding. Referencing property names with strings is just ugly, and I know learn from you that it has both performance and compatibility issues as well.

    Now... honestly I lost you after that. Let's put it this way....: I just picked up coding like you pick up your mother tongue language.... I speak English because my mom always talked to me in English but I don't know the rules (just what "sounds" or "looks" right). So Dynamic Accessors, Standard Reflection are all terms that I have yet to learn.
     
  14. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,539
    Welp, that's not how C# works.

    There are only delegate references which don't support property/fields. So instead you need to wrap the property/field with a getter/setter delegates (which is how DOTween does it).

    Also... really wondering what you'd be talking about. Because neither PHP or AS3 support it.

    The most I could think is how JS/AS3 do support duck typed objects that could be passed into the tweener and then the names are read by string internally off of said duck typed objects. Ala:
    upload_2021-3-14_18-36-17.png

    But note, all those "x" and "rotation" and "scale" properties on those dynamic/duck typed objects (the {...}) are reflected and handled as string internally.

    So you may be thinking you were directly manipulating using "strict coding"... but you actually weren't.

    I mean come on... we're talking about JS/AS3 here. They're not strict languages in any sense of the word strict.

    C# on the other hand... it's strict. And that's why you can't do what you're asking for without some heavy lifting on your part. Hence why I referenced how I did it, and how others have as well in things like itween, hotween, and dotween.

    We do them these ways for a reason...
     
  15. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,539
    Note if you don't like the delegates, you may be able to get Expression Trees to do what you want. Expression Trees uses the DLR (dynamic language runtime) to emit delegates which is the same basis on which the 'dynamic' aspects of C# added in more recent versions comes from. This would give you things like the duck-typed plain old objects like that in the GSAP example I showed earlier, just in C#.

    But again... heavy lifting ahead.
    https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/expression-trees/

    Also this likely will not work with IL2CPP as it builds IL at runtime.
     
  16. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,539
    Oh, and while I'm sharing examples. This is the delegate wrapper I'm talking about for DOTween:
    Code (csharp):
    1. DOTween.To(()=> transform.position, x=> transform.position = x, new Vector3(2,2,2), 1);
    The "x=>transform.position = x" is the setter delegate. And the "()=>transform.position" is the getter delegate.

    ...

    I'll put it to you this way. I've been programming since 1995, writing C# since 2006, and using Unity since 2010. In all my experience the only options you really got are:

    1) strings/reflection
    2) emit/dynamics (IL2CPP be damned)
    3) delegates

    That's what you got.

    ... and once you start bringing in serialization (like an editor gui like the one I showed before) that lets you save/load your stuff. Strings are honestly the most versatile. If you're afraid of properties/fields changing names... use the 'nameof' expression:
    https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/nameof
     
    Last edited: Mar 14, 2021
  17. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,752
    This all day long.

    If it's good enough to run the global internet (hint: the internet is ALL strings), it's good enough for me.

    EDIT: if I recall correctly, Quake was one of the first times I saw only strings used to control an entire game, down to the actual frame-to-frame control inputs.
     
    Last edited: Mar 14, 2021
  18. Ascanio1980

    Ascanio1980

    Joined:
    Jun 7, 2019
    Posts:
    51
    Thanks fellas, I have some studying to do :)

    Regarding passing a property as reference, I must be being affected by poor memory. Sorry for that!

    I will look into the code for the easing frameworks you... referenced.

    Thanks again!
     
  19. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,752
    They definitely have a place in any UI makers toolkit. It's just a matter of identifying the best tools for each part of the job:

    - mindless unchanging animations -> animator

    - variable destination tweens ('go here to there') -> tweening frameworks

    - more interactive -> custom code
     
  20. Ascanio1980

    Ascanio1980

    Joined:
    Jun 7, 2019
    Posts:
    51
    Kurt-Dekker, you want to look at something really convoluted?
    Automotive HMI development toolchains... Kanzi
     
  21. Ascanio1980

    Ascanio1980

    Joined:
    Jun 7, 2019
    Posts:
    51
    Here is an example of something I would be looking forward to building iterating and tweaking for best user experience:

    https://www.framer.com/examples/card-paging/

    I would need to support the following interaction modes:
    1) Touch-screen with surface gestures (drag), so must be on a consumer tablet, like iPad
    2) Remote-control with rotary knob (+ 4-way tilt) via USB custom interface that emulates a generic HID Keyboard

    This is very close to what many automotive UI's use today for the gateway/homepage in hybrid physical-digital interactions.
     
  22. Ascanio1980

    Ascanio1980

    Joined:
    Jun 7, 2019
    Posts:
    51
    I am going through the code for DOTween. There is one thing I can't seem to find by searching through source code and Google:

    How do they extend "known Unity objects", to make shortcut methods available through default Unity objects?
    This is something I'd love to learn!
     
  23. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,539
  24. nilsdr

    nilsdr

    Joined:
    Oct 24, 2017
    Posts:
    374
    Perhaps you mean static extensions?

    https://docs.microsoft.com/en-us/do...g-guide/classes-and-structs/extension-methods
     
  25. Ascanio1980

    Ascanio1980

    Joined:
    Jun 7, 2019
    Posts:
    51
    Thank you guys. Yes I came across the Extension Methods articles right after writing the question.
    Thanks for the GitHub link, I was sifting through the open code in the DOTween package but I guess some of it is compiled beforehand and not readable/searchable.