Search Unity

Walking Quarduped with physics

Discussion in 'Physics' started by Renofox, Jan 14, 2015.

  1. Renofox

    Renofox

    Joined:
    Jan 14, 2015
    Posts:
    10
    I'm trying to make a quadruped that moves with in-game physics. At the moment my plan is to use legs on joints, which work by lifting up, rotating towards the destination, extending and returning to original position. Rear legs would do the same without sideways movement, so the creature would automatically turn to face the direction its moving.

    Apparently the customizable joints should be best for the wobbly movement I'm looking for, but I have no idea how to make them rotate. I have successfully made a leg spin, but how do I simply rotate the limb from one specific position to another?

    I'm going about this wrong or unoptimally, suggestions for better methods of making this are welcome too.
     
  2. B1PPER

    B1PPER

    Joined:
    Dec 22, 2014
    Posts:
    23
    The first thing you need to realize about getting this to work with physics is that using "AddForce" behaves like a thruster... there is no reactive force. So as the leg presses down against the terrain, it will stop and won't "push away" from the terrain which elevates the body of the walker. You can move the bones or joints a few different ways. You can use translate (which doesn't really use physics), you can use "AddForce" which applies a force and moves a rigidbody in the direction specified, then you can also use joint motor (which I still don't understand very well).

    Have a look at this thread...
    http://forum.unity3d.com/threads/be...draulic-stabilizers-on-a-mobile-crane.287274/

    I was trying to do something semi-similar except I was looking to model the outriggers on a mobile crane. Uberpete shared a method of implementing the joint motion using a spring motor, or joint motor. The other thing to keep in mind is that you may need to lock the joints at some point and you can't use the "Freeze Position" property because it'll lock the model up and not allow it to move. You also can't just lock that movement direction because it will return the joint to its original position. So it seems the best way to lock the joint is to create (then destroy) a fixed joint. You also might be able to do this with Inverse Kinematics... but I haven't had much experience with it. Check out this asset store plug-in:

    http://forum.unity3d.com/threads/fi...m-look-at-fabrik-ccd-ik-beta-released.222685/

    The creator of that plug in used it to create a quadruped, so it may be just what you're looking for and may save you from having to re-invent a wheel.
     
  3. Renofox

    Renofox

    Joined:
    Jan 14, 2015
    Posts:
    10
    Thanks for the response. I'm using joints to move the rigidbody limbs, which at least seems to work when the leg is just spinning around. The problem is, I still haven't found out how to control the joint target rotation from the script.

    I'm also starting to consider using an extra part for elbows to get one hingejoint for back and forth movement and another for sideways movement, because I don't have any clue how quaternions work. Would this double the processor overhead for each joint though?

    The IK plugin looks nice, but it's not what I'm looking for. This game requires Surgeon Simulator -style fumbling and stumbling to some extent. ;)
     
  4. B1PPER

    B1PPER

    Joined:
    Dec 22, 2014
    Posts:
    23
    I haven't played Surgeon Simulator so I'll have to take your word for it. I don't really understand quaternions either, so maybe someone else will be able to step in with some other ideas.
     
  5. Renofox

    Renofox

    Joined:
    Jan 14, 2015
    Posts:
    10
    I need some proper tutorials for scripting joints at all. Here's my attempt at changing the target position of a hinge joint, but it gives the error "Cannot modify the return value of 'UnityEngine.HingeJoint.spring' because it is not a variable":

    Code (CSharp):
    1. //creating variables for the joint
    2. public GameObject LeftShoulder;
    3. public HingeJoint leftShoulderJoint;
    4.  
    5. //setting the joint to the variable
    6. LeftShoulder = transform.Find ("LeftShoulder").gameObject;
    7. leftShoulderJoint = LeftShoulder.GetComponent<HingeJoint> ();
    8.  
    9. //Attempt to change the targetposition of the joint, does not work.
    10. leftShoulderJoint.spring.targetPosition++;
    I'd also need to know how to work with several joints in a same part, as just GetComponent<HingeJoint> works when there's only one hinge to control.
     
  6. B1PPER

    B1PPER

    Joined:
    Dec 22, 2014
    Posts:
    23
    First let me preface all of this by saying that I'm relatively new to Unity myself, so take all of this with a grain of salt. I'm also liable to end up in over my head real quick so hopefully someone with a bit more experience can comment on this as well.

    First, In the inspector (in the editor), do you have your LeftShoulder game object selected in the parameters for the script? If so, you don't need to use "transform.Find". If you're instantiating objects and so forth, then maybe you will... but that's a different discussion.

    Found this:

    http://forum.unity3d.com/threads/assign-hingejoint-spring-targetposition-in-c.105427/
    and this
    http://forum.unity3d.com/threads/rotation-interpolation-with-constant-speed.48076/#post-308915

    Looks like you have to go down another level and declare a variable for the spring component. I didn't bother with a variable for the hingeJoint but you could do that as well. This code shouldn't matter what game object it's attached to as long as you set the desired joint in the inspector.

    so this code should work (tested):


    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class elbowScript : MonoBehaviour {
    5.  
    6.     public GameObject LeftShoulder;
    7.     public float SpringCoefficient = 30;
    8.     public float Damper = 10;
    9.     private float target;
    10.     // Controls
    11.  
    12.     public KeyCode upKey = KeyCode.UpArrow;
    13.     public KeyCode downKey = KeyCode.DownArrow;
    14.     public KeyCode leftKey = KeyCode.LeftArrow;
    15.     public KeyCode rightKey = KeyCode.RightArrow;
    16.     private JointSpring shoulderSpring;
    17.  
    18.     // Use this for initialization
    19.     void Start () {
    20.         //creating variables for the joint
    21.  
    22.    
    23.         shoulderSpring = LeftShoulder.hingeJoint.spring;
    24.         shoulderSpring.targetPosition = 0;
    25.         shoulderSpring.spring = SpringCoefficient;
    26.         shoulderSpring.damper = Damper;
    27.         LeftShoulder.hingeJoint.spring = shoulderSpring;
    28.  
    29.     }
    30.  
    31.     // Update is called once per frame
    32.     void FixedUpdate () {
    33.  
    34.         if (Input.GetKey (upKey)) {
    35.             //Attempt to change the targetposition of the joint, does not work.
    36.             shoulderSpring.spring = SpringCoefficient;
    37.             shoulderSpring.damper = Damper;
    38.             shoulderSpring.targetPosition++;
    39.             LeftShoulder.hingeJoint.spring = shoulderSpring;
    40.  
    41.                 }
    42.         else if (Input.GetKey (downKey)) {
    43.             shoulderSpring.targetPosition--;
    44.             shoulderSpring.spring = SpringCoefficient;
    45.             shoulderSpring.damper = Damper;
    46.             LeftShoulder.hingeJoint.spring = shoulderSpring;
    47.         }
    48.         else if (Input.GetKey (leftKey)) {
    49.  
    50.         }
    51.         else if (Input.GetKey (rightKey)) {
    52.  
    53.  
    54.         }
    55.  
    56.  
    57.     }
    58. }
    You can change GetKey to GetKeyDown if you want it to be a continuous change. Just remember you're setting to an angle, so the movement doesn't stop immediately when you release the key.
     
    Last edited: Jan 18, 2015
  7. Renofox

    Renofox

    Joined:
    Jan 14, 2015
    Posts:
    10
    Thanks again, apparently the problem is that C# cannot change a single value of a struct, and instead of using simply

    Code (JavaScript):
    1. hingeJoint.spring.targetPosition = 0;
    it would need to use

    Code (CSharp):
    1.     JointSpring spr = hingeJoint.spring;
    2.     spr.targetPosition = 0;
    3.     hingeJoint.spring = spr;
    4.  
    Is that slower to run, and should I do the movement code in javascript instead?
     
  8. B1PPER

    B1PPER

    Joined:
    Dec 22, 2014
    Posts:
    23
    I doubt it will make much difference.
     
  9. shaderbytes

    shaderbytes

    Joined:
    Nov 11, 2010
    Posts:
    900
    No Unity script is doing exactly the same operation behind the scenes ( compiler magic ) its just been abstracted to setting it directly.
     
  10. Renofox

    Renofox

    Joined:
    Jan 14, 2015
    Posts:
    10
    Ok, now I have successfully made the leg move, and even found out how to add more joints via script through trial and error.

    I made what seemed like a brisk gallop in the editor, but when I compile it into an executable it slows down to about 1/30th of the original speed. Physics and everything else works as fast as before, but the animation (adding 0.3 to target rotation each Update) is incredibly slow. What could be causing this, and how do I fix it?
     
  11. Renofox

    Renofox

    Joined:
    Jan 14, 2015
    Posts:
    10
    Even more problems... Even though the limb movement is well-adjusted, the creature just randomly slides around the ground even when all its legs are still! Is there a friction setting or something to actually make the limbs stick to the ground when they're planted?
     
  12. shaderbytes

    shaderbytes

    Joined:
    Nov 11, 2010
    Posts:
    900
    Unity has physics materials , you can set the global material and then a material for each physics item. A physics material has parameters for how friction and bounce are calculated between surfaces.