Complete Physics Platformer Kit 学习-LMLPHP

 using UnityEngine;

 /// <summary>
 /// 摄像机跟随玩家
 /// </summary>
 public class CameraFollow : MonoBehaviour
 {
     /// <summary>
     /// 目标
     /// </summary>
     public Transform target;
     /// <summary>
     /// 和目标之间的偏移
     /// </summary>
     );
     /// <summary>
     /// 是否锁定旋转
     /// </summary>
     public bool lockRotation;
     /// <summary>
     /// 跟随速度
     /// </summary>
     ;
     /// <summary>
     /// 围绕目标旋转的速度
     /// </summary>
     ;
     /// <summary>
     /// 是否可以由鼠标控制旋转(只有在相机没有被固定的情况下)
     /// </summary>
     public bool mouseFreelook;
     /// <summary>
     /// 旋转阻尼
     /// </summary>
     ;
     /// <summary>
     /// 摄像机在水中时的过滤物体
     /// </summary>
     public GameObject waterFilter;
     /// <summary>
     ///
     /// </summary>
     public string[] avoidClippingTags;

     /// <summary>
     /// Camera Target
     /// </summary>
     private Transform followTarget;
     /// <summary>
     /// 暂未用到
     /// </summary>
     private bool camColliding;

     //setup objects
     void Awake()
     {
         //创建跟随物体(Camera Target)
         followTarget = new GameObject().transform;
         followTarget.name = "Camera Target";
         if(waterFilter)
             waterFilter.GetComponent<Renderer>().enabled = false;
         if(!target)
             Debug.LogError("'CameraFollow script' has no target assigned to it", transform);

         //如果用鼠标控制旋转,旋转阻尼为0
         if(mouseFreelook)
             rotateDamping = 0f;
     }

     void Update()
     {
         //没有目标不处理
         if (!target)
             return;
         //平滑跟随
         SmoothFollow ();
         //平滑朝向玩家
         )
             SmoothLookAt();
         //直接朝向玩家
         else
             transform.LookAt(target.position);
     }

     void OnTriggerEnter(Collider other)
     {
         //打开水遮罩
         if (other.tag == "Water" && waterFilter)
             waterFilter.GetComponent<Renderer>().enabled = true;
     }

     void OnTriggerExit(Collider other)
     {
         //关闭水遮罩
         if (other.tag == "Water" && waterFilter)
             waterFilter.GetComponent<Renderer>().enabled = false;
     }

     /// <summary>
     /// 平滑朝向目标
     /// </summary>
     void SmoothLookAt()
     {
         Quaternion rotation = Quaternion.LookRotation (target.position - transform.position);
         transform.rotation = Quaternion.Slerp (transform.rotation, rotation, rotateDamping * Time.deltaTime);
     }

     /// <summary>
     /// 平滑跟随目标
     /// </summary>
     void SmoothFollow()
     {
         followTarget.position = target.position;
         followTarget.Translate(targetOffset, Space.Self);
         if (lockRotation)
             followTarget.rotation = target.rotation;

         //鼠标控制围绕目标旋转
         if(mouseFreelook)
         {
             float axisX = Input.GetAxis ("Mouse X") * inputRotationSpeed * Time.deltaTime;
             followTarget.RotateAround (target.position,Vector3.up, axisX);
             float axisY = Input.GetAxis ("Mouse Y") * inputRotationSpeed * Time.deltaTime;
             followTarget.RotateAround (target.position, transform.right, -axisY);
         }
         //键盘控制围绕目标旋转
         else
         {
             float axis = Input.GetAxis ("CamHorizontal") * inputRotationSpeed * Time.deltaTime;
             followTarget.RotateAround (target.position, Vector3.up, axis);
         }

         //计算相机的下一帧位置
         Vector3 nextFramePosition = Vector3.Lerp(transform.position, followTarget.position, followSpeed * Time.deltaTime);
         Vector3 direction = nextFramePosition - target.position;
         //射线检测这个位置
         RaycastHit hit;
         if(Physics.Raycast (target.position, direction, out hit, direction.magnitude + 0.3f))
         {
             transform.position = nextFramePosition;
             foreach(string tag in avoidClippingTags)
                 //如果这个位置有物体,修改相机位置
                 if(hit.transform.tag == tag)
                     transform.position = hit.point - direction.normalized * 0.3f;
         }
         else
         {
             //直接修改相机位置
             transform.position = nextFramePosition;
         }
     }
 }

CameraFollow

 using UnityEngine;

 /// <summary>
 /// 角色移动
 /// </summary>
 [RequireComponent(typeof(Rigidbody))]
 public class CharacterMotor:MonoBehaviour {
     /// <summary>
     /// 是否冻结z轴的移动
     /// </summary>
     public bool sidescroller;
     /// <summary>
     /// 当前速度
     /// </summary>
     [HideInInspector]
     public Vector3 currentSpeed;
     /// <summary>
     /// 到目标的距离
     /// </summary>
     [HideInInspector]
     public float DistanceToTarget;
     /// <summary>
     /// 刚体
     /// </summary>
     private Rigidbody rigid;

     void Awake() {
         //设置rigidbody
         rigid = GetComponent<Rigidbody>();
         rigid.interpolation = RigidbodyInterpolation.Interpolate;
         if(sidescroller)
             rigid.constraints = RigidbodyConstraints.FreezeRotation | RigidbodyConstraints.FreezePositionZ;
         else
             rigid.constraints = RigidbodyConstraints.FreezeRotation;
         //添加光滑的物理材质
         if(GetComponent<Collider>().material.name == "Default (Instance)") {
             PhysicMaterial pMat = new PhysicMaterial();
             pMat.name = "Frictionless";
             pMat.frictionCombine = PhysicMaterialCombine.Multiply;
             pMat.bounceCombine = PhysicMaterialCombine.Multiply;
             pMat.dynamicFriction = 0f;
             pMat.staticFriction = 0f;
             GetComponent<Collider>().material = pMat;
             Debug.LogWarning("No physics material found for CharacterMotor, a frictionless one has been created and assigned",transform);
         }
     }

     /// <summary>
     /// 移动刚体到指定位置
     /// </summary>
     public bool MoveTo(Vector3 destination,float acceleration,float stopDistance,bool ignoreY) {
         Vector3 relativePos = (destination - transform.position);
         //忽略y轴?
         if(ignoreY)
             relativePos.y = ;

         DistanceToTarget = relativePos.magnitude;
         if(DistanceToTarget <= stopDistance)
             return true;
         else
             rigid.AddForce(relativePos.normalized * acceleration * Time.deltaTime,ForceMode.VelocityChange);
         return false;
     }

     /// <summary>
     /// 旋转刚体朝向当前速度
     /// </summary>
     public void RotateToVelocity(float turnSpeed,bool ignoreY) {
         Vector3 dir;
         if(ignoreY)
             dir = new Vector3(rigid.velocity.x,0f,rigid.velocity.z);
         else
             dir = rigid.velocity;

         if(dir.magnitude > 0.1) {
             Quaternion dirQ = Quaternion.LookRotation(dir);
             Quaternion slerp = Quaternion.Slerp(transform.rotation,dirQ,dir.magnitude * turnSpeed * Time.deltaTime);
             rigid.MoveRotation(slerp);
         }
     }

     /// <summary>
     /// 旋转刚体朝向指定方向
     /// </summary>
     public void RotateToDirection(Vector3 lookDir,float turnSpeed,bool ignoreY) {
         Vector3 characterPos = transform.position;
         //忽略y轴?
         if(ignoreY) {
             characterPos.y = ;
             lookDir.y = ;
         }

         Vector3 newDir = lookDir - characterPos;
         Quaternion dirQ = Quaternion.LookRotation(newDir);
         Quaternion slerp = Quaternion.Slerp(transform.rotation,dirQ,turnSpeed * Time.deltaTime);
         rigid.MoveRotation(slerp);
     }

     /// <summary>
     /// 管理速度
     /// </summary>
     public void ManageSpeed(float deceleration,float maxSpeed,bool ignoreY) {
         currentSpeed = rigid.velocity;
         //忽略y轴
         if(ignoreY)
             currentSpeed.y = ;

         ) {
             rigid.AddForce((currentSpeed * -) * deceleration * Time.deltaTime,ForceMode.VelocityChange);
             if(rigid.velocity.magnitude > maxSpeed)
                 rigid.AddForce((currentSpeed * -) * deceleration * Time.deltaTime,ForceMode.VelocityChange);
         }
     }
 }

CharacterMotor

 using UnityEngine;

 /// <summary>
 /// 检查点
 /// </summary>
 [RequireComponent(typeof(CapsuleCollider))]
 [RequireComponent(typeof(AudioSource))]
 public class Checkpoint : MonoBehaviour
 {
     /// <summary>
     /// 激活颜色
     /// </summary>
     public Color activeColor = Color.green;
     /// <summary>
     /// 激活时的不透明度
     /// </summary>
     public float activeColorOpacity = 0.4f;

     /// <summary>
     /// 生命
     /// </summary>
     private Health health;
     /// <summary>
     /// 默认颜色
     /// </summary>
     private Color defColor;
     /// <summary>
     /// 检查点列表
     /// </summary>
     private GameObject[] checkpoints;
     /// <summary>
     /// 渲染器
     /// </summary>
     private Renderer render;
     /// <summary>
     /// AudioSource
     /// </summary>
     private AudioSource aSource;

     void Awake()
     {
         render = GetComponent<Renderer>();
         aSource = GetComponent<AudioSource>();
         //标签不是Respawn,自动修改标签
         if(tag != "Respawn")
         {
             tag = "Respawn";
             Debug.LogWarning ("'Checkpoint' script attached to object without the 'Respawn' tag, tag has been assigned automatically", transform);
         }
         GetComponent<Collider>().isTrigger = true;
         //设置默认颜色和不透明度
         if(render)
             defColor = render.material.color;
         activeColor.a = activeColorOpacity;
     }

     void Start()
     {
         checkpoints = GameObject.FindGameObjectsWithTag("Respawn");
         health = GameObject.FindGameObjectWithTag("Player").GetComponent<Health>();
         if(!health)
             Debug.LogError("For Checkpoint to work, the Player needs 'Health' script attached", transform);
     }

     void OnTriggerEnter(Collider other)
     {
         //如果碰到玩家
         if(other.transform.tag == "Player" && health)
         {
             health.respawnPos = transform.position;

             if(render.material.color != activeColor)
             {
                 foreach (GameObject checkpoint in checkpoints)
                     checkpoint.GetComponent<Renderer>().material.color = defColor;
                 aSource.Play();
                 render.material.color = activeColor;
             }
         }
     }
 }

Checkpoint

 using UnityEngine;

 /// <summary>
 /// 金币
 /// </summary>
 [RequireComponent(typeof(SphereCollider))]
 public class Coin : MonoBehaviour
 {
     /// <summary>
     /// 被收集时的声音
     /// </summary>
     public AudioClip collectSound;
     /// <summary>
     /// 旋转
     /// </summary>
     , , );
     /// <summary>
     /// 玩家靠近时,增加的旋转
     /// </summary>
     , , );
     /// <summary>
     /// 金币向玩家移动的速度
     /// </summary>
     public float startSpeed = 3f;
     /// <summary>
     /// 金币向玩家移动的加速度
     /// </summary>
     public float speedGain = 0.2f;

     /// <summary>
     /// 是否被搜集
     /// </summary>
     private bool collected;
     /// <summary>
     /// 玩家
     /// </summary>
     private Transform player;
     /// <summary>
     /// 子物体的触发器
     /// </summary>
     private TriggerParent triggerParent;
     /// <summary>
     /// GUI
     /// </summary>
     private GUIManager gui;

     void Awake()
     {
         gui = FindObjectOfType(typeof(GUIManager)) as GUIManager ;
         if(tag != "Coin")
         {
             tag = "Coin";
             Debug.LogWarning ("'Coin' script attached to object not tagged 'Coin', tag added automatically", transform);
         }
         GetComponent<Collider>().isTrigger = true;
         triggerParent = GetComponentInChildren<TriggerParent>();
         //添加bounds子物体
         if(!triggerParent)
         {
             GameObject bounds = new GameObject();
             bounds.name = "Bounds";
             bounds.AddComponent<SphereCollider>();
             bounds.GetComponent<SphereCollider>().radius = 7f;
             bounds.GetComponent<SphereCollider>().isTrigger = true;
             bounds.transform.parent = transform;
             bounds.transform.position = transform.position;
             bounds.AddComponent<TriggerParent>();
             triggerParent = GetComponentInChildren<TriggerParent>();
             triggerParent.tagsToCheck = ];
             triggerParent.tagsToCheck[] = "Player";
             Debug.LogWarning ("No pickup radius 'bounds' trigger attached to coin: " + transform.name + ", one has been added automatically", bounds);
         }
     }

     void Start()
     {
         player = GameObject.FindGameObjectWithTag("Player").transform;
     }

     void Update()
     {

         transform.Rotate (rotation * Time.deltaTime, Space.World);

         if(triggerParent.collided)
             collected = true;

         //增加金币的旋转速度和移动速度,将金币移向玩家
         if (collected)
         {
             startSpeed += speedGain;
             rotation += rotationGain;
             transform.position = Vector3.Lerp (transform.position, player.position, startSpeed * Time.deltaTime);
         }
     }

     void OnTriggerEnter(Collider other)
     {
         if (other.tag == "Player")
             CoinGet();
     }

     /// <summary>
     /// 获取金币
     /// </summary>
     void CoinGet()
     {
         if(collectSound)
             AudioSource.PlayClipAtPoint(collectSound, transform.position);
         if (gui)
             gui.coinsCollected ++;
         Destroy(gameObject);
     }
 }

Coin

 using UnityEngine;

 /// <summary>
 /// 处理伤害
 /// </summary>
 public class DealDamage : MonoBehaviour
 {
     /// <summary>
     /// 受害人的生命
     /// </summary>
     private Health health;

     /// <summary>
     /// 攻击
     /// </summary>
     public void Attack(GameObject victim, int dmg, float pushHeight, float pushForce)
     {
         health = victim.GetComponent<Health>();

         //推物体
         Vector3 pushDir = (victim.transform.position - transform.position);
         pushDir.y = 0f;
         pushDir.y = pushHeight * 0.1f;
         if (victim.GetComponent<Rigidbody>() && !victim.GetComponent<Rigidbody>().isKinematic)
         {
             victim.GetComponent<Rigidbody>().velocity = , , );
             victim.GetComponent<Rigidbody>().AddForce (pushDir.normalized * pushForce, ForceMode.VelocityChange);
             victim.GetComponent<Rigidbody>().AddForce (Vector3.up * pushHeight, ForceMode.VelocityChange);
         }
         //应用伤害
         if(health && !health.flashing)
             health.currentHealth -= dmg;
     }
 }

DealDamage

 using UnityEngine;
 using System.Collections;

 /// <summary>
 /// 摧毁物体
 /// </summary>
 public class DestroyObject : MonoBehaviour
 {
     /// <summary>
     /// 摧毁声音
     /// </summary>
     public AudioClip destroySound;
     /// <summary>
     /// 延迟
     /// </summary>
     public float delay;
     /// <summary>
     /// 是否分离子物体并且不摧毁子物体
     /// </summary>
     public bool destroyChildren;
     /// <summary>
     /// 从父物体中心推开子物体的数量
     /// </summary>
     public float pushChildAmount;

     void Start()
     {
         //获取子物体列表
         Transform[] children = new Transform[transform.childCount];
         ; i < transform.childCount; i++)
             children[i] = transform.GetChild(i);

         //分离子物体
         if (!destroyChildren)
             transform.DetachChildren();

         //给子物体添加一个推力和旋转
         foreach (Transform child in children)
         {
             Rigidbody rigid = child.GetComponent<Rigidbody>();
             )
             {
                 Vector3 pushDir = child.position - transform.position;
                 rigid.AddForce(pushDir * pushChildAmount, ForceMode.Force);
                 rigid.AddTorque(Random.insideUnitSphere, ForceMode.Force);
             }
         }

         //删除父物体
         if(destroySound)
             AudioSource.PlayClipAtPoint(destroySound, transform.position);
         Destroy (gameObject, delay);
     }
 }

DestroyObject

 using UnityEngine;
 using System.Collections;

 /// <summary>
 /// 敌人AI
 /// </summary>
 [RequireComponent(typeof(CharacterMotor))]
 [RequireComponent(typeof(DealDamage))]
 public class EnemyAI : MonoBehaviour
 {
     /// <summary>
     /// 移动加速度
     /// </summary>
     public float acceleration = 35f;
     /// <summary>
     /// 移动减速度
     /// </summary>
     public float deceleration = 8f;
     /// <summary>
     /// 旋转速度
     /// </summary>
     public float rotateSpeed = 0.7f;
     /// <summary>
     /// 速度极限
     /// </summary>
     public float speedLimit = 10f;
     /// <summary>
     /// 玩家跳到敌人头上时应用到玩家身上的力
     /// </summary>
     , , );
     /// <summary>
     /// 玩家跳到敌人头上时的声音
     /// </summary>
     public AudioClip bounceSound;
     /// <summary>
     /// 玩家碰到敌人时受到的推力
     /// </summary>
     public float pushForce = 10f;
     /// <summary>
     /// 玩家碰到敌人时玩家的高度
     /// </summary>
     public float pushHeight = 7f;
     /// <summary>
     /// 敌人对玩家的伤害
     /// </summary>
     ;
     /// <summary>
     /// 是否追逐视野内的目标
     /// </summary>
     public bool chase = true;
     /// <summary>
     /// 追逐时是否忽略y轴
     /// </summary>
     public bool ignoreY = true;
     /// <summary>
     /// 追逐停止的距离
     /// </summary>
     public float chaseStopDistance = 0.7f;
     /// <summary>
     /// 视野范围
     /// </summary>
     public GameObject sightBounds;
     /// <summary>
     /// 攻击范围
     /// </summary>
     public GameObject attackBounds;
     /// <summary>
     /// Animator
     /// </summary>
     public Animator animatorController;
     /// <summary>
     /// 移动到路标点
     /// </summary>
     public MoveToPoints moveToPointsScript;

     /// <summary>
     /// 视野触发器
     /// </summary>
     private TriggerParent sightTrigger;
     /// <summary>
     /// 攻击触发器
     /// </summary>
     private TriggerParent attackTrigger;
     /// <summary>
     ///  玩家移动
     /// </summary>
     private PlayerMove playerMove;
     /// <summary>
     /// 角色移动
     /// </summary>
     private CharacterMotor characterMotor;
     /// <summary>
     /// 处理伤害
     /// </summary>
     private DealDamage dealDamage;

     void Awake()
     {
         characterMotor = GetComponent<CharacterMotor>();
         dealDamage = GetComponent<DealDamage>();
         if(tag != "Enemy")
         {
             tag = "Enemy";
             Debug.LogWarning("'EnemyAI' script attached to object without 'Enemy' tag, it has been assign automatically", transform);
         }

         if(sightBounds)
         {
             sightTrigger = sightBounds.GetComponent<TriggerParent>();
             if(!sightTrigger)
                 Debug.LogError("'TriggerParent' script needs attaching to enemy 'SightBounds'", sightBounds);
         }
         if(!sightBounds)
             Debug.LogWarning("Assign a trigger with 'TriggerParent' script attached, to 'SightBounds' or enemy will not be able to see", transform);

         if(attackBounds)
         {
             attackTrigger = attackBounds.GetComponent<TriggerParent>();
             if(!attackTrigger)
                 Debug.LogError("'TriggerParent' script needs attaching to enemy 'attackBounds'", attackBounds);
         }
         else
             Debug.LogWarning("Assign a trigger with 'TriggerParent' script attached, to 'AttackBounds' or enemy will not be able to attack", transform);
     }

     void Update()
     {
         //追逐
         if (sightTrigger && sightTrigger.colliding && chase && sightTrigger.hitObject != null && sightTrigger.hitObject.activeInHierarchy)
         {
             characterMotor.MoveTo (sightTrigger.hitObject.transform.position, acceleration, chaseStopDistance, ignoreY);

             if(animatorController)
                 animatorController.SetBool("Moving", true);

             if(moveToPointsScript)
                 moveToPointsScript.enabled = false;
         }
         else
         {

             if(animatorController)
                 animatorController.SetBool("Moving", false);

             if(moveToPointsScript)
                 moveToPointsScript.enabled = true;
         }

         //攻击
         if (attackTrigger && attackTrigger.collided)
         {
             dealDamage.Attack(attackTrigger.hitObject, attackDmg, pushHeight, pushForce);

             if(animatorController)
                 animatorController.SetBool("Attacking", true);
         }
         else if(animatorController)
             animatorController.SetBool("Attacking", false);
     }

     void FixedUpdate()
     {
         characterMotor.ManageSpeed(deceleration, speedLimit, ignoreY);
         characterMotor.RotateToVelocity (rotateSpeed, ignoreY);
     }

     /// <summary>
     /// 弹开玩家
     /// </summary>
     public void BouncedOn()
     {
         if(!playerMove)
             playerMove = GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerMove>();
         if (bounceSound)
             AudioSource.PlayClipAtPoint(bounceSound, transform.position);
         if(playerMove)
         {
             Vector3 bounceMultiplier = new Vector3(0f, 1.5f, 0f) * playerMove.onEnemyBounce;
             playerMove.Jump (bounceForce + bounceMultiplier);
         }
         else
             Debug.LogWarning("'Player' tagged object landed on enemy, but without playerMove script attached, is unable to bounce");
     }
 }

EnemyAI

 using UnityEngine;

 /// <summary>
 /// 关卡目标
 /// </summary>
 [RequireComponent(typeof(CapsuleCollider))]
 public class Goal : MonoBehaviour
 {
     /// <summary>
     /// 举起玩家的力
     /// </summary>
     public float lift;
     /// <summary>
     /// 加载下一个关卡的等待时间
     /// </summary>
     public float loadDelay;
     /// <summary>
     /// 下一个场景的索引
     /// </summary>
     public int nextLevelIndex;

     /// <summary>
     /// 计时器
     /// </summary>
     private float counter;

     void Awake()
     {
         GetComponent<Collider>().isTrigger = true;
     }

     void OnTriggerStay(Collider other)
     {
         Rigidbody rigid = other.GetComponent<Rigidbody>();
         if(rigid)
             rigid.AddForce(Vector3.up * lift, ForceMode.Force);

         if (other.tag == "Player")
         {
             counter += Time.deltaTime;
             if(counter > loadDelay)
                 Application.LoadLevel (nextLevelIndex);
         }
     }

     void OnTriggerExit(Collider other)
     {
         if (other.tag == "Player")
             counter = 0f;
     }
 }

Goal

 using UnityEngine;
 using System.Collections;

 /// <summary>
 /// GUI
 /// </summary>
 public class GUIManager : MonoBehaviour
 {
     /// <summary>
     /// GUISkin
     /// </summary>
     public GUISkin guiSkin;
     /// <summary>
     /// 已收集的金币
     /// </summary>
     [HideInInspector]
     public int coinsCollected;
     /// <summary>
     /// 场景中的金币数量
     /// </summary>
     private int coinsInLevel;
     /// <summary>
     /// 生命
     /// </summary>
     private Health health;

     void Start()
     {
         coinsInLevel = GameObject.FindGameObjectsWithTag("Coin").Length;
         health = GameObject.FindGameObjectWithTag("Player").GetComponent<Health>();
     }

     void OnGUI()
     {
         GUI.skin = guiSkin;
         GUILayout.Space(5f);

         if(health)
             GUILayout.Label ("Health: " + health.currentHealth);
         )
             GUILayout.Label ("Cubes: " + coinsCollected + " / " + coinsInLevel);
     }
 }

GUIManager

 using UnityEngine;
 using System.Collections;

 /// <summary>
 /// 障碍
 /// </summary>
 [RequireComponent(typeof(DealDamage))]
 [RequireComponent(typeof(AudioSource))]
 public class Hazard : MonoBehaviour
 {
     /// <summary>
     /// 推开受害者的力
     /// </summary>
     public float pushForce = 25f;
     /// <summary>
     /// 向上推的力
     /// </summary>
     public float pushHeight = 6f;
     /// <summary>
     /// 照成的伤害
     /// </summary>
     ;
     /// <summary>
     /// 是否是触发
     /// </summary>
     public bool triggerEnter;
     /// <summary>
     /// 是否是碰撞
     /// </summary>
     public bool collisionEnter = true;
     /// <summary>
     /// 影响的单位的标签
     /// </summary>
     public string[] effectedTags = {"Player"};
     /// <summary>
     /// 碰撞声音
     /// </summary>
     public AudioClip hitSound;

     /// <summary>
     ///  处理伤害
     /// </summary>
     private DealDamage dealDamage;
     /// <summary>
     /// AudioSource
     /// </summary>
     private AudioSource aSource;

     //setup
     void Awake()
     {
         aSource = GetComponent<AudioSource>();
         aSource.playOnAwake = false;
         dealDamage = GetComponent<DealDamage>();
     }

     void OnCollisionEnter(Collision col)
     {
         //不是碰撞
         if(!collisionEnter)
             return;
         //遍历检查标签
         foreach(string tag in effectedTags)
             //标签相等
             if(col.transform.tag == tag)
             {
                 //处理伤害
                 dealDamage.Attack (col.gameObject, damage, pushHeight, pushForce);
                 //播放声音
                 if (hitSound)
                 {
                     aSource.clip = hitSound;
                     aSource.Play();
                 }
             }
     }

     void OnTriggerEnter(Collider other)
     {
         //不是触发器
         if(!triggerEnter)
             return;
         //遍历标签
         foreach(string tag in effectedTags)
             //标签相等
             if(other.transform.tag == tag)
                 //处理伤害
                 dealDamage.Attack (other.gameObject, damage, pushHeight, pushForce);
     }
 }

Hazard

 using UnityEngine;
 using System.Collections;

 /// <summary>
 /// 生命
 /// </summary>
 [RequireComponent(typeof(AudioSource))]
 public class Health : MonoBehaviour
 {
     /// <summary>
     /// 撞击声音
     /// </summary>
     public AudioClip impactSound;
     /// <summary>
     /// 受到伤害时的声音
     /// </summary>
     public AudioClip hurtSound;
     /// <summary>
     /// 死亡声音
     /// </summary>
     public AudioClip deadSound;
     /// <summary>
     /// 当前生命
     /// </summary>
     ;
     /// <summary>
     /// 是否能受到撞击伤害
     /// </summary>
     public bool takeImpactDmg;
     /// <summary>
     /// 是否只能受到刚体伤害
     /// </summary>
     public bool onlyRigidbodyImpact;
     /// <summary>
     /// 是否可以重生
     /// </summary>
     public bool respawn;
     /// <summary>
     /// 不会受到撞击伤害的标签
     /// </summary>
     public string[] impactFilterTag;
     /// <summary>
     /// 受到伤害时的闪烁延迟
     /// </summary>
     public float hitFlashDelay = 0.1f;
     /// <summary>
     /// 闪烁持续时间
     /// </summary>
     public float flashDuration = 0.9f;
     /// <summary>
     /// 受到伤害时的闪烁颜色
     /// </summary>
     public Color hitFlashColor = Color.red;
     /// <summary>
     /// 闪烁的物体
     /// </summary>
     public Transform flashObject;
     /// <summary>
     ///
     /// </summary>
     public GameObject[] spawnOnDeath;

     /// <summary>
     /// 是否死亡,是否闪烁
     /// </summary>
     [HideInInspector]
     public bool dead, flashing;
     /// <summary>
     /// 重生位置
     /// </summary>
     [HideInInspector]
     public Vector3 respawnPos;

     /// <summary>
     /// 原始颜色
     /// </summary>
     private Color originalColor;
     /// <summary>
     ///
     /// </summary>
     private int defHealth, h, hitForce;
     private bool hitColor = false;
     /// <summary>
     /// 下一个闪烁,停止闪烁时间
     /// </summary>
     private float nextFlash, stopFlashTime;
     /// <summary>
     /// 扔物体
     /// </summary>
     private Throwing throwing;
     /// <summary>
     /// 闪烁渲染器
     /// </summary>
     private Renderer flashRender;
     /// <summary>
     /// AudioSource
     /// </summary>
     private AudioSource aSource;

     void Awake()
     {
         aSource = GetComponent<AudioSource>();
         )
             Debug.LogWarning(transform.name + " has 'currentHealth' set to 0 or less in 'Health' script: it has died upon scene start");
         aSource.playOnAwake = false;
         if(flashObject == null)
             flashObject = transform;
         flashRender = flashObject.GetComponent<Renderer>();
         originalColor = flashRender.material.color;
         defHealth = currentHealth;
         respawnPos = transform.position;
     }

     void Update()
     {
         //受到伤害,闪烁
         if (currentHealth < h)
         {
             flashing = true;
             stopFlashTime = Time.time + flashDuration;
             if (hurtSound)
                 AudioSource.PlayClipAtPoint(hurtSound, transform.position);
         }
         h = currentHealth;

         if (flashing)
         {
             Flash ();
             if (Time.time > stopFlashTime)
             {
                 flashRender.material.color = originalColor;
                 flashing = false;
             }
         }

         dead = (currentHealth <= ) ? true : false;
         if (dead)
             Death();
     }

     /// <summary>
     /// 闪烁
     /// </summary>
     void Flash()
     {
         flashRender.material.color = (hitColor) ? hitFlashColor : originalColor;
         if(Time.time > nextFlash)
         {
             hitColor = !hitColor;
             nextFlash = Time.time + hitFlashDelay;
         }
     }

     /// <summary>
     /// 死亡
     /// </summary>
     void Death()
     {

         if(tag == "Player")
             throwing = GetComponent<Throwing>();
         if(throwing && throwing.heldObj && throwing.heldObj.tag == "Pickup")
             throwing.ThrowPickup();

         if (deadSound)
             AudioSource.PlayClipAtPoint(deadSound, transform.position);
         flashing = false;
         flashObject.GetComponent<Renderer>().material.color = originalColor;
         if(respawn)
         {
             Rigidbody rigid = GetComponent<Rigidbody>();
             if(rigid)
                 rigid.velocity *= ;
             transform.position = respawnPos;
             dead = false;
             currentHealth = defHealth;
         }
         else
             Destroy (gameObject);

         )
             foreach(GameObject obj in spawnOnDeath)
                 Instantiate(obj, transform.position, Quaternion.Euler(Vector3.zero));
     }

     void OnCollisionEnter(Collision col)
     {
         //播放撞击声音
         if(!aSource.isPlaying && impactSound)
         {
             aSource.clip = impactSound;
             aSource.volume = col.relativeVelocity.magnitude/;
             aSource.Play();
         }

         //不会受到撞击伤害,返回
         if (!takeImpactDmg)
             return;
         //找到标签,返回
         foreach(string tag in impactFilterTag)
             if(col.transform.tag == tag)
                 return;
         //只能受到刚体撞击且没有刚体,返回
         if(onlyRigidbodyImpact && !col.rigidbody)
             return;

         //计算受到的伤害
         if(col.rigidbody)
             hitForce = ( * col.rigidbody.mass);
         else
             hitForce = (;
         currentHealth -= hitForce;
         //print (transform.name + " took: " + hitForce + " dmg in collision with " + col.transform.name);
     }
 }

Health

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

 /// <summary>
 /// 移动到指定的点
 /// </summary>
 [RequireComponent(typeof(Rigidbody))]
 public class MoveToPoints:MonoBehaviour {
     /// <summary>
     /// 移动速度
     /// </summary>
     public float speed;
     /// <summary>
     /// 延迟
     /// </summary>
     public float delay;
     /// <summary>
     /// 移动类型
     /// </summary>
     public type movementType;

     /// <summary>
     /// 移动类型
     /// </summary>
     public enum type {
         /// <summary>
         /// 在最后一个路标停止
         /// </summary>
         PlayOnce,
         /// <summary>
         /// 转圈
         /// </summary>
         Loop,
         /// <summary>
         /// 来回
         /// </summary>
         PingPong
     }
     /// <summary>
     /// 当前路标索引
     /// </summary>
     private int currentWp;
     /// <summary>
     /// 到达时间
     /// </summary>
     private float arrivalTime;
     /// <summary>
     /// 是否向前,是否到达
     /// </summary>
     private bool forward = true, arrived = false;
     /// <summary>
     /// 路标列表
     /// </summary>
     private List<Transform> waypoints = new List<Transform>();
     /// <summary>
     /// 角色移动
     /// </summary>
     private CharacterMotor characterMotor;
     /// <summary>
     /// 敌人AI
     /// </summary>
     private EnemyAI enemyAI;
     /// <summary>
     /// 刚体
     /// </summary>
     private Rigidbody rigid;

     void Awake() {
         //标签不是Enemy
         if(transform.tag != "Enemy") {
             //没有刚体,添加刚体
             if(!GetComponent<Rigidbody>())
                 gameObject.AddComponent<Rigidbody>();
             //动力学
             GetComponent<Rigidbody>().isKinematic = true;
             //不使用重力
             GetComponent<Rigidbody>().useGravity = false;
             //修改插值类型
             GetComponent<Rigidbody>().interpolation = RigidbodyInterpolation.Interpolate;
         } else {
             //角色移动
             characterMotor = GetComponent<CharacterMotor>();
             //获取敌人AI
             enemyAI = GetComponent<EnemyAI>();
         }
         //获取刚体
         rigid = GetComponent<Rigidbody>();
         //遍历子物体
         foreach(Transform child in transform)
             //添加路标
             if(child.tag == "Waypoint")
                 waypoints.Add(child);
         //分离路标
         foreach(Transform waypoint in waypoints)
             waypoint.parent = null;

         )
             Debug.LogError("No waypoints found for 'MoveToPoints' script. To add waypoints: add child gameObjects with the tag 'Waypoint'",transform);
     }

     void Update() {
         //路标数量大于0
         ) {
             //没有到达
             if(!arrived) {
                 //与下一个路标的距离小于0.3
                 if(Vector3.Distance(transform.position,waypoints[currentWp].position) < 0.3f) {
                     //设置到达时间
                     arrivalTime = Time.time;
                     //修改到达标志位
                     arrived = true;
                 }
             //到达
             } else {
                 //当前时间大于到达时间加延迟
                 if(Time.time > arrivalTime + delay) {
                     //获取下一个路标
                     GetNextWP();
                     //修改到达标志位
                     arrived = false;
                 }
             }
         }
         //标签是Enemy,路标数量大于0
         ) {
             //没有到达位置
             if(!arrived) {
                 //玩家移动到指定路标
                 characterMotor.MoveTo(waypoints[currentWp].position,enemyAI.acceleration,0.1f,enemyAI.ignoreY);
                 //播放动画
                 if(enemyAI.animatorController)
                     enemyAI.animatorController.SetBool("Moving",true);
             //到达位置
             } else
                 //播放动画
                 if(enemyAI.animatorController)
                     enemyAI.animatorController.SetBool("Moving",false);
         }
     }

     void FixedUpdate() {
         //标签为Enemy
         if(transform.tag != "Enemy") {
             //没有到达且路标数量大于0
             ) {
                 //计算和路标的距离
                 Vector3 direction = waypoints[currentWp].position - transform.position;
                 //刚体移动
                 rigid.MovePosition(transform.position + (direction.normalized * speed * Time.fixedDeltaTime));
             }
         }
     }

     /// <summary>
     /// 获取下一个路标
     /// </summary>
     private void GetNextWP() {
         //一次
         if(movementType == type.PlayOnce) {
             currentWp++;
             if(currentWp == waypoints.Count)
                 enabled = false;
         }
         //循环
         if(movementType == type.Loop)
             currentWp = (currentWp == waypoints.Count - ) ?  : currentWp += ;
         //来回
         if(movementType == type.PingPong) {
             )
                 forward = false;
             )
                 forward = true;
             currentWp = (forward) ? currentWp +=  : currentWp -= ;
         }
     }

     void OnDrawGizmos() {
         Gizmos.color = Color.cyan;
         foreach(Transform child in transform) {
             if(child.tag == "Waypoint")
                 Gizmos.DrawSphere(child.position,.7f);
         }
     }
 }

MoveToPoints

 using UnityEngine;
 using System.Collections;

 /// <summary>
 /// 玩家移动
 /// </summary>
 [RequireComponent(typeof(CharacterMotor))]
 [RequireComponent(typeof(DealDamage))]
 [RequireComponent(typeof(AudioSource))]
 [RequireComponent(typeof(Rigidbody))]
 public class PlayerMove:MonoBehaviour {
     /// <summary>
     /// 是否是卷轴模式
     /// </summary>
     public bool sidescroller;
     /// <summary>
     /// 主相机,FloorChecks游戏物体Transform
     /// </summary>
     public Transform mainCam, floorChecks;
     /// <summary>
     /// Animator
     /// </summary>
     public Animator animator;
     /// <summary>
     /// 跳跃声音
     /// </summary>
     public AudioClip jumpSound;
     /// <summary>
     /// 着陆声音
     /// </summary>
     public AudioClip landSound;

     /// <summary>
     /// 加速度
     /// </summary>
     public float accel = 70f;
     /// <summary>
     /// 空中加速度
     /// </summary>
     public float airAccel = 18f;
     /// <summary>
     /// 减速度
     /// </summary>
     public float decel = 7.6f;
     /// <summary>
     /// 空中减速度
     /// </summary>
     public float airDecel = 1.1f;
     /// <summary>
     /// 旋转速度,空中旋转速度
     /// </summary>
     [Range(0f,5f)]
     public float rotateSpeed = 0.7f, airRotateSpeed = 0.4f;
     /// <summary>
     /// 最高移动速度
     /// </summary>
     ;
     /// <summary>
     /// 最大坡度,最大滑坡速度
     /// </summary>
     , slideAmount = ;
     /// <summary>
     /// 移动平台的摩擦力
     /// </summary>
     public float movingPlatformFriction = 7.7f;

     /// <summary>
     /// 常规跳跃力
     /// </summary>
     ,,);
     /// <summary>
     /// 2连跳力
     /// </summary>
     ,,);
     /// <summary>
     /// 3连跳力
     /// </summary>
     ,,);
     /// <summary>
     /// 两次跳跃间的延迟
     /// </summary>
     public float jumpDelay = 0.1f;
     /// <summary>
     /// 着陆前仍然可以按下跳跃的时间
     /// </summary>
     public float jumpLeniancy = 0.17f;
     [HideInInspector]
     public int onEnemyBounce;
     /// <summary>
     /// 跳跃类型
     /// </summary>
     private int onJump;
     /// <summary>
     /// 是否着陆
     /// </summary>
     private bool grounded;
     /// <summary>
     /// 检查是否着陆的Transform列表(玩家身体的下面9个点)
     /// </summary>
     private Transform[] floorCheckers;
     /// <summary>
     ///
     /// </summary>
     private Quaternion screenMovementSpace;
     /// <summary>
     /// 按下跳跃的时间,着陆后的时间,当前加速度,当前减速度,当前旋转速度,斜率
     /// </summary>
     private float airPressTime, groundedCount, curAccel, curDecel, curRotateSpeed, slope;
     /// <summary>
     /// 方向,移动方向,屏幕向前移动,屏幕向右移动,移动物体的速度
     /// </summary>
     private Vector3 direction, moveDirection, screenMovementForward, screenMovementRight, movingObjSpeed;

     /// <summary>
     /// 角色移动
     /// </summary>
     private CharacterMotor characterMotor;
     /// <summary>
     /// 敌人AI
     /// </summary>
     private EnemyAI enemyAI;
     /// <summary>
     /// 处理伤害
     /// </summary>
     private DealDamage dealDamage;
     /// <summary>
     /// Rigidbody
     /// </summary>
     private Rigidbody rigid;
     /// <summary>
     /// AudioSource
     /// </summary>
     private AudioSource aSource;

     void Awake() {
         //没有检查列表
         if(!floorChecks) {
             //添加
             floorChecks = new GameObject().transform;
             floorChecks.name = "FloorChecks";
             floorChecks.parent = transform;
             floorChecks.position = transform.position;
             //添加单个子物体
             GameObject check = new GameObject();
             check.name = "Check1";
             check.transform.parent = floorChecks;
             check.transform.position = transform.position;
             Debug.LogWarning("No 'floorChecks' assigned to PlayerMove script, so a single floorcheck has been created",floorChecks);
         }
         //标签不是Player
         if(tag != "Player") {
             //标签改为Player
             tag = "Player";
             Debug.LogWarning("PlayerMove script assigned to object without the tag 'Player', tag has been assigned automatically",transform);
         }

         //获取主摄像机
         mainCam = GameObject.FindGameObjectWithTag("MainCamera").transform;
         //获取处理伤害
         dealDamage = GetComponent<DealDamage>();
         //获取角色移动
         characterMotor = GetComponent<CharacterMotor>();
         //获取刚体
         rigid = GetComponent<Rigidbody>();
         //获取AudioSource
         aSource = GetComponent<AudioSource>();

         //设置检查列表
         floorCheckers = new Transform[floorChecks.childCount];
         ;i < floorCheckers.Length;i++)
             floorCheckers[i] = floorChecks.GetChild(i);
     }

     void Update() {
         //激活刚体
         rigid.WakeUp();
         //计算跳跃
         JumpCalculations();

         //根据玩家是否着地设置当前加速度
         curAccel = (grounded) ? accel : airAccel;
         //根据玩家是否着地设置当前减速度
         curDecel = (grounded) ? decel : airDecel;
         //根据玩家是否着地设置当前旋转速度
         curRotateSpeed = (grounded) ? rotateSpeed : airRotateSpeed;

         screenMovementSpace = Quaternion.Euler(,mainCam.eulerAngles.y,);
         screenMovementForward = screenMovementSpace * Vector3.forward;
         screenMovementRight = screenMovementSpace * Vector3.right;

         float h = Input.GetAxisRaw("Horizontal");
         float v = Input.GetAxisRaw("Vertical");

         //不是卷轴模式
         if(!sidescroller)
             direction = (screenMovementForward * v) + (screenMovementRight * h);
         //是卷轴模式
         else
             //方向等于水平轴的输入*Vector3.right
             direction = Vector3.right * h;
         //移动方向等于当前位置加方向
         moveDirection = transform.position + direction;
     }

     void FixedUpdate() {
         //检查是否着地
         grounded = IsGrounded();
         //角色移动
         characterMotor.MoveTo(moveDirection,curAccel,0.7f,true);
         //旋转角色
          && direction.magnitude != )
             characterMotor.RotateToDirection(moveDirection,curRotateSpeed * ,true);
         //管理角色速度
         characterMotor.ManageSpeed(curDecel,maxSpeed + movingObjSpeed.magnitude,true);
         //播放动画
         if(animator) {
             animator.SetFloat("DistanceToTarget",characterMotor.DistanceToTarget);
             animator.SetBool("Grounded",grounded);
             animator.SetFloat("YVelocity",GetComponent<Rigidbody>().velocity.y);
         }
     }

     void OnCollisionStay(Collision other) {
         if(other.collider.tag != "Untagged" || grounded == false)
             return;
         //在小坡度上停止下滑
          && slope < slopeLimit && rigid.velocity.magnitude < ) {
             rigid.velocity = Vector3.zero;
         }
     }

     /// <summary>
     /// 检查是否着陆
     /// </summary>
     private bool IsGrounded() {
         //计算距离
         float dist = GetComponent<Collider>().bounds.extents.y;

         //遍历所有检查点
         foreach(Transform check in floorCheckers) {
             RaycastHit hit;
             //向下发射射线
             if(Physics.Raycast(check.position,Vector3.down,out hit,dist + 0.05f)) {
                 //如果不是触发器
                 if(!hit.transform.GetComponent<Collider>().isTrigger) {
                     //计算斜率
                     slope = Vector3.Angle(hit.normal,Vector3.up);
                     //斜率大于最大斜率,不是Pushable
                     if(slope > slopeLimit && hit.transform.tag != "Pushable") {
                         //计算滑动方向
                         Vector3 slide = new Vector3(0f,-slideAmount,0f);
                         //刚体施加滑动力
                         rigid.AddForce(slide,ForceMode.Force);
                     }
                     //碰到敌人,y轴速度小于0
                     ) {
                         //获取敌人AI
                         enemyAI = hit.transform.GetComponent<EnemyAI>();
                         //弹开玩家
                         enemyAI.BouncedOn();
                         //
                         onEnemyBounce++;
                         //处理伤害
                         dealDamage.Attack(hit.transform.gameObject,,0f,0f);
                     } else
                         //
                         onEnemyBounce = ;
                     //移动平台或Pushable
                     if(hit.transform.tag == "MovingPlatform" || hit.transform.tag == "Pushable") {
                         //移动物体的速度为刚体的速度
                         movingObjSpeed = hit.transform.GetComponent<Rigidbody>().velocity;
                         //移动物体的y轴速度为0
                         movingObjSpeed.y = 0f;
                         //根据移动物体的速度和摩檫力给玩家刚体添加力
                         rigid.AddForce(movingObjSpeed * movingPlatformFriction * Time.fixedDeltaTime,ForceMode.VelocityChange);
                     } else {
                         //移动物体的速度归0
                         movingObjSpeed = Vector3.zero;
                     }
                     return true;
                 }
             }
         }
         //移动物体的速度归0
         movingObjSpeed = Vector3.zero;
         return false;
     }

     /// <summary>
     /// 计算跳跃
     /// </summary>
     private void JumpCalculations() {
         //保存着陆后的时间
         groundedCount = (grounded) ? groundedCount += Time.deltaTime : 0f;

         //着陆时间小于0.25并且不等于0,正在播放声音,y轴的速度小于1
          && !GetComponent<AudioSource>().isPlaying && landSound && GetComponent<Rigidbody>().velocity.y < ) {
             //根据y轴的速度修改音量
             aSource.volume = Mathf.Abs(GetComponent<Rigidbody>().velocity.y) / ;
             //修改声音
             aSource.clip = landSound;
             //播放声音
             aSource.Play();
         }
         //按下jump且没有着陆
         if(Input.GetButtonDown("Jump") && !grounded)
             //修改按下跳跃的时间为当前时间
             airPressTime = Time.time;

         //着陆,斜率小于最大斜率
         if(grounded && slope < slopeLimit) {
             //按下Jump
             if(Input.GetButtonDown("Jump") || airPressTime + jumpLeniancy > Time.time) {
                 //切换跳跃类型
                 onJump = (groundedCount < jumpDelay) ? Mathf.Min(,onJump + ) : ;

                 )
                     Jump(jumpForce);
                 )
                     Jump(secondJumpForce);
                 ) {
                     Jump(thirdJumpForce);
                     onJump--;
                 }
             }
         }
     }

     /// <summary>
     /// 跳跃
     /// </summary>
     public void Jump(Vector3 jumpVelocity) {
         //播放跳跃声音
         if(jumpSound) {
             aSource.volume = ;
             aSource.clip = jumpSound;
             aSource.Play();
         }
         //改变刚体的y轴速度
         rigid.velocity = new Vector3(rigid.velocity.x,0f,rigid.velocity.z);
         //给刚体添加力
         rigid.AddRelativeForce(jumpVelocity,ForceMode.Impulse);
         //重置按下跳跃的时间
         airPressTime = 0f;
     }
 }

PlayerMove

 using UnityEngine;
 using System.Collections;

 /// <summary>
 /// 让玩家拾取,扔,推物体
 /// </summary>
 [RequireComponent(typeof(AudioSource))]
 [RequireComponent(typeof(Rigidbody))]
 [RequireComponent(typeof(PlayerMove))]
 public class Throwing : MonoBehaviour
 {
     /// <summary>
     /// 拾取声音
     /// </summary>
     public AudioClip pickUpSound;
     /// <summary>
     /// 扔声音
     /// </summary>
     public AudioClip throwSound;
     /// <summary>
     /// 用来抓物体的子游戏物体
     /// </summary>
     public GameObject grabBox;
     /// <summary>
     /// 举起物体的偏移
     /// </summary>
     public Vector3 holdOffset;
     /// <summary>
     /// 扔的力
     /// </summary>
     , , );
     /// <summary>
     /// 转向物体的速度
     /// </summary>
     ;
     /// <summary>
     /// 检查玩家头部的范围
     /// </summary>
     public float checkRadius = 0.5f;
     /// <summary>
     /// 拾取物体的重量
     /// </summary>
     [Range(0.1f, 1f)]
     public float weightChange = 0.3f;
     /// <summary>
     /// 未用
     /// </summary>
     [Range(10f, 1000f)]
     , holdingBreakTorque = ;
     /// <summary>
     /// Animator
     /// </summary>
     public Animator animator;
     /// <summary>
     /// 手臂动画层
     /// </summary>
     public int armsAnimationLayer;

     /// <summary>
     /// 举起或抓住的物体
     /// </summary>
     [HideInInspector]
     public GameObject heldObj;
     /// <summary>
     /// 举起物体的位置
     /// </summary>
     private Vector3 holdPos;
     /// <summary>
     /// 连接物体和角色的关节
     /// </summary>
     private FixedJoint joint;
     /// <summary>
     /// 举起物体的时间,扔物体的时间,默认旋转速度
     /// </summary>
     private float timeOfPickup, timeOfThrow, defRotateSpeed;
     /// <summary>
     /// gizmo颜色
     /// </summary>
     private Color gizmoColor;
     /// <summary>
     /// AudioSource
     /// </summary>
     private AudioSource aSource;
     /// <summary>
     /// 玩家移动
     /// </summary>
     private PlayerMove playerMove;
     /// <summary>
     /// 父物体下的子物体的触发器
     /// </summary>
     private TriggerParent triggerParent;
     /// <summary>
     /// 默认刚体插值类型
     /// </summary>
     private RigidbodyInterpolation objectDefInterpolation;

     void Awake()
     {
         //获取AudioSource
         aSource = GetComponent<AudioSource>();
         //没有抓物体的子物体
         if(!grabBox)
         {
             //新建
             grabBox = new GameObject();
             //添加碰撞器
             grabBox.AddComponent<BoxCollider>();
             //设置为触发器
             grabBox.GetComponent<Collider>().isTrigger = true;
             //设置玩家为父物体
             grabBox.transform.parent = transform;
             //修改局部坐标
             grabBox.transform.localPosition = new Vector3(0f, 0f, 0.5f);
             //修改层(Ignore Raycast)
             grabBox.layer = ;
             Debug.LogWarning("No grabBox object assigned to 'Throwing' script, one has been created and assigned for you", grabBox);
         }
         //获取玩家移动脚本
         playerMove = GetComponent<PlayerMove>();
         //设置默认旋转速度
         defRotateSpeed = playerMove.rotateSpeed;
         //Animator不为空
         if(animator)
             //设置手臂动画层的权重
             animator.SetLayerWeight(armsAnimationLayer, );
     }

     void Update()
     {
         //按下Grab键,有举起或抓住的物体,当前时间比举起物体的时间大0.1f
         if (Input.GetButtonDown ("Grab") && heldObj && Time.time > timeOfPickup + 0.1f)
         {
             //举起物体的标签为"Pickup"
             if(heldObj.tag == "Pickup")
                 //扔掉举起的物体
                 ThrowPickup();
         }
         //有Animator
         if(animator)
             //有举起的物体且物体标签为"Pickup"
             if(heldObj && heldObj.tag == "Pickup")
                 animator.SetBool ("HoldingPickup", true);
             else
                 animator.SetBool ("HoldingPickup", false);
             //有抓住的物体且物体标签为"Pushable"
             if(heldObj && heldObj.tag == "Pushable")
                 animator.SetBool ("HoldingPushable", true);
             else
                 animator.SetBool ("HoldingPushable", false);

         //有抓住的物体且物体标签为"Pushable"
         if (heldObj && heldObj.tag == "Pushable")
         {
             //按下Grab
             if(Input.GetButtonUp ("Grab"))
             {
                 //丢弃物体
                 DropPushable();
             }
             //没有关节
             if(!joint)
             {
                 //丢弃物体
                 DropPushable();
                 print ("'Pushable' object dropped because the 'holdingBreakForce' or 'holdingBreakTorque' was exceeded");
             }
         }
     }

     void OnTriggerStay(Collider other)
     {
         //按下Grab
         if(Input.GetButton("Grab"))
         {
             //标签为"Pickup",没有举起的物体,当前时间大于扔物体的时间加0.2
             if(other.tag == "Pickup" && heldObj == null && timeOfThrow + 0.2f < Time.time)
                 //举起物体
                 LiftPickup(other);
             //标签为"Pushable",没有抓住的物体,当前时间大于扔物体的时间加0.2
             if(other.tag == "Pushable" && heldObj == null && timeOfThrow + 0.2f < Time.time)
                 //抓物体
                 GrabPushable(other);
         }
     }

     /// <summary>
     /// 抓住物体
     /// </summary>
     private void GrabPushable(Collider other)
     {
         //抓住的物体为碰撞的物体
         heldObj = other.gameObject;
         //获取物体的插值类型
         objectDefInterpolation = heldObj.GetComponent<Rigidbody>().interpolation;
         //修改物体的插值为内插值
         heldObj.GetComponent<Rigidbody>().interpolation = RigidbodyInterpolation.Interpolate;
         //添加关节,连接玩家和物体
         AddJoint ();
         //设置破坏关节的力为无限
         joint.breakForce = Mathf.Infinity;
         //设置破坏关节的扭矩力为无限
         joint.breakTorque = Mathf.Infinity;
         //设置玩家移动的旋转速度为0
         playerMove.rotateSpeed = ;
     }

     /// <summary>
     /// 举起物体
     /// </summary>
     private void LiftPickup(Collider other)
     {
         //获取物体的网格
         Mesh otherMesh = other.GetComponent<MeshFilter>().mesh;
         //计算举起的位置
         holdPos = transform.position + transform.forward * holdOffset.z + transform.right * holdOffset.x + transform.up * holdOffset.y;
         //举起的位置的y值加碰撞器的范围的y值加碰撞物体网格的范围的y值
         holdPos.y += (GetComponent<Collider>().bounds.extents.y) + (otherMesh.bounds.extents.y);

         //检测举起位置的圆形范围
         if(!Physics.CheckSphere(holdPos,checkRadius)) {
             //修改gizmo颜色
             gizmoColor = Color.green;
             //缓存举起的物体
             heldObj = other.gameObject;
             //修改默认插值类型
             objectDefInterpolation = heldObj.GetComponent<Rigidbody>().interpolation;
             //修改举起物体的插值类型
             heldObj.GetComponent<Rigidbody>().interpolation = RigidbodyInterpolation.Interpolate;
             //修改举起物体的位置
             heldObj.transform.position = holdPos;
             //修改举起物体的旋转
             heldObj.transform.rotation = transform.rotation;
             //添加关节,连接物体和玩家
             AddJoint();
             //修改举起物体的质量
             heldObj.GetComponent<Rigidbody>().mass *= weightChange;
             //修改举起物体的时间为当前时间
             timeOfPickup = Time.time;
         } else {
             //修改gizmo颜色
             gizmoColor = Color.red;
             print("Can't lift object here. If nothing is above the player, perhaps you need to add a layerMask parameter to line 136 of the code in this script," +
                 "the CheckSphere function, in order to make sure it isn't detecting something above the players head that is invisible");
         }
     }

     /// <summary>
     /// 放下物体
     /// </summary>
     private void DropPushable()
     {
         //修改抓住物体的插值类型
         heldObj.GetComponent<Rigidbody>().interpolation = objectDefInterpolation;
         //销毁关节
         Destroy (joint);
         //修改玩家移动的旋转速度为默认旋转速度
         playerMove.rotateSpeed = defRotateSpeed;
         heldObj = null;
         timeOfThrow = Time.time;
     }

     /// <summary>
     /// 扔掉物体
     /// </summary>
     public void ThrowPickup()
     {
         //播放扔物体声音
         if(throwSound)
         {
             aSource.volume = ;
             aSource.clip = throwSound;
             aSource.Play ();
         }
         //删除关节
         Destroy (joint);
         //获取举起物体的刚体
         Rigidbody r = heldObj.GetComponent<Rigidbody>();
         //恢复物体的插值类型
         r.interpolation = objectDefInterpolation;
         //恢复物体的质量
         r.mass /= weightChange;
         //给刚体添加力
         r.AddRelativeForce (throwForce, ForceMode.VelocityChange);

         heldObj = null;
         timeOfThrow = Time.time;
     }

     /// <summary>
     /// 添加关节,连接玩家和物体
     /// </summary>
     private void AddJoint()
     {
         //如果有物体
         if (heldObj)
         {
             //播放拾取声音
             if(pickUpSound)
             {
                 aSource.volume = ;
                 aSource.clip = pickUpSound;
                 aSource.Play ();
             }
             //在物体上添加关节
             joint = heldObj.AddComponent<FixedJoint>();
             //设置关节的连接物体为玩家的刚体
             joint.connectedBody = GetComponent<Rigidbody>();
         }
     }

     void OnDrawGizmosSelected()
     {
         Gizmos.color = gizmoColor;
         Gizmos.DrawSphere (holdPos, checkRadius);
     }
 }

Throwing

 using UnityEngine;
 using System.Collections;

 /// <summary>
 /// 父物体下的子物体的触发器
 /// </summary>
 public class TriggerParent:MonoBehaviour {

     /// <summary>
     /// 要检查的标签列表
     /// </summary>
     public string[] tagsToCheck;

     /// <summary>
     /// 是否发生了碰撞,是否在碰撞中
     /// </summary>
     [HideInInspector]
     public bool collided, colliding;
     /// <summary>
     /// 撞击的物体
     /// </summary>
     [HideInInspector]
     public GameObject hitObject;

     void Awake() {
         //没有Collider或有Collider但不是触发器
         if(!GetComponent<Collider>() || (GetComponent<Collider>() && !GetComponent<Collider>().isTrigger))
             Debug.LogError("'TriggerParent' script attached to object which does not have a trigger collider",transform);
     }

     void OnTriggerEnter(Collider other) {
         //标签列表长度大于0且没有碰撞过
          && !collided) {
             //遍历标签
             foreach(string tag in tagsToCheck) {
                 //找到标签
                 if(other.tag == tag) {
                     //已发生碰撞
                     collided = true;
                     //存储碰撞物体
                     hitObject = other.gameObject;
                     break;
                 }

             }
         } else
             //已发生碰撞
             collided = true;
         //存储碰撞物体
         hitObject = other.gameObject;
     }

     void OnTriggerStay(Collider other) {
         //标签列表长度大于0
         ) {
             //遍历标签
             foreach(string tag in tagsToCheck) {
                 //找到标签
                 if(other.tag == tag) {
                     //正在碰撞
                     colliding = true;
                     //存储碰撞物体
                     hitObject = other.gameObject;
                     break;
                 }
             }
         } else {
             //存储碰撞物体
             hitObject = other.gameObject;
             //正在碰撞
             colliding = true;
         }
     }

     void OnTriggerExit(Collider other) {
         //标签列表长度大于0
         ) {
             //遍历标签
             foreach(string tag in tagsToCheck) {
                 //找到标签
                 if(other.tag == tag) {
                     colliding = false;
                     hitObject = null;
                     break;
                 }
             }
         } else
             return;
     }

     void LateUpdate() {
         //重置collided,hitObject
         if(collided) {
             collided = false;
             hitObject = null;
         }
     }
 }

TriggerParent

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

 /// <summary>
 /// 水
 /// </summary>
 [RequireComponent(typeof(BoxCollider))]
 public class Water:MonoBehaviour {
     /// <summary>
     /// 玩家进水的声音
     /// </summary>
     public AudioClip splashSound;
     /// <summary>
     /// 水的推力
     /// </summary>
     ,);
     /// <summary>
     /// 玩家是否会受到水的阻力影响
     /// </summary>
     public bool effectPlayerDrag;
     /// <summary>
     /// 刚体受到的水的阻力(不包含玩家)
     /// </summary>
     public float resistance = 0.4f;
     /// <summary>
     /// 刚体受到的角阻力(不包含玩家)
     /// </summary>
     public float angularResistance = 0.2f;

     /// <summary>
     /// 刚体受到的阻力字典
     /// </summary>
     private Dictionary<GameObject,float> dragStore = new Dictionary<GameObject,float>();
     /// <summary>
     /// 刚体受到的角阻力字典
     /// </summary>
     private Dictionary<GameObject,float> angularStore = new Dictionary<GameObject,float>();

     void Awake() {
         //自动修改"Water"标签
         if(tag != "Water") {
             tag = "Water";
             Debug.LogWarning("'Water' script attached to an object not tagged 'Water', it been assigned the tag 'Water'",transform);
         }
         //设置Trigger
         GetComponent<Collider>().isTrigger = true;
     }

     void OnTriggerEnter(Collider other) {
         //获取物体的刚体
         Rigidbody r = other.GetComponent<Rigidbody>();
         //刚体不为空
         if(r) {
             //播放入水声音
             if(splashSound) {
                 ;
                 AudioSource.PlayClipAtPoint(splashSound,other.transform.position,volume);
             }

             //是玩家且不受水的阻力影响
             if(r.tag == "Player" && !effectPlayerDrag)
                 return;

             //存储受到的阻力
             dragStore.Add(r.gameObject,r.drag);
             //存储受到的角阻力
             angularStore.Add(r.gameObject,r.angularDrag);

             //修改刚体受到的阻力
             r.drag = resistance;
             //修改刚体受到的角阻力
             r.angularDrag = angularResistance;
         } else if(splashSound)
             //播放入水声音
             AudioSource.PlayClipAtPoint(splashSound,other.transform.position);
     }

     void OnTriggerStay(Collider other) {
         //计算表面高度
         float surface = transform.position.y + GetComponent<Collider>().bounds.extents.y;
         Rigidbody rigid = other.GetComponent<Rigidbody>();
         if(rigid) {
             //计算物体相对于表面高度的深度
             float depth = surface - other.transform.position.y;
             //深度大于0.4
             if(depth > 0.4f)
                 //用一个较小的力往上推刚体
                 rigid.AddForce(force,ForceMode.Force);
             //深度小于等于0.4
             else
                 //用一个较大的力往上推刚体
                 rigid.AddForce(force * (depth * ),ForceMode.Force);
         }
     }

     void OnTriggerExit(Collider other) {
         //获取物体的刚体
         Rigidbody r = other.GetComponent<Rigidbody>();
         //有刚体
         if(r) {
             //是玩家且不受阻力水的阻力影响
             if(r.tag == "Player" && !effectPlayerDrag)
                 return;

             //阻力和角阻力字典包含刚体的游戏物体
             if(dragStore.ContainsKey(r.gameObject) && angularStore.ContainsKey(r.gameObject)) {
                 //恢复阻力
                 r.drag = dragStore[r.gameObject];
                 //恢复角阻力
                 r.angularDrag = angularStore[r.gameObject];
                 //移除阻力
                 dragStore.Remove(r.gameObject);
                 //移除角阻力
                 angularStore.Remove(r.gameObject);
             } else {
                 //重置阻力
                 r.drag = 0f;
                 //重置角阻力
                 r.angularDrag = 0.05f;
                 print("Object left water: couldn't get drag values, restored to defaults");
             }
         }
     }
 }

Water

视频:https://pan.baidu.com/s/1mhF7hmo

项目:https://pan.baidu.com/s/1pL6nMTP

05-11 13:05