This has been solved. However, the movement is not 'fluid' and is moving per pixel (like in 2D). Special thanks to [tedthebug], [LeftyRighty] & [martinmr]. Useful Links used: http://noobtuts.com/unity/2d-snake-game - the main website that helped me! - the camera controls - the one that made me realise that I can integrate 2D Games into 3D Games in Unity I will post the codes if many people wants it, or after I finish the project.
I did something like this last year. I had a list of the snake body parts & increased the length of the list. I iterated through it to make sure that each was instantiated. Edit: I had posted the code for it in unity answers but I can't find it now.
This is my updated code, and I used Instantiation, but there's a compiler error. Do you know how to solve it? Code (CSharp): using UnityEngine; using System.Collections; using System.Collections.Generic; using System.Linq; public class Movement : MonoBehaviour { public float speed; private Vector3 dir; List<Transform> tail = new List<Transform>(); bool ate = false; public GameObject tailPrefab; void Start () { dir = Vector3.right; } void Update () { if (Input.GetMouseButtonDown (0)) { //anti-clockwise movement if (dir == Vector3.right) { dir = Vector3.forward; } else if (dir == Vector3.forward) { dir = Vector3.left; } else if (dir == Vector3.left) { dir = Vector3.back; } else if (dir == Vector3.back) { dir = Vector3.right; } } if (Input.GetMouseButtonDown (1)) { //clockwise movement if (dir == Vector3.right) { dir = Vector3.back; } else if (dir == Vector3.back) { dir = Vector3.left; } else if (dir == Vector3.left) { dir = Vector3.forward; } else if (dir == Vector3.forward) { dir = Vector3.right; } } float amountToMove = speed * Time.deltaTime; transform.Translate (dir * amountToMove); } void Move () { Vector3 v = transform.position; transform.Translate (dir); if (ate) { GameObject tailPrefab; Instantiate(tailPrefab, transform.position, transform.rotation) as Transform; tailPrefab.transform.position = "-1, 0, 0"; ate = false; } else if (tail.Count > 0) { tail.Last ().position = v; tail.Insert (0, tail.Last ()); tail.RemoveAt (tail.Count - 1); } } void OnCollisionEnter(Collision coll) { if (coll.gameObject.name == "FoodPrefab") { ate = true; Destroy(coll.gameObject); } } }
... which says what? edit: oh, it's probably this Code (csharp): tailPrefab.transform.position="-1, 0, 0"; you can't do this. What are you trying to do with that?
also part 60 to 67 will not work this way. this you have to change: Code (CSharp): if (ate) { Transfrom tailPrefab = Instantiate(tailPrefab, transform.position, transform.rotation) as Transform;; tailPrefab.position = new Vector3(-1f, 0f, 0f); ate = false; } hope this will work for you but question, normaly you want to set te new tail object at the end of the snake, but with -1 0 0 it will be set at the world koordiantes -1 0 0 and not at the end of your snake
it occurred to me that I never actually made a snake prototype... so I made one GameManager is a little "placeholderish" but the overall snake movement is working nicely Spoiler Code (csharp): using UnityEngine; public class GameManager : MonoBehaviour { [SerializeField] private float speed = 1; [SerializeField] private float speedUpFactor = 0.1f; [SerializeField] private GameObject currentFood; [SerializeField] private GameObject foodPrefab; [SerializeField] private int gameWidth; [SerializeField] private int gameHeight; public float GetSpeed() { return speed; } public void Update() { // would make more sense to have this trigger off the food being eaten via an event, // but it's small scale app so isn't going to impact performance much if(!currentFood) { speed *= 1-speedUpFactor; // really needs to check there isn't a snake part at that location... currentFood = (GameObject)Instantiate(foodPrefab, new Vector3(Random.Range(0, gameWidth), 0, Random.Range(0, gameHeight)), Quaternion.identity); } } } Code (csharp): using UnityEngine; using System.Collections; public class SnakeHead : MonoBehaviour { [SerializeField] private SnakeBody nextSection; [SerializeField] private Vector3 direction; [SerializeField] private bool alive; [SerializeField] private GameObject bodyPrefab; [SerializeField] private GameManager gameManager; void Awake() { direction = new Vector3(1, 0, 0); gameManager = FindObjectOfType<GameManager>(); } void Start() { alive = true; StartCoroutine(MoveSnake()); } void Update() { // get inputs float v = Input.GetAxisRaw("Vertical"); float h = Input.GetAxisRaw("Horizontal"); // change direction if(v != 0) { direction = new Vector3(0, 0, v); } else if(h != 0) { direction = new Vector3(h, 0, 0); } } public IEnumerator MoveSnake() { while (alive) { yield return new WaitForSeconds(gameManager.GetSpeed()); bool nom = false; // store old position Vector3 oldPosition = transform.position; // add raycast code for collision check here Ray ray = new Ray(transform.position, direction); RaycastHit hit; if(Physics.Raycast(ray, out hit, 1f)) { // check for food ahead SnakeFood food = hit.transform.GetComponent<SnakeFood>(); if(food) { nom = true; food.Eaten(); } // check for body ahead SnakeBody body = hit.transform.GetComponent<SnakeBody>(); if(body) { alive = false; } } // we've eaten add new body section where the head is before moving forward to where the food is if (nom) { SnakeBody clone = ((GameObject)Instantiate(bodyPrefab, transform.position, Quaternion.identity)).GetComponent<SnakeBody>(); clone.SetNextSection(nextSection); // ensure continuity with rest of body nextSection = clone; } // move the head transform.Translate(direction); // move the rest of the snake if we didn't eat if(nextSection && !nom) { nextSection.MoveSection(oldPosition); } } } } Code (csharp): using UnityEngine; public class SnakeBody : MonoBehaviour { [SerializeField] private SnakeBody nextSection; public void MoveSection(Vector3 pos) { Vector3 oldPosition = transform.position; transform.position = pos; if(nextSection) { nextSection.MoveSection(oldPosition); } } public void SetNextSection(SnakeBody s) { nextSection = s; } } Code (csharp): using UnityEngine; public class SnakeFood : MonoBehaviour { [SerializeField] private float delay = 0; [SerializeField] private AudioClip eatenClip; public void Eaten() { // do sound stuff if(eatenClip) { AudioSource audio = FindObjectOfType<AudioSource>(); if(audio) { audio.PlayOneShot(eatenClip); delay = eatenClip.length; } } // stop further collisions foreach (Collider c in GetComponents<Collider>()) { c.enabled = false; } // remove gameobject Destroy(gameObject, delay); } }
Actually, I wanted to set the new tail object at the end of the snake. So how do I do it? And also there seem to be an error after I placed your codes: " Use of unassigned local variable 'tailPrefab' " Thanks for helping though!
I tried it but somehow it couldn't work? There were compiler errors. Thanks for your help anyways. . I guess I have to try some other solutions for this
I did the snake as segments (spheres) & to make it move I destroyed the last segment & instantiated a new one in front. I put a small delay on the instantiate so it looked smooth. As I said before, I kept a track of the # needed in a list so when I destroyed one it was the last one in the list & when I instantiated one I inserted it into the beginning.
Anyone who is willing to see my actual project can ask me through a conversation, or maybe even here! I would be more than happy to send my project to fix it.
You'll need to do the prefabs & other setup stuff first. Check through the code & make sure you know what it is doing so you know how to fix it. I wrote it last year & have forgotten most of it
I was a bit confused while reading the codes. But from what I read (I'm a beginner), the prefabs are [bodySegments, bodyPrefab, startspot, exit]. Are these the only 4 prefabs needed in the code? And also is there a child "Start" under "startspot"? I apologise if I'm really blur and all.
I got an error, "The type or namespace name 'InstantiateBody' could not be found. Are you missing a using directive or an assembly reference?"
Did you create the list? No offence, but if you are completely new to coding I'd suggest you put this project aside for a while & start with the roll a ball tutorial in the unity learn section (link above). They gradually take you through coding in unity so you can start to work on your own stuff as you learn new concepts.
Well, I decided to follow the tutorial on the "Roll The Ball - Tutorial", and I've implemented some codes. However when the Player eats the "Pick Up", it won't get a tail. Code (CSharp): using UnityEngine; using UnityEngine.UI; using System.Collections; using System.Collections.Generic; using System.Linq; public class PlayerController : MonoBehaviour { List<Transform> tail = new List<Transform> (); bool ate = false; public GameObject tailPrefab; public float speed; public Text countText; public Text winText; private Rigidbody rb; private int count; void Start () { rb = GetComponent<Rigidbody> (); count = 0; SetCountText (); winText.text = ""; } void FixedUpdate () { float moveHorizontal = Input.GetAxis ("Horizontal"); float moveVertical = Input.GetAxis ("Vertical"); Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical); rb.AddForce (movement * speed); } void OnTriggerEnter(Collider other) { if (other.gameObject.CompareTag ("Pick Up")) { other.gameObject.SetActive(false); count = count + 1; SetCountText (); ate = true; } } void SetCountText () { countText.text = "Score: " + count.ToString (); if (count >= 8) { winText.text = "You Win!"; } } void Move () { Vector3 v = transform.position; if (ate) { GameObject g = (GameObject)Instantiate (tailPrefab, v, Quaternion.identity); tail.Insert (0, g.transform); ate = false; } else if (tail.Count > 0) { tail.Last().position = v; tail.Insert(0, tail.Last()); tail.RemoveAt(tail.Count - 1); } } }
You don't need a bool, you can just instantiate a new body piece. Make sure that when you instantiate a new body piece you add it to the list. You really need to do the other tutorials, the roll a ball is basic so work your way through the other ones. I made my snake game as my major work (it had UI, maths sums & multiple answers & the kids had to eat the correct answer, a table that showed all the sums they got wrong & what the correct answers were) after doing a 6mth c# course using unity.
However, the movement is not that fluid, but I might edit it. I will post the links that I've used for this.