Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Rigidbody and "Normal" movement result in either jittering movement or collisions

Discussion in 'Scripting' started by xxfelixlangerxx, May 4, 2020.

  1. xxfelixlangerxx

    xxfelixlangerxx

    Joined:
    Feb 6, 2019
    Posts:
    31
    Hey,

    i am currently working on a 3D snake game.
    The code looks like this:
    Code (CSharp):
    1. public class SnakeScript : MonoBehaviour
    2. {
    3.     //movement
    4.     private Rigidbody rb;
    5.     public float force;
    6.     public float turnspeed;
    7.  
    8.     //spawning
    9.     public int spawndelay;
    10.     private GameObject activesegment;
    11.     private GameObject activetail;
    12.     private List<Vector3> lastpos = new List<Vector3>();
    13.     private List<Quaternion> lastrotation = new List<Quaternion>();
    14.     public List<GameObject> segments = new List<GameObject>();
    15.     public float spawnthreshold;
    16.     private bool spawninque = false;
    17.  
    18.     //graphic
    19.     public int skin;
    20.     public List<GameObject> heads = new List<GameObject>();
    21.     public List<GameObject> bodys = new List<GameObject>();
    22.     public List<GameObject> tails = new List<GameObject>();
    23.     private bool hastail = false;
    24.     private GameObject tail;
    25.  
    26.  
    27.  
    28.     private int i = 1;
    29.  
    30.     private void Start()
    31.     {
    32.         activetail = tails[skin];
    33.         activesegment = bodys[skin];
    34.         rb = GetComponent<Rigidbody>();
    35.         GameObject body = Instantiate(heads[skin], transform.position, transform.rotation);
    36.         body.transform.SetParent(this.gameObject.transform);
    37.  
    38.         //InvokeRepeating("addnewSegment", 3.0f, 2f);
    39.     }
    40.  
    41.     private void Update()
    42.     {
    43.         if (spawninque)
    44.         {
    45.             addnewSegment();
    46.             spawninque = false;
    47.         }
    48.  
    49.         Move();
    50.  
    51.         lastpos.Insert(0, transform.position);
    52.         lastrotation.Insert(0, transform.rotation);
    53.  
    54.         UpdateSegments();
    55.  
    56.         int index = (segments.Count+2) * spawndelay;
    57.         if(index < lastpos.Count){
    58.             lastpos.RemoveRange(index, lastpos.Count - index);
    59.         }
    60.  
    61.  
    62.     }
    63.  
    64.     public void Move()
    65.     {
    66.         if (Input.touchCount > 0)
    67.         {
    68.             Touch touch = Input.GetTouch(0);
    69.  
    70.             if (touch.position.x > Screen.width / 2)
    71.             {
    72.                 print("Moveleft");
    73.             }
    74.             else
    75.             {
    76.                 print("MoveRights");
    77.             }
    78.         }
    79.  
    80.         if (Input.GetMouseButton(0))
    81.         {
    82.  
    83.             if (Input.mousePosition.x > Screen.width / 2)
    84.             {
    85.                 //rechts
    86.                 rb.AddRelativeTorque(turnspeed * transform.up * Time.deltaTime, ForceMode.Force);
    87.  
    88.             }
    89.             else
    90.             {
    91.                 //Link
    92.                 rb.AddRelativeTorque(-turnspeed * transform.up * Time.deltaTime, ForceMode.Force);
    93.  
    94.             }
    95.         }
    96.         rb.angularVelocity = Vector3.Lerp(rb.angularVelocity, Vector3.zero, 0.1f);
    97.         //rb.velocity = force * transform.forward * Time.deltaTime;
    98.         transform.position += force * transform.forward;
    99.         //rb.MovePosition(transform.position + force * transform.forward);
    100.         //rb.position += force * transform.forward;
    101.     }
    102.  
    103.     private void FixedUpdate()
    104.     {
    105.         //rb.velocity = force * transform.forward;
    106.  
    107.     }
    108.  
    109.     public void addnewSegment()
    110.     {
    111.  
    112.         if (Vector3.Distance(transform.position, lastpos[spawndelay * i]) > spawnthreshold)
    113.         {
    114.             if (hastail)
    115.             {
    116.                 GameObject newsegment = Instantiate(activesegment, lastpos[spawndelay * i], lastrotation[spawndelay * i]);
    117.                 segments.Add(newsegment);
    118.                 newsegment.GetComponent<SegmentScript>().spawnint = spawndelay * (i - 1);
    119.                 tail.GetComponent<SegmentScript>().spawnint += spawndelay;
    120.                 i++;
    121.             }
    122.             else
    123.             {
    124.                 tail = Instantiate(activetail, lastpos[spawndelay * i], lastrotation[spawndelay * i]);
    125.                 segments.Add(tail);
    126.                 tail.GetComponent<SegmentScript>().spawnint = spawndelay * i;
    127.                 i++;
    128.                 hastail = true;
    129.             }
    130.            
    131.         }
    132.         else
    133.         {
    134.             spawninque = true;
    135.         }
    136.     }
    137.  
    138.     void UpdateSegments()
    139.     {
    140.  
    141.         foreach (GameObject intsegment in segments)
    142.         {
    143.             intsegment.transform.position = lastpos[intsegment.GetComponent<SegmentScript>().spawnint];
    144.             intsegment.transform.rotation = lastrotation[intsegment.GetComponent<SegmentScript>().spawnint];
    145.         }
    146.     }
    147.  
    148. }
    so basically I move my object, then the position and rotation to a list and have all the snake segments follow that list.
    The problem is that with using rb.velocity = force * transform.forward; I get jittery forward movement.
    When using transform.position += force * transform.forward; I get jittery collisions. What am I doing wrong?
    I´ve tried every combination of fixedupdate and normal with or without fixed delta time.
     
  2. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    You shouldn't be doing all that rigidbody stuff outside of FixedUpdate. Keep your input detection in Update though.

    If you're modifying the transform.position directly, you will probably want to raycast to know a collision will occur instead of waiting for the physics update to knock the object back after one occurs.
     
  3. Noblauch

    Noblauch

    Joined:
    May 23, 2017
    Posts:
    270
    Is it really necessary to use physics for that?
    I would suggest that you just move the snake via script.
    You should also in most cases not mix transform.position (setting) in combination with physics.
     
    PraetorBlue likes this.
  4. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,773
    You need to split up your input and physics code. Always do physics code in FixedUpdate, and never do input code in FixedUpdate. The former is the more important one here.

    Doing physics code in Update can have jittery results for different reasons, usually boiling down to one of two things:
    1) All of the AddForce/AddTorque type functions apply force across the duration of the "frame" in which they're being called - a game frame in Update, or a physics frame in FixedUpdate. If they're called in FixedUpdate, this duration is always the same value, so there's no inconsistency. If they're called in Update, this duration will change every time, so the amount of force can change every frame.
    2) physics updates may happen zero, one, or more times for each game frame. So as an example, if you set velocity = 4 each frame in Update, there will be an unpredictable number of physics updates which may be altering the velocity, e.g. via friction. If there are more physics frames, then friction will be taking a more dominant role in the object's speed compared to you forcibly setting it to 4, so the average speed may be lower. That inconsistency is bad.

    As for altering transform.position vs rigibody.velocity, choose one:
    A) change transform.position manually always, and set your rigidbody to kinematic. Do this in Update. (This will make your snake steamroll any and all obstacles - effectively, not being affected by physics at all. Collisions with other moveable physics objects may cause unpredictable bounces.)
    B) only ever set rigidbody.velocity, never touching the transform.position [except for things like teleportation, level reset, etc]. Do this in FixedUpdate (This will be affected by physics, e.g. will slide along walls properly. Other moveable objects will bounce in a predictable way off your snake. This is probably what you what.)

    So, stick to setting anything to do with physics in FixedUpdate, and only ever setting your .velocity, and go from there. If you do just that, does that behave correctly, or is there still something left to fix?
     
  5. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,773
    On another note: Rather than List<GameObject>, you can store a List<SegmentScript> directly, avoiding the dozens or hundreds of GetComponent<> calls per frame in your UpdateSegments function.
     
  6. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,890
    100% agree with @Noblauch, Snake is a game that doesn't make much sense with physics-based movement, unless you're trying to do something really different from a traditional Snake.