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框架 ...
随机推荐
- MicroBlaze核的串行接口实验:SPI UART
reference : https://blog.csdn.net/weixin_42413559/article/details/80720566 串行接口:SPI UART XPS->SDK ...
- 特殊权限stick_bit
stick_bit 防删除位:文件是否可以被某用户删除,主要取决于该文件所在的目录是否对该用户具有写权限.如果没有写权限,则这个目录下的所有文件都不能删除,同时也不能添加新的文件.如果希望用户能够添加 ...
- MySq:权限表
权限表 一.介绍 ①MySQL服务器通过权限表来控制用户对数据库的访问,权限表存放在MySQL数据库中,由mysql_install_db脚本初始化.②存储账户权限信息表主要有:user.db.hos ...
- IONIC和Cordova安装、打包踩过的坑
1.问题1:直接执行npm install -g cordova ionic,因为网络原因,执行不成功 解决方案:将npm映射到淘宝服务器:npm install -g cnpm --registry ...
- python 异常处理函数--raise
Python 异常处理--raise函数用法 在Python中,要想引发异常,最简单的形式就是输入关键字raise,后跟要引发的异常的名称.异常名称标识出具体的类: Python异常处理是那些类的对象 ...
- 【Python】requests.post请求注册实例
#encoding=utf-8 import requests import json import time import random import multiprocessing from mu ...
- SQL注入之Sqli-labs系列第八篇(基于布尔盲注的注入)
开始挑战第八关(Blind- Boolian- Single Quotes- String) 这关首先需要用到以下函数: 开始测试,使用测试语句,利用单引号进行闭合 猜解字段 union select ...
- 通过putty进行端口映射并且启动jupyter notebook
通过内网穿透之后,一般而言,我们访问内网中的机器在ubuntu下一句命令: ssh name@阿里云 -p 6000即可进行访问,其中-p是表示端口号:同样的通过windows下的putty也可修改对 ...
- HanLP 配置与使用
https://github.com/hankcs/HanLP 下载 hanlp-1.6.0.jar和 hanlp.properties 放在主目录下 修改 hanlp.properties 参考官网 ...
- NOI-1.8-17-最好的草-矩阵找最大连接井号-【递归】
17:最好的草 查看 提交 统计 提问 总时间限制: 10000ms 单个测试点时间限制: 1000ms 内存限制: 65536kB 描述 奶牛Bessie计划好好享受柔软的春季新草.新草分布在 ...