0
\$\begingroup\$

I try to make a game like the classic snake game but on a round ground (Earth). On a plane, the script works well, but when i moved it on a sphere, the bodyparts (prefabs), are not working good as you can see in the picture ( they are going right/left, but they do not sit on the spehre and i tried already to use sphere collider, box collider, rigidbody) and i dont know really how to make it so that they will follow 100% correctly the player. Thanks for help! :/ . Here i put the script for the Player and bodyparts:

using System.Collections;

using System.Collections.Generic;

using UnityEngine; using UnityEngine.UI;

public class PlayerMovementScript : MonoBehaviour {

protected Joystick joystick;
public float speed;
[SerializeField] private float turnFactor;
[SerializeField] private Transform planet;
public List<Transform> bodyParts = new List<Transform>();
public float minDistance = 0.25f;
public int beginSize;
public float rotationSpeed = 50;
public float timeFromLastRetry;
public GameObject bodyprefabs;
public Text currentScore;
public Text scoreText;
public GameObject deadScreen;
private float dis;
private Transform curBodyPart;
private Transform PrevBodyPart;

public bool isAlive;
 void Start()
{
 joystick = FindObjectOfType<Joystick>();
 speed = 3f;
 StartLevel();
}
public void StartLevel()
{
 timeFromLastRetry = Time.deltaTime;
 //deadScreen.SetActive(false);
 for (int i = bodyParts.Count -1; i > beginSize; i++)
 {
     Destroy(bodyParts[i].gameObject);
     bodyParts.Remove(bodyParts[i]);
 }
 bodyParts[0].position = new Vector3(0, 0.5f, 0);
 for (int i = 0; i < beginSize - 1; i++)
 {
     AddBodyPart();
 }
 bodyParts[0].position = new Vector3(0, 0.5f, 0);
 bodyParts[0].rotation = Quaternion.identity;
 currentScore.gameObject.SetActive(true);
 currentScore.text = "Score: 0";
 isAlive = true;
}
void Update()
{
 if (isAlive)
       Move();
 if (Input.GetKey(KeyCode.Q))
     AddBodyPart();
 //RotateAroundPlanet();
 var rb = GetComponent<Rigidbody>();
 //rb.velocity = new Vector3(joystick.Horizontal * 100f, rb.velocity.y, joystick.Vertical * 100f);
}
public void Move()
{
 float curspeed = speed;
 //if (Input.GetKey(KeyCode.W))
 //    curspeed *= 2;
 bodyParts[0].Translate(bodyParts[0].forward * curspeed * Time.smoothDeltaTime, Space.World);
 if (Input.GetAxis("Horizontal") != 0)
     bodyParts[0].Rotate(Vector3.up * rotationSpeed * Time.deltaTime * Input.GetAxis("Horizontal"));
 for (int i = 1; i < bodyParts.Count; i++)
 {
     curBodyPart = bodyParts[i];
     PrevBodyPart = bodyParts[i - 1];
     dis = Vector3.Distance(PrevBodyPart.position, curBodyPart.position);
     Vector3 newpos = PrevBodyPart.position;
     newpos.y = bodyParts[0].position.y;
     float T = Time.deltaTime * dis / minDistance * curspeed;
     if (T > 0.5f)
         T = 0.5f;
     curBodyPart.position = Vector3.Slerp(curBodyPart.position, newpos, T);
     curBodyPart.rotation = Quaternion.Slerp(curBodyPart.rotation, PrevBodyPart.rotation, T);
 }
}
public void AddBodyPart()
{
 Transform newpart = (Instantiate(bodyprefabs, bodyParts[bodyParts.Count - 1].position, 
 bodyParts[bodyParts.Count - 1].rotation) as GameObject).transform;
 newpart.SetParent(transform);
 bodyParts.Add(newpart);
 currentScore.text = "Score: " + (bodyParts.Count - beginSize).ToString();
}
public void Die()
{
 isAlive = false;
 scoreText.text = "Your score was: " + (bodyParts.Count - beginSize).ToString();
 currentScore.gameObject.SetActive(false);
 deadScreen.SetActive(true);
}

enter image description here

\$\endgroup\$
2
  • \$\begingroup\$ You should probably remove the line newpos.y = bodyParts[0].position.y;. That doesn't make sense for the type of 3D movement you're trying to achieve. \$\endgroup\$
    – Kevin
    Mar 29, 2021 at 22:16
  • \$\begingroup\$ OMG, that was the only thing I had to do to make it work! Thanks a lot! ^^ \$\endgroup\$
    – Vlad Stefy
    Mar 30, 2021 at 11:27

2 Answers 2

0
\$\begingroup\$

If the planet and body parts are all spheres, you don't even need to use colliders or physics. Keep in mind that by definition, every single point on the surface of a perfect sphere is exactly the same distance from the center of the sphere (that distance being the sphere's radius). Using this fact and Vector3.MoveTowards(), we can easily implement logic to move along a sphere's surface.

[SerializeField] private Transform sphere; //set in Inspector
float bodyPartSpacing = 1; //change to suit the size of your body parts
float sphereRadius = 10; //change to suit the size of your sphere
void Update() {
    //other code goes here
    //[...]

    //align the snake's head to the surface of the sphere
    SetDistance(bodyParts[0], sphere, sphereRadius + bodyPartSpacing / 2f);
    //align body parts
    for (int i = 1; i < bodyParts.Count; i++) {
        curBodyPart = bodyParts[i];
        prevBodyPart = bodyParts[i - 1];
        //align to previous body part
        SetDistance(curBodyPart, prevBodyPart, bodyPartSpacing);
        //align to surface of sphere
        SetDistance(curBodyPart, sphere, sphereRadius);

        //update rotation; simply look at the previous body part
        //while maintaining "up" as directly-away-from-the-sphere
        Vector3 up = curBodyPart.position - sphere.position;
        curBodyPart.LookAt(prevBodyPart.positiion, up);
    }
}

//Move 'a' so that it is 'desiredDistance' units from 'b'
private void SetDistance(Transform a, Transform b, float desiredDistance) {
     float distance = Vector3.Distance(a.position, b.position);
     float excess = distance - desiredDistance;
     a.position = Vector3.MoveTowards(a.position, b.position, excess);
}

\$\endgroup\$
-1
\$\begingroup\$

One very simple way to do this would be to only move the front ball and attach each ball to the next ball with a joint component. Here is a useful video describing all the joint components in unity: https://www.youtube.com/watch?v=MElbAwhMvTc.

\$\endgroup\$
2
  • \$\begingroup\$ I don't think it would work for the same reason that a trailer does not follow the exact same path as the car pulling it: the pulled objects held with joints will take the shortest path available and "flatten" the curves made by the head. \$\endgroup\$
    – Vaillancourt
    Mar 29, 2021 at 11:54
  • \$\begingroup\$ It's not working well. I tough that maybe in my code i need to modify something if you can help m. I'm new and a bit noob :/ \$\endgroup\$
    – Vlad Stefy
    Mar 29, 2021 at 17:16

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .