Unity makes greedy snake

Posted by TomNomNom on Mon, 03 Jan 2022 04:35:19 +0100

design sketch:

Idea: the core of the snake playing method is that players control one box to eat another box. The box they eat becomes their own body and moves with the previous box. The more they eat, the faster they will be. At the end of the game, judge whether they hit the wall or their own body

1, Scene layout

1. Camera settings

Modify camera parameters: set ClearFlags to SolidColor to display the scene in the game in pure color, set Projection to Orthographic orthogonal camera, and size to set the size of camera angle of view

2. Scene setting

Set the game background, four walls, snake heads and food components and properties, as well as a UI interface for game failure and score display.

① Background image: create a new 2D object -- > Sprite, name GameBG, set the picture wizard, and adjust the scale size to 30 * 30

Fence Wall: set the Tag tag, set the collision box for the Wall (used to judge the death of hitting the Wall), copy the three fences and adjust the size position

② Snake head snake player adds rigid body Rigidbody2D and boxcolorer2d components. Here, note that the Gravity Scale of 2D rigid body components is set to 0 (gravity is not required for plane movement) and the adjustment position xy is 0.5 (why to adjust to 0.5 will be explained below)

③ Create food: the FoodPool is used as an object pool for storing food, create food, add BoxColider2D component, set Tag to food (for collision detection), and adjust the position xy to 0.5 like snake head

Why should snakehead and food set position to 0.5?

Because the snake and food we created are rectangles with a scale of 1 * 1, we need to set its initial position to 0.5 (i.e. half the size of scale/2) if we want it to move with the scene box. In fact, we don't need to set Xiaobian. It's a little obsessive-compulsive. It's good-looking, hehe

④ set UI interface

Create an empty object UIManager as a node container to store components, Text in the upper left corner is the score, RefreshPanel game failure background UI, create a new Text as the game failure Text, and a Button as the restart Button.

2, Function realization

1. First create the snake movement function and create a new script playermovement All functions of CS greedy snake are put in this script

Snake eating function:

① The movement of the snake is automatic. We only need to control the direction of the snake's left, right or up and down movement,

② When the snake moves to the left (or down), we can't operate the snake to move to the right (or left).

③ The snake head eats the food when it triggers the food, and the game ends when it triggers the wall or its own body

Understand the mobile mode, let's start writing functions.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//Direction type
public enum DirectionType
{
    Horizontal, Vertical
}

public class PlayerMovement : MonoBehaviour
{
    public static Vector3 direction = new Vector3(1, 0, 0);//Moving direction
    public float currentTimespeed; //Current movement speed (the smaller the time, the faster the speed. Here I use time to speed up)
    public float timerSpeedRatio;//Time subtracted from each meal (i.e. snake acceleration)
    float timer;//For time calculation

    bool isDie = false;//Death
    int foodnumber = 0;//Amount of food eaten

    //Food object pool 
    public FoodData foodPrefab;
    public Transform foodPool;
    //The snake container is used to store the food eaten and become the body
    public Transform snakePool;


    //Game map
    public Transform GameBG;

    void Start()
    {
        //Initialize timer
        timer = currentTimespeed;
        //Initialization location
        transform.position = new Vector3(0.5f, 0.5f, 1);
    }

    void Update()
    {
        //Player movement
        float h = Input.GetAxis("Horizontal");
        float V = Input.GetAxis("Vertical");

        //Judge the moving direction
        if (h != 0)
        {
            SetDirection(DirectionType.Horizontal, h);
        }
        if (V != 0)
        {
            SetDirection(DirectionType.Vertical, V);
        }

        //Move not executed
        if (!isDie)
        {
            Move();
        }
    }

    //Modify direction
    private void SetDirection(DirectionType directionType, float _direction)
    {
        //Judge horizontal left-right movement or vertical up-down movement
        float value = _direction > 0 ? 1f : -1f;

        //Judge the direction type and set the moving direction 
        switch (directionType)
        {
            case DirectionType.Horizontal:
                if (direction.x==0)
                {
                    direction = new Vector2(value, 0);
                }
                break;
            case DirectionType.Vertical:
                if (direction.y==0)
                {
                    direction = new Vector2(0, value);
                }
                break;
            default:
                break;
        }
    }

    //move
    private void Move()
    {
        timer -= Time.deltaTime;
        if (timer < 0)
        {
            //Perform move
            GetComponent<FoodData>().Move(transform.position + direction);
            timer = currentTimespeed;
        }
    }

    //Detection (requires FoodData and UIManager scripts)
    void OnTriggerEnter2D(Collider2D col)
    {
        //Judge whether it triggered the wall or yourself
        if (col.transform.tag.Equals("Wall") || col.transform.tag.Equals("Player"))
        {
            //death
            isDie = true;
            UIManager.uiMagr.DieUI();
        }

        //food
        if (col.transform.tag.Equals("Food"))
        {
            //Judge whether the greedy snake has a body
            if (snakePool.childCount > 0)
            {
                col.transform.GetComponent<FoodData>().SetDataInt(snakePool.GetChild(snakePool.childCount - 1).GetComponent<FoodData>());
            }

            if (snakePool.childCount <= 0)
            {
                col.transform.GetComponent<FoodData>().SetDataInt(GetComponent<FoodData>());
            }
            col.transform.SetParent(snakePool);
            if (col.transform== snakePool.GetChild(0))
            {
                col.transform.tag = "Untagged";
            }
            else
            {
                col.transform.tag = "Player";
            }

            //Create food
            CreatFood();
            //accelerate
            currentTimespeed -= timerSpeedRatio;
            if (currentTimespeed<=0.1f)
            {
                currentTimespeed = 0.1f;
            }
            //UI
            foodnumber++;
            UIManager.uiMagr.SetNumber(foodnumber);
        }

       
    }

    //Create food
    public void CreatFood()
    {
        //Base value
        float basePos = 0.5f;
        int h_value = (int)(GameBG.localScale.x / 2);
        int v_value = (int)(GameBG.localScale.y / 2);
        int h = Random.Range(-h_value, h_value + 1);
        int v = Random.Range(-v_value, v_value + 1);

        Vector2 pos = new Vector2(h + 0.5f, v + 0.5f);
        if (pos.x > 15)
        {
            pos = new Vector2(h_value - 0.5f, pos.y);
        }
        if (pos.y > 15)
        {
            pos = new Vector2(pos.x, v_value - 0.5f);
        }

        GetFood(0).position = pos;
    }

    //Get food
    public Transform GetFood(int index)
    {
        Transform food;
        if (index <= foodPool.childCount)
        {
            food = Instantiate(foodPrefab.transform, foodPool);
        }
        else
        {
            food = foodPool.GetChild(index);
        }
        return food;
    }

}

There are detailed explanations in the code. Copying the code directly will cause problems because fooddata is required CS and uimanager Methods in CS script

Set the initial properties of greedy snake

 

2. Create the food (and body) attribute script FoodData , drag the script to snake player and food

This food script becomes the body of a snake after being eaten by a snake.

Function introduction:

① The basic attribute is the position information before moving, the upper level object and the lower level object.

② When the food is eaten, the last body of the snake should be obtained as its upper level. After the upper level moves, the next level moves to the position before the upper level moves

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FoodData : MonoBehaviour
{
    public Vector3 oldPos;//Record last move
    public FoodData parentObj;//Get the previous body part attribute of the body part (used to move the next box to the position of the previous box when the greedy snake moves)
    public FoodData newObj;//Record the next body part property (for the next move after the body moves).
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    //Get the last object (called when food is eaten)
    public void SetDataInt(FoodData obj) 
    {
        parentObj = obj;
        //Set the newobj of the previous object as itself
        parentObj.newObj = this;
        //The food was eaten and turned white
        transform.GetComponent<SpriteRenderer>().color = Color.white;
        //Location initialization
        transform.position = parentObj.oldPos;
    }

    //Move (used to move the next object after the current object is moved)
    public void Move() 
    {
        //Record the last moving position (this value is required for the next object to move)
        oldPos=transform.position;

        //modify location
        transform.position = parentObj.oldPos;

        //Execute the move command of the next object
        if (newObj!=null)
        {
            newObj.Move();
        }
    }

    //Movement (the snake's head needs to be transmitted)
    public void Move(Vector3 pos) 
    {
        oldPos = transform.position;
        //modify location
        transform.position = pos;

        if (newObj != null)
        {
            newObj.Move();
        }
    }
}

3. Script UIManager CS drag to empty object UIManager

using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine;
using UnityEngine.SceneManagement;//Reference is required when loading the scene

public class UIManager : MonoBehaviour
{
    public static UIManager uiMagr;
    public Text number_txt;//fraction
    public Button refreshBtn;//Restart button
    public Transform dieUI;//Game failure panel

    void Start()
    {
        //initialization
        uiMagr = this;
        dieUI.gameObject.SetActive(false);
        refreshBtn.onClick.AddListener(Refresh);
    }

    // Update is called once per frame
    void Update()
    {
        //Press esc to exit the program
        if (Input.GetKeyDown(KeyCode.Escape))
        {
            Application.Quit();
        }
    }

    //Modify score value
    public void SetNumber(int value) 
    {
        number_txt.text = value.ToString();
    }

    //Show death UI
    public void DieUI() 
    {
        dieUI.gameObject.SetActive(true);
    }

    //Refresh
    void Refresh() 
    {
        //Reload scene
        SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
    }
}

Project package https://pan.baidu.com/s/1JzgD-E5H8bJU7RTq5aVOqw Extraction code: syq1