zoukankan      html  css  js  c++  java
  • 总结一下今天做的面试题(二):随机漫游与汽车爆炸

    同样的,先看需求

    可以看到题目分两个部分,汽车警报响起的前后有着不同的行为,首先我们要完成的是僵尸的随机漫游。

    题目要求僵尸在一定半径的圆形范围内做随机运动,直接随机僵尸的xy坐标是行不通的,不过我们可以采取极坐标的方式随机角度和半径,然后计算僵尸的坐标:

    在确定一个坐标后,僵尸就开始移动,直到移动到目标地点后,僵尸随机下一个坐标并开始移动,这里用一个Bool型的moved变量和协程进行控制:

        void Update () {
            if (!moved) {
                StartCoroutine (roam());//if zombie reach the end,start the next roam
            }
        }
        IEnumerator roam(){
            moved = true;
            float _angle = Random.Range (0,360f);
            float _radius = Random.Range (1f, radius);
            Vector3 start_place = m_transform.position;
            Vector3 end_place = new Vector3 (x + _radius * Mathf.Cos (_angle),y,z + _radius * Mathf.Sin (_angle));//get end place with angle and radius
            m_transform.LookAt (end_place);
            float time = (m_transform.position - end_place).magnitude/normal_speed;
            float time0 = 0;
            while (time0 < time) {
                time0 += Time.deltaTime;
                m_rigidbody.MovePosition(m_transform.position+(end_place-start_place).normalized*normal_speed*Time.deltaTime);//move to end place with physical
                yield return null;
                if (alarm)
                    break;
            }
            moved = false;
        }

    需要注意的是移动的时候不能直接改变僵尸的坐标,而是要让它向着目标地点“向前走”,因为场景中会有其他碰撞体(比如车),直接改变僵尸的坐标的话,遇到这些碰撞虽然暂时不会穿过去,但一旦选定的坐标穿过去了,僵尸也就穿过去了(这句话有点拗口,希望能够理解)

    做好僵尸的漫游功能后,在场景中放上车和僵尸的模型,并把相应的脚本绑定这僵尸上:

    随后是控制车的血量的脚本,先把血条和点击扣血的时间做出来,这里参考了别人的代码,直接在gui上画了血条。

      
      private Camera camera;
      public
    Texture2D blood_red;//pic for red blood public Texture2D blood_black;//pic for lose blood private int hp = 100,alarm_hp=95,click_down=1,max_hp;//the hp of cars void OnMouseDown(){ HP-=click_down; if (hp == alarm_hp) { car_alarm (); } } void OnGUI(){ Vector3 worldPosition = new Vector3 (transform.position.x , transform.position.y + carHeight,transform.position.z);//the positon of blood texture Vector2 position = camera.WorldToScreenPoint (worldPosition); position = new Vector2 (position.x, Screen.height - position.y);//change it to 2D world Vector2 bloodSize = GUI.skin.label.CalcSize (new GUIContent(blood_red));//get the height and width of blood texture int blood_width = blood_red.width * HP/max_hp;//get the width of red blood GUI.DrawTexture(new Rect(position.x - (bloodSize.x/2),position.y - bloodSize.y ,bloodSize.x,bloodSize.y),blood_black); GUI.DrawTexture(new Rect(position.x - (bloodSize.x/2),position.y - bloodSize.y ,blood_width,bloodSize.y),blood_red);//draw blood texture }

    然后是血量掉到alarm_hp时触发的警报事件,为了方便,这里用一个存在三秒的Button来代替。

    由于警报响起必然会触发大量事件,所以这里肯定是采用一个委托

    public Action car_alarm;

    然后给委托加上相应的事件

    car_alarm+=()=>StartCoroutine(show_alarm(alarm_time));

        IEnumerator show_alarm(float time){
            alarm = true;
            yield return new WaitForSeconds (time);
            alarm = false;
        }

    OnGUI上加上对应的button

            if (alarm)
            if (GUI.Button (new Rect (Screen.width/2-80, Screen.height/2-30, 160, 60), "警报响了!!")) {
                alarm = false;
            }

    警报响了以后,僵尸也应当停止漫游,向汽车跑去,并且开始攻击(由于有两个攻击动画,所以我做了一个随机)

    在控制僵尸的脚本上获取这个委托,并注册相应的事件:

    car_transform = GameObject.FindGameObjectWithTag ("car").transform;
            car = car_transform.gameObject.GetComponent<cartrick>();
    car.car_alarm += Atk_Car;//attack car when car alarm
        void Atk_Car(){
            alarm = true;
            StartCoroutine (GoAndAtk());
        }
        IEnumerator GoAndAtk(){
            Vector3 start_place = m_transform.position;
            Vector3 end_place = car_transform.position;
            m_transform.LookAt (end_place);
            m_animation.Play (clipName[3]);//the zombie change to run
            float time = (m_transform.position - end_place).magnitude/special_speed;
            float time0 = 0;
            while (time0 < time) {
                time0 += Time.deltaTime;
                m_rigidbody.MovePosition(m_transform.position+(end_place-start_place).normalized*special_speed*Time.deltaTime);//move to end place with physical
                yield return null;
            }
            while (true) {
                float i = Random.Range (5f, 7f);//random attack ways
                yield return StartCoroutine (playanimation(clipName[(int)i],1f));
            }
        }
        IEnumerator playanimation(string name,float time){
            m_animation.Play (name);
            yield return new WaitForSeconds(time/2);
            car.HP -= zombie_attack;//down the hp in half of the animator
            yield return new WaitForSeconds(time/2);
        }

    之后,类似的,在汽车hp降为0后,提示爆炸信息,汽车爆炸,就不细说了。

    效果预览:

    本次用到的两个脚本:

    using UnityEngine;
    using System.Collections;
    
    public class zombie_move : MonoBehaviour {
        Transform m_transform,car_transform;
        cartrick car;
        float radius=3,x,y,z;//the radius and the start place the zombie moves
        float normal_speed=2f,special_speed=3f;//the speed when zombie walk and move to car
        string[] clipName={"idle","crawl","shamble","run","fallBack","attack1","attack2"};
        int zombie_attack=2;//one hit damage to the car
        Animation m_animation;
        bool moved=false,alarm=false;
        Rigidbody m_rigidbody;
        // Use this for initialization
        void Start () {
            m_transform = this.transform;
            m_animation = m_transform.GetComponent<Animation> ();
            car_transform = GameObject.FindGameObjectWithTag ("car").transform;
            car = car_transform.gameObject.GetComponent<cartrick>();
            m_rigidbody=m_transform.GetComponent<Rigidbody> ();
            x = m_transform.position.x;
            y = m_transform.position.y;
            z = m_transform.position.z;
            m_animation.Play (clipName[2]);
            car.car_alarm += Atk_Car;//attack car when car alarm
            car.explosion += () => Destroy (m_transform.gameObject);//destroy the zombie when car explose
        }
        
        // Update is called once per frame
        void Update () {
            if (!moved) {
                StartCoroutine (roam());//if zombie reach the end,start the next roam
            }
        }
        IEnumerator roam(){
            moved = true;
            float _angle = Random.Range (0,360f);
            float _radius = Random.Range (1f, radius);
            Vector3 start_place = m_transform.position;
            Vector3 end_place = new Vector3 (x + _radius * Mathf.Cos (_angle),y,z + _radius * Mathf.Sin (_angle));//get end place with angle and radius
            m_transform.LookAt (end_place);
            float time = (m_transform.position - end_place).magnitude/normal_speed;
            float time0 = 0;
            while (time0 < time) {
                time0 += Time.deltaTime;
                m_rigidbody.MovePosition(m_transform.position+(end_place-start_place).normalized*normal_speed*Time.deltaTime);//move to end place with physical
                yield return null;
                if (alarm)
                    break;
            }
            if (!alarm) moved = false;
        }
        IEnumerator GoAndAtk(){
            Vector3 start_place = m_transform.position;
            Vector3 end_place = car_transform.position;
            m_transform.LookAt (end_place);
            m_animation.Play (clipName[3]);//the zombie change to run
            float time = (m_transform.position - end_place).magnitude/special_speed;
            float time0 = 0;
            while (time0 < time) {
                time0 += Time.deltaTime;
                m_rigidbody.MovePosition(m_transform.position+(end_place-start_place).normalized*special_speed*Time.deltaTime);//move to end place with physical
                yield return null;
            }
            while (true) {
                float i = Random.Range (5f, 7f);//random attack ways
                yield return StartCoroutine (playanimation(clipName[(int)i],1f));
            }
        }
        void Atk_Car(){
            alarm = true;
            StartCoroutine (GoAndAtk());
        }
        IEnumerator playanimation(string name,float time){
            m_animation.Play (name);
            yield return new WaitForSeconds(time/2);
            car.HP -= zombie_attack;//down the hp in half of the animator
            yield return new WaitForSeconds(time/2);
        }
    }
    zombie_move.cs
    using UnityEngine;
    using System.Collections;
    using System;
    
    public class cartrick : MonoBehaviour {
        Transform p_transform;
        private Camera camera;
        float carHeight=2f,alarm_time=3f,explosion_time=3f;
        public Texture2D blood_red;//pic for red blood
        public Texture2D blood_black;//pic for lose blood
        private int hp = 100,alarm_hp=95,click_down=1,max_hp;//the hp of cars
        bool alarm=false,isexplosion=false;
        public int HP{
            get{ return hp;}
            set{ if (value <= 0) {
                    value = 0;
                    StartCoroutine (take_explosion(explosion_time));
                }
                hp = value;}
        }
        //public delegate void _delegate();
        //public _delegate car_alarm; 
        public Action car_alarm,explosion;
        // Use this for initialization
        void Start () {
            p_transform = this.transform.parent.transform;
            camera = Camera.main;//get the main camera
            car_alarm+=()=>StartCoroutine(show_alarm(alarm_time));
            explosion += () => {
                //StartCoroutine (show_explosion (explosion_time));
                Destroy (p_transform.gameObject);
            };
            max_hp = HP;
        }
        
        // Update is called once per frame
        void Update () {
        
        }
        void OnMouseDown(){
            HP-=click_down;
            if (hp == alarm_hp) {
                car_alarm ();
            }
        }
        void OnGUI(){
            if (alarm)
            if (GUI.Button (new Rect (Screen.width/2-80, Screen.height/2-30, 160, 60), "警报响了!!")) {
                alarm = false;
            }
            if (isexplosion)
            if (GUI.Button (new Rect (Screen.width/2-80, Screen.height/2-30, 160, 60), "车要炸了!")) {
                isexplosion = false;
            }
            Vector3 worldPosition = new Vector3 (transform.position.x , transform.position.y + carHeight,transform.position.z);//the positon of blood texture
            Vector2 position = camera.WorldToScreenPoint (worldPosition);
            position = new Vector2 (position.x, Screen.height - position.y);//change it to 2D world
            Vector2 bloodSize = GUI.skin.label.CalcSize (new GUIContent(blood_red));//get the height and width of blood texture
            int blood_width = blood_red.width * HP/max_hp;//get the width of red blood 
            GUI.DrawTexture(new Rect(position.x - (bloodSize.x/2),position.y - bloodSize.y ,bloodSize.x,bloodSize.y),blood_black);
            GUI.DrawTexture(new Rect(position.x - (bloodSize.x/2),position.y - bloodSize.y ,blood_width,bloodSize.y),blood_red);//draw blood texture
        }
        IEnumerator show_alarm(float time){
            alarm = true;
            yield return new WaitForSeconds (time);
            alarm = false;
        }
        IEnumerator show_explosion(float time){
            isexplosion = true;
            yield return new WaitForSeconds (time);
        }
        IEnumerator take_explosion(float time){
            isexplosion = true;
            yield return new WaitForSeconds (time);
            explosion ();
            isexplosion = false;
        }
    }
    cartrick.cs
  • 相关阅读:
    【Windows socket+IP+UDP+TCP】网络基础
    【我所认知的BIOS】—> uEFI AHCI Driver(8) — Pci.Read()
    Unity3D十款最火的的插件推荐
    静态路由解决双外卡,PC做路由器的实现
    00096_Properties类
    TensorFlow2_200729系列---4、手写数字识别理论
    损失函数基础知识总结
    为什么选择onehot编码(总结)
    TensorFlow2_200729系列---3、梯度下降求简单线性回归实例
    numpy生成随机数据实例
  • 原文地址:https://www.cnblogs.com/Swallowtail/p/6183053.html
Copyright © 2011-2022 走看看