Help with snake like movement

Hi all!

i’m trying to create snake like movement that act more like cars convoy then a snake. below the code i came with. it works well as snake but i can’t figure out how to keep distance between body parts and keep the movement smooth (like car movement):

this part create a “hidden” snake and take care of controlling it.

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
 
public class MovementController : MonoBehaviour {
 
    public int ConvoyLength=3;
    public GameObject HeadObj;
    public GameObject SpacerObj;
    public GameObject temp;
    public static List<Member> Convoy = new List<Member>();
    private Vector3 pos;
    private float Speed = 10f;
    private float xDir;
    private float zDir;
 
    private int direction=4;
    private float timer;
    public float deltaTimer=1f;
 
    // Use this for initialization
    void Start () {
       xDir=Speed;
       HeadObj= Resources.Load ("Prefabs/test/Body") as GameObject;
       SpacerObj= Resources.Load ("Prefabs/test/Spacer") as GameObject;
 
       //Convoy.Add (HeadObj);
       if(ConvoyLength>1){
         Debug.Log ("adding more body");
         AddConvoyMembers();
       }
       pos= new Vector3(0f,0f,0f);
 
 
 
    }
 
    // Update is called once per frame
    void Update () {
       timer+=Time.deltaTime;
       //Convoy[0].transform.position=pos;
       if(Input.GetKey(KeyCode.UpArrow) ){
         xDir= 0f;
         zDir=Speed;
         direction= 1;
       }
       if(Input.GetKey(KeyCode.DownArrow) ){
         xDir= 0f;
         zDir= -Speed;
         direction=3;
       }
       if(Input.GetKey(KeyCode.LeftArrow) ){
         xDir= -Speed;
         zDir= 0f;
         direction=2;
       }
       if(Input.GetKey(KeyCode.RightArrow) ){
         xDir= Speed;
         zDir= 0f;
         direction=4;
       }
//   if(Input.GetKeyDown(KeyCode.Space) ){
//       ConvoyLength+=1;
//       Convoy.Add (BodyObj);
//       Convoy[ConvoyLength]= Instantiate (BodyObj,pos,Quaternion.identity) as GameObject;     
//   }
 
 
       //Convoy[0].posX = Convoy[0].posX + xDir* Time.deltaTime;
       //Convoy[0].posZ = Convoy[0].posZ + zDir* Time.deltaTime;
       if(timer > deltaTimer){
         Convoy[0].posX = Convoy[0].posX + xDir* Time.deltaTime;
         Convoy[0].posZ = Convoy[0].posZ + zDir* Time.deltaTime;
         Convoy[0].Dir = direction;
         MoveConvoy();    
         timer-=deltaTimer;
       }
    }
 
    void AddConvoyMembers(){
       float tempPos=0;
       Vector3 tempPos2 = new Vector3(tempPos,0f,0f);
       for(int i=0;i<ConvoyLength;i++ ){
         Convoy.Add (new Member());
       }
 
 
       temp = Instantiate (SpacerObj,tempPos2,Quaternion.identity) as GameObject;
       temp.tag="0";
       for(int i=1;i<ConvoyLength;i++ ){
         Convoy[i] = new Member();
         //Convoy[i].posX = tempPos;
         if(i%2==0){temp = Instantiate (HeadObj,tempPos2,Quaternion.identity) as GameObject;
         temp.tag=i.ToString ();
         }
       }
    }
    void MoveConvoy(){
       for(int index=ConvoyLength-1;index>0;index--){
 
          Convoy[index].posX = Convoy[index-1].posX;
          Convoy[index].posZ = Convoy[index-1].posZ;
          Convoy[index].Dir = Convoy[index-1].Dir;
 
       }
 
 
    }

then i have this code for the body parts, the idea that when i spawn new part with specific tag number it snap to it place on the hidden snake. it also make sure it rotate nicely to the current direction.

using UnityEngine;
using System.Collections;
 
public class MemberController : MonoBehaviour {
    private int TagNumber;
    private GameObject nextMember;
    private Vector3 pos;
    public float TurnSpeed;
    // Use this for initialization
    void Start () {
       TagNumber= int.Parse(this.tag);
       //this.transform.position=MovementController.Convoy[TagNumber].transform.position;
       }
 
    // Update is called once per frame
    void Update () {
       pos= new Vector3(MovementController.Convoy[TagNumber].posX,0f,MovementController.Convoy[TagNumber].posZ);
       this.transform.position= Vector3.Lerp (this.transform.position,pos,TurnSpeed* Time.deltaTime) ;
       //this.transform.position= pos;
       if(MovementController.Convoy[TagNumber].Dir==2){
         Quaternion target = Quaternion.Euler(0, 180f, 0f);
         transform.rotation = Quaternion.Slerp(transform.rotation, target, TurnSpeed * Time.deltaTime);
       }
       if(MovementController.Convoy[TagNumber].Dir==4){
         Quaternion target = Quaternion.Euler(0, 0f, 0f);
         transform.rotation = Quaternion.Slerp(transform.rotation, target, TurnSpeed *Time.deltaTime);
 
       }
       if(MovementController.Convoy[TagNumber].Dir==1){
         Quaternion target = Quaternion.Euler(0, -90f, 0f);
         transform.rotation = Quaternion.Slerp(transform.rotation, target, TurnSpeed *Time.deltaTime);
 
       }
       if(MovementController.Convoy[TagNumber].Dir==3){
         Quaternion target = Quaternion.Euler(0, 90f, 0f);
         transform.rotation = Quaternion.Slerp(transform.rotation, target, TurnSpeed *Time.deltaTime);
 
       }
       //this.transform.position=MovementController.Convoy[TagNumber].transform.position;
    }
}

and this public class for the body hidden parts:

public class Member{
    public float posX{ get; set;}
    public float posZ{ get; set;}
    public int Dir{ get; set;}
}

that’s it. not very complected. in the main script i have the variable “Speed” if i set it to high number i do get gaps between parts but the snake moves too fast for my needs. i tried to implement timing to slow it down but then it create jumpy movement.

i’m open to your suggestions…

thanks!!

So i was tinkering with this, and there are two methods to consider. 1) just follow at the closest distance to the direction you are planning or 2) follow in the exact movement schedule that you are going.

so, 1) is nothing but keeping track of a bunch of cars, and have them look at the target and move forward. the forward movement is controlled by the amount of distance to the target minus (the car length plus the follow distance). This is a very simple way, but it doesn’t look exactly like a snake, they turn to reach the next point just like a follow script. The next would be to modify this so that it may only rotate so much and progress a certain step amount. As long as the first unit cannot go over that rotation, then it would appear to snake behind it. This is actually pretty hard to control and make sure it is correct.

  1. Is a bit more simplistic. You create a series of points that you update each movement cycle. At that point you add the current head to the front, and remove the back, (back being relative to the last piece of your snake) Then, the movement cycle starts and each piece moves towards the target assigned on that list. This type of snake movement is not good for distance between cars.

One of the things I noticed on your script is that you are adding a piece at any time, rather than forcing the new piece to adapt to the snake at point intervals.

lastly, there is a thing like a train track, where you define a curve and get a position on that curve to assign things to. That has to do with biezer curves.

thanks for reply!

while waiting for answer i kept digging and find this link:

with some changes and tweaks it appear to be a much better solution then my.
with this i can control the gaps, the body follow nicely and i even made nice rotation for each body part…

thanks for your kind help any way!