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 updatevoid 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&¤tState!=ENEMYSTATE.WARN&¤tState!=ENEMYSTATE.ATTACK&¤tState!=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 updatevoid 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 updatevoid 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 framevoid 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 updatevoid Start(){initPosition = transform.localPosition;}// Update is called once per framevoid 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;//当前HPpublic int initHP;//初始HPpublic 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 updatevoid 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 framevoid 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;//生命值Spublic 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 updateprotected 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 frameprotected 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,//BOSSIDLE,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 updatevoid Start(){Time.timeScale = 0f;}// Update is called once per framevoid 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 updateprotected override void Start(){base.Start();PoolManager.Instance.InitPool(explosionEffect,1);}// Update is called once per frameprotected 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 updatevoid Start(){rotateSpeed = 50;}// Update is called once per framevoid 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 updatevoid Start(){rotateSpeed = 50;}// Update is called once per framevoid 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 updatevoid 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 framevoid 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 updatevoid Start(){initFOV = Camera.main.fieldOfView;}// Update is called once per framevoid 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 updatevoid 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 framevoid 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&¤tWeaponState!=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
}