Search Unity

[Solved] 3D Snake Game

Discussion in 'Scripting' started by Argonite, Nov 24, 2015.

?

Should I post the source code?

  1. Yes

    100.0%
  2. No

    0 vote(s)
    0.0%
  1. Argonite

    Argonite

    Joined:
    Nov 1, 2015
    Posts:
    18
    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.
     
    Last edited: Nov 26, 2015
  2. tedthebug

    tedthebug

    Joined:
    May 6, 2015
    Posts:
    2,570
    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.
     
  3. Argonite

    Argonite

    Joined:
    Nov 1, 2015
    Posts:
    18
    This is my updated code, and I used Instantiation, but there's a compiler error. Do you know how to solve it?

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using System.Linq;
    5.  
    6. public class Movement : MonoBehaviour {
    7.  
    8.     public float speed;
    9.     private Vector3 dir;
    10.     List<Transform> tail = new List<Transform>();
    11.  
    12.     bool ate = false;
    13.     public GameObject tailPrefab;
    14.  
    15.     void Start ()
    16.     {
    17.         dir = Vector3.right;
    18.     }
    19.  
    20.     void Update ()
    21.     {
    22.         if (Input.GetMouseButtonDown (0)) {
    23.             //anti-clockwise movement
    24.             if (dir == Vector3.right) {
    25.                 dir = Vector3.forward;
    26.             } else if (dir == Vector3.forward) {
    27.                 dir = Vector3.left;
    28.             } else if (dir == Vector3.left) {
    29.                 dir = Vector3.back;
    30.             } else if (dir == Vector3.back) {
    31.                 dir = Vector3.right;
    32.             }
    33.         }
    34.  
    35.         if (Input.GetMouseButtonDown (1)) {
    36.             //clockwise movement
    37.             if (dir == Vector3.right) {
    38.                 dir = Vector3.back;
    39.             } else if (dir == Vector3.back) {
    40.                 dir = Vector3.left;
    41.             } else if (dir == Vector3.left) {
    42.                 dir = Vector3.forward;
    43.             } else if (dir == Vector3.forward) {
    44.                 dir = Vector3.right;
    45.             }
    46.         }
    47.      
    48.      
    49.             float amountToMove = speed * Time.deltaTime;
    50.  
    51.             transform.Translate (dir * amountToMove);
    52.     }
    53.  
    54.     void Move ()
    55.     {
    56.         Vector3 v = transform.position;
    57.  
    58.         transform.Translate (dir);
    59.  
    60.         if (ate) {
    61.             GameObject tailPrefab;
    62.             Instantiate(tailPrefab, transform.position, transform.rotation) as Transform;
    63.  
    64.             tailPrefab.transform.position = "-1, 0, 0";
    65.  
    66.             ate = false;
    67.         }
    68.         else if (tail.Count > 0) {
    69.             tail.Last ().position = v;
    70.  
    71.             tail.Insert (0, tail.Last ());
    72.             tail.RemoveAt (tail.Count - 1);
    73.         }
    74.     }
    75.  
    76.     void OnCollisionEnter(Collision coll)
    77.     {
    78.         if (coll.gameObject.name == "FoodPrefab")
    79.         {
    80.             ate = true;
    81.  
    82.             Destroy(coll.gameObject);
    83.         }
    84.     }
    85. }
    86.  
     
  4. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    ... which says what?


    edit: oh, it's probably this

    Code (csharp):
    1.  
    2. tailPrefab.transform.position="-1, 0, 0";
    3.  
    you can't do this. What are you trying to do with that?
     
  5. Argonite

    Argonite

    Joined:
    Nov 1, 2015
    Posts:
    18
    I was trying to spawn the tailPrefab at that position, but I just realise the mistake XD
     
  6. Argonite

    Argonite

    Joined:
    Nov 1, 2015
    Posts:
    18
    Any expert know how to solve this? This will help me alot! :)
     
  7. martinmr

    martinmr

    Joined:
    Mar 25, 2015
    Posts:
    325
    tailPrefab.transform.position= new Vector3(-1, 0, 0); that's how you normaly declare a new Position
     
  8. martinmr

    martinmr

    Joined:
    Mar 25, 2015
    Posts:
    325
    also

    part 60 to 67 will not work this way. this you have to change:

    Code (CSharp):
    1. if (ate) {
    2.    Transfrom tailPrefab = Instantiate(tailPrefab, transform.position, transform.rotation) as Transform;;
    3.    tailPrefab.position = new Vector3(-1f, 0f, 0f);
    4.    ate = false;
    5. }
    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
     
  9. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    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

    Code (csharp):
    1.  
    2. using UnityEngine;
    3.  
    4. public class GameManager : MonoBehaviour
    5. {
    6.     [SerializeField]
    7.     private float speed = 1;
    8.     [SerializeField]
    9.     private float speedUpFactor = 0.1f;
    10.  
    11.     [SerializeField]
    12.     private GameObject currentFood;
    13.     [SerializeField]
    14.     private GameObject foodPrefab;
    15.  
    16.  
    17.     [SerializeField]
    18.     private int gameWidth;
    19.     [SerializeField]
    20.     private int gameHeight;
    21.  
    22.  
    23.     public float GetSpeed()
    24.     {
    25.         return speed;
    26.     }
    27.  
    28.     public void Update()
    29.     {
    30.         // would make more sense to have this trigger off the food being eaten via an event,
    31.         // but it's small scale app so isn't going to impact performance much
    32.         if(!currentFood)
    33.         {
    34.             speed *= 1-speedUpFactor;
    35.             // really needs to check there isn't a snake part at that location...
    36.             currentFood = (GameObject)Instantiate(foodPrefab, new Vector3(Random.Range(0, gameWidth), 0, Random.Range(0, gameHeight)), Quaternion.identity);
    37.         }
    38.     }
    39. }
    40.  
    41.  
    42.  
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class SnakeHead : MonoBehaviour
    6. {
    7.     [SerializeField]
    8.     private SnakeBody nextSection;
    9.  
    10.     [SerializeField]
    11.     private Vector3 direction;
    12.  
    13.     [SerializeField]
    14.     private bool alive;
    15.  
    16.     [SerializeField]
    17.     private GameObject bodyPrefab;
    18.  
    19.     [SerializeField]
    20.     private GameManager gameManager;
    21.  
    22.     void Awake()
    23.     {
    24.         direction = new Vector3(1, 0, 0);
    25.         gameManager = FindObjectOfType<GameManager>();
    26.     }
    27.  
    28.     void Start()
    29.     {
    30.         alive = true;
    31.         StartCoroutine(MoveSnake());
    32.     }
    33.  
    34.     void Update()
    35.     {
    36.         // get inputs
    37.         float v = Input.GetAxisRaw("Vertical");
    38.         float h = Input.GetAxisRaw("Horizontal");
    39.  
    40.         // change direction
    41.         if(v != 0)
    42.         {
    43.             direction = new Vector3(0, 0, v);
    44.         }
    45.         else if(h != 0)
    46.         {
    47.             direction = new Vector3(h, 0, 0);
    48.         }
    49.     }
    50.  
    51.     public IEnumerator MoveSnake()
    52.     {
    53.         while (alive)
    54.         {
    55.             yield return new WaitForSeconds(gameManager.GetSpeed());
    56.  
    57.             bool nom = false;
    58.  
    59.             // store old position
    60.             Vector3 oldPosition = transform.position;
    61.          
    62.             // add raycast code for collision check here
    63.             Ray ray = new Ray(transform.position, direction);
    64.             RaycastHit hit;
    65.             if(Physics.Raycast(ray, out hit, 1f))
    66.             {
    67.                 // check for food ahead
    68.                 SnakeFood food = hit.transform.GetComponent<SnakeFood>();
    69.                 if(food)
    70.                 {
    71.                     nom = true;
    72.                     food.Eaten();
    73.                 }
    74.  
    75.                 // check for body ahead
    76.                 SnakeBody body = hit.transform.GetComponent<SnakeBody>();
    77.                 if(body)
    78.                 {
    79.                     alive = false;
    80.                 }
    81.             }
    82.  
    83.             // we've eaten add new body section where the head is before moving forward to where the food is
    84.             if (nom)
    85.             {
    86.                 SnakeBody clone = ((GameObject)Instantiate(bodyPrefab, transform.position, Quaternion.identity)).GetComponent<SnakeBody>();
    87.                 clone.SetNextSection(nextSection); // ensure continuity with rest of body
    88.                 nextSection = clone;
    89.             }
    90.  
    91.             // move the head
    92.             transform.Translate(direction);
    93.          
    94.             // move the rest of the snake if we didn't eat
    95.             if(nextSection && !nom)
    96.             {
    97.                 nextSection.MoveSection(oldPosition);
    98.             }
    99.         }
    100.     }
    101.  
    102. }
    103.  
    104.  
    Code (csharp):
    1.  
    2. using UnityEngine;
    3.  
    4. public class SnakeBody : MonoBehaviour
    5. {
    6.     [SerializeField]
    7.     private SnakeBody nextSection;
    8.  
    9.     public void MoveSection(Vector3 pos)
    10.     {
    11.         Vector3 oldPosition = transform.position;
    12.         transform.position = pos;
    13.  
    14.         if(nextSection)
    15.         {
    16.             nextSection.MoveSection(oldPosition);
    17.         }
    18.     }
    19.  
    20.     public void SetNextSection(SnakeBody s)
    21.     {
    22.         nextSection = s;
    23.     }
    24. }
    25.  
    26.  
    Code (csharp):
    1.  
    2. using UnityEngine;
    3.  
    4. public class SnakeFood : MonoBehaviour
    5. {
    6.     [SerializeField]
    7.     private float delay = 0;
    8.     [SerializeField]
    9.     private AudioClip eatenClip;
    10.  
    11.     public void Eaten()
    12.     {
    13.         // do sound stuff
    14.         if(eatenClip)
    15.         {
    16.             AudioSource audio = FindObjectOfType<AudioSource>();
    17.             if(audio)
    18.             {
    19.                 audio.PlayOneShot(eatenClip);
    20.                 delay = eatenClip.length;
    21.             }
    22.         }
    23.  
    24.         // stop further collisions
    25.         foreach (Collider c in GetComponents<Collider>())
    26.         {
    27.             c.enabled = false;
    28.         }
    29.  
    30.         // remove gameobject
    31.         Destroy(gameObject, delay);
    32.     }
    33. }
    34.  
    35.  
     
    Argonite and martinmr like this.
  10. Argonite

    Argonite

    Joined:
    Nov 1, 2015
    Posts:
    18
    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! :D
     
  11. Argonite

    Argonite

    Joined:
    Nov 1, 2015
    Posts:
    18
    I tried it but somehow it couldn't work? There were compiler errors. Thanks for your help anyways. :D. I guess I have to try some other solutions for this :(
     
  12. tedthebug

    tedthebug

    Joined:
    May 6, 2015
    Posts:
    2,570
    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.
     
  13. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    which were... ?
     
  14. Argonite

    Argonite

    Joined:
    Nov 1, 2015
    Posts:
    18
    I deleted it. But I guess I will put the codes back again.
     
  15. Argonite

    Argonite

    Joined:
    Nov 1, 2015
    Posts:
    18
    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. :D
     
  16. tedthebug

    tedthebug

    Joined:
    May 6, 2015
    Posts:
    2,570
  17. Argonite

    Argonite

    Joined:
    Nov 1, 2015
    Posts:
    18
  18. tedthebug

    tedthebug

    Joined:
    May 6, 2015
    Posts:
    2,570
    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
     
  19. Argonite

    Argonite

    Joined:
    Nov 1, 2015
    Posts:
    18
    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.
     
    Last edited: Nov 26, 2015
  20. Argonite

    Argonite

    Joined:
    Nov 1, 2015
    Posts:
    18
    I got an error, "The type or namespace name 'InstantiateBody' could not be found. Are you missing a using directive or an assembly reference?"
     
  21. tedthebug

    tedthebug

    Joined:
    May 6, 2015
    Posts:
    2,570
    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.
     
  22. Argonite

    Argonite

    Joined:
    Nov 1, 2015
    Posts:
    18
    Yes, I have created the list.
     
  23. tedthebug

    tedthebug

    Joined:
    May 6, 2015
    Posts:
    2,570
    Did you include the but on the line after it saying it is a new list?
     
  24. Argonite

    Argonite

    Joined:
    Nov 1, 2015
    Posts:
    18
    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):
    1. using UnityEngine;
    2. using UnityEngine.UI;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5. using System.Linq;
    6.  
    7. public class PlayerController : MonoBehaviour {
    8.  
    9.     List<Transform> tail = new List<Transform> ();
    10.  
    11.     bool ate = false;
    12.  
    13.     public GameObject tailPrefab;
    14.     public float speed;
    15.     public Text countText;
    16.     public Text winText;
    17.  
    18.     private Rigidbody rb;
    19.     private int count;
    20.  
    21.     void Start ()
    22.     {
    23.         rb = GetComponent<Rigidbody> ();
    24.         count = 0;
    25.         SetCountText ();
    26.         winText.text = "";
    27.     }
    28.  
    29.     void FixedUpdate ()
    30.     {
    31.         float moveHorizontal = Input.GetAxis ("Horizontal");
    32.         float moveVertical = Input.GetAxis ("Vertical");
    33.  
    34.         Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);
    35.  
    36.         rb.AddForce (movement * speed);
    37.     }
    38.  
    39.     void OnTriggerEnter(Collider other)
    40.     {
    41.         if (other.gameObject.CompareTag ("Pick Up"))
    42.         {
    43.             other.gameObject.SetActive(false);
    44.             count = count + 1;
    45.             SetCountText ();
    46.             ate = true;
    47.         }
    48.     }
    49.  
    50.     void SetCountText ()
    51.     {
    52.         countText.text = "Score: " + count.ToString ();
    53.         if (count >= 8)
    54.         {
    55.             winText.text = "You Win!";
    56.         }
    57.     }
    58.  
    59.     void Move ()
    60.     {
    61.         Vector3 v = transform.position;
    62.  
    63.         if (ate) {
    64.             GameObject g = (GameObject)Instantiate (tailPrefab, v, Quaternion.identity);
    65.  
    66.             tail.Insert (0, g.transform);
    67.  
    68.             ate = false;
    69.         }
    70.  
    71.         else if (tail.Count > 0) {
    72.             tail.Last().position = v;
    73.  
    74.             tail.Insert(0, tail.Last());
    75.             tail.RemoveAt(tail.Count - 1);
    76.         }
    77.     }
    78. }
     
  25. tedthebug

    tedthebug

    Joined:
    May 6, 2015
    Posts:
    2,570
    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.
     
  26. Argonite

    Argonite

    Joined:
    Nov 1, 2015
    Posts:
    18
    I SOLVED IT!!! AFTER a week of RESEARCHING I have finally done it.
     
    martinmr likes this.
  27. Argonite

    Argonite

    Joined:
    Nov 1, 2015
    Posts:
    18
    However, the movement is not that fluid, but I might edit it. I will post the links that I've used for this.
     
  28. jister

    jister

    Joined:
    Oct 9, 2009
    Posts:
    1,749
    change your title to solved then :)