消灭病毒gamedemo

 

DestoryVirus

一、AudioSourceManager 

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

public class AudioSourceManager : MonoBehaviour
{
    public  static AudioSourceManager Instance { get; private set; }
    public SoundPlayer soundPlayer;

    // Start is called before the first frame update
    void Start()
    {
        Instance = this;
        PoolManager.Instance.InitPool(soundPlayer,20);
    }

   public void playSound(AudioClip audioClip,float pitchMin=1,float pitchMax=1)
    {
        PoolManager.Instance.GetInstance<SoundPlayer>(soundPlayer).PlayClip(audioClip,pitchMin,pitchMax);
    }
}

二、BloodCell 

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

public class BloodCell : Enemy
{
    public int addValue;//加血
    public AudioClip audioClip;

    protected override void OnCollisionEnter(Collision collision)
    {
        base.OnCollisionEnter(collision);
        if (collision.transform.tag=="Player")
        {
            AudioSourceManager.Instance.playSound(audioClip);
            playerTrans.GetComponent<DoctorController>().TakeDamage(-addValue);
            gameObject.SetActive(false);
        }
    }

    public override void TakeDamage(float damageValue)
    {
        base.TakeDamage(damageValue);
        if (currentHealth<=0)
        {
            AudioSourceManager.Instance.playSound(audioClip);
            playerTrans.GetComponent<DoctorController>().TakeDamage(-addValue);
        }
    }
}

三、Boss 

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

public class Boss : Enemy
{
    protected Animator animator;
    protected bool isWaking;
    protected bool isDead;//是否死亡
    public Light pointLight;
    private bool isAngryState;
    public bool hasSkill;//是否有技能
    public AnimationClip attackAnimationClip;
    public float attackSpeed;
    public GameObject keyGo;
    public float takeDamageTime;
    private float takeDamageTimer;
    public AudioClip deadClip;

   // public Transform targetTrans;

    protected override void Start()
    {
        base.Start();
        animator = GetComponentInChildren<Animator>();
        animator.SetFloat("Born", -0.5f);
        currentState = ENEMYSTATE.IDLE;
        //float result= Vector3.Dot(transform.forward, targetTrans.position - transform.position);
        //if (result>0)
        //{
        //    Debug.Log("在前方");
        //}
        //else
        //{
        //    Debug.Log("在后方");
        //}
        //float result = Vector3.Cross(transform.forward, targetTrans.position).y;

        //float result = Vector3.Dot(transform.right, targetTrans.position);
        //if (result<0)
        //{
        //    Debug.Log("在左方");
        //}
        //else
        //{
        //    Debug.Log("在右方");
        //}

        currentMoveSpeed = moveSpeed;       
        if (attackAnimationClip!=null)
        {
            animator.SetFloat("AttackSpeed",attackSpeed);
            actRestTime = attackAnimationClip.length / attackSpeed;
        }
        else
        {
            animator.SetFloat("AttackSpeed", 1);
        }
        takeDamageTimer = takeDamageTime;
    }

    protected override void Update()
    {
        if (isDead)
        {
            transform.Translate(-Vector3.up * Time.deltaTime * moveSpeed);
            pointLight.intensity -= Time.deltaTime*2;
            if (transform.position.y<=-10)
            {
                Destroy(gameObject);
            }
            return;
        }
        takeDamageTimer -= Time.deltaTime;
        base.Update();
    }
    protected override void EnemyAct()
    {
        if (isWaking||isDead)
        {
            return;
        }
        base.EnemyAct();
        switch (currentState)
        {
            case ENEMYSTATE.PATROL:
                break;
            case ENEMYSTATE.CHASE:
               //animator.ResetTrigger("Hit");
                animator.ResetTrigger("Attack");
                if (hasSkill)
                {
                    animator.ResetTrigger("UseSkill");
                }
                animator.SetBool("Moving", true);
                if (isAngryState)
                {
                    animator.SetFloat("MoveSpeed", 1);
                    currentMoveSpeed=moveSpeed*3;
                }
                break;
            case ENEMYSTATE.ATTACK:
                animator.SetBool("Moving", false);
                animator.ResetTrigger("Hit");
                if (isAngryState&&hasSkill)
                {
                    animator.SetTrigger("UseSkill");
                }
                else
                {
                    animator.SetTrigger("Attack");
                }
                break;
            case ENEMYSTATE.RETURN:
                animator.SetBool("Moving", true);
                animator.ResetTrigger("Hit");
                break;
            case ENEMYSTATE.IDLE:
                animator.SetBool("Moving", false);
                break;
            case ENEMYSTATE.WARN:
              //  animator.ResetTrigger("Hit");
                break;
            case ENEMYSTATE.USESKILL:
                break;
            default:
                break;
        }
    }
    /// <summary>
    /// 苏醒
    /// </summary>
    protected void Warn()
    {
        if (isWaking)
        {
            return;
        }
        float wakeValue = animator.GetFloat("Born");
        if (wakeValue<0)//还没苏醒过
        {
            animator.SetFloat("Born",1);
            isWaking = true;
            Invoke("FinishWaking",9);
            animator.Play("Born", 0, 0);
        }
        else
        {
            animator.SetTrigger("Roar");
            transform.LookAt(new Vector3(playerTrans.position.x, transform.position.y
                , playerTrans.position.z));

        }
    }
    /// <summary>
    /// 完成苏醒
    /// </summary>
    private void FinishWaking()
    {
        animator.ResetTrigger("Hit");
        isWaking = false;
    }
    protected override void CheckDistance()
    {

        if (currentState == ENEMYSTATE.RETURN||isWaking||isDead)
        {
            return;
        }
        float distance = Vector3.Distance(playerTrans.position, transform.position);
        if (distance<1.5*chaseRange&&currentState!=ENEMYSTATE.WARN&&
            currentState!=ENEMYSTATE.ATTACK&&
            currentState!=ENEMYSTATE.CHASE)
        {
            Warn();
            currentState = ENEMYSTATE.WARN;
        }
        if (distance <= attackRange && enemyFunction.canAttack)
        {
            currentState = ENEMYSTATE.ATTACK;
        }
        else if (distance <= chaseRange && enemyFunction.canChase)
        {
            currentState = ENEMYSTATE.CHASE;
        }
        else if (distance >= safeRange && enemyFunction.canReturn)
        {
            if (currentState == ENEMYSTATE.CHASE&&enemyFunction.canChase)
            {
                currentState = ENEMYSTATE.RETURN;
            }
        }

    }

    protected override void ReturnToInitPos()
    {
        if (!CanMove())
        {
            return;
        }
        currentHealth = initHealth;
        if (Vector3.Distance(transform.position,initPos)<=2)
        {
            currentState = ENEMYSTATE.IDLE;
            isAngryState = false;
            transform.eulerAngles = new Vector3(0, 180, 0);
            currentMoveSpeed = moveSpeed;
            chaseRange = initChaseRange;
            safeRange = initSafeRange;
            return;
        }
        transform.Translate(transform.forward * Time.deltaTime * currentMoveSpeed,Space.World);
        transform.LookAt(new Vector3(initPos.x,transform.position.y,initPos.z));
    }

    public void TakeDamage(float damageValue,Vector3 hitPos)
    {
        if (isWaking||isDead)
        {
            return;
        }
        currentHealth -= damageValue;
        base.RecoverAttackRangeValue();
        if (currentState==ENEMYSTATE.IDLE||currentState==ENEMYSTATE.WARN)
        {
            chaseRange = initChaseRange * 2;
            safeRange = initSafeRange * 1.5f;
        }
        if (currentHealth<=initHealth/3&&!isAngryState)
        {
            isAngryState = true;
        }
        if (takeDamageTimer<=0)
        {
            if (soundPlayer != null)
            {
                soundPlayer.PlayRandomSound();
            }
            else
            {
                AudioSourceManager.Instance.playSound(hurtClip);
            }
            animator.SetTrigger("Hit");
            animator.SetFloat("HitY", 0);
            animator.SetFloat("HitX", 0);
            float y = Vector3.Dot(transform.forward, hitPos - transform.position);
            float x = Vector3.Dot(transform.right, hitPos);
            Debug.Log("x:" + x);
            Debug.Log("y:" + y);
            if (ForwardBehindOrLeftRight(hitPos))
            {
                if (y > 0)
                {
                    Debug.Log("在前方");
                    animator.SetFloat("HitY", 1);
                }
                else
                {
                    Debug.Log("在后方");
                    animator.SetFloat("HitY", -1);
                }
            }
            else
            {
                if (x > 0)
                {
                    Debug.Log("在右方");
                    animator.SetFloat("HitX", 1);
                }
                else
                {
                    Debug.Log("在左方");
                    animator.SetFloat("HitX", -1);
                }
            }
            takeDamageTimer = takeDamageTime;
        }
       
        if (currentHealth>0)
        {
            return;
        }
        AudioSourceManager.Instance.playSound(deadClip);
        animator.SetTrigger("Die");
        isDead = true;
        keyGo.SetActive(true);
        keyGo.transform.position = transform.position+new Vector3(0,2,0);
        rigid.isKinematic = true;
        rigid.constraints = RigidbodyConstraints.FreezeAll;
    }
    /// <summary>
    /// 判断前后或者左右影响度(true前后优先级更高,false左右优先级更高)
    /// </summary>
    /// <param name="targetPos"></param>
    /// <returns></returns>
    private bool ForwardBehindOrLeftRight(Vector3 targetPos)
    {
        float ZDistance =Mathf.Abs(transform.position.z - targetPos.z);
        float XDistance = Mathf.Abs(transform.position.x - targetPos.x);
        if (ZDistance>=XDistance)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    protected override void Attack()
    {
        if (Time.time-lastActTime<attackRange)
        {
            return;
        }
        lastActTime = Time.time;
        transform.LookAt(new Vector3(playerTrans.position.x, playerTrans.position.y,playerTrans.position.z));
    }

    protected bool CanMove()
    {
        return animator.GetCurrentAnimatorStateInfo(0).shortNameHash != Animator.StringToHash("Attack") &&
        animator.GetCurrentAnimatorStateInfo(0).shortNameHash != Animator.StringToHash("Hit") &&
        animator.GetCurrentAnimatorStateInfo(0).shortNameHash != Animator.StringToHash("Boar")&&
        animator.GetCurrentAnimatorStateInfo(0).shortNameHash != Animator.StringToHash("UseSkill");
    }

    protected override void Chase()
    {
        if (!CanMove())
        {
            return;
        }
        transform.LookAt(new Vector3(playerTrans.position.x, playerTrans.position.y, playerTrans.position.z));
        transform.Translate(transform.forward * Time.deltaTime * currentMoveSpeed, Space.World);
    }
}

四、BossBehavior

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

public class BossBehavior : MonoBehaviour
{
    public GameObject bossWeaponViewGo;//Boss武器的显示
    private Transform playerTrans;
    public GameObject skillWeapon;//Boss技能的武器 (具体与玩家交互的各种技能游戏物体)
    public Transform attackTrans;//攻击位置
    public AudioClip skillClip;

    // Start is called before the first frame update
    void Start()
    {
        playerTrans = GameObject.FindGameObjectWithTag("Player").transform;
        if (skillWeapon!=null)
        {
            PoolManager.Instance.InitPool(skillWeapon, 10);
        }
    }

    private void ShowWeapon()
    {
        bossWeaponViewGo.SetActive(true);
    }
    private void HideWeapon()
    {
        bossWeaponViewGo.SetActive(false);
    }
    /// <summary>
    /// 隐藏
    /// </summary>
    private void CreatSkillBall()
    {
        bossWeaponViewGo.SetActive(false);
      GameObject go= PoolManager.Instance.GetInstance<GameObject>(skillWeapon);
        go.SetActive(true);
        go.transform.SetParent(null);
        go.transform.position = attackTrans.position;
        go.transform.LookAt(playerTrans.position);
        transform.parent.LookAt(playerTrans.position);
        AudioSourceManager.Instance.playSound(skillClip);

    }
}

五、BossWeapon

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

public class BossWeapon : MonoBehaviour
{
    public int damageValue=10;//伤害值
    private DoctorController doctorController;
    public float moveSpeed = 5;
    //public Vector3 targetPos;
    private float destoryTime=10;//销毁计时器
    private float timeVal;
    public ParticleSystem destoryEffect; //特效引用
    public bool canMove;//是否可以移动
    private bool canTakeDamage;//开关
    private float damageTimeVal;
    public float initDamageTime = 2;
    public bool isSmoke;//烟雾

    // Start is called before the first frame update
    void Start()
    {
        doctorController =GameObject.FindGameObjectWithTag("Player").GetComponent<DoctorController>();
        if (destoryEffect!=null)
        {
            PoolManager.Instance.InitPool(destoryEffect, 10);
        }
        damageTimeVal = initDamageTime;
       // transform.LookAt(targetPos);

    }

    // Update is called once per frame
    void Update()
    {
        //技能型武器
        if (damageTimeVal<=0)
        {
            canTakeDamage = true;
            damageTimeVal = initDamageTime;
        }
        else
        {
            damageTimeVal -= Time.deltaTime;
        }
        //近战武器
        if (canMove)
        {
            return;
        }
        //远程武器
        transform.Translate(transform.forward * moveSpeed * Time.deltaTime, Space.World);
        if (timeVal>=destoryTime)
        {
            gameObject.SetActive(false);//隐藏
            gameObject.transform.SetParent(PoolManager.Instance.transform);
            timeVal = 0;
        }
        else
        {
            timeVal += Time.deltaTime;
        }
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.tag=="Player")
        {
            doctorController.TakeDamage(damageValue);
            if (destoryEffect!=null)
            {
             ParticleSystem particleSystem= PoolManager.Instance.GetInstance<ParticleSystem>(destoryEffect);
                particleSystem.gameObject.SetActive(true);
                particleSystem.transform.position = transform.position;
                particleSystem.time = 0;
                particleSystem.Play();
            } 
            if (canMove)
            {
                gameObject.transform.SetParent(PoolManager.Instance.transform);
                timeVal = 0;
            }
            if (isSmoke)
            {
                if (canTakeDamage)
                {
                    doctorController.TakeDamage(damageValue);
                    canTakeDamage = false;
                    damageTimeVal = initDamageTime;
                }
            }
            else
            {
                doctorController.TakeDamage(damageValue);
                gameObject.SetActive(false);//隐藏
            }
        }
    }

    private void OnTriggerStay(Collider other)
    {
        if (other.tag == "Player")
        {
            if (canTakeDamage)
            {
                doctorController.TakeDamage(damageValue);
                canTakeDamage = false;
                damageTimeVal = initDamageTime;
            }
        }
       
    }

    private void OnTriggerExit(Collider other)
    {
        if (other.tag=="Player")
        {
            canTakeDamage = true;
            damageTimeVal = initDamageTime;
        }     
    }
}

 六、CameraShaker

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

public class CameraShaker : MonoBehaviour
{
    private Vector3 initPosition;
    private float remainingShakeTime;
    private float shakeStrength;

    // Start is called before the first frame update
    void Start()
    {
        initPosition = transform.localPosition;
    }

    // Update is called once per frame
    void Update()
    {
        if (remainingShakeTime>0)
        {
            remainingShakeTime -= Time.deltaTime;
            if (remainingShakeTime<=0)
            {
                transform.localPosition = initPosition;
            }
            else
            {
                Vector3 randomDir = Random.insideUnitSphere;
                transform.localPosition = initPosition + shakeStrength*randomDir;
            }
        }
    }

    public void SetShakeValue(float shakeTime,float strength)
    {
        remainingShakeTime = shakeTime;
        shakeStrength = strength;
    }
}

七、DoctorController

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

public class DoctorController : MonoBehaviour
{
    private CharacterController characterController;
    public float moveSpeed;
    public float mouseSensitivity;//角度值
    private float angleY;
    private float angleX;
    private Transform cameraTrans;
    public float runningSpeed;
    private bool isGrounded;
    public float jumpSpeed;
    private CollisionFlags collisionFlags;
    public int currentWeaponID;
    private Dictionary<int,Weapon> weaponsDict;
    private Transform weaponPlaceTrans;
    private Dictionary<int, int> ammoInventory;//玩家的装备库(背包,当前玩家剩余某个武器以及其剩余的子弹数量)
    public int currentHP;//当前HP
    public int initHP;//初始HP
    public float decreaseSpeed;
    public float actualSpeed;
    public CameraShaker cameraShaker;
    public bool dead;
    public Transform deadPositionTrans;
    public AudioClip jumoClip;
    public AudioClip landClip;
    private bool canPlayLandClip;
    public AudioClip deadClip;
    public AudioClip hurtClip;
    public Weapon[] weapons;
    public GameObject gameOverPanel;

    // Start is called before the first frame update
    void Start()
    {
        characterController= GetComponent<CharacterController>();
        moveSpeed = 5;
        mouseSensitivity = 2.4f;
        angleY = transform.eulerAngles.y;
        cameraTrans = Camera.main.transform;
        angleX = cameraTrans.eulerAngles.x;
        //Cursor.visible = false;
        //Cursor.lockState = CursorLockMode.Locked;
        runningSpeed = 10;
        jumpSpeed = 0;
        isGrounded = true;
        currentWeaponID = -1;
        weaponPlaceTrans = cameraTrans.Find("WeaponPlace");
        //weapons = new List<Weapon>()
        //{
        //        weaponPlaceTrans.GetChild(0).GetComponent<Weapon>(),
        //        weaponPlaceTrans.GetChild(1).GetComponent<Weapon>(),
        //        weaponPlaceTrans.GetChild(2).GetComponent<Weapon>(),
        //};
        weaponsDict = new Dictionary<int, Weapon>();
        ammoInventory = new Dictionary<int, int>();
        currentHP = initHP;
        UIManager.Instance.ShowOrHideWeaponUIView(false);
        for (int i = 0; i < weapons.Length; i++)
        {
            weapons[i].gameObject.SetActive(false);
            weapons[i].PickUp(this);
        }
    }

    // Update is called once per frame
    void Update()
    {
        if (dead)
        {
            return;
        }
        Move();
        TurnAndLook();
        Jump();
        ChangeCurrentWeapon();
    }
    /// <summary>
    /// 移动
    /// </summary>
    private void Move()
    {
      
            actualSpeed = Input.GetButton("Run") ? runningSpeed - decreaseSpeed : moveSpeed - decreaseSpeed;
            Vector3 move = Vector3.zero;
            float h = Input.GetAxis("Horizontal");
            float v = Input.GetAxis("Vertical");
            move = new Vector3(h, 0, v);
            move.Normalize();
            move = move * actualSpeed * Time.deltaTime;
            move = transform.TransformDirection(move);
            collisionFlags = characterController.Move(move);
            if (h < -0.1f && v <= 0.1f)
            {
                actualSpeed = 0;
            }
       
    }
    /// <summary>
    /// 转向和上下看
    /// </summary>
    private void TurnAndLook()
    {
        if (GameManager.Instance.isGameing == true)
        {
            float turnAngle = Input.GetAxis("Mouse X") * mouseSensitivity;
            angleY = angleY + turnAngle;
            transform.eulerAngles = new Vector3(transform.eulerAngles.x, angleY, transform.eulerAngles.z);
            float lookAngle = -Input.GetAxis("Mouse Y") * mouseSensitivity;
            angleX = Mathf.Clamp(angleX + lookAngle, -90f, 90f);
            cameraTrans.eulerAngles = new Vector3(angleX, cameraTrans.eulerAngles.y, cameraTrans.eulerAngles.z);
        }
    }
    /// <summary>
    /// 跳跃方法
    /// </summary>
    private void Jump()
    {
        if (Input.GetButton("Jump"))
        {
            isGrounded = false;
            jumpSpeed = 5;
            AudioSourceManager.Instance.playSound(jumoClip,0.8f,1.1f);
            canPlayLandClip = true;
        }
        if (!isGrounded)//跳起来了,不在地面上
        {
         jumpSpeed  = jumpSpeed - 10 * Time.deltaTime;
         Vector3 jump = new Vector3(0, jumpSpeed * Time.deltaTime, 0);
         collisionFlags= characterController.Move(jump);
            if (collisionFlags==CollisionFlags.Below)
            {
                jumpSpeed = 0;
                isGrounded = true;
            }
        }
        if (isGrounded&&collisionFlags==CollisionFlags.None)
        {
            if (canPlayLandClip)
            {
                canPlayLandClip = false;
                AudioSourceManager.Instance.playSound(landClip, 0.8f, 1.1f);
            }
            isGrounded = false;
        }
    }
    /// <summary>
    /// 具体切换武器
    /// </summary>
    /// <param name="id"></param>
    private void ChangeWeapon(int id)
    {
        if (weaponsDict.Count==0)
        {
            return;
        }
        处理索引的上下边界
        //if (id>= weaponsDict.Count)
        //{
        //    id = 0;
        //}
        //else if (id<=-1)
        //{
        //    id = weaponsDict.Count - 1;
        //}
       
        if (id>weaponsDict.Keys.Max())
        {
            id = weaponsDict.Keys.Min();
        }
        else if (id<weaponsDict.Keys.Min())
        {
            id = weaponsDict.Keys.Max();
        }
        if (id==currentWeaponID)//只有一种武器时不切换,否则会出现颠簸颤抖的情况
        {
            return;
        }
        while (!weaponsDict.ContainsKey(id))
        {
            if (id>currentHP)
            {
                id++;
            }
            else
            {
                id--;
            }
        }
        //隐藏上一把武器
        if (currentWeaponID!=-1)//排除第一次没有武器的情况
        {
            weaponsDict[currentWeaponID].PutAway();
        }
        //显示当前武器
        weaponsDict[id].Selected();
        currentWeaponID = id;
    }
    /// <summary>
    /// 切换当前武器
    /// </summary>
    public void ChangeCurrentWeapon(bool aut0Change=false)
    {
        if (aut0Change)
        {
            //切换到最新拿到的一把
            //ChangeWeapon(weaponsDict.Count-1);
            ChangeWeapon(weaponsDict.Keys.Last());
        }
        else
        {
            if (Input.GetAxis("Mouse ScrollWheel") < 0)
            {
                ChangeWeapon(currentWeaponID + 1);
            }
            else if (Input.GetAxis("Mouse ScrollWheel") > 0)
            {
                ChangeWeapon(currentWeaponID - 1);
            }
            for (int i = 0; i < 10; i++)
            {
                if (Input.GetKeyDown(KeyCode.Alpha0 + i))
                {
                    int num = 0;
                    if (i == 0)
                    {
                        num = 10;
                    }
                    else
                    {
                        num = i - 1;
                    }
                    if (weaponsDict.ContainsKey(num))
                    {
                        ChangeWeapon(num);
                    }
                }
            }
        }
        
    }
    /// <summary>
    /// 拾取武器
    /// </summary>
    /// <param name="weaponName"></param>
    public void PickUpWeapon(int weaponID)
    {
        if (weaponsDict.ContainsKey(weaponID))
        {
            //补充弹药
            Weapon weapon = weaponsDict[weaponID];
            ammoInventory[weapon.GetID()] = weapon.GetInitAmount();
            weapon.clipContent = weapon.clipSize;
            if (currentWeaponID==weaponID)
            {
                UIManager.Instance.UpdateBulletNum(weapon.clipSize, weapon.GetInitAmount());
            }
            //if (!weapon.HasBullet())
            //{
            //    weapon.Reload();
            //}
        }
        else//当前这种名称的武器列表里没有
        {
            //GameObject weaponGo= Instantiate(Resources.Load<GameObject>("Prefabs/Weapons/"+weaponID.ToString()));
            // weaponGo.transform.SetParent(weaponPlaceTrans);
            // weaponGo.transform.localPosition = Vector3.zero;
            // weaponGo.transform.localRotation = Quaternion.identity;
            // weaponGo.gameObject.SetActive(false);
            // Weapon weapon = weaponGo.GetComponent<Weapon>();
            //weapon.PickUp(this);
            weapons[weaponID].clipContent = weapons[weaponID].clipSize;
            weaponsDict.Add(weaponID,weapons[weaponID]);
            ammoInventory.Add(weaponID, weapons[weaponID].GetInitAmount());
            ChangeWeapon(weaponID);
        }
    }
    /// <summary>
    /// 获取某一种武器在武器库中子弹的剩余数量
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public int GetAmmoAmount(int id)
    {
        int value = 0;
        ammoInventory.TryGetValue(id, out value);
        return value;
    }
    /// <summary>
    /// 更新当前武器库中某一种武器装备剩余子弹的数量
    /// </summary>
    /// <param name="id"></param>
    /// <param name="value"></param>
    public void UpdateAmmoAmount(int id,int value)
    {
        if (ammoInventory.ContainsKey(id))
        {
            ammoInventory[id] += value;
        }
    }
    /// <summary>
    /// 受伤害
    /// </summary>
    /// <param name="value"></param>
    public void TakeDamage(int value)
    {
        if (dead)
        {
            return;
        }        
        if (value<0)
        {
            if (currentHP<initHP)
            {
                currentHP -= value;
                if (currentHP>=initHP)
                {
                    currentHP = initHP;
                }
            }         
        }
        else
        {
            currentHP -= value;
        }
        if (currentHP<=0)
        {
            dead = true;
            gameOverPanel.SetActive(true);
            cameraTrans.localPosition = deadPositionTrans.localPosition;
            cameraTrans.eulerAngles = deadPositionTrans.eulerAngles;
            weaponPlaceTrans.gameObject.SetActive(false);
            currentHP = 0;
            UIManager.Instance.ShowDeadUI();
            AudioSourceManager.Instance.playSound(deadClip);
        }
        else
        {
            if (value>0)
            {
                AudioSourceManager.Instance.playSound(hurtClip);
                UIManager.Instance.ShowTakeDamageView();
                cameraShaker.SetShakeValue(0.2f, 0.5f);
            }
        }
        UIManager.Instance.UpdateHPValue(currentHP);
    
    }
}

八、Door

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

public class Door : MonoBehaviour
{
    public GameObject keyGo;
    private bool unLocked;//是否打开
    public float moveSpeed;
    //public SoundPlayer soundPlayer;
    public AudioClip openDoorClip;
    public AudioClip cantOpenClip;
    public AudioClip doorClip;
  
    private void OnTriggerEnter(Collider other)
    {
        if (other.transform.tag == "Player")
        {
            if (!unLocked)
            {
                if (keyGo == null)
                {
                    unLocked = true;
                    AudioSourceManager.Instance.playSound(openDoorClip);
                    AudioSourceManager.Instance.playSound(doorClip);
                }
                else
                {
                    AudioSourceManager.Instance.playSound(cantOpenClip);
                }
            }
        }
    }
    private void Update()
    {
        if (unLocked)
        {
            //soundPlayer.PlaySound(true);
            transform.Translate(-Vector3.up * Time.deltaTime * moveSpeed * 0.3f);
            if (transform.position.y <= -1.4)
            {
                Destroy(gameObject);
            }
        }
    }
  
}

九、Enemy

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

public class Enemy : MonoBehaviour
{
    public float initHealth = 10;
    public float currentHealth;//生命值S
    public ParticleSystem destoryEffect;
    public ENEMYSTATE currentState;//敌人状态
    public float moveSpeed;
    protected float lastActTime;
    public float actRestTime;//行为转换的CD,攻击时长
    private Quaternion targetRotation;
    protected Vector3 initPos;
    public EnemyFunction enemyFunction;
    protected Transform playerTrans;
    public float attackRange;//攻击距离
    public float chaseRange;//追逐距离
    public float safeRange;//安全距离
    protected Rigidbody rigid;
    protected float currentMoveSpeed;//目前移动速度
    protected float initChaseRange;//初始追赶范围
    protected float initSafeRange;
    protected float initAttackRange;
    public GameObject smokeColliderGo;
    public SoundPlayer soundPlayer;
    public AudioClip hurtClip;
    public AudioClip attackClip;
    private float canTurnTimer;

    // Start is called before the first frame update
    protected virtual void Start()
    {
        if (destoryEffect)
        {
            PoolManager.Instance.InitPool(destoryEffect, 4);
        }
        currentHealth = initHealth;
        currentState = ENEMYSTATE.PATROL;
        initPos = transform.position;
         playerTrans = GameObject.FindGameObjectWithTag("Player").transform;
      //  playerTrans = GameObject.Find("Doctor").transform;
        rigid = GetComponent<Rigidbody>();
        initSafeRange = safeRange;
        initChaseRange = chaseRange;
        initAttackRange = attackRange;
        currentMoveSpeed = moveSpeed;
        canTurnTimer = Time.time;
    }

    // Update is called once per frame
   protected virtual void Update()
    {
        EnemyAct();
        CheckDistance();
    }
    /// <summary>
    /// 受伤
    /// </summary>
    /// <param name="damageValue">伤害值</param>
    public virtual void TakeDamage(float damageValue)
    {
        currentHealth -= damageValue;      
        RecoverAttackRangeValue();
        if (soundPlayer!=null)
        {
            soundPlayer.PlayRandomSound();
        }
        else
        {
            AudioSourceManager.Instance.playSound(hurtClip);
        }
        if (currentHealth>0)
        {
            return;
        }
        if (destoryEffect)
        {
            ParticleSystem ps = PoolManager.Instance.GetInstance<ParticleSystem>(destoryEffect);
            ps.time = 0;
            ps.Play();
            ps.transform.position = transform.position+new Vector3(0,0.5f,0);
        }
        gameObject.SetActive(false);
    }
    /// <summary>
    /// 敌人动作
    /// </summary>
    protected virtual void EnemyAct()
    {
        switch (currentState)
        {
            case ENEMYSTATE.PATROL:
                Move();
                if (Time.time-lastActTime>actRestTime)
                {
                    lastActTime = Time.time;
                    targetRotation = Quaternion.Euler(GetRandomEuler());
                }
                break;
            case ENEMYSTATE.CHASE:
                Chase();
                break;
            case ENEMYSTATE.ATTACK:
                Attack();
                break;
            case ENEMYSTATE.RETURN:
                break;
            default:
                break;
        }
    }

    private void Move()
    {
        transform.Translate(transform.forward*Time.deltaTime*currentMoveSpeed,Space.World);
        transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation,0.01f);
    }

    protected virtual void OnCollisionEnter(Collision collision)
    {
        if (currentState==ENEMYSTATE.PATROL&&collision.gameObject.layer!=11
            &&Time.time-canTurnTimer>5)
        {
            canTurnTimer = Time.time;
            targetRotation = Quaternion.LookRotation(-transform.forward,transform.up);
            lastActTime = Time.time;
        }
        else if (currentState==ENEMYSTATE.CHASE||currentState==ENEMYSTATE.RETURN||currentState==ENEMYSTATE.ATTACK)
        {
            rigid.isKinematic = true;
            Invoke("CloseIsKinematicState",1);
        }
    }

    private void CloseIsKinematicState()
    {
        rigid.isKinematic = false;
    }
    protected virtual void ReturnToInitPos()
    {
        transform.Translate(transform.forward * Time.deltaTime * currentMoveSpeed, Space.World);
        transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, 0.1f);
        if (Vector3.Distance(transform.position,initPos)<=1)
        {
            currentState = ENEMYSTATE.PATROL;
        }
    }
    /// <summary>
    /// 检测与某一个对象的距离并转换敌人的状态
    /// </summary>
    protected virtual void CheckDistance()
    {
        if (currentState==ENEMYSTATE.RETURN)
        {
            return;
        }
        float distance = Vector3.Distance(playerTrans.position, transform.position);
        if (distance <= attackRange&&enemyFunction.canAttack)
        {
            currentState = ENEMYSTATE.ATTACK;
        }
        else if (distance <= chaseRange&&enemyFunction.canChase)
        {
            currentState = ENEMYSTATE.CHASE;
        }
        else if (distance>=safeRange&&enemyFunction.canReturn)
        {
            if (currentState==ENEMYSTATE.PATROL&&Vector3.Distance(transform.position, initPos) >= 8)
            {
                currentState = ENEMYSTATE.RETURN;
                targetRotation = Quaternion.LookRotation(initPos - transform.position, transform.up);
            }
            else if (currentState==ENEMYSTATE.CHASE)
            {
                currentState = ENEMYSTATE.RETURN;
                targetRotation = Quaternion.LookRotation(initPos - transform.position, transform.up);
            }
        }
    }

    private Vector3 GetRandomEuler()
    {
        float x = 0, y = 0, z = 0;
        if (enemyFunction.canRotateX)
        {
            x = Random.Range(1, 5) * 90;
        }
        if (enemyFunction.canRotateY)
        {
            y = Random.Range(1, 5) * 90;
        }
        if (enemyFunction.canRotateZ)
        {
            z = Random.Range(1, 5) * 90;
        }
        return new Vector3(x, y, z);
    }
    /// <summary>
    /// 追逐方法
    /// </summary>
    protected virtual void Chase()
    {
        transform.LookAt(playerTrans);
        transform.Translate(transform.forward * Time.deltaTime * currentMoveSpeed, Space.World);
    }
    /// <summary>
    /// 攻击方法
    /// </summary>
    protected virtual void Attack()
    {
        Debug.Log(gameObject.name + "正在攻击!");
    }
    /// <summary>
    /// 设置烟雾距离
    /// </summary>
    public void SetRange(float value)
    {
        attackRange = chaseRange = value;
        currentState = ENEMYSTATE.IDLE;
    }
    /// <summary>
    /// 恢复
    /// </summary>
    public void RecoverAttackRangeValue()
    {
        attackRange = initAttackRange;
        chaseRange = initChaseRange;
        if (enemyFunction.canPatrol)
        {
            currentState = ENEMYSTATE.PATROL;
        }
    }
    /// <summary>
    /// 用于烟雾弹检测
    /// </summary>
    /// <param name="state"></param>
    public void SetSmokeCollierState(bool state)
    {
        smokeColliderGo.SetActive(state);
      
    }
}

public enum ENEMYSTATE
{
    PATROL,//巡逻
    CHASE,//追逐
    ATTACK,
    RETURN,
    //BOSS
    IDLE,
    WARN,//警戒状态(播放动画,看向玩家)
   // WAKE,//出生状态,觉醒状态(第一次遇到玩家)
    USESKILL//使用技能
}
[System.Serializable]
public struct EnemyFunction
{
    public bool canPatrol;
    public bool canChase;
    public bool canAttack;
    public bool canReturn;
    public bool canRotateX;
    public bool canRotateY;
    public bool canRotateZ;
}

十、GameManager

using System.Collections;
using System.Collections.Generic;
using UnityEditor.Timeline;
using UnityEngine;
using UnityEngine.SceneManagement;
using static UnityEditor.FilePathAttribute;

public class GameManager : MonoBehaviour
{
    public static GameManager Instance { get; private set; }

    public bool isGameing = false;
    private void Awake()
    {
        
        Instance = this;
        Cursor.visible = true;
        Cursor.lockState = CursorLockMode.None;
    }
    // Start is called before the first frame update
    void Start()
    {
        
       Time.timeScale = 0f;

    }

    // Update is called once per frame
    void Update()
    {
        
    }

    public void StartGameBtn()
    {
        Cursor.visible = false;
        Cursor.lockState = CursorLockMode.Locked;
        Time.timeScale = 1.0f;
        isGameing = true;

    }


    public void ReStartBtn()
    {
        SceneManager.LoadScene(0);

    }
    public void ExitGameBtn()
    {
        UnityEditor.EditorApplication.isPlaying = false;
        Application.Quit();
    }
    public void ReTime() 
    {
        
    }

    
}

十一、GameSuccessTiger

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

public class GameSuccessTiger : MonoBehaviour
{
    public GameObject gameScuessPanel;
    public void OnTriggerEnter(Collider other)
    {
        Cursor.visible = true;
        Cursor.lockState = CursorLockMode.None;
        gameScuessPanel.SetActive(true);
        GameManager.Instance.isGameing = false;
    }
}

十二、GermSlime

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

public class GermSlime : Enemy
{
    public int damageValue;
    protected override void Attack()
    {
        if (Time.time-lastActTime<actRestTime)
        {
            return;
        }
        transform.LookAt(playerTrans);
        lastActTime = Time.time;
        playerTrans.GetComponent<DoctorController>().TakeDamage(damageValue);
    }
}

十三、GermSpike

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

public class GermSpike : Enemy
{

    public GameObject explosionEffect;//爆炸特效
    public int damageValue;//伤害值

    // Start is called before the first frame update
    protected override void Start()
    {
        base.Start();
        PoolManager.Instance.InitPool(explosionEffect,1);
    }

    // Update is called once per frame
    protected override void Attack()
    {
        base.Attack();
        if (Time.time - lastActTime < actRestTime)
        {
            return;
        }
        transform.LookAt(playerTrans);
        lastActTime = Time.time;
        playerTrans.GetComponent<DoctorController>().TakeDamage(damageValue);
        GameObject effect = PoolManager.Instance.GetInstance<GameObject>(explosionEffect);
        effect.transform.position = transform.position;
        effect.transform.localScale = Vector3.one * 3;
        effect.SetActive(true);
    }
}

十四、Key

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

public class Key : MonoBehaviour
{
    public float rotateSpeed;
    public AudioClip pickupClip;
    //public Door door;

    // Start is called before the first frame update
    void Start()
    {
        rotateSpeed = 50;
    }

    // Update is called once per frame
    void Update()
    {
        transform.eulerAngles += new Vector3(0, rotateSpeed * Time.deltaTime, 0);
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.tag=="Player")
        {
            // door.OpenDoor();
            AudioSourceManager.Instance.playSound(pickupClip);
            Destroy(gameObject);
        }
    }

}

十五、PickUpItem

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

public class PickUpItem : MonoBehaviour
{
    public float rotateSpeed;
    public int itemID=-1;
    public AudioClip pickupClip;

    // Start is called before the first frame update
    void Start()
    {
        rotateSpeed = 50;
    }

    // Update is called once per frame
    void Update()
    {
        transform.eulerAngles += new Vector3(0, rotateSpeed * Time.deltaTime, 0);
    }
    private void OnTriggerEnter(Collider other)
    {
        if (other.name== "Doctor")
        {
            DoctorController doctorController = other.GetComponent<DoctorController>();
            doctorController.PickUpWeapon(itemID);
            //doctorController.ChangeCurrentWeapon(true);
            AudioSourceManager.Instance.playSound(pickupClip);
            Destroy(gameObject);
        }
    }
}

十六、PoolManager

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

public class PoolManager : MonoBehaviour
{
    public static PoolManager Instance { get; private set; }
    //通过传入类型找到对应的池子
    private Dictionary<Object, Queue<Object>> poolsDict;

    private void Awake()
    {
        Instance = this;
        poolsDict = new Dictionary<Object, Queue<Object>>();
    }
    /// <summary>
    /// 初始化某一个对象池
    /// </summary>
    /// <param name="prefab">指定预制体的类型</param>
    /// <param name="size">当前对应类型的对象池的长度</param>
   public void InitPool(Object prefab,int size)
    {
        if (poolsDict.ContainsKey(prefab))
        {
            return;
        }
        Queue<Object> queue = new Queue<Object>();
        for (int i = 0; i < size; i++)
        {
         Object go=Instantiate(prefab);
            CreatGameObjectAndSetActive(go,false);
            queue.Enqueue(go);
        }
        poolsDict[prefab] = queue;
    }
    private void CreatGameObjectAndSetActive(Object obj,bool active)
    {
        GameObject itemGo = null;
        if (obj is Component)
        {
            Component component = obj as Component;
            itemGo = component.gameObject;
        }
        else
        {
           itemGo= obj as GameObject;
        }
        itemGo.transform.SetParent(transform);
        itemGo.SetActive(active);
    }

    public T GetInstance<T>(Object prefab)where T:Object
    {
        Queue<Object> queue;
        if (poolsDict.TryGetValue(prefab,out queue ))
        {
            Object obj;
            if (queue.Count>0)
            {
              obj= queue.Dequeue();
            }
            else
            {
                obj = Instantiate(prefab);
            }
            CreatGameObjectAndSetActive(obj, true);
            queue.Enqueue(obj);
            return obj as T;
        }

        Debug.LogError("还没有当前的资源池被实例化");
        return null;
    }
}

十七、Projectile

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

public class Projectile : MonoBehaviour
{
    private Rigidbody rigid;
    public ParticleSystem explosionEffect;
    public float destoryTime;
    private float destoryTimer;
    public bool destoryOnHit;
    public float explosionRadius;//爆炸半径
    private Collider[] sphereCastPool;//当前检测到的爆炸范围内的敌人
    public float damageValue;//伤害值
    public ParticleSystem bulletTrailEffect;
    public ParticleSystem bulletSizeParticle;//如果子弹是粒子且需要变换大小
    public AudioClip hitWallClip;
    public AudioClip explosionClip;

    // Start is called before the first frame update
    void Awake()
    {
        rigid = GetComponent<Rigidbody>();
        destoryTime = 3;
        PoolManager.Instance.InitPool(explosionEffect, 4);
        sphereCastPool = new Collider[10];
        if (bulletTrailEffect!=null)
        {
            bulletTrailEffect.time = 0;
            bulletTrailEffect.Play();
        }
       
    }

    // Update is called once per frame
    void Update()
    {
        destoryTimer += Time.deltaTime;
        if (destoryTimer>destoryTime)
        {
            if (destoryOnHit)
            {
                DestoryProjectile();
            }
            else
            {
                DestoryExplosionProjectile();
            }
        }
    }
    /// <summary>
    /// 子弹发射
    /// </summary>
    /// <param name="laucher">发射器</param>
    /// <param name="direction">发射方向</param>
    /// <param name="force">发射力的大小</param>
    public void Launch(Weapon laucher,Vector3 direction,float force)
    {
        transform.position = laucher.GetShootPoint().position;
        transform.forward = laucher.GetShootPoint().forward;
        rigid.AddForce(direction * force);
    }

    private void DestoryExplosionProjectile()
    {
        if (explosionEffect!=null)
        {
            ParticleSystem effect = PoolManager.Instance.GetInstance<ParticleSystem>(explosionEffect);
            effect.transform.position = transform.position;
            effect.gameObject.SetActive(true);
            effect.time = 0;
            effect.Play();
        }     
        gameObject.SetActive(false);
        rigid.velocity = Vector3.zero;
        rigid.angularVelocity = Vector3.zero;
        gameObject.transform.rotation = Quaternion.identity;
        destoryTimer = 0;
        if (damageValue>0)
        {
            int count = Physics.OverlapSphereNonAlloc(transform.position, explosionRadius, sphereCastPool, 1 << 9);
            for (int i = 0; i < count; i++)
            {
                sphereCastPool[i].GetComponent<Enemy>().TakeDamage(damageValue);
            }
            int bossCount = Physics.OverlapSphereNonAlloc(transform.position, explosionRadius, sphereCastPool, 1 << 10);
            if (bossCount > 0)
            {
                sphereCastPool[0].GetComponentInParent<Boss>().TakeDamage(damageValue, transform.position);
            }
        }   
        AudioSourceManager.Instance.playSound(explosionClip);
    }

    private void DestoryProjectile(GameObject enemyGo=null)
    {
        if (explosionEffect != null)
        {
            ParticleSystem effect = PoolManager.Instance.GetInstance<ParticleSystem>(explosionEffect);
            effect.transform.position = transform.position;
            effect.gameObject.SetActive(true);
            effect.time = 0;
            effect.Play();
        }
        gameObject.SetActive(false);
        rigid.velocity = Vector3.zero;
        rigid.angularVelocity = Vector3.zero;
        gameObject.transform.rotation = Quaternion.identity;
        destoryTimer = 0;
        TakeDamage(enemyGo);
    }
    private void OnCollisionEnter(Collision collision)
    {
        if (destoryOnHit)
        {
            DestoryProjectile(collision.gameObject);
        }
    }
    private void OnTriggerEnter(Collider other)
    {
        if (destoryOnHit)
        {
            DestoryProjectile(other.gameObject);          
        }
    }
    /// <summary>
    /// 设置聚能枪子弹大小
    /// </summary>
    public void SetBulletSize(float size)
    {
        bulletSizeParticle.startSize = size;
    }
    /// <summary>
    /// 设置伤害值
    /// </summary>
    public void SetBulletDamageValue(float value)
    {
        damageValue = value;
    }
    /// <summary>
    /// 伤害
    /// </summary>
    private void TakeDamage(GameObject enemyGo=null)
    {
        if (enemyGo!=null)
        {
            if (enemyGo.layer==9)
            {
                enemyGo.GetComponent<Enemy>().TakeDamage(damageValue);
            }
            else if (enemyGo.layer==10)
            {
                enemyGo.GetComponentInParent<Boss>().TakeDamage(damageValue, transform.position);
            }
            else
            {
                AudioSourceManager.Instance.playSound(hitWallClip);
            }
        }       
    }
}

十八、Smoke

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

public class Smoke : MonoBehaviour
{
    public ParticleSystem particleSystem;
    private List<GameObject> enemyList = new List<GameObject>();
    private void OnEnable()
    {
        particleSystem.time = 0;
        particleSystem.Play();
        Invoke("HideSelf",25);
    }

    private void HideSelf()
    {
        particleSystem.Stop();
        Invoke("HideGameObject", 7);
    }

    private void HideGameObject()
    {
        gameObject.SetActive(false);
    }
    private void OnDisable()
    {
        CancelInvoke();
        for (int i = 0; i < enemyList.Count; i++)
        {
            if (enemyList[i])
            {
                Enemy enemy = enemyList[i].GetComponentInParent<Enemy>();
                if (enemy)
                {
                    enemy.RecoverAttackRangeValue();
                    enemy.SetSmokeCollierState(true);
                }
            }     
        }
        enemyList.Clear();
        StopAllCoroutines();
    }
    private void OnTriggerExit(Collider other)
    {
        if (other.tag == "Enemy")
        {
            if (enemyList.Contains(other.gameObject))
            {
                enemyList.Remove(other.gameObject);
            }
           
        }
    }
    private void OnTriggerEnter(Collider other)
    {
        if (other.tag=="Enemy")
        {
            if (!enemyList.Contains(other.gameObject))
            {
                enemyList.Add(other.gameObject);
            }
            StartCoroutine(OutSmoke(other));
            Debug.Log("进入烟雾");
        }
    }
    
    IEnumerator OutSmoke(Collider other)
    {
        //进入迷失状态
        yield return new WaitForSeconds(2);
        Enemy enemy = other.GetComponentInParent<Enemy>();
        if (enemy.enabled)
        {
            enemy.SetRange(2);
            enemy.SetSmokeCollierState(false);
        }      
       
        //解除迷失状态
        yield return new WaitForSeconds(15);
        if (enemy.enabled)
        {
            enemy.SetSmokeCollierState(true);
        }
    
    }
}

十九、SoundPlayer

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

public class SoundPlayer : MonoBehaviour
{
    public AudioSource audioSource;
    public AudioClip clipSource;
    public AudioClip[] audioClips;
    public float currentPitchMin=1;
    public float currentPitchMax=1;

    private void Awake()
    {
        audioSource = GetComponent<AudioSource>();
        if (clipSource)
        {
            audioSource.clip = clipSource;
        }
    }
    /// <summary>
    /// 外部调用
    /// </summary>
    /// <param name="audioClip"></param>
    /// <param name="pitchMin"></param>
    /// <param name="pitchMax"></param>
    public void PlayClip(AudioClip audioClip,float pitchMin=1,float pitchMax=1)
    {
        audioSource.pitch = Random.Range(pitchMin,pitchMax);
        audioSource.PlayOneShot(audioClip);
    }

    public void PlayRandomSound()
    {
        audioSource.pitch = Random.Range(currentPitchMin, currentPitchMax);
        audioSource.PlayOneShot(audioClips[Random.Range(0,audioClips.Length)]);
    }

    public void PlaySound(bool loop=false)
    {
        if (audioSource.clip!=null)
        {
            if (!audioSource.isPlaying)
            {
                audioSource.loop = loop;
                audioSource.Play();
            }
        }      
    }
}

二十、TelesopicView    倍镜

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

public class TelesopicView : MonoBehaviour
{
    public float zoomLevel = 2;//倍镜缩放等级
    public float OpenSpeed=100;
    public float CloseSpeed=80;
    private float initFOV;
    private bool openTelesopicView;//倍镜开关

    // Start is called before the first frame update
    void Start()
    {
        initFOV = Camera.main.fieldOfView;
    }

    // Update is called once per frame
    void Update()
    {
        if (openTelesopicView)
        {
            OpenTelesopicView();
        }
        else
        {
            CloseTelesopicView();
        }
    }
    /// <summary>
    /// 打开倍镜方法
    /// </summary>
    private void OpenTelesopicView()
    {
        if (Camera.main.fieldOfView!=initFOV/zoomLevel)
        {
            if (Mathf.Abs(Camera.main.fieldOfView - initFOV / zoomLevel)<5)
            {
                Camera.main.fieldOfView = initFOV / zoomLevel;
            }
            else
            {
                Camera.main.fieldOfView -= Time.deltaTime * OpenSpeed;
            }
        }
        UIManager.Instance.OpenOrCloseTelesopicView();
    }
    /// <summary>
    /// 关闭倍镜方法
    /// </summary>
    private void CloseTelesopicView()
    {
        if (Camera.main.fieldOfView != initFOV)
        {
            if (Mathf.Abs(Camera.main.fieldOfView - initFOV ) < 5)
            {
                Camera.main.fieldOfView = initFOV;
            }
            else
            {
                Camera.main.fieldOfView += Time.deltaTime * CloseSpeed;
            }
        }
        UIManager.Instance.OpenOrCloseTelesopicView(false);
    }

    public void OpenTheTelesopicView(bool open=true)
    {
        openTelesopicView = open;
    }

}

二十一、UIManager

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;

public class UIManager : MonoBehaviour
{
    public GameObject imgSnipeRifle;
    public GameObject imgTakeDamage;
    public GameObject weaponUIViewGo;
    public GameObject[] weaponUIGos;
    public Text textHealth;
    public Text textBulletNum;
    public GameObject imgDaeaGo;
    public AudioClip lossClip;
    public static UIManager Instance { get; private set; }

    private void Awake()
    {
        Instance = this;
    }

    public void OpenOrCloseTelesopicView(bool open=true)
    {
        imgSnipeRifle.SetActive(open);
    }
    public void ShowTakeDamageView()
    {
        imgTakeDamage.SetActive(true);
        CancelInvoke();
        Invoke("HideTakeDamageView", 2);
    }

    public void HideTakeDamageView()
    {
        imgTakeDamage.SetActive(false);
    }

    public void ShowOrHideWeaponUIView(bool show)
    {
        weaponUIViewGo.SetActive(show);
    }

    public void ChangeWeaponUIView(int id)
    {
        for (int i = 0; i < weaponUIGos.Length; i++)
        {
            weaponUIGos[i].SetActive(false);
        }
        weaponUIGos[id].SetActive(true);
    }
    /// <summary>
    /// 血量更新
    /// </summary>
    public void UpdateHPValue(int value)
    {
        textHealth.text = value.ToString();
    }
    /// <summary>
    /// 子弹更新
    /// </summary>
    public void UpdateBulletNum(int curretNum,int totalNum)
    {
        textBulletNum.text = curretNum.ToString() + "/" + totalNum.ToString();
    }
    public void ShowDeadUI()
    {
        imgDaeaGo.SetActive(true);
        Invoke("PlayLossMusic", 2);
    }

    private void PlayLossMusic()
    {
        AudioSourceManager.Instance.playSound(lossClip);
        Invoke("LoadCurrentScence", 3);
    }

    public void LoadCurrentScence()
    {
        SceneManager.LoadScene(0);
    }
}

二十二、Weapon

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

public class Weapon : MonoBehaviour
{
    private DoctorController owner;
    public int itemID = -1;
    public int initAmount = -1;
    private Animator animator;
    public LineRenderer rayTrailPrefab;
    public Transform shootPoint;
    public WEAPONTYPE weaponType;
    private List<ActiveTrail> activeTrails;
    public Projectile projectilePrefab;
    public float projectilelauchForce=200;
    public AdvancedWeaponSettings advancedWeaponSettings;
    public int clipSize = 4;//弹夹里子弹数量(当前可以往里放的最大数量)
    public int clipContent;//当前弹夹里剩余子弹数
    private WEAPONSTATE currentWeaponState;//当前武器状态
    private int fireNameHash;
    private int reloadNameHash;
    public float reloadTime = 2.0f;//更换弹夹的速度
    public float fireRete = 0.5f;//攻击频率(CD)
    private float shotTimer = -1;//CD计时器
    public AnimationClip fireAnimatortionClip;
    public AnimationClip reloadAnimationClip;
    public float damageValue = 1;//初始伤害值
    public ParticleSystem raycastHitEffectPrefab;//粒子特效
    public WEAPONMOOD weaponMode;
    public bool hasTelesopicView;//有无倍镜功能
    private TelesopicView telesopicView;
    private float bulletSize;
    public ParticleSystem bulletViewEffect;
    private float currentDamageValue;//当前伤害值
    public float decreaseSpeed;//减少量
    public AudioClip shootClip;
    public AudioClip hitWallClip;
    public AudioClip reloadClip;//换弹夹
    public AudioClip cockClip;
    private float chargeTimer;
    public AudioSource chargeAudio;
    private float stopChargeTimer;//计时器
    public AudioSource cockAudio;

    private void Awake()
    {
        animator = GetComponentInChildren<Animator>();
    }
    // Start is called before the first frame update
    void Start()
    {
     
        if (rayTrailPrefab!=null)
        {
            //如果当前武器可以发射激光,那么需要先生成几个备用的预制体
            PoolManager.Instance.InitPool(rayTrailPrefab, 8);
        }
        activeTrails = new List<ActiveTrail>();
        if (projectilePrefab!=null)
        {
            PoolManager.Instance.InitPool(projectilePrefab, 8);
        }
        currentWeaponState = WEAPONSTATE.IDLE;
        fireNameHash=Animator.StringToHash("fire");
        reloadNameHash = Animator.StringToHash("reload");
        clipContent = clipSize;
        if (raycastHitEffectPrefab!=null)
        {
            PoolManager.Instance.InitPool(raycastHitEffectPrefab, 8);
        }
        if (hasTelesopicView)
        {
            telesopicView = Camera.main.transform.GetComponent<TelesopicView>();
        }
        chargeTimer = 0;
        chargeAudio = GetComponent<AudioSource>();
    }

    // Update is called once per frame
    void Update()
    {
        UpdateController();
        FireInput();
        if (Input.GetMouseButtonDown(0))
        {
            Fire();
        }
        if (Input.GetButtonDown("Reload"))
        {
            Reload();
        }
        if (shotTimer>0)
        {
            shotTimer -= Time.deltaTime;
        }
        UpdateTrailState();
    }
    /// <summary>
    /// 获取子弹数量
    /// </summary>
    /// <returns></returns>
    public int GetInitAmount()
    {
        return initAmount;
    }
    /// <summary>
    /// 获取武器的ID
    /// </summary>
    /// <returns></returns>
    public int GetID()
    {
        return itemID;
    }
    /// <summary>
    /// 选择当前武器
    /// </summary>
    public void Selected()
    {
        gameObject.SetActive(owner.GetAmmoAmount(itemID)!=0||clipContent!=0);
        animator.SetTrigger("selected");
        if (fireAnimatortionClip!=null)
        {
            animator.SetFloat("fireSpeed",fireAnimatortionClip.length/fireRete);
        }
        if (reloadAnimationClip!=null)
        {
            animator.SetFloat("reloadSpeed", reloadAnimationClip.length / reloadTime);
        }
        currentWeaponState = WEAPONSTATE.IDLE;
        owner.decreaseSpeed = decreaseSpeed;
        UIManager.Instance.ShowOrHideWeaponUIView(true);
        UIManager.Instance.ChangeWeaponUIView(itemID);
        UIManager.Instance.UpdateBulletNum(clipContent, owner.GetAmmoAmount(itemID));
        if (reloadClip != null)
        {
            AudioSourceManager.Instance.playSound(reloadClip);
        }
       
    }
    /// <summary>
    /// 收起武器
    /// </summary>
    public void PutAway()
    {
        gameObject.SetActive(false);
        if (weaponMode == WEAPONMOOD.ACCUMULATION)
        {
            InitAccumulationWeapon();
        }
        if (weaponType == WEAPONTYPE.RAYCAST)
        {
            for (int i = 0; i < activeTrails.Count; i++)
            {
                activeTrails[i].renderer.gameObject.SetActive(false);
            }
            activeTrails.Clear();
        }
    }
      
    /// <summary>
    /// 捡起武器,制定当前武器拥有者即DoctorController的引用
    /// </summary>
    public void PickUp(DoctorController doctorController)
    {
        owner = doctorController;
    }
    /// <summary>
    /// 攻击方法
    /// </summary>
    public void Fire()
    {
        if (currentWeaponState!=WEAPONSTATE.IDLE||shotTimer>0)
        {
            return;
        }
        if (clipContent==0)
        {
            if (cockAudio.isPlaying)
            {
                cockAudio.Play();
            }
            return;
        }
        AudioSourceManager.Instance.playSound(shootClip);
        shotTimer = fireRete;
        clipContent -= 1;
        UIManager.Instance.UpdateBulletNum(clipContent, owner.GetAmmoAmount(itemID));
        animator.SetTrigger("fire");
        owner.cameraShaker.SetShakeValue(advancedWeaponSettings.shakeTime, 0.05f * advancedWeaponSettings.shakeStrength);
        currentWeaponState = WEAPONSTATE.FIRING;
        if (weaponType==WEAPONTYPE.RAYCAST)
        {
            RayCastShot();
        }
        else
        {
            ProjectileShot();
        }
    }
    /// <summary>
    /// 发射激光类型枪的攻击
    /// </summary>
    private void RayCastShot()
    {
        //发散比例(当前单位长度)
        float spreadRatio = advancedWeaponSettings.spreadAngle / Camera.main.fieldOfView;
        Vector2 spread = spreadRatio*Random.insideUnitCircle;
        Ray ray= Camera.main.ViewportPointToRay(Vector3.one*0.5f+(Vector3)spread);
        RaycastHit hit;
        if (Physics.Raycast(ray, out hit, 1000, ~(1 << 8), QueryTriggerInteraction.Ignore))
        {
            ParticleSystem ps= PoolManager.Instance.GetInstance<ParticleSystem>(raycastHitEffectPrefab);
            ps.transform.position = hit.point;
            ps.transform.forward= hit.normal;
            ps.gameObject.SetActive(true);
            ps.Play();
            if (hit.collider.gameObject.layer==9)
            {
                Enemy enemy = hit.collider.GetComponent<Enemy>();
                enemy.TakeDamage(damageValue);
            }
            else if (hit.collider.gameObject.layer==10)
            {
                Boss enemy = hit.collider.GetComponentInParent<Boss>();
                enemy.TakeDamage(damageValue,transform.position);
            }
            else
            {
                AudioSourceManager.Instance.playSound(hitWallClip);
            }
            if (rayTrailPrefab!=null)
            {
              LineRenderer lineRenderer= PoolManager.Instance.GetInstance<LineRenderer>(rayTrailPrefab);
                lineRenderer.gameObject.SetActive(true);
                Vector3[] trailPos = new Vector3[] { shootPoint.position,hit.point};
                lineRenderer.SetPositions(trailPos);
                activeTrails.Add(
                    new ActiveTrail()
                    {
                        renderer=lineRenderer,
                        direction=(trailPos[1]-trailPos[0]).normalized,
                        remainningTime=0.3f 
                    }
                    );
            }
        }
       
    }
    /// <summary>
    /// 更新激光拖尾效果(模拟位移)
    /// </summary>
    private void UpdateTrailState()
    {
        Vector3[] pos = new Vector3[2];
        for (int i = 0; i < activeTrails.Count; i++)
        {
            ActiveTrail activeTrail = activeTrails[i];
            activeTrail.renderer.GetPositions(pos);       
            activeTrail.remainningTime -= Time.deltaTime;
            pos[0] += activeTrail.direction * 50 * Time.deltaTime;
           // pos[1] += activeTrail.direction * 50 * Time.deltaTime;
            activeTrail.renderer.SetPositions(pos);
            if (activeTrail.remainningTime<=0||Vector3.Distance(pos[0],pos[1])<=0.5F)
            {
                activeTrail.renderer.gameObject.SetActive(false);
                activeTrails.RemoveAt(i);
                i--;
            }
        }
        
    }
    /// <summary>
    /// 发射子弹类型枪的攻击方式(包括投掷类武器比如手雷)
    /// </summary>
    private void ProjectileShot()
    {
     Projectile projectile=PoolManager.Instance.GetInstance<Projectile>(projectilePrefab);
        projectile.gameObject.SetActive(true);
        if (weaponMode==WEAPONMOOD.ACCUMULATION)
        {
            projectile.SetBulletDamageValue(currentDamageValue);
            projectile.SetBulletSize(bulletSize);
        }
        Vector2 angleDir = Random.insideUnitCircle*Mathf.Sin(advancedWeaponSettings.spreadAngle*Mathf.Deg2Rad) ;
        Vector3 dir = shootPoint.forward + (Vector3)angleDir;
        dir.Normalize();
        projectile.Launch(this, dir, projectilelauchForce);
    }
    public Transform GetShootPoint()
    {
        return shootPoint;
    }
    /// <summary>
    /// 换弹夹
    /// </summary>
    public void Reload()
    {
        if (clipContent==clipSize||currentWeaponState!=WEAPONSTATE.IDLE)//弹夹子弹数已满
        {
            return;
        }
      int remainningBullet= owner.GetAmmoAmount(itemID);
        if (remainningBullet==0)
        {
            if (itemID==2||itemID==6)
            {
                PutAway();
            }
            return;
        }
      int chargeInClip= Mathf.Min(remainningBullet,clipSize-clipContent);
        clipContent += chargeInClip;
        currentWeaponState = WEAPONSTATE.RELOADING;
        owner.UpdateAmmoAmount(itemID, -chargeInClip);
        UIManager.Instance.UpdateBulletNum(clipContent, owner.GetAmmoAmount(itemID));
        animator.SetTrigger("reload");
        if (weaponMode==WEAPONMOOD.ACCUMULATION)
        {
            bulletViewEffect.gameObject.SetActive(false);
            bulletViewEffect.startSize = 0;
        }
        if (reloadClip!=null)
        {
            AudioSourceManager.Instance.playSound(reloadClip);
        }      
    }
    /// <summary>
    /// 更新动画控制器以及武器的状态
    /// </summary>
    private void UpdateController()
    {
        animator.SetFloat("moveSpeed", owner.actualSpeed / 5);
       AnimatorStateInfo animatorStateInfo= animator.GetCurrentAnimatorStateInfo(0);
        WEAPONSTATE newState;
        if (animatorStateInfo.shortNameHash==fireNameHash)
        {
            newState = WEAPONSTATE.FIRING;
        }
        else if (animatorStateInfo.shortNameHash==reloadNameHash)
        {
            newState = WEAPONSTATE.RELOADING;
        }
        else
        {
            newState = WEAPONSTATE.IDLE;
        }
        if (newState!=currentWeaponState)
        {
           WEAPONSTATE lastState= currentWeaponState;
            currentWeaponState = newState;
            if (lastState==WEAPONSTATE.FIRING&&clipContent==0)
            {
                Reload();
            }
        }
    }

    public bool HasBullet()
    {
        return clipContent > 0;
    }

    private void FireInput()
    {
        switch (weaponMode)
        {
            case WEAPONMOOD.NORMAL:
                if (Input.GetMouseButtonDown(0))
                {
                    Fire();
                }
                if (hasTelesopicView)
                {
                    if (Input.GetMouseButton(1))
                    {
                        telesopicView.OpenTheTelesopicView();
                    }
                    else
                    {
                        telesopicView.OpenTheTelesopicView(false);
                    }
                    if (currentWeaponState == WEAPONSTATE.RELOADING)
                    {
                        telesopicView.OpenTheTelesopicView(false);
                    }
                }              
                break;
            case WEAPONMOOD.AUTO:
                if (Input.GetMouseButton(0))
                {
                    Fire();
                }
                break;
            case WEAPONMOOD.ACCUMULATION:
                if (Input.GetMouseButtonUp(0))//释放
                {
                    Fire();
                    InitAccumulationWeapon();
                }
                else if (Input.GetMouseButtonDown(0)&&clipContent>0&&currentWeaponState!=WEAPONSTATE.RELOADING)//聚能  
                {
                    AccumulateEnergy();
                }               
                break;
            default:
                break;
        }
    }

    private void InitAccumulationWeapon()
    {
        chargeTimer = 0;
        chargeAudio.Stop();
        bulletViewEffect.gameObject.SetActive(false);
        bulletViewEffect.startSize = 0;
    }
    /// <summary>
    /// 聚能方法
    /// </summary>
    public void AccumulateEnergy()
    {
        bulletViewEffect.gameObject.SetActive(true);
        if (bulletViewEffect.startSize<=0.3)
        {
            bulletViewEffect.startSize += Time.deltaTime;
        }
        if (currentDamageValue<=5*damageValue)
        {
            currentDamageValue += Time.deltaTime;
        }
        //第一次播放完整聚能音效
        if (chargeTimer<=0)
        {
            chargeTimer = Time.deltaTime;
            chargeAudio.time = 0;
            chargeAudio.Play();
        }
        //后续播放持续循环的部分(即聚能)
        if (Time.deltaTime-chargeTimer>=1.463f)
        {
            if (!chargeAudio.isPlaying)
            {
                //只持续播放某一个时间点到最后的音效
                chargeAudio.time = 0.4f;
                chargeAudio.Play();
                stopChargeTimer = Time.time;
            }
            if (Time.time-stopChargeTimer>=0.5f)
            {
                chargeAudio.Stop();
            }
        }
    }
}
public enum WEAPONTYPE
{
    RAYCAST,
    PROJECTILE
}
/// <summary>
/// 激光信息类
/// </summary>
public class ActiveTrail
{
    public LineRenderer renderer;
    public Vector3 direction;
    public float remainningTime;
}
/// <summary>
/// 武器的额外设置
/// </summary>
[System.Serializable]
public class AdvancedWeaponSettings
{
    public float spreadAngle;//偏移 (发散) 角度(单位不是传统意义上的度数,而是计量单位)
    public float shakeTime;//震动时间
    public float shakeStrength;//震动大小
}

public enum WEAPONSTATE
{
    IDLE,
    FIRING,
    RELOADING
}
/// <summary>
/// 攻击模式
/// </summary>
public enum WEAPONMOOD
{
    NORMAL,
    AUTO,
    ACCUMULATION
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值