zoukankan      html  css  js  c++  java
  • 阶段学习总结-见缝插针案例

    技术类技能学习就是需要多学习实例,多总结。今天又学习了一个见缝插针案例,特记录总结。

    一.案例说明

      本案例是siki学院的免费课程,可以自行搜索。本案例是2D项目案例。

     二.效果图

    游戏初始状态

     

    游戏运行中

     

    游戏结束

    三.脚本说明

    public class RotateSelf : MonoBehaviour
    {
        //旋转速度
        public float rotateSpeed;
        // Start is called before the first frame update
        void Start()
        {
            
        }
    
        // Update is called once per frame
        void Update()
        {
            //旋转
            transform.Rotate(new Vector3(0, 0, rotateSpeed * Time.deltaTime));
        }
    }

    首先是大黑圈会自动旋转,在其上挂载自动旋转脚本,这个脚本很简单,开放了旋转速度参数,在Update方法中旋转自身即可。

    public class GameManager : MonoBehaviour
    {
        //针的准备位置,需要使用空物体记录这个位置
        public Transform startPoint;
        //同样使用空物体记录针的生成位置,在游戏界面外部生成针,再使针移动到准备位置
        public Transform initiationPoint;
        //Pin是针上面挂载的脚本,上面有startFly方法,使实例化出来的针从实例位置向准备发射位置移动
        private Pin currentPin;
        //针的prefab
        public GameObject pin;
        //记录游戏是否结束的布尔值,游戏中两个针头发生碰撞游戏就会结束,这个布尔值是为了避免多个针实例重复调用游戏结束方法
        private bool isGameOver = false;
        //记录游戏分数(插上圆圈的针个数)
        private int score = 0;
        //实时显示分数
        public Text text;
        //主摄像机,在游戏结束时需要将摄像机镜头拉近,因此需要获取主摄像机上的camera组件,调整size属性值
        private Camera mainCamera;
        //游戏结束时需要将背景色渐变,使用线性插值Color.Lerp进行渐变,这里定义的时插值的第三个参数,初始值0.9变化会非常快
        public float colorChangeSpeed = 0.9f;
        // Start is called before the first frame update
        void Start()
        {
            //首先在屏幕外生成一个针并记录下来,针会自动向准备位置移动
            currentPin = Instantiate(pin, initiationPoint.position, pin.transform.rotation).GetComponent<Pin>();
            //获取摄像机
            mainCamera = GameObject.FindGameObjectWithTag("MainCamera").GetComponent<Camera>();
        }
    
        // Update is called once per frame
        void Update()
        {
            //如果游戏已经结束,不再更新
            if (isGameOver) return;
            //实时显示分数
            text.text = score.ToString();
            //当按下鼠标左键时
            if (Input.GetMouseButtonDown(0))
            {
                //按下鼠标左键后调用startFly方法,针开始从准备位置向黑球移动
                currentPin.startFly();
                //再次实例化一个针,并自动移动到准备位置
                currentPin = Instantiate(pin, initiationPoint.position, pin.transform.rotation).GetComponent<Pin>();
            }
        }
    
        //游戏结束方法
        public void gameOver()
        {
            //游戏已经结束就不再调用此方法
            if (isGameOver) return;
            else
            {
                //找到圆圈物体,禁用自动旋转组件,停止旋转
                GameObject.Find("Circle").GetComponent<RotateSelf>().enabled = false;
                //开启结束游戏的协程
                StartCoroutine(GameOverAnimation());
            }
            //记录下游戏已经结束
            isGameOver = true;
        }
    
        //加分,这个方法由针调用,当针到达指定位置并且针头没有和其他针头发生碰撞,调用此方法
        public void scoreCount()
        {
            score++;
        }
    
        //结束游戏的协程
        IEnumerator GameOverAnimation()
        {
            while (true)
            {
                //改变渲染的背景色
                mainCamera.backgroundColor = Color.Lerp(mainCamera.backgroundColor, Color.red, colorChangeSpeed * Time.deltaTime);
                //改变摄像机正交视野大小
                mainCamera.orthographicSize = Mathf.Lerp(mainCamera.orthographicSize, 4f, colorChangeSpeed * Time.deltaTime);
                //当视野改变和背景色改变完成后结束循环
                if(Mathf.Abs(mainCamera.orthographicSize - 4f) < 0.01f)
                {
                    break;
                }
                yield return 0;
            }
            //暂停一秒
            yield return new WaitForSeconds(1);
            //重新加载场景
            SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
    
        }
    }

    这段脚本用于管理游戏进程,主要包括计分、发射针和结束游戏等操作。脚本和针上面的控制针运动的脚本耦合性很高,两者相互调用较多,还有改善空间。

    public class Pin : MonoBehaviour
    {
        //记录针运动的速度
        public float speed = 5;
        //记录针是否已经发射并向目标位置运动,初始为false,下面会做if判断,在else语句中有针运动向准备位置的代码,即针实例化出来后立刻从初始化位置运动往准备位置
        private bool isFly = false;
        //记录针是否到达准备位置
        private bool isReach = false;
        //游戏中间的圆圈,针发射后需要到达的位置
        private Transform circle;
        //针的目标位置,即发射后需要到达的位置
        private Vector3 targetPosition;
        //针的起始位置
        private Transform startPoint;
        // Start is called before the first frame update
        void Start()
        {
            //初始化
            startPoint = GameObject.Find("StartPoint").transform;
            circle = GameObject.Find("Circle").transform;
            //计算针发射后需要到达的位置,在圆圈下方1.36处
            targetPosition = circle.position;
            targetPosition.y -= 1.36f;
        }
    
        // Update is called once per frame
        void Update()
        {
            //如果针在飞行,初始化出来的针这个值为false
            if (isFly)
            {
                //如果结束飞行说明针到达了准备位置,针就可以发射,在游戏管理脚本中按下鼠标左键后会将isFly的值设置为true,接下来针就会往发射目标位置飞行
                transform.position = Vector3.MoveTowards(transform.position, targetPosition, speed * Time.deltaTime);
                //如果飞行到达目标位置
                if (Vector3.Distance(transform.position, targetPosition) < 0.05)
                {
                    //将真的位置设置为发射终点位置(最终针的到达位置和发射终点位置有微小的偏差)
                    transform.position = targetPosition;
                    //将针设置为圆圈的子物体,针将跟着圆圈一起旋转
                    transform.parent = circle;
                    //调用游戏管理的计分方法,记录分数
                    GameObject.FindGameObjectWithTag("GameController").GetComponent<GameManager>().scoreCount();
                    //设置针的状态为已经到达并没有在飞行
                    isReach = true;
                    isFly = false;
                }
            }
            //如果针没有在飞行,这里的飞行是指发射后向发射终点位置的飞行,值为false则针并未开始发射
            else
            {
                //判断针是否到达准备位置
                if (isReach)
                {
    
                }
                //针未到达准备位置则向准备位置运动
                else
                {
                    //向准备位置运动
                    transform.position = Vector3.MoveTowards(transform.position, startPoint.position, speed * Time.deltaTime);
                    //如果到达准备位置,将是否到达准备位置的布尔值设置为true
                    if(Vector3.Distance(transform.position,startPoint.position) < 0.05)
                    {
                        isReach = true;
                    }
                }
            }
        }
    
        //供游戏管理组件调用的方法,按下鼠标左键后会调用此方法,将是否飞行的布尔值设置为true,代表将向发射终点飞行
        public void startFly()
        {
            isFly = true;
    
        }
    
        //判断针头是否发生碰撞,如果碰撞则游戏结束
        private void OnTriggerEnter2D(Collider2D collision)
        {
            //针上设置了PinHead标签,通过标签判断碰撞到的位置是否是针头,如果是则将结束游戏
            if(collision.tag == "PinHead")
            {
                //调用游戏管理组件的游戏结束方法结束游戏
                GameObject.Find("GameManager").GetComponent<GameManager>().gameOver();
            }
        }
    
    }

    这段脚本用于管理生成的针prefab的运动和碰撞等。这段脚本逻辑复杂了一些,主要设置了两个布尔值,一个isFly代表针是否已经发射,一个isReach代表是否已经到达准备发射位置。刚生成的针的isFly初始值为false,isReach的值也为false,代表没有开始发射并且没有到达准备发射位置,在Update中做两次判断,双false的话针向准备发射位置运动。当按下鼠标左键时,不论针是否到达准备发射位置,isFly值都设置为true,代表针开始发射的飞行,飞行的终点位置为发射终点位置。因此代码Update方法中先判断isFly值看针是否已经发射,已经发射就使针向发射终点运动,如果未发射再判断针是否到达准备发射位置,未到达准备发射位置向准备发射位置运动。在发射到达发射终点后,再将isFly值设置为false,代表不用再飞行,同时设置isReach为true,不用再向发射准备位置运动。

  • 相关阅读:
    故事讲的好,才会有人去思考:什么是成功的商业片——记《疯狂的石头》
    收集的特色flash网站
    pf负载均衡
    squid故障与解决方法汇总
    IIS7.0在Vista上的错误 0x80070021
    PF 默认会限制最大连接数5000问题
    Squid日志详解
    samba结合AD实现大型网络方案
    inotify监听+rsync
    AD帐号登陆samba自动创建主目录脚本
  • 原文地址:https://www.cnblogs.com/movin2333/p/14050933.html
Copyright © 2011-2022 走看看