Search Unity

Looking for best practices on creating an action-adventurer character (Mecanim)

Discussion in 'Animation' started by Reverend-Speed, Jul 24, 2019.

  1. Reverend-Speed

    Reverend-Speed

    Joined:
    Mar 28, 2011
    Posts:
    151
    Hey folks. I'm building a game a little like Hob or Hyper Light Drifter or Akane or Beacon, etc - a hack-and-slash action adventure.

    store.steampowered.com/app/404680/Hob/
    store.steampowered.com/app/257850/Hyper_Light_Drifter/
    store.steampowered.com/app/884260/Akane/
    https://steamcommunity.com/app/856610

    I'm a reasonably experienced Unity dev and at the moment I'm the team's sole character modeller and animator (not a very good one). I have a little experience with Mecanim and I'm slowly exploring the options open to me, but as a coder I'm loath to solve a problem which is already well-understood. =D

    I'm wondering if anybody can point me towards best practices or tutorials on Mecanim state machines handling animation blending, animation events, root motion, combos, cancelling attacks, different movement states. I'd even take a recommendation of a good example on the Unity Asset Store - I'd really like to find something that maybe approaches the quality of Uncharted.

    Thank you in advance.
     
  2. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    506
    You might be interested in my Animancer plugin which has lots of examples and solves many of the problems with Mecanim from a coding perspective.
     
  3. Reverend-Speed

    Reverend-Speed

    Joined:
    Mar 28, 2011
    Posts:
    151
    That's an amazing-looking plugin, @Kybernetik - I'll spend some time studying that. Thank you.
     
  4. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    4,125
    If you end up using the Animator, here's some considerations:

    If you use triggers, note that they're implemented such that if it's set, it stays set until it gets consumed. So if you do this:

    Code (csharp):
    1. // one place in the code:
    2. if (AttackPressed())
    3.     animator.SetTrigger("Attack");
    4.  
    5. // some other place in the code:
    6. public void TakeDamage() {
    7.     animator.SetTrigger("Damaged");
    8. }
    You now have a bug, where if the player presses attack about at the same time as it's getting damaged, you'll get two animations in a row in a very weird way. To solve this, avoid triggers when you can, and be very proactive about Reseting them. You will miss this, it will lead to bugs.

    By default, transitions can't be interrupted. This is bad, since you want every single transition to be interuptable unless you want your input to feel like garbage. You'll have to turn transitions on manually every time you make one. You will forget this, it will lead to bugs.

    Transitions by default have "exit time" checked. That looks bad in all cases unless you're automatically transitioning from one state to another. You will lose a lot of time on going back to your animator to uncheck that toggle.

    All the messages you get on a State Machine Behaviour has some kind of absurd implementation. OnStateEnter and OnStateExit is called at really strange times, OnStateMachineEnter and OnStateMachineExit is only called when you use the enter/exit nodes of the state machine. It will be very tempting to use these for game logic, but their design makes that an incredibly bad idea. Only use these for modifying the animation on the state they're on, anything else is bogus.
    Let me repeat that: you cannot use the enter/exit messages on these states to tell anything else about what state the animator is in, that is broken, by design.

    Getting info about what state you're in is error prone. The API is very cumbersome, and the behaviour of "what state you are in" when transitioning is ill-defined and not documented.


    In short... it's got a lot of pitfalls!
    I'd second @Kybernetik; don't use the Animator for this. It does some things well, but especially combos and cancelling stuff is very, very error prone.

    You can either use his Animancer framework, or do the same thing as that does by writing your own animation control script on top of Playables. That's a bit daunting, but I've done it myself, and the results are pretty good. I've got an earlier version of our framework on GitHub. I should probably get around to updating it to match the version in our code base at some point! It's not ready for use, but if you end up building your own, you can look at it for how to use Playables.
     
    Kybernetik and craigjwhitmore like this.
  5. craigjwhitmore

    craigjwhitmore

    Joined:
    Apr 15, 2018
    Posts:
    14
    I'm convinced that I should not use the animator now and use Animancer, thank you.
     
  6. Reverend-Speed

    Reverend-Speed

    Joined:
    Mar 28, 2011
    Posts:
    151
    @Baste Holy S***! World to the West! I should have mentioned you guys earlier, but I was picking names out of the air. As it happens, I should have namechecked you earlier - except for Beacon, none of the games I've previously mentioned were made in Unity, and similarly we're going for a more authored game than anything procedural.

    World to the West is awesome (the variety and beautiful art and the mechanical depth...!), and Sir Clonington is a great example of the kind of combo behaviour we'd like to get going in our game.

    My fellow coder and I read your notes on Github, especially your Motivation document. Yikes. I'm usually a big Unity booster (I run the local Unity User Group) and I had no idea Unity was so weak in this area. It's really horrifying.

    At the moment we're starting to take a look at Playables. We may even try to contribute something to your github project, depending on how things go.

    It's infuriating that this is required, though. Obviously when something is broken, you have to fix it yourself, but I've seen really fluid, impressive combo gameplay in Unity before - Aztez is a real gold standard. It's obviously possible, somehow, but...!

    Until now I haven't noticed how few Axonometric Action Adventures are built with Unity... or really, anything with interruptable transitions.

    Thanks for your contributions, guys. I'll see if I can get some more eyes on this, and if I find out anything I'll report back here.
     
  7. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    4,125
    Hey, thanks! I wrote pretty much all of that code. It way... a bit of a mess, and I'm not 100% happy with how it turned out, but it was a lot of fun! I'm very happy that we got to put in a dedicated flex button.

    Easter egg: one of my coworkers added a feature where if you do the running jump slam thing, and just hold the button down so he keeps lying there, the camera zooms in to give you an extra glorious view after like 10 seconds.

    To be fair, Playables is pretty good. It's really hard to get into, due to being built in a strange way. The docs also suffer from the documentation software not really handling that strange implementation very well.
    It's also very, very clearly not meant to be something you use to play your animations directly, but something you use to build up those components from.

    Still, it's fast, and so far most things have worked the way I expected them to. I don't have any of the kinds of bugs I had with the Animator in the AnimationPlayer. To be fair, our current game has much less complex animation transitions going on, so it might be that I'm missing stuff, but the "just do a default linear transition if no transition is defined" gives us so much fewer issues than the old way.

    About AnimationPlayer; Let me know if you want to seriously give it a go, and I'll take the time to push an up to date version of the code. I've been avoiding doing it because there's a version of state queuing in there that I'm not very happy with. There's also a big question of when I pull the plug on rewriting the UI (it's bad) - I probably want to rewrite it in UI elements, our current project's probably staying on 2018.4 for the foreseeable future.
     
  8. Reverend-Speed

    Reverend-Speed

    Joined:
    Mar 28, 2011
    Posts:
    151
    Man as perfection - sexual magnetism personified! Love the easter egg... =D

    I also love all the little details the game is filled with - the gorgeous particle effects, the footprints, the flowers recoiling from impacts, etc...

    It works really well. I might be able to see one or two tiny bits where you'd want to tune it (and I know you're aware of them), but the whole interface really sells Clonington as an idea and experience. Great work...! =D

    Interesting! We're also targeting 2018.4 at the moment. Right now I'm going to focus on building infrastructure (menus, faders, etc) for the game, then I'll dive into animation proper (my co-coder, who will be mostly fighting with this, is on holiday atm). Thank you for the offer of updating Animation Player, but we should probably not immediately bother you on this until we've done all our due diligence...!

    It is a bit of a shame, though. I - like most Unity programmers - was fairly resistant to Mecanim when it turned up first, but I slowly came around to the idea of it being something that freed up animators/designers to focus on animation and gameplay harmony. And now I find out that the goal Mecanim was meant to serve, it precisely thwarts.

    Hmm. Sadface.
     
  9. dibdab

    dibdab

    Joined:
    Jul 5, 2011
    Posts:
    818
    as Baste said, avoid triggers

    - use CrossFade (keep triggers for selected cases)
    - keep track of your animator states yourself
    - interrupt and transition to states by CrossFade

    recently discovered this animator events which look good (haven't tried yet)
    https://github.com/forestrf/UnityAnimatorEvents

    - keep in mind that transitions are grey zone,
    but UnityAnimatorEvents says it can track transition starts/ends
     
  10. Reverend-Speed

    Reverend-Speed

    Joined:
    Mar 28, 2011
    Posts:
    151
    @dibdab - Yeah, triggers seem like the kiss of death. Full disclosure, I've used them for tons of stuff in the past and it's mostly been fine. I've encountered the fail-to-reset issue, but this use case really brings out the worst in them. Will take your other notes on board.

    Hey, that does look promising. Will investigate in a while...!

    Thanks for these notes.
     
  11. Reverend-Speed

    Reverend-Speed

    Joined:
    Mar 28, 2011
    Posts:
    151
    So, just continuing some research, I figured I'd take a look at Unity's best examples for this kind of input. At the moment, I'm poking around with their 3D Game Kit, a project intended to provide a foundation for a 3rd Person action adventure.

    I also built it as a WebGL player in case anybody wants to take a look. KB&M is WASD + Left Mouse, while controllers are recognised but the camera yaw is reversed. =/

    Aside from them using a Character Controller component (I thought everybody was using Rigidbody!) and some very nifty mecanim setups, it doesn't take long before you encounter a bunch of interrupt issues - such as if you take damage and immediately jump, the character just levitates upwards without going into the 'jump' animation.

    They've also got a bunch of 'triggers' in the animator, which seem like they're causing trouble ('inputDetected' is one of them, which you'd think you'd handle as a bool).

    I appreciate the amount of prefabs they've built for common interactions, but the main character feels a bit clunky. It's disappointing.

    I'm going to try out some more Unity examples shortly, including the recently released RPG Creator Kit - but if anybody has a better Unity example for me to try, I'm all ears.

    Had no time to experiment with Playables yet, looking forward to it.
     
    Last edited: Jul 29, 2019
  12. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    4,125
    I updated the github repo!

    I've been wanting to learn how to distribute my github repos through the package manager for a while, so I went and did that. It's surprisingly simple.

    Now, to use the AnimationPlayer, you can add it to your manifest.json file:

    Code (csharp):
    1. "com.baste.animationplayer": "https://github.com/Baste-RainGames/AnimationPlayer.git"
    Or, if you want to make changes, you can just clone the entire repo into the Packages folder. If your project is already a git project, you can include it as a submodule:

    Code (csharp):
    1. cd Packages/
    2. git submodule add https://github.com/Baste-RainGames/AnimationPlayer
    I haven't used submodules much, so we'll see how well it works.
     
  13. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    506
    "A bit clunky" is a massive understatement. I actually started looking at the 3D Game Kit today in order to use it as an example of how to rework an Animator Controller based setup to use Animancer instead and I'm absolutely astounded at how bad it is for something that's supposed to be a showcase of what Unity can do and how to implement things properly.

    Take the basic movement for example. The animations move your character forward as they turn, meaning that it moves you perpendicular to the direction of your input. Here's a gif of me pressing A and D to move left and right, yet the character keeps moving towards the camera with each turn (especially at the end):

    Recording.gif

    That alone makes it absolutely horrible to control with any precision, but there are several other basic issues too like how you can't jump again during the landing animation, which is absurd in a platformer.

    Then you get into the actual implementation of the code and Animator Controller which is of course a total mess:
    • There's an IdleSM sub state machine with a default idle and several others for when you stand idle too long. It has a RandomStateSMB script which will pick one of the others after a random amount of time. Sounds good. Min 0, max 5 (x normalized time of the basic animation which is about 4 seconds long). That doesn't sound right, because the character could get bored immediately any time you return to idle. Not to worry though, because the LocomotionSM actually has an Idle state of its own with one of its exit transitions being a TimeOutToIdle trigger that gets set somewhere in the 680 line PlayerController class using a manually updated float timer to count towards a value set in the Inspector (5 seconds).
    • So to implement the behaviour of "if the player stands idle for between 5 and 25 seconds, play a different animation", they used a convoluted combination of a state machine behaviour, a regular script, the animation length, and an extra Idle state inside the Locomotion sub state machine.
    • And since Animator Controllers have no concept of data structures, adding another animation to the random choices would require manually adding another state, setting up another 4 transitions (and making sure they're the same as the others), and also remembering to tell the RandomStateSMB that there are now 4 options. All that instead of just having an array that you could just add another element to and everything treating it as an array would continue working properly.
    • Then there's the PlayerInput class which has a singleton instance that it assigns in its own Awake method so some things access it through that property, but others use FindObjectOfType to find it for some reason and then the PlayerController uses GetComponent to find it.
    • It also has an attack wait time which is a constant 0.03 seconds, which really isn't the sort of thing that should be hard coded. But what's it used for? Of course it's to set a bool back to false after that time, so instead of "hey, the user clicked, if they can attack then do so" it's actually "hey, the user clicked, I have no idea if they can actually attack right now so just keep trying for about 2 frames and then give up".
    • Even their naming convention is shoddy. The PlayerInput class has an m_Movement field backing a MoveInput property ... well OK, there's also CameraInput and JumpInput and ... Attack and Pause ...
    That's all I've actually looked at so far and every single bit of it has been utterly terrible.

    Edit: BTW, sorry for the rant.
     
  14. Reverend-Speed

    Reverend-Speed

    Joined:
    Mar 28, 2011
    Posts:
    151
    Holy S***, @Baste, that's fantastic! I've yet to have time to sit down and really evaluate everything, but I really appreciate you uploading that! When my co-coder returns from his holidays, we'll devour that... =D

    @Kybernetik , no need to apologise for the rant. I started the thread seeking best practices for action adventure characters with interruptable animations; I think pulling apart what's been previously offered as 'the example' totally fits with that rubric... it's analysis.

    Regards the character moving forward with the animations - I'm the team's current animator and I'm not a good one, but isn't this kind of thing usually part of incorporating root motion, which helps avoid skating, etc? Isn't this what's used for games like Uncharted, et al? I guess the solution here is that there should be more animations with varying degrees of forward movement, handled by a blend tree.

    I don't have a PS3/4, so I can't really test how this works in Uncharted for myself atm. =)

    0_o

    Would you have any suggestions on better naming conventions? I see your point, I'm just curious. =D

    ...


    It'd still be nice to find a way to make things just work with Animator. To give credit to my co-coder, he also found the following two videos on the topic... I might try to get in touch with these folks:



    And speaking of alternative frameworks, here's a... very particular, somewhat limited one...

    Hope to come back with some more tests and information shortly.

    Thank you so much for taking an interest in this.
     
  15. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    4,125
    No problem! It's actually really valuable for me to get that project properly into it's own package living in a git submodule in our game, so I don't have to go copy over files from our game to the github repo every time I want to use the code in a different project.

    So the problem with root motion is that while you get better-looking result, it takes more time to make.

    If you're animating without root motion, you're just telling the blend tree where you're moving, and you hope that you can match that as well as possible based on some parameters. Let's call this "Best-fit" animation.

    Best-fit animation looks worse. You get foot-sliding and other mismatches between how the animator animated the model to move, and how it actually moves.

    Root motion looks much better. The character moves like the animator made it to move. There's also some things you can get away with not coding - like you don't have to add acceleration or deacceleration to the gameplay code, it just happens because when you set the speed blend to max or 0, the animation system is set up to do just that.

    On the other hand, it limits you to exactly the kinds of movements that's in the animation set. If you really need the character to turn real fast like, but you don't have a real fast like turn animation, you just can't do that, and have to go ask the animator to do that.
    There's also things that are harder to program. If you need your character to stop exactly at a position, that becomes hard as you're not setting the position of the character, you're steering it by setting values in a blend tree. If you have ever seen an npc in a AAA game that just keeps walking in tight circles around some target that it's trying to get to, I'll bet that the turn radius is tighter than the tightest turn radius it has animations for.

    So root motion vs. best-fit really comes down to resources. Do you have enough animator time to implement all the motions you need for your game? Do you have the programming time to work around the parts of root motion that are difficult? Do you need that level of fidelity?

    For World to the West, we only had one guy doing all the character models and all of the animations. We also didn't share any rigs between any of the characters, and none of them were Humanoid-compatible, so we literally had to hand-make every single animation for everyone.
    Oh and that guy didn't work full-time. So yeah we didn't use root motion.
    Also like don't do that. Also don't animate in 50 fps. Also don't put blend files directly in the project. We did everything wrong.

    Anyways, looking at the 3D game kit gif from above, it seems like the character has an instant turn animation, but for some reason it's only happening when turning from right to left, not left-to-right. Or, probably more precisely, it's happening every second time the character does a sharp turn. I'm guessing that the animator controller's set up with too few transitions that are interrupt-able, so the blending visits states that push the character downwards with root motion.
     
  16. Reverend-Speed

    Reverend-Speed

    Joined:
    Mar 28, 2011
    Posts:
    151
    Tangent -

    I have a bit about learning. Folks sometimes talk about learning, wisdom, etc - as the tree of knowledge. You climb the tree, you win the apple of understanding, etc.

    Bullshit.

    I think you start at the top of the tree of knowledge and fall down through it, hitting every branch on the way down.

    And maybe, if you get through the tree and survive the landing, you'll have learnt something.

    Which is to say I appreciate the work you guys did on World to the West, and I doubly appreciate you (and @Kybernetik !) for sharing that hard-won wisdom. My team are just balancing on the edge of the diving board above this next tree of knowledge (so what if it's a weird metaphor, it's my metaphor, if you don't like it go F*** yourself) and anything you can share to save us from getting hit by the same branches is very gratefully received.

    We'll undoubtedly hit hundreds of different branches, but we'll try to pass the fruits of those bruisings on in the same spirit.

    TLDR: Facts. Cheers, @Baste.

    As I said, at the moment, I'm our animator (we're a team of 3 atm and unwilling to expand until we have the basics right). I'm not a great one, in fairness, but I'm willing to do a bunch of different movement animations for our character as we explore systems. I kinda wanted to try doing things the 'right' way and avoid skating, etc, but given your notes and the angle we're playing at (very similar to World to the West), we'll probably stick with 'Best-fit'. We probably don't need super-high fidelity.

    ...That said...!

    Here's some Uncharted data from 2010 (relevant bit starts at 10.40 (idle and turning on the spot root motion), though the whole vid is interesting). Related info as .pdf. Obviously the dev is talking about a team that can afford 1 animator and 1 programmer per character and I can't afford to replace this piece of S*** Microsoft keyboard I'm using, but I think there's still some interesting stuff there about blending multiple animations together to save memory (and, presumably, time spent animating?). I don't think I'd mind about enemy characters not having this much attention on them if we made the main character look groovy...

    Just looking around again at games made from this point of view (Axonometric Top Down 60Degree Cabinet Oblique Zelda-Like With Perspective) - with the exception of the esteemed World to the West and Lucah, nearly everything is being made with UE... Seven, Redeemer, etc. Annoying.

    Well, time to start hitting those branches...

    Thanks again folks.
     
  17. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    506
    Yeah, @Baste described the problem accurately here. Though one thing I plan on trying when I get to it is using root motion but cancelling out any motion perpendicular to the player's input so in theory you get a middle ground between avoiding sliding and responsive controls.

    The specific convention you use is less important than sticking to it, because names like JumpInput and Attack suggest that those properties are fundamentally different somehow when they actually aren't. I would just use Jump/Attack/etc. because there's no point in suffixing everything with "Input" when you're inside a PlayerInput class.
     
  18. Reverend-Speed

    Reverend-Speed

    Joined:
    Mar 28, 2011
    Posts:
    151
    @Kybernetik - that sounds like a nice compromise between root motion and player intention. Please let us know how that goes, it's vital work. =D

    Regards naming conventions, yeah, that's basically what I was thinking. Verbose, consistent, aware of context. Great advice.
     
  19. dibdab

    dibdab

    Joined:
    Jul 5, 2011
    Posts:
    818
    about Uncharted-type of ways and methods:

    in Unity all layers consume processing time. so it's not wise to have too many layers.

    you can mix (playables might be better for this) in anim like the idlesinglepose+breathin in the video but needs to have separate animator controller and probably best to keep it separate from mecanim of the original anim (the idle) the pose should not be one-frame anim (because it might not play well with mecanim transitions)

    then adding in lateupdate (or anywhere later added on top of it) still have to write them on skeleton ie. read the bone curves out

    okay like this it doesn't look like many
    animlayers.jpg

    it probably has some ways to inject animation data on bodyparts separately (arms, legs, etc)
    yeah propably need to make the animations on T-pose, which makes up the additive anim (so cannot use animations already made, or at least you need to convert (zero out bone rotations etc)

    if you build up your mecanim by bodypart layers, then the system that animates them will be quite special... every "animation" will need a list of layers, on which it is played
     
    Last edited: Jul 30, 2019
  20. Reverend-Speed

    Reverend-Speed

    Joined:
    Mar 28, 2011
    Posts:
    151
    Well, ultimately there's a balance to be struck here between something that's practical for a small indie team and doing things 'properly', especially given your notes on multiple layers consuming processing time.

    Again, kind of a novice in this particular area, but don't we have avatar masks for just the purpose of putting animation data on bodyparts separately?

    At the moment I'm leaning towards the layer setup mentioned in the first video I linked to above, where you have one layer for locomotion, one override layer for combat actions and one additive layer for pain reactions.

    I'd quite like to have information about the character conveyed by posture as well, so I need to look into whether we should modify the normal animations or just swap out walkcycles and the like. Might be able to minimise that further, though.

    Thanks @dibdab , really useful information!
     
  21. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    506
    Here's another piece of awesomeness from the 3D Game Kit's character controller:
    Recording.gif
    It's exactly what it looks like. The bottom of the capsule is just touching the corner so it counts as grounded, but that ground is too steep for it to be allowed to move in that direction ...
     
  22. Reverend-Speed

    Reverend-Speed

    Joined:
    Mar 28, 2011
    Posts:
    151
    Hey @Kybernetik - I see you giving the asset a good kicking on their store page too. =D They just updated the project, but I can't seem to see a changelog, so it's impossible to see if they're paying attention to notes and suggestions without downloading the entire huge project...!

    Regards the capsule issue, a certain amount of that is kinda expected edge-case jankiness, no? Granted, I'm a novice in this area, so please feel free to put me right here.

    My default character size is usually 1.76y (average European male height), .64x, .32z, which gives me a capsule radius of .64. (I tend to run everything off a rigidbody - which also confused me about the 3DGameKit - should I be using Character Controllers?)
    upload_2019-7-31_10-48-54.png upload_2019-7-31_10-51-40.png
    Obviously a thinner capsule will help solve some of the levitation issues you've identified, but aside from maybe doing some raycast/overlapsphere tests to check for slopes and groundedness (which could also be somewhat expensive - multiple physics calls, even if spread out over frames etc), what's the good alternative to using capsule colliders?

    Would love to learn if there's a better way to achieve this on an indie budget!

    It also strikes me that we should maybe make a reference to this thread in the official 3D Game Kit thread, or post some of our notes and suggestions in there.

    Lastly, I note that one of your Unity Assets is named 'Inspector Gadgets'. I think that deserves a polite, but appreciative, round of golf claps.

    PS: Btw, your comment on the asset store page, "You can't jump again during the landing animation, which feels extremely clunky for a platformer" is absolutely on-point, that's a real weakness there.
     
  23. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    506
    Of course there will always be edge cases, but the handling of slopes and corners is one of the main things a character controller needs to focus on.

    I've always built my characters with Rigidbodies too so I can control things like this instead of relying on Unity's black box which has plenty of known issues.

    For this particular problem, I've often inherently solved it by simply having the slope detection (to determine if you can't move in a direction because it's too steep) being part of the regular ground detection code. So if your only contact normal is too steep, you aren't grounded so stop applying so much friction and the capsule will naturally slide off the corner.

    In one of my prototypes I even added code for when that happens to also calculate how much of the acceleration due to gravity is being countered each frame by the platform preventing the character from falling straight down so that I can re-apply that acceleration in the downhill direction. I never ended up releasing that game, but from what I can remember the idea worked quite well.

    If I had to do it again I'd start by looking at the top controllers on the Asset Store and github. I remember seeing the Kinematic Character Controller when it was released and its videos went through lots of common situations which it seemed so handle quite well. Chances are I'd still end up doing it myself, but I'd use them for inspiration.
     
  24. dibdab

    dibdab

    Joined:
    Jul 5, 2011
    Posts:
    818
    avatar masks and additive layers

    on the video starting at 17:10 he talks about that "stiffness"

    made a test using delta rotations

    this is how it looks
    deltaR1.gif

    Code (CSharp):
    1. public class addDeltaR : MonoBehaviour {
    2.  
    3.     public Transform[] def;//T-pose
    4.     public Transform[] mod;
    5.     public Transform[] addto;
    6.  
    7.     public Vector3[] eulDif;
    8.     int i;
    9.  
    10.     void LateUpdate () {
    11.  
    12.         for (i = 0; i < def.Length; i++) {
    13.            
    14.             Quaternion a = def[i].localRotation;
    15.             Quaternion b = mod[i].localRotation;
    16.             Quaternion relative = Quaternion.Inverse (a) * b;
    17.  
    18.             eulDif[i] = relative.eulerAngles;
    19.             addto[i].localRotation = relative;
    20.         }
    21.     }
    22. }
     
  25. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    4,125
    The built-in character controller isn't that bad, it's just made to be generic, and is only appropriate up to the point where you need the character movement to be more specific to your game.

    Since you get some things "for free" with it, I'd start with that (or the Kinematic Character Controller), and stick with it until it's not good enough anymore.

    You're going to want to be shooting out a lot of Raycasts. I think the characters in WttW does something like 20 each frame. They're surprisingly cheap, by the way.

    For ledges, as you notice when you play the game, we do a bunch of stuff. Mostly you just jump off when you move directly towards them, that's done with raycasts. If you move towards them at an angle, we steer you sideways so you run perpendicular to the edge - it's a variation on this (which we also do). You can wiggle your way into a situation similar to what's happening in @Kybernetik's example from the game kit, in which case we make you just slide down once you're far enough over.

    That took a ton of time to do. Not all at once, but gradually over the project. It took a day here, a couple of hours there, and sometimes several days at once, and gradually we improved the movement.

    This boils down to two pieces of advice:
    - Iterate a bunch on the character controller. You'll need something usable to start out with, but as your design changes, you'll want to change the controller.
    - Don't rely on physics simulations unless you're making a physics simulation game. For snappy controls, you definitely want to set the velocity of the character directly for the most part. Unless you're using root motion, I guess.
     
  26. Reverend-Speed

    Reverend-Speed

    Joined:
    Mar 28, 2011
    Posts:
    151
    - Just a quote from a friend with a fairly successful Unity game on Steam (which is played from the axonometric angle). Echos a lot of what Baste's said...!

    @Baste:

    I've been using the Rigidbody since Unity released examples of characters using Rigidbody. I figured, oh, we're moving in this direction, I should check it out... and really, it's proven to be a very reliable workhorse for me since then.

    Interesting regards Raycasts! Didn't think they were that cheap, I've always ended up staggering them over frames. But then I've been using fairly weak hardware until now, and we're currently targeting modern consoles for our game. Thanks for the advice.

    The info on World to the West is really useful. Our intention is to have no dedicated 'jump' - we'll employ dashing ala Hyper Light Drifter, but the Zelda-like hop on edges would also be very useful. My compliments to your implementation on WttW, it's very reliable, as I remember.

    To clarify, are you saying we should iterate on top of the built-in controller, or that we should iterate on our own character controller throughout the project? If it's the latter, yeah, I think we'll probably do that. Good advice.

    Regards your second point of advice, well, I think we're probably going to use the Rigidbody, but move it with Rigidbody.movePosition , which has always served me well in the past as a responsive solution (with the occasional Rigidbody.angularVelocity = 0.0f, to halt the craziness). Per your advice, I think we'll ditch root motion and go with best fit (goodbye 'right' way of doing things, hello snappy controls).


    @dibdab:

    0_o

    quaternions that's above my paygrade sir

    ulp

    I'll take a look, though. Thank you.


    @Kybernetik:

    I'm kinda hoping I can encounter these as I develop the game, iterating similar to Baste's advice above. And... you can get away with a lot, I've found, with an appropriately sized Rigidbody, some movePositions and moveRotations and a smattering of physics materials...

    Do you mind if I ask - do you continually detect the ground? In the past I've always just fired a raycast at the ground on jump input, and with a little care it seems to have worked passably well. Mind you, that's just in tests - this is the first 'production level' game of this type that I'll have made. I can see the constant 'isGrounded' test also being useful for slope detection (and other things).

    Actually, another thought - a colleague of mine recently remarked that he used overlapSphere instead of raycasts for ground detection, and on doing some research it seems overlapSphere is indeed as effective and a little more efficient. I'm reminded that Brendan Chung used sphere checks for mantling etc in Quadrilateral Cowboy, with Valve using them for zombie navigation in L4D... so I might start investing in spheres in the future...

    Hmm. So I presume the 'identify countered gravity and then re-apply' is to prevent people from, uh, Elder Scrollsing their way up things like mountains?

    I definitely plan to take a look at the top controllers on Asset Store and github... or at least the ones I can afford and understand. KCC is WAY beyond my paygrade. I think for a lot of this we'll follow Baste's advice and get stuck in and when we hit a problem we'll just have to reinvent calculus.

    Still pissed off about the mecanim situation, though. I'll let you know how I get on.

    Thank you all for your wonderful advice.
     
  27. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    506
    If you don't want the Rigidbody rotating, set its constraints to freeze rotation. I usually have the character model as a child of the Rigidbody. Rotate the model, move the Rigidbody.

    There's almost always a need to constantly know the grounded state to determine whether to play falling animations, how much acceleration the player has, etc.

    I often use physics collision events to determine groundedness (based on the angle of the collision normal).

    Yeah, any time you can't jump because the slope is too steep, my controller would slide you down as if in free fall where the Elder Scrolls controller lets you stand on and walk along super steep slopes with only slow sliding when you stand still.
     
  28. Reverend-Speed

    Reverend-Speed

    Joined:
    Mar 28, 2011
    Posts:
    151
    Sorry, yes, the last couple of times I've used Rigidbody it was useful to rotate it as well, but you're right, of course:
    Play the ball, not the man. =D

    So, when you say physics collision events, are you talking about something like OnCollision? So, OnCollision, iterate through array of colliders, dot product the collider normals and if we find one similar to the vertical orientation of the player character / vector3.up (depending on gameplay), then we're grounded? Hmm. I'd really got it into my head that in most cases a few raycasts would suffice. Makes sense, though.

    Thanks again, man.
     
  29. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    506
    Yeah, that's pretty much it. If you don't need to account for changing gravity, just find the normal with the largest y value and that's your most groundy contact. So either that's the ground, or you use it for the free fall calculation.
     
  30. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    4,125
    You might be able to use collision events for grounded checks. You might not.

    If you have a mesh that looks like this:

    upload_2019-8-1_16-29-58.png

    And your capsule-based rigidbody hits it like this:

    upload_2019-8-1_16-32-10.png

    You can get into all kinds of hairy situations. Right there you're not grounded, so you should start falling right down. But, if you're still in contact with the wall when you hit the ground, I'm pretty sure that you're not getting a new OnCollisionEnter message, if the ground is the same collider as the wall.

    That being said, I haven't tried this too much, so I might be missing a solution, or the problem might not be as big as I imagine.
     
  31. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    506
    You should get OnCollisionStay messages every frame unless your Rigidbody goes to sleep and they should contain multiple contact points. I don't remember specifically testing something like that, but I know that you can get multiple collision messages in one frame and each of them can have multiple contact points so I would expect that to mean it should work properly (but I might not have tested that either since like Unity 3).
     
  32. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    4,125
    I generally avoid OnCollision/TriggerStay as those have a quite high perf overhead. I've had those methods just existing wreck framerate. That being said, that's on objects that there are many of, it should be 100% fine on a character controller.
     
  33. Reverend-Speed

    Reverend-Speed

    Joined:
    Mar 28, 2011
    Posts:
    151
    @Baste - Your point on OnCollision performance is why I've mainly avoided using it in the past - seemed to make more sense to only get that information if I really needed it (on jump). That said, if it's reasonable on one player (or maybe a couple), then I'll use this going forward. I'll also look into OnCollisionStay - thank you, @Kybernetik.
     
  34. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    506
    I just released Animancer v3.1 which includes the new example that remakes the player from the 3D Game Kit to use Animancer instead. In particular, this section goes over the locomotion problem I mentioned.

    It turns out that I was wrong about being unable to jump during the landing animation. The actual issue was an even simpler mistake on their part: the PlayerController only checks the jump input in FixedUpdate so it can randomly miss the input if there happen to be multiple Updates between two FixedUpdates.

    Also, I was never able to get the character to levitate by jumping and getting hit at the same time like you described, but again I think that was actually a simpler issue ... it just does it randomly for no apparent reason as you can see in the first gif here.
     
  35. Reverend-Speed

    Reverend-Speed

    Joined:
    Mar 28, 2011
    Posts:
    151
    Wow, @Kybernetik, that's a really thorough examination of the 3D Game Kit and its failings...! The FixedInput thing is... ugh. I wonder how that happened, that's a fairly rookie error (said the rookie).

    You make Animancer look extremely attractive. =D I'm currently hit with some heavy work, so I can't really dig into this at the moment...

    ...but I do have some more ideas for investigations. 3D Game Kit isn't the only 'best practice' project Unity's released recently...! =D

    Thanks again, man, really appreciate your insight.