Unity版本愤怒的小鸟设计与实现

 

      物理向的小游戏,首先我们需要知道这个组件:SpringJoint,也就是2D弹簧组件,很有意思的组件,做UI的时候可以用来实现那种绳子吊着木牌悬挂的感觉。

这是这个小游戏实现的核心之一。

Unity版本愤怒的小鸟设计与实现_第1张图片

哦,对了,还有这个组件:LineRender组件,也就是划线的组件,其实主要就是用到了它的setPosition方法。

Unity版本愤怒的小鸟设计与实现_第2张图片

 

知道了这些后,看下实现效果:

细心可以发现,这里面包含了,“猪的死亡”,“鸟的发射”,“换鸟操作”,还有游戏输赢逻辑判断。

小鸟身上的脚本:主要是控制我们弹弓的划线,和小鸟自身的游戏飞出

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

/*
作者:王祥瑞
*/
namespace JumpAgent
{

    public class Birds : MonoBehaviour
    {

        private bool isClick = false;
        public bool isFlyed = false;
        public float maxDistance = 3.0f;
        private SpringJoint2D sp;
        private Rigidbody2D rb;

        //划线
        public LineRenderer right;
        public LineRenderer left;
        public Transform leftPos;
        public Transform rightPos;

        public SpringJoint2D Sp
        {
            get
            {
                return sp;
            }

            set
            {
                sp = value;
            }
        }
        public Rigidbody2D Rb
        {
            get
            {
                return rb;
            }

            set
            {
                rb = value;
            }
        }

        private void Awake()
        {
            sp = this.GetComponent();
            rb = this.GetComponent();
            sp.enabled = false;//禁用bird身上的这个组件,要不然一开始所有的小鸟都会飞到弹弓上去
        }

        private void OnMouseDown()
        {
            isClick = true;
            //鼠标抬起的时候禁用划线组件
            right.enabled = true;
            left.enabled = true;
            rb.isKinematic = true;
        }

        private void OnMouseUp()
        {
            isClick = false;
            rb.isKinematic = false;
            isFlyed = true;
            Invoke("fly", 0.1f);
            //鼠标抬起的时候禁用划线组件
            right.enabled = false;
            left.enabled = false;
        }


        void Update()
        {
            if (isClick)
            {
                transform.position = Camera.main.ScreenToWorldPoint(Input.mousePosition);
                transform.position += new Vector3(0, 0, -Camera.main.transform.position.z);

                if (Vector3.Distance(transform.position, rightPos.position) > maxDistance)
                {
                    Vector3 offset = (transform.position - rightPos.position).normalized;
                    offset *= maxDistance;
                    transform.position = offset + rightPos.position;
                }
                LineRender();
            }

        }
        /// 
        /// 控制小鸟飞翔
        /// 
        private void fly()
        {
            sp.enabled = false;
        }
        /// 
        /// 划线的实现
        /// 
        private void LineRender()
        {
            right.SetPosition(0, rightPos.position);
            right.SetPosition(1, transform.position);
            left.SetPosition(0, leftPos.position);
            left.SetPosition(1, transform.position);
        }
        /// 
        /// 这里我没有采用直接销毁游戏物体,取而代之的是将其隐藏起来.
        /// 
        public void Dohidethis()
        {
            Invoke("hidethis", 5f);

        }
        public void hidethis()
        {
            this.gameObject.SetActive(false);
        }

    }//类

}//命名空间

然后是猪(障碍物)的脚本:

这个猪的脚本主要是控制猪的受伤(根据碰撞时的速度来判断伤害,伤害处理机制,我封装了一个脚本),其实这个猪的脚本可以泛用的,比如就是说可以用到我们的障碍物身上,小鸟撞击障碍物,会进行同样的伤害判定,还可以通过修改不同障碍物的生命值来控制实现不同障碍物的不同特性,不过在这里我并没有进行泛用,虽说可以泛用,但是只是95%代码一样,猪比障碍物多了个死亡没死亡的bool判断值,这在下面的GameManager脚本里解释。

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

/*
作者:王祥瑞
*/
namespace JumpAgent
{

    public class Pig : MonoBehaviour
    {
        private float maxSpeed = 10;//碰撞最大速度
        private float minSpeed = 3;//碰撞最小速度
        [SerializeField]
        private float hp = 100;
        public GameObject Bloom;
        public GameObject[] ScorePrefab;//头顶分数
        private SpriteRenderer spriteRenderer;
        public Sprite[] sp;//存放不同级别的受损图片,不过一般这游戏就是一张受损
        public bool isPigDead = false;//猪是不是死了



        private void Awake()
        {
            spriteRenderer = this.GetComponent();
        }
//猪(障碍物)与鸟的碰撞检测,
        private void OnCollisionEnter2D(Collision2D collision)
        {
            if (collision.relativeVelocity.magnitude > maxSpeed && collision.gameObject.tag == "Player")
            {
                float damage = (collision.relativeVelocity.magnitude * 10f);
                PigDeathJudge(damage);
                collision.gameObject.GetComponent().Dohidethis();
            }
            if (collision.relativeVelocity.magnitude > minSpeed && collision.relativeVelocity.magnitude < maxSpeed)
            {
                if (!isPigDead)
                {
                    float damage = (collision.relativeVelocity.magnitude * 10f);
                    PigDeathJudge(damage);
collision.gameObject.GetComponent().Dohidethis();
                }
            }
        }
//猪的伤害判定脚本
        private void PigDeathJudge(float damage)
        {
            hp -= damage;
            if (hp <= 0)
            {
                isPigDead = true;
                GameObject temp = Instantiate(ScorePrefab[0], new Vector3(transform.position.x, (this.transform.position.y + 1f), this.transform.position.z), Quaternion.identity);
                temp.SetActive(true);
                this.spriteRenderer.color = Color.clear;
                Bloom.SetActive(true);
                Invoke("PigDestory", 0.467f);
            }
            if (hp <= 50 && hp > 0)
            {
                spriteRenderer.sprite = sp[0];
            }
        }

        private void PigDestory()
        {
            this.gameObject.SetActive(false);
        }

    }//类

}//命名空间

然后是我们的游戏核心逻辑代码了:

里面有:换鸟操作,和两个分别管理猪,鸟的集合,也就是说我们判断输赢,就只需要维护我们的这两个集合就好啦。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
/*
作者:王祥瑞
*/
namespace JumpAgent
{

    public class GameManager : MonoBehaviour
    {
        public List birds;
        public List pigs;

        public GameObject win;
        public GameObject lose;

        public static GameManager _instance;

        private void Awake()
        {
            _instance = this;
            birds = new List();
            pigs = new List();
        }

        private void Start()
        {
            AllFindPigAndBird();//初始化好所有的猪和鸟
            BirdsAlternate();//换上第一只鸟
            StartCoroutine("GameWinOrLoseJudgment");//开始游戏逻辑
        }
        /// 
        /// 游戏输赢判断
        /// 
        /// 
        private IEnumerator GameWinOrLoseJudgment()
        {
            int pigAliveCount = 0;
            int birdFlyedCount = 0;
            while (true)
            {
                yield return new WaitForSeconds(3);
                //遍猪的数组,如果猪的状态都为Dead,则游戏胜利
                foreach (Pig item in pigs)
                {
                    if (!item.isPigDead)
                    {
                        pigAliveCount++;
                    }
                }
                // Debug.Log("现在猪的数量为:" + pigAliveCount);
                if (pigAliveCount == 0)
                {
                    Debug.Log("游戏胜利");
                    //TODO:游戏胜利的逻辑
                    win.SetActive(true);
                    Time.timeScale = 0;
                }
                else//反之则开始判断小鸟的飞出数量
                {
                    pigAliveCount = 0;
                }

                //在这里可以考虑一下延时
                yield return new WaitForSeconds(1);

                //遍历小鸟数组,如果小鸟飞出的数量等于小鸟原来集合的Count的话
                foreach (Birds item in birds)
                {
                    if (item.isFlyed)
                    {
                        birdFlyedCount++;
                    }
                }
                Debug.Log("小鸟数量为" + (birds.Count - birdFlyedCount) + "/" + birds.Count);
                if ((birds.Count - birdFlyedCount) == 0)//如果剩余的小鸟数量(所有鸟的数量减去已经飞出的小鸟的数量==0)
                {
                    Debug.Log("游戏失败");
                    //TODO:游戏失败的逻辑
                    lose.SetActive(true);
                }
                else//反之则为游戏进行中
                {
                    birdFlyedCount = 0;
                    BirdsAlternate();//调用换鸟
                }


            }
        }

        /// 
        /// 换鸟操作
        /// 
        public void BirdsAlternate()
        {
            //本质上就是遍历鸟的集合,逐次的打开小鸟身上相对应的组件
            for (int i = 0; i < birds.Count; i++)
            {
                if (!birds[i].isFlyed)
                {
                    birds[i].transform.position = new Vector3(-6.5f, -1.8f, 0);
                    birds[i].enabled = true;
                    birds[i].Sp.enabled = true;                    
                    break;
                }
            }

        }
        /// 
        /// 初始化猪和鸟的集合
        /// 
        public void AllFindPigAndBird()
        {
            GameObject[] GObird = GameObject.FindGameObjectsWithTag("Player");
            GameObject[] GOpig = GameObject.FindGameObjectsWithTag("Enemy");

            for (int i = 0; i < GObird.Length; i++)
            {
                birds.Add(GObird[i].GetComponent());
            }
            for (int i = 0; i < GOpig.Length; i++)
            {
                pigs.Add(GOpig[i].GetComponent());
            }

            //把小鸟的birds组件都先禁用
            for (int i = 0; i < birds.Count; i++)
            {
                birds[i].enabled = false;
            }


        }


    }//类

}//命名空间

然后是多关卡的实现,这里说下实现思路:

首先我们不能就是说,有多少关就做多少个场景,然后在选关界面做一堆Button,然后点哪个就跳哪个场景,那样是不可取的,除去会让游戏变得很大之外,而且如果那样的话,上面写的这堆自动判断输赢,自动查找鸟和猪以及自动换鸟的这些操作就没有任何意义了。

那么该如何实现呢?我们要做的仅仅是做出不同的障碍物组合,然后把他们放到prefabs文件夹,然后根据每个关卡(为每个关卡设置枚举)的枚举数,来在地图相应的位置(位置要先定义好)来加载你需要的鸟和障碍物即可,只要你把你需要的障碍物和鸟加到游戏场景中,游戏就会自动运行。

你可能感兴趣的:(Unity)