Complete Physics Platformer Kit 学习
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
Complete Physics Platformer Kit 学习的更多相关文章
- iOS7 Sprite Kit 学习
iOS7 Sprite Kit 学习 iOS 7有一个新功能 Sprite Kit 这个有点类似cocos2d 感觉用法都差不多.下面简单来介绍下Sprite Kit About Sprite Kit ...
- S老师 Top-Down RPG Starter Kit 学习
character creation using UnityEngine; using System.Collections; public class CharacterCreation : Mon ...
- Sprite Kit编程指南(1)-深入Sprite Kit
深入Sprite Kit 学习Sprite Kit最好的方法是在实践中观察它.此示例创建一对场景和各自的动画内容.通过这个例子,你将学习使用Sprite Kit内容的一些基础技术,包括: · ...
- [Unity3D]Unity资料大全免费分享
都是网上找的连七八糟的资料了,整理好分享的,有学习资料,视频,源码,插件……等等 东西比较多,不是所有的都是你需要的,可以按 ctrl+F 来搜索你要的东西,如果有广告,不用理会,关掉就可以了,如 ...
- 【转】iOS 开发怎么入门?
原文网址:http://www.zhihu.com/question/20264108 iOS 开发怎么入门? 请问有设计模式.内存管理方面的资料吗?最好有除了官方文档之外的其它内容,10 条评论 分 ...
- DirectX SDK版本与Visual Studio版本
对于刚刚接触 DirectShow 的人来说,安装配置是一个令人头疼的问题,经常出现的情况是最基本的 baseclass 就无法编译.一开始我也为此费了很大的功夫,比如说修改代码.修改编译选项使其编译 ...
- How to Write Doc Comments for the Javadoc Tool
http://www.oracle.com/technetwork/java/javase/documentation/index-137868.html This document describe ...
- DirectX
DirectX 9.0 Complete Software Development Kit (SDK) :(2002-12-19) 点击下载 DirectX 9.0 SDK Update - (Sum ...
- 转 springboot 教程
转 Spring Boot 揭秘与实战 系列 拓展阅读: https://zhuanlan.zhihu.com/dreawer?topic=Java 发表于 2016-12-21 | Spring框架 ...
随机推荐
- 几大principal
1.A class should have only one reason to change. 一个类只负责一件事 2.高层抽象不依赖低层实现
- minifilter
暑假刚开始的时候,参照<寒江独钓>这本书,用VS2015写过的一个minifilter的框架,今天在博客上分享出来. VS2015已经有了minifilter的框架模板,直接生成了mini ...
- mybatis mapper配置文件 CustomerMapper.xml
Dao @Repositorypublic interface CustomerDAO { public void create(CustomerModel cm); public voi ...
- 牛客多校第四场 F Beautiful Garden
链接:https://www.nowcoder.com/acm/contest/142/F来源:牛客网 题目描述 There's a beautiful garden whose size is n ...
- transform带来的坑
1.transform会使子元素fixed定位和absolute定位失效. 2.父元素设置了border-radius和overflow:hidden, 但是子元素有transform属性,父元素设置 ...
- 2019.2.13 SW
- android小程序-电子钢琴-多点触控
我在第一篇博客<android小程序-电子钢琴-滑动连续响应>中实现了一个简单地7键钢琴,这几天把它又完善了一下,增加了多点触控,按键也增加了一个低音区和一个高音区,使得又可以多弹一点简单 ...
- python day08作业答案
1. a f=open('11.txt','r',encoding='utf-8') a=f.read() print(a) f.flush() f.close() b. f=open('11.txt ...
- CentOS7下-bash: nano: command not found
由于安装的是纯净版系统,运行nano命令是提示没有找到该命令,以下是解决方法,用root权限的用户运行以下命令安装nano: yum install nano 遇到询问时一路点y即可. 安装好后运行: ...
- 2016ICPC-大连 A Simple Math Problem (数学)
Given two positive integers a and b,find suitable X and Y to meet the conditions: X+Y=a Least Common ...