Unity游戏开发之贪吃蛇(下)

共 23672字,需浏览 48分钟

 ·

2021-05-28 12:25

作者: 虚拟喵

来源: https://blog.csdn.net/qq_35361471/article/details/79327038

开发版本:unity 2017.1.1f1

适合人群:初学Unity者

源文件链接请见文末!

开启学习之旅吧!

边界传送

完善蛇头的触发检测,使用switch判断蛇头碰撞的墙面

//判断碰撞到物体的名字
                switch (collision.gameObject.name)
                {
                    case "Up":
                        //-transform.localPosition.y + 30 需要注意这里添加一个偏差值,防止蛇头刚移动到底部就碰到底部的碰撞器,下面同理
                        transform.localPosition = new Vector3(transform.localPosition.x, -transform.localPosition.y + 30, transform.localPosition.z);
                        break;
                    case "Down":
                        transform.localPosition = new Vector3(transform.localPosition.x, -transform.localPosition.y - 30, transform.localPosition.z);
                        break;
                    case "Left":
                        transform.localPosition = new Vector3(-transform.localPosition.x + 210, transform.localPosition.y, transform.localPosition.z);
                        break;
                    case "Right":
                        transform.localPosition = new Vector3(-375, transform.localPosition.y, transform.localPosition.z);
                        break;
                }

设计UI

首先实现分数和长度的记录

新建MainUIController.cs脚本,做成单例模式

添加UpdateUI()方法,用于外部调用更新UI显示

private static MainUIController instance;
    public static MainUIController Instance
    {
        get
        {
            return instance;
        }
    }
 private void Awake()
    {
        if (instance == null)
        {
            instance = this;
        }
    }
    public int score = 0;
    public int length = 0;
    public Text scoreText;
    public Text lengthText;
 
 public void UpdateUI(int s = 5, int l = 1)
    {
        score += s;
        length += l;
        scoreText.text = "得分:\n" + score;
        lengthText.text = "长度:\n" + length;
    }

然后在SnakeHead.cs的触发检测中调用

if (collision.gameObject.CompareTag("Food"))
        {
            Destroy(collision.gameObject);
            MainUIController.Instance.UpdateUI();
            AddBody();
            FoodCreator.Instance.CreateFood((Random.Range(0, 100) < 20) ? true : false);
        }
        else if (collision.gameObject.CompareTag("Reward"))
        {
            Destroy(collision.gameObject);
            MainUIController.Instance.UpdateUI(Random.Range(5, 15) * 10);
            AddBody();
        }

设计暂停按钮,新建Pause按钮

public bool isPause = false;
 
 public void Pause()
    {
        isPause = !isPause;
        if (isPause)
        {
            Time.timeScale = 0;
            //按钮图片的切换
            pauseBtn.GetComponent<Image>().sprite = pauseSprites[1];
        }
        else
        {
            Time.timeScale = 1;
            pauseBtn.GetComponent<Image>().sprite = pauseSprites[0];
        }
    }

然后将暂停按钮监听Pause方法

同理,返回键就重新加载场景 注意引用命名空间using UnityEngine.UI;

public void BackToHome()
    {
        SceneManager.LoadScene("StartScene");
    }

设立一个布尔值用来判断是否有边界

public bool hasBorder

后续操作待定。。。

蛇死亡处理

实现蛇死亡特效

在SnakeHead.cs中添加Die()方法。微信搜索公众号 [爱上游戏开发],回复 “资料”,免费领取 200G 学习资料

public GameObject dieEffect;
 
  void Die()
    {
        audioSource.clip = dieClip;
        audioSource.Play();
        //取消蛇移动的InvokeRepeating调用
        CancelInvoke();
        isDie = true;
        //实例化死亡效果
        Instantiate(dieEffect, transform.position - Vector3.forward, Quaternion.identity);
        //数据持久化PlayerPrefs以键值对的形式保存数据,可以保存int、string、float三种数据类型,类似字典
        //Set用于保存数据,Get用于得到数据
        PlayerPrefs.SetInt("lastLength", MainUIController.Instance.length);
        PlayerPrefs.SetInt("lastScore", MainUIController.Instance.score);
        //如果当前分数高于最高分数,就将最高数据进行更换
        //GetInt("bestScore", 0)如果当前有bestScore值的话,则返回该值,如果没有,则返回0
        if (PlayerPrefs.GetInt("bestScore", 0) < MainUIController.Instance.score)
        {
            PlayerPrefs.SetInt("bestLength", MainUIController.Instance.length);
            PlayerPrefs.SetInt("bestScore", MainUIController.Instance.score);
        }
        //开启协成,调用GameOver方法
        StartCoroutine(GameOver(1.5f));
    }
 
    IEnumerator GameOver(float t)
    {
        //停顿t秒执行下面语句
        yield return new WaitForSeconds(t);
        //重新加载到开始场景
        UnityEngine.SceneManagement.SceneManager.LoadScene("StartScene");
    }

完善蛇头触发检测

private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.CompareTag("Food"))
        {
            Destroy(collision.gameObject);
            MainUIController.Instance.UpdateUI();
            AddBody();
            FoodCreator.Instance.CreateFood((Random.Range(0, 100) < 20) ? true : false);
        }
        else if (collision.gameObject.CompareTag("Reward"))
        {
            Destroy(collision.gameObject);
            MainUIController.Instance.UpdateUI(Random.Range(5, 15) * 10);
            AddBody();
        }
        else if (collision.gameObject.CompareTag("Body"))
        {
            Die();
        }
        else
        {
            if (MainUIController.Instance.hasBorder)
            {
                Die();
            }
            else
            {
                switch (collision.gameObject.name)
                {
                    case "Up":
                        transform.localPosition = new Vector3(transform.localPosition.x, -transform.localPosition.y + 30, transform.localPosition.z);
                        break;
                    case "Down":
                        transform.localPosition = new Vector3(transform.localPosition.x, -transform.localPosition.y - 30, transform.localPosition.z);
                        break;
                    case "Left":
                        transform.localPosition = new Vector3(-transform.localPosition.x + 210, transform.localPosition.y, transform.localPosition.z);
                        break;
                    case "Right":
                        transform.localPosition = new Vector3(-375, transform.localPosition.y, transform.localPosition.z);
                        break;
                }
            }
        }
    }

存储用户设置

我们使用数据持久化保存PlayerPrefs来保存用户的设置,实现保存玩家上一次的设置,上一节我们就用该方法保存了游戏的得分

需要将蛇头和所有蛇身的精灵资源放在Resources文件夹中,动态加载资源

新建四个方法BlueSelected(),YellowSelected(),BorderSelected(),NoBorderSelected(),分别绑定开始界面的四个Toggle选项

使用PlayerPrefs来存储用户设置

public class StartUIController : MonoBehaviour
{
    public Text lastText;
    public Text bestText;
    public Toggle blue;
    public Toggle yellow;
    public Toggle border;
    public Toggle noBorder;
 
    private void Start()
    {
        lastText.text = "上次:长度"+PlayerPrefs.GetInt("lastLength",0)+",分数" + PlayerPrefs.GetInt("lastScore", 0);
        bestText.text = "最好:长度" + PlayerPrefs.GetInt("bestLength", 0) + ",分数" + PlayerPrefs.GetInt("bestScore", 0);
        //GetString如果sh已经有值,则判断是否为样式一小蛇,如果用户还没有设置,则默认为样式一
        if (PlayerPrefs.GetString("sh""sb01") == "sb01")
        {
            blue.isOn = true;
            BlueSelected(true);
        }
        else
        {
            yellow.isOn = true;
            YellowSelected(true);
        }
        //有无边界的判断如上
        if (PlayerPrefs.GetInt("border", 0) == 1)
        {
            border.isOn = true;
            BorderSelected(true);
        }
        else
        {
            noBorder.isOn = true;
            NoBorderSelected(true);
        }
    }
 
    //选择了样式一小蛇
    public void BlueSelected(bool isOn)
    {
        if (isOn)
        {
            PlayerPrefs.SetString("sh""sh01");
            PlayerPrefs.SetString("sb01""sb0101");
            PlayerPrefs.SetString("sb02""sb0102");
            //如果选择该样式,修改图片颜色,用于区别
            blue.GetComponentInChildren<Image>().color = new Color32(1, 159, 232, 90);
        }
        else
        {
            blue.GetComponentInChildren<Image>().color = new Color32(1, 159, 232, 50);
        }
    }
 
    //选择了样式二小蛇
    public void YellowSelected(bool isOn)
    {
        if (isOn)
        {
            PlayerPrefs.SetString("sh""sh02");
            PlayerPrefs.SetString("sb01""sb0201");
            PlayerPrefs.SetString("sb02""sb0202");
            yellow.GetComponentInChildren<Image>().color = new Color32(1, 159, 232, 90);
        }
        else
        {
            yellow.GetComponentInChildren<Image>().color = new Color32(1, 159, 232, 50);
        }
    }
 
    //选择有边界模式
    public void BorderSelected(bool isOn)
    {
        if (isOn)
        {
            PlayerPrefs.SetInt("border", 1);
        }
    }
 
    //选择无边界模式
    public void NoBorderSelected(bool isOn)
    {
        if (isOn)
        {
            PlayerPrefs.SetInt("border", 0);
        }
    }
 
    //开始游戏
    public void StartGame()
    {
        UnityEngine.SceneManagement.SceneManager.LoadScene("MainScene");
    }
}

用户设置已经存储,需要在游戏开始后,SnakeHead.cs中动态读取设置

private void Awake()
    {
        gameObject.GetComponent<Image>().sprite = Resources.Load<Sprite>(PlayerPrefs.GetString("sh""sh01"));
        bodySprites[0] = Resources.Load<Sprite>(PlayerPrefs.GetString("sb01""sb0101"));
        bodySprites[1] = Resources.Load<Sprite>(PlayerPrefs.GetString("sb02""sb0102"));
    }

在MainUIController.cs中读取用户是否设置边界

private void Start()
    {
        //判断是否设置了边界
        if (PlayerPrefs.GetInt("border", 0) == 0)
        {
            //hasBorder标志位用于判断蛇头碰到边界是否死亡
            hasBorder = false;
            //遍历bgImage父物体下所有子物体
            foreach (Transform item in bgImage.gameObject.transform)
            {
                //在无边界模式下,禁用掉边界
                item.gameObject.GetComponent<Image>().enabled = false;
            }
        }
        else
        {
            hasBorder = true;
        }
    }

添加音效和背景音乐都是相同操作,在此不再赘述!

对了,为了方便,我直接设置屏幕大小为1280*720,只需要在awake方法中加Screen.SetResolution(1280, 720,false);

基本完成游戏的开发,大家也可以发挥想象力,再添砖加瓦,完善功能!

素材及工程文件:百度云链接https://pan.baidu.com/s/1eIfkkd9A9hl4dNvdI6tr9Q   提取码:4x8o


-- END --


公众号后台回复「资料」获取超多学习福利

>>> 点击进入技术讨论群 <<<
▽想深入了解么?

长按/扫码关注我吧↑↑↑


觉得不错就点个在看

浏览 84
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报