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框架 ...
随机推荐
- SQL-33 创建一个actor表,包含如下列信息
题目描述 创建一个actor表,包含如下列信息 列表 类型 是否为NULL 含义 actor_id smallint(5) not null 主键id first_name varchar(45) ...
- 国行 lg g3 D858 刷 lg g3 D858hk 教程(备忘)
纯手打,转载请注明出处~ 刷机有风险,出现问题概不负责! 本着自娱自乐的宗旨 ,分享一下,出了问题不负责! 准备的材料: 1,手机一枚(废话)国行lg g3 d858 2,root 工具 用来root ...
- MERGE INTO 解决大数据量 10w 更新缓慢的问题
有个同事处理更新数据缓慢的问题,数据量超10w的量,更新速度太慢耗时较长,然后改成了 MERGE INTO 效率显著提高. 使用方法如下 MERGE INTO 表A USING 表B ON 关联条件 ...
- Windows 窗体设计器生成的代码
namespace 窗体的浮动及隐藏{ partial class Form1 { /// <summary> /// 必需的设计器变量. ...
- 基于ArduinoLeonardo板子的BadUSB攻击实战
0X00 前言 在Freebuf上许多同学已经对HID攻击谈了自己的看法,如维克斯同学的<利用Arduino快速制作Teensy BadUSB>无论从科普还是实践都给我们详尽的描述了Bad ...
- django本身提供了runserver,为什么不能用来部署(runserver与uWSGI的区别)
runserver方法是调试django时经常用到的运行方式,它使用django自带的. WSGI Server 运行,主要在测试和开发使用,并且runserver 开启的方式也是单线程. uWSGI ...
- git 清空缓冲区
git rm与git rm --cached 当我们需要删除暂存区或分支上的文件, 同时工作区也不需要这个文件了, 可以使用 git rm file_path git commit -m 'delet ...
- XML Schema——笔记整理
什么是 XML Schema? 定义可出现在文档中的元素 定义可出现在文档中的属性 定义哪个元素是子元素 定义子元素的次序 定义子元素的数目 定义元素是否为空,或者是否可包含文本 定义元素和属性的数据 ...
- Eclipse 通过JPA自动生成注解实体
hibernate是JPA最常用的实现之一,而且hiberante自身也对注释语法进行了支持.现在再不用去看那一堆堆的XML映射了.而且eclipse还提供了从数据库直接生成Entity Class的 ...
- 运放积分电路MULTISIM
有些需要反馈回路