Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We are updating our Terms of Service for all Unity subscription plans, effective October 13, 2022, to create a more streamlined, user-friendly set of terms. Please review them here: unity.com/legal/terms-of-service.
    Dismiss Notice
  3. Have a look at our Games Focus blog post series which will show what Unity is doing for all game developers – now, next year, and in the future.
    Dismiss Notice

Trouble creating fluid snake tail movement

Discussion in 'Scripting' started by LazyGoblinCody, Nov 19, 2017.

  1. LazyGoblinCody

    LazyGoblinCody

    Joined:
    Mar 18, 2015
    Posts:
    66
    Hey everyone right now I am trying to make a snake type game and I am having troubles making to tail move more smoothly.

    I have followed this tutorial: https://noobtuts.com/unity/2d-snake-game

    but this gives it more of a retro feel and I am looking to give mine more of a smoother type of feel. If that makes sense.

    Here is the body movement code with the InvokeRepeating commented out because I think that may be an issue but if I run it in update the tail just stacks on top

    Thanks in advance!

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using UnityEngine;
    5.  
    6. public class BodyMovement : MonoBehaviour {
    7.  
    8.     public float waitTime;
    9.  
    10.     public GameObject tailPrefab;
    11.  
    12.     public PlayerMovement move;
    13.  
    14.     // Keep Track of Tail
    15.     public List<Transform> tail = new List<Transform>();
    16.  
    17.     public BodyMovement body;
    18.  
    19.     void Awake()
    20.     {
    21.         move = FindObjectOfType<PlayerMovement>();
    22.         body = GetComponent<BodyMovement>();
    23.     }
    24.  
    25.     // Use this for initialization
    26.     void Start()
    27.     {
    28.         //InvokeRepeating("TailTest", 0.1f, waitTime);
    29.     }
    30.  
    31.     // Update is called once per frame
    32.     void Update () {
    33.         TailTest();
    34.     }
    35.  
    36.     void TailTest()
    37.     {
    38.         Vector2 v = transform.position;
    39.  
    40.         if (move.didEat)
    41.         {
    42.  
    43.             //Load prefab into the world
    44.             GameObject tempTail = (GameObject)Instantiate(tailPrefab, v, Quaternion.identity);
    45.  
    46.             //Keep track of it in our tail list
    47.             tail.Insert(0, tempTail.transform);
    48.  
    49.             //Reset the bool for eat
    50.             move.didEat = false;
    51.         }
    52.  
    53.         //Do we have a tail?
    54.         if (tail.Count > 0)
    55.         {
    56.             //Move last tail element to where the head was
    57.             tail.Last().position = v;
    58.  
    59.             //Add to front of list, remove from the back
    60.             tail.Insert(0, tail.Last());
    61.             tail.RemoveAt(tail.Count - 1);
    62.         }
    63.  
    64.     }
    65. }
    of each other.
     
  2. fire7side

    fire7side

    Joined:
    Oct 15, 2012
    Posts:
    1,819
    Here are the problems with smooth movement.
    You won't be able to move the last piece of tail to the head. All the tail pieces have to move a small amount. Otherwise your eye would see it, I think. Unity could easily do that, it just requires code where each piece follows the piece in front of it.
    It can only turn when the head is at the center of a grid. This means there will be a slight delay if the player hits a key, but only a slight one.

    The code would be quite different. Probably the best way to start is to get smooth movement of the head that turns at the proper time, then design a body piece that follows the piece in front and turns at the same point the one in front turned.
    One function that might help would be MoveTowards();
    Then you could give it the next grid position, and when it reached that point, it could decide whether to turn or continue straight.
     
    Last edited: Nov 20, 2017
  3. LazyGoblinCody

    LazyGoblinCody

    Joined:
    Mar 18, 2015
    Posts:
    66
    So I will need to create grid positions in order for it to work with smooth movement?
     
    unity_Up2CFeVz2Ty7wg likes this.
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    28,314
    To get a feel for what is possible smooth-wise, try attaching the built-in Unity TrailRenderer to a blank game object and wherever you move it, it will leave a trail behind it.

    Make a little bit of trail and switch the scene to Wire Frame mode and you can see what kind of geometry Unity produces to get that smooth effect, and you can produce this yourself in code.

    You can also buy a package such as Vectrosity (Unity Asset Store) that will give you a leg up on how to create these sorts of line-based things.
     
  5. LazyGoblinCody

    LazyGoblinCody

    Joined:
    Mar 18, 2015
    Posts:
    66
    Well, the thing is I have one gameobject which is the main character and when the character hits a pick up or trigger object then it will add a different object behind it to follow and so on kind of like the game snake. I do not want to create a continuous single line like an actual snake.

    When I talk about smooth I mean that there is no jitters with my code above it feels/looks jittery if I do the invokerepeating I want it to be smooth and not jittery at all.

    Hope this makes sense.
     
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    28,314
    If you have discrete objects lined up behind the smoothly-moving player (I assume like a conga line), what you essentially need to do is create a conveyor belt of positions for subsequent objects to follow in precisely the same way that your player character moves.

    For a first pass and to understand what is happening, you can just create an ever-growing List<Vector3> of positions that your player occupies, and then you can keep adding to it as the player moves around.

    To space out the objects behind your player, you would travel backward down this list and select a position (or tween between two positions) in that historical list in order to have each follower smoothly follow. If you reach the first position, then all the conga followers will stack up on that first position.

    Once you have that working, then you can come up with a way to prune the list so it does not grow endlessly without bounds. But even if you never get around to that, the above setup will work fine and only consume a very small amount of memory for the ever-growing list.
     
  7. LazyGoblinCody

    LazyGoblinCody

    Joined:
    Mar 18, 2015
    Posts:
    66
    Cool! Thank you, that is a good way to break it down and start!
     
    Kurt-Dekker likes this.
  8. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    28,314
    I knew this sounded familiar so I ransacked my code and found a little demo I posted to these forums some time ago.

    I enclose it here if you wanna futz around with it.

    That one actually supports both "follow by time" or "follow by distance" and has a little demo scene.
     

    Attached Files:

    Kelborn likes this.
  9. LazyGoblinCody

    LazyGoblinCody

    Joined:
    Mar 18, 2015
    Posts:
    66
    Thanks! I will give it a look.
     
  10. ookk47oo

    ookk47oo

    Joined:
    Mar 17, 2017
    Posts:
    76
    Hi, I struggled to get a way to prone the position list but could not find an property algorithm. Could you
    give some inspiration?
     
  11. ookk47oo

    ookk47oo

    Joined:
    Mar 17, 2017
    Posts:
    76
    Never mind. I got it
     
unityunity