Unity 制作愤怒的小鸟


参考视频: 【SiKi学院Unity】Unity初级案例 - 愤怒的小鸟



一、项目准备

资源下载: http://www.sikiedu.com/course/134

新建工程:

在这里插入图片描述

选择2D,填写项目名称并选择项目路径:
在这里插入图片描述


将资源中的ImageMusic复制到项目文件夹中:

在这里插入图片描述
在这里插入图片描述



二、切片

选择猪和鸟的第一章图片,将其Sprite Mode改为MultipleApply
在这里插入图片描述


如下图所示进行切片:
在这里插入图片描述


发现四个爆炸烟雾未切分好,手动切分一下:
在这里插入图片描述


Apply:
在这里插入图片描述


在场景中拖入弹弓和小鸟,设置层级关系:
在这里插入图片描述



三、实现小鸟的拖拽与飞出


1. 添加并设置Spring Joint 2D

为小鸟添加Spring Joint 2D组件,添加后会自动添加刚体组件:
在这里插入图片描述


同时给弹弓右部加上刚体组件,并设置为Static(防止其受重力影响):
在这里插入图片描述


将弹弓右部的刚体拖到Spring Joint 2D中,并设置Spring Joint 2D的各项参数:
在这里插入图片描述


2. 实现小鸟跟随鼠标移动

添加碰撞体和Bird脚本:
在这里插入图片描述


bird.cs:

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

public class Bird : MonoBehaviour
{
    
    
    private bool isClick = false;


    private void Update()
    {
    
    
        MoveWithMouse();
    }

    private void MoveWithMouse()
    {
    
    
        // 让小鸟跟随鼠标的位置
        if (isClick)
        {
    
    
            transform.position = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            transform.position += new Vector3(0, 0, -Camera.main.transform.position.z);
        }
    }

    // 鼠标按下
    private void OnMouseDown()
    {
    
    
        isClick = true;   
    }

    // 鼠标抬起
    private void OnMouseUp()
    {
    
    
        isClick = false;
    }

}

此时小鸟被鼠标拖拽时会跟随鼠标移动。


3. 限定小鸟最大拖拽距离


首先在弹弓右部设置一个点,作为小鸟绕着转的点:
在这里插入图片描述


Bird.cs中声明rightPos 和 maxDis变量:

    public Transform rightPos;   // 弹弓右部点,即拖拽小鸟时让其跟着转
    public float maxDis;  // 最大推拽距离

修改MoveWithMouse()如下:

    private void MoveWithMouse()
    {
    
    
        // 让小鸟跟随鼠标的位置
        if (isClick)
        {
    
    
            transform.position = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            transform.position += new Vector3(0, 0, -Camera.main.transform.position.z);

            // 限定小鸟最大拖拽距离
            if (Vector2.Distance(transform.position, rightPos.position) >= maxDis)
            {
    
    
                transform.position = rightPos.position + (transform.position - rightPos.position).normalized * maxDis;
            }
        }
    }

Inspector面板中将rightPos拖拽到bird脚本中,并设置maxDis,此时小鸟被限定了拖拽距离:
在这里插入图片描述


4. 实现小鸟飞出

鼠标按下时,刚体状态设置为动力学。
在鼠标松开时,动力学设为false,一段时间后禁用SpringJoint2D组件:

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

public class Bird : MonoBehaviour
{
    
    
    private SpringJoint2D springJoint;
    private Rigidbody2D rb;

    public Transform rightPos;   // 弹弓右部点,即拖拽小鸟时让其跟着转
    public float maxDis;  // 最大推拽距离


    private bool isClick = false;


    private void Start()
    {
    
    
        springJoint = GetComponent<SpringJoint2D>();
        rb = GetComponent<Rigidbody2D>();
    }

    private void Update()
    {
    
    
        MoveWithMouse();
    }

    private void MoveWithMouse()
    {
    
    
        // 让小鸟跟随鼠标的位置
        if (isClick)
        {
    
    
            transform.position = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            transform.position += new Vector3(0, 0, -Camera.main.transform.position.z);

            // 限定小鸟最大拖拽距离
            if (Vector2.Distance(transform.position, rightPos.position) >= maxDis)
            {
    
    
                transform.position = rightPos.position + (transform.position - rightPos.position).normalized * maxDis;
            }
        }
    }

    // 鼠标按下
    private void OnMouseDown()
    {
    
    
        isClick = true;
        rb.isKinematic = true;
    }

    // 鼠标抬起
    private void OnMouseUp()
    {
    
    
        isClick = false;
        rb.isKinematic = false;
        Invoke(nameof(Fly), 0.12f);
    }

    private void Fly()
    {
    
    
        springJoint.enabled = false;
    }

}


5. 实现弹弓的划线


在弹弓上创建一个leftPos点,此时leftPosrightPos两个点用于划线:
在这里插入图片描述


left添加Line Renderer组件:
在这里插入图片描述


设置材质、颜色和长度:
在这里插入图片描述


将该组件复制到right上:
在这里插入图片描述
在这里插入图片描述


编写代码:
bird.cs:

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

public class Bird : MonoBehaviour
{
    
    
    private SpringJoint2D springJoint;
    private Rigidbody2D rb;

    [Header("弹弓")]
    public Transform rightPos;   // 弹弓右部点,即拖拽小鸟时让其跟着转; 同时画线
    public Transform leftPos;    // 弹弓左部点, 画线
    public LineRenderer leftLine;
    public LineRenderer rightLine;

    [Space]
    public float maxDis;  // 最大推拽距离


    private bool isClick = false;


    private void Start()
    {
    
    
        springJoint = GetComponent<SpringJoint2D>();
        rb = GetComponent<Rigidbody2D>();
    }

    private void Update()
    {
    
    
        MoveWithMouse();
    }

    private void MoveWithMouse()
    {
    
    
        // 让小鸟跟随鼠标的位置
        if (isClick)
        {
    
    
            transform.position = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            transform.position += new Vector3(0, 0, -Camera.main.transform.position.z);

            // 限定小鸟最大拖拽距离
            if (Vector2.Distance(transform.position, rightPos.position) >= maxDis)
            {
    
    
                transform.position = rightPos.position + (transform.position - rightPos.position).normalized * maxDis;
            }

            DrawLine();
        }
    }

    // 鼠标按下
    private void OnMouseDown()
    {
    
    
        isClick = true;
        rb.isKinematic = true;
    }

    // 鼠标抬起
    private void OnMouseUp()
    {
    
    
        isClick = false;
        rb.isKinematic = false;
        DeleteLine();  // 删除弹弓的线
        Invoke(nameof(Fly), 0.12f);
    }

    // 飞出
    private void Fly()
    {
    
    
        springJoint.enabled = false;
    }

    // 画线
    private void DrawLine()
    {
    
    
        // 设置线的两个端点
        leftLine.SetPosition(0, leftPos.position);
        leftLine.SetPosition(1, transform.position);

        rightLine.SetPosition(0, rightPos.position);
        rightLine.SetPosition(1, transform.position);
    }

    // 删除线
    private void DeleteLine()
    {
    
    
        leftLine.SetPosition(1, leftPos.position);
        rightLine.SetPosition(1, rightPos.position);
    }
}

此时拖拽小鸟时可正常划线,松开则线消失。


6. 让小鸟不能重复拖拽


此时小鸟被拖拽放飞后,再次按住小鸟任然能回到弹弓上。

为了解决该bug,给小鸟添加一个bool参数:

    private bool flied = false;  // 是否飞过,用以让小鸟不能重复拖拽

鼠标抬起后,设置为true:

    // 鼠标抬起
    private void OnMouseUp()
    {
    
    
        isClick = false;
        flied = true;
        rb.isKinematic = false;
        DeleteLine();  // 删除弹弓的线
        Invoke(nameof(Fly), 0.12f);
    }

鼠标按下后,如果flied已经为true,则无效:

    // 鼠标按下
    private void OnMouseDown()
    {
    
    
        if (flied)
            return;
        isClick = true;
        rb.isKinematic = true;
    }

此时小鸟只能被拖拽一次。



四、场景搭建


选择场景1进行切割:
在这里插入图片描述


将地面拖入并添加碰撞体:
在这里插入图片描述


创建预制体相关文件夹,并将其拖入:
在这里插入图片描述


设置地面:
在这里插入图片描述


同理,设置天空:
在这里插入图片描述



五、实现小鸟攻击猪


添加猪,并添加相关组件并设置图层:
在这里插入图片描述


将鸟和猪的角阻力都设置为2,防止其在地面滚动不停止:
在这里插入图片描述


1. 猪的受伤与死亡


给猪添加Pig脚本:
在这里插入图片描述


设置猪受到小鸟的碰撞时,受伤和死亡应该达到的相对速度:

    public float hurtSpeed = 5.0f;  // 受伤速度
    public float deadSpeed = 10.0f;  // 死亡速度

设置猪受伤后的图片:

    // 受伤图片
    public Sprite hurtSprite;

在这里插入图片描述


拖入相应的烟雾的图片到场景中:
在这里插入图片描述

创建boom动画:
在这里插入图片描述


打开Animation进行相应的调整:
在这里插入图片描述


同时将该动画取消循环播放:
在这里插入图片描述


Boom添加一个脚本Boom:
在这里插入图片描述


编写代码:
Boom.cs:

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

public class Boom : MonoBehaviour
{
    
    
    public void DestorySelf()
    {
    
    
        Destroy(gameObject);
    }
}

Animation中设置,当播放完之后执行该函数,即销毁自身:
在这里插入图片描述

Boom物体制成预制体:
在这里插入图片描述


猪的死亡逻辑:

若相对速度大于死亡速度:则死亡;
若相对速度只是大于受伤速度:此时猪若是受伤状态,则死亡;反之则受伤

Pig.cs中,实现猪的受伤与死亡:

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

public class Pig : MonoBehaviour
{
    
    
    private SpriteRenderer spriteRenderer;

    // 受伤图片
    public Sprite hurtSprite;
    public GameObject boomPrefab;

    [Header("相对速度")]
    public float hurtSpeed = 5.0f;  // 受伤速度
    public float deadSpeed = 10.0f;  // 死亡速度

    private bool isHurt = false;

    private void Start()
    {
    
    
        spriteRenderer = GetComponent<SpriteRenderer>();
    }

    private void OnCollisionEnter2D(Collision2D collision)
    {
    
    
        float relativeV = collision.relativeVelocity.magnitude;
        print(relativeV);
        // 大于死亡速度
        if (relativeV >= deadSpeed)
        {
    
    
            Dead();
        }
        // 大于受伤速度
        else if (relativeV >= hurtSpeed)
        {
    
    
            if (isHurt)
                Dead();
            else
            {
    
    
                isHurt = true;
                spriteRenderer.sprite = hurtSprite;
            }
        }
    }

    // 死亡,生成爆炸动画和分数
    private void Dead()
    {
    
    
        Instantiate(boomPrefab, transform.position, Quaternion.identity);
        Destroy(gameObject);
    }

}

2. 猪的加分

切割分数图片:
在这里插入图片描述


拖拽出一个分数并制为预制体:
在这里插入图片描述


编写pig.cs代码:

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

public class Pig : MonoBehaviour
{
    
    
    private SpriteRenderer spriteRenderer;

    // 受伤图片
    public Sprite hurtSprite;
    public GameObject boomPrefab;
    public GameObject scorePrefab;

    [Header("相对速度")]
    public float hurtSpeed = 5.0f;  // 受伤速度
    public float deadSpeed = 10.0f;  // 死亡速度

    private bool isHurt = false;

    [Space]
    public float scoreYOffset = 0.65f;  // 分数相对猪的Y位置

    private void Start()
    {
    
    
        spriteRenderer = GetComponent<SpriteRenderer>();
    }

    private void OnCollisionEnter2D(Collision2D collision)
    {
    
    
        float relativeV = collision.relativeVelocity.magnitude;
        print(relativeV);
        // 大于死亡速度
        if (relativeV >= deadSpeed)
        {
    
    
            Dead();
        }
        // 大于受伤速度
        else if (relativeV >= hurtSpeed)
        {
    
    
            if (isHurt)
                Dead();
            else
            {
    
    
                isHurt = true;
                spriteRenderer.sprite = hurtSprite;
            }
        }
    }

    // 死亡,生成爆炸动画和分数
    private void Dead()
    {
    
    
        GameManager.instance.pigs.Remove(this);
        Instantiate(boomPrefab, transform.position, Quaternion.identity);
        GameObject scoreObject = Instantiate(scorePrefab, transform.position + new Vector3(0, scoreYOffset, 0),
            Quaternion.identity);
        Destroy(scoreObject, 1.5f);
        Destroy(gameObject);
    }

}


六、实现多只鸟的控制

将小鸟制为预制体,并复制两只:

在这里插入图片描述


创建一个Game Manager空物体,新建并挂上GameManager脚本:
在这里插入图片描述

使用单例模式并用列表存储小鸟和猪:

public class GameManager : MonoBehaviour
{
    
    
    public static GameManager instance;

    public List<Bird> birds;
    public List<Pig> pigs;


    private void Awake()
    {
    
    
        instance = this;
    }

}

Bird中编写,让小鸟飞出几秒后销毁,并生成爆炸动画,并从GameManager的列表中移除:


    private bool isClick = false;
    private bool flied = false;  // 是否飞过,用以让小鸟不能重复拖拽

    // 飞出
    private void Fly()
    {
    
    
        springJoint.enabled = false;
        Invoke(nameof(DestroySelf), flyTime);
    }
    
    // 飞出5秒后销毁
    private void DestroySelf()
    {
    
    
        GameManager.instance.birds.Remove(this);
        Instantiate(boomPrefab, transform.position, Quaternion.identity);
        Destroy(gameObject);
    }

同理,猪死亡时,在GameManger的列表中也需要删除:

    // 死亡,生成爆炸动画和分数
    private void Dead()
    {
    
    
        GameManager.instance.pigs.Remove(this);
        Instantiate(boomPrefab, transform.position, Quaternion.identity);
        GameObject scoreObject = Instantiate(scorePrefab, transform.position + new Vector3(0, scoreYOffset, 0),
            Quaternion.identity);
        Destroy(scoreObject, 1.5f);
        Destroy(gameObject);
    }

GameManager中,起初启用第一只小鸟、禁用其他小鸟的脚本和SpringJoint,并在小鸟销毁后判断游戏状态以及是否启用下一只小鸟:
GameManager.cs:

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

public class GameManager : MonoBehaviour
{
    
    
    public static GameManager instance;

    public List<Bird> birds;
    public List<Pig> pigs;

    private Vector3 originBirdPos;  // 小鸟初始位置

    private void Awake()
    {
    
    
        instance = this;
        if (birds.Count > 0)
            originBirdPos = birds[0].transform.position;
        InitBird();
    }

    // 初始化小鸟
    private void InitBird()
    {
    
    
        for(int i = 0; i <birds.Count; i++)
        {
    
    
            if (i == 0)
            {
    
    
                birds[i].transform.position = originBirdPos;
                birds[i].enabled = true;
                birds[i].GetComponent<SpringJoint2D>().enabled = true;
            }
            else
            {
    
    
                birds[i].enabled = false;
                birds[i].GetComponent<SpringJoint2D>().enabled = false;
            }
        }
    }

    // 判断游戏状态 及 是否启用下一只小鸟
    public void Next()
    {
    
    
        if (pigs.Count == 0)
        {
    
    
            // 游戏胜利
        }
        else
        {
    
    
            if (birds.Count == 0)
            {
    
    
                // 游戏失败
            }
            else
            {
    
    
                InitBird();
            }
        }
    }

}

在小鸟销毁后,调用`Next()`: `bird.cs`:
    // 飞出5秒后销毁
    private void DestroySelf()
    {
    
    
        GameManager.instance.birds.Remove(this);
        GameManager.instance.Next();
        Instantiate(boomPrefab, transform.position, Quaternion.identity);
        Destroy(gameObject);
    }

最后在Inspector面板中拖拽小鸟和猪后,可正常控制多只小鸟。



七、小鸟尾迹的实现

导入素材中的Unity包:
在这里插入图片描述

在这里插入图片描述

只添加Weapon Trail
在这里插入图片描述


给小鸟添加Trail Renderer组件:
在这里插入图片描述


设置拖尾的材质、持续时间已经宽度:
在这里插入图片描述


同时加载到其他预制体上:
在这里插入图片描述


拖尾效果:
请添加图片描述



八、给猪造房子


切割:
在这里插入图片描述


以方形木头为例:
在这里插入图片描述


Pig.cs脚本中添加bool的isPig,让木块等也能使用:

    [Space]
    public bool isPig = false;
    
    // 死亡,生成爆炸动画和分数
    private void Dead()
    {
    
    
        if (isPig)
            GameManager.instance.pigs.Remove(this);
        Instantiate(boomPrefab, transform.position, Quaternion.identity);
        GameObject scoreObject = Instantiate(scorePrefab, transform.position + new Vector3(0, scoreYOffset, 0),
            Quaternion.identity);
        Destroy(scoreObject, 1.5f);
        Destroy(gameObject);
    }

将之前的猪勾选isPig
在这里插入图片描述


将木头挂载该脚本并不勾选isPig,然后设置hurtSpeed等参数 :
在这里插入图片描述

木头需要组件: 刚体、碰撞体、Pig脚本


同理,新增其他物品。

设置简单的场景如下:
在这里插入图片描述


运行效果:
请添加图片描述



九、游戏胜利、失败界面


1. 显示胜利、失败基本界面


切割:

在这里插入图片描述


制作UI(参考第15集).

Lose UI:
请添加图片描述


Win UI:
请添加图片描述


在游戏胜利时,根据关卡中的剩余小鸟数量,判断应该获得的星星数量,GameManager.cs部分代码如下:

    [Header("UI")]
    public GameObject winUI;
    public GameObject loseUI;

    [Header("胜利得到星星的数量需要的小鸟存活数")]
    public int birdNumOf3Star;
    public int birdNumOf2Star;

    // 判断游戏状态 及 是否启用下一只小鸟
    public void Next()
    {
    
    
        if (pigs.Count == 0)
        {
    
    
            // 游戏胜利
            winUI.SetActive(true);
        }
        else
        {
    
    
            if (birds.Count == 0)
            {
    
    
                // 游戏失败
                loseUI.SetActive(true);
            }
            else
            {
    
    
                InitBird();
            }
        }
    }

    public void WinLevel()
    {
    
    
        if (birds.Count >= birdNumOf3Star)  // 3颗星星
        {
    
    

        }
        else if (birds.Count >= birdNumOf2Star) // 2颗
        {
    
    

        }
        else // 1颗
        {
    
    

        }
    }

同时,为Win UI创建一个Win.cs的脚本:

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

public class Win : MonoBehaviour
{
    
    
    // 动画播放完(显示UI后) 显示星星
    public void ShowStar()
    {
    
    
        GameManager.instance.WinLevel();
    }
}

在动画结束后调用:
在这里插入图片描述


2. 星星粒子效果


切割星星:
在这里插入图片描述


三颗星星的摆放:
在这里插入图片描述


根据https://www.bilibili.com/video/BV1qb411c76x?p=16第16到18集设置星星的粒子效果。


3. 星星显示


GameManager.cs中,利用协程,每隔0.7s,显示一颗星星:

    public GameObject[] starsUI = new GameObject[3];
    
    public void WinLevel()
    {
    
    
        if (birds.Count >= birdNumOf3Star)  // 3颗星星
        {
    
    
            StartCoroutine("ShowTheStar", 3);
        }
        else if (birds.Count >= birdNumOf2Star) // 2颗
        {
    
    
            StartCoroutine("ShowTheStar", 2);
        }
        else // 1颗
        {
    
    
            StartCoroutine("ShowTheStar", 1);
        }
    }

    // 每隔0.7秒,显示一颗星星
    IEnumerator ShowTheStar(int num)
    {
    
    
        for(int i = 0; i < num; i++)
        {
    
    
            starsUI[i].SetActive(true);
            yield return new WaitForSeconds(0.7f);
        }
    }

Insepctor面板中拖入星星:
在这里插入图片描述


此时正常显示星星:

请添加图片描述




十、暂停界面


1. 界面以及动画

P20

暂停按钮:

在这里插入图片描述


暂停面板:

在这里插入图片描述


实现暂停动画:

在这里插入图片描述

实现继续动画:

在这里插入图片描述


两个动画都取消循环播放:

在这里插入图片描述


2. 实现暂停和继续


Animator中创建两个Trigger参数,并将两个动画相连:

在这里插入图片描述


Pause动画与Resume的连线:

在这里插入图片描述

在这里插入图片描述


创建PausePanle脚本并放入Pause Panel:

在这里插入图片描述

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

public class PausePanel : MonoBehaviour
{
    
    
    private Animator anim;

    // Start is called before the first frame update
    void Start()
    {
    
    
        anim = GetComponent<Animator>();
    }


    // 点击继续按钮
    public void Resume()
    {
    
    
        anim.SetTrigger("resume");
    }

    // 继续动画结束后,调用
    public void AfterResume()
    {
    
    
        this.gameObject.SetActive(false);
        anim.SetTrigger("pause");  // 切换回暂停动画,下次active true时则调用暂停动画
    }

}

GameManager.cs中添加代码:

    [Space]
    public GameObject pausePanel;

    // 暂停按钮调用函数
    public void PauseGame()
    {
    
    
        pausePanel.SetActive(true);
    }

Inspector面板中,拖入Pause Panel:

在这里插入图片描述


Pause Btn添加点击事件,为GameManager的暂停方法:

在这里插入图片描述


Resume Btn添加点击事件,为Pause PanelPause方法:

在这里插入图片描述


Resume动画结束时,调用AfterResume函数:

在这里插入图片描述


效果:

请添加图片描述


3. 实现Restart Level


GameManager.cs中添加重启关卡方法:

using UnityEngine.SceneManagement;

    // 重启关卡
    public void RestartLevel()
    {
    
    
        SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
    }

在各个重启按钮中调用:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


运行效果:
请添加图片描述



十一、相机跟随


1. 跟随第一只小鸟

打开Package Manager:
在这里插入图片描述


下载Cinemachine:
在这里插入图片描述


添加一个2D Camera
在这里插入图片描述


将第一只小鸟拖入Follow,让相机跟随小鸟:
在这里插入图片描述


调节部分参数,以选取合适位置:
在这里插入图片描述


同时创建一个名为Camera BG的空物体,为其加上Polygon碰撞体,勾选Is Trigger,用作相机的范围,(即小鸟若超出该范围,相机则不跟随):
在这里插入图片描述


在刚刚的CM vcam1中,添加CinemachineConfiner
在这里插入图片描述


将刚刚的Camera BG拖入:
在这里插入图片描述


2. 按顺序跟随多只小鸟

GameManager中引入:

using Cinemachine;

若报错,则导入Cinemachine示例程序场景:
在这里插入图片描述


GameManager.cs更改的代码:

using Cinemachine;

    [Header("相机和弹弓")]
    public CinemachineVirtualCamera virtualCamera;
    public Transform slingshotLeftPos;    // 弹弓左部点,用于小鸟死后视角回到弹弓

    // 初始化小鸟
    private void InitBird()
    {
    
    
        for(int i = 0; i <birds.Count; i++)
        {
    
    
            if (i == 0)
            {
    
    
                birds[i].transform.position = originBirdPos;
                birds[i].enabled = true;
                birds[i].GetComponent<SpringJoint2D>().enabled = true;
                virtualCamera.Follow = birds[i].transform;  // 相机跟随小鸟
            }
            else
            {
    
    
                birds[i].enabled = false;
                birds[i].GetComponent<SpringJoint2D>().enabled = false;
            }
        }
    }
    
	// 判断游戏状态 及 是否启用下一只小鸟
    public void Next()
    {
    
    
        virtualCamera.Follow = slingshotLeftPos;
        virtualCamera.transform.position = slingshotLeftPos.position;

        if (pigs.Count == 0)
        {
    
    
            // 游戏胜利
            winUI.SetActive(true);
        }
        else
        {
    
    
            if (birds.Count == 0)
            {
    
    
                // 游戏失败
                loseUI.SetActive(true);
            }
            else
            {
    
    
                InitBird();
            }
        }
    }

最终演示效果:

请添加图片描述



参考

【SiKi学院Unity】Unity初级案例 - 愤怒的小鸟

猜你喜欢

转载自blog.csdn.net/weixin_46628481/article/details/122272140
今日推荐