initial upload
This commit is contained in:
@ -0,0 +1,77 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
/// <summary>
|
||||
/// The base abstract class for all character animation controllers.
|
||||
/// </summary>
|
||||
public abstract class CharacterAnimationBase: MonoBehaviour {
|
||||
|
||||
public bool smoothFollow = true;
|
||||
public float smoothFollowSpeed = 20f;
|
||||
|
||||
protected bool animatePhysics;
|
||||
private Vector3 lastPosition;
|
||||
private Vector3 localPosition;
|
||||
private Quaternion localRotation;
|
||||
private Quaternion lastRotation;
|
||||
|
||||
// Gets the rotation pivot of the character
|
||||
public virtual Vector3 GetPivotPoint() {
|
||||
return transform.position;
|
||||
}
|
||||
|
||||
// Is the animator playing the grounded state?
|
||||
public virtual bool animationGrounded {
|
||||
get {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Gets angle around y axis from a world space direction
|
||||
public float GetAngleFromForward(Vector3 worldDirection) {
|
||||
Vector3 local = transform.InverseTransformDirection(worldDirection);
|
||||
return Mathf.Atan2 (local.x, local.z) * Mathf.Rad2Deg;
|
||||
}
|
||||
|
||||
protected virtual void Start() {
|
||||
if (transform.parent.GetComponent<CharacterBase>() == null) {
|
||||
Debug.LogWarning("Animation controllers should be parented to character controllers!", transform);
|
||||
}
|
||||
|
||||
lastPosition = transform.position;
|
||||
localPosition = transform.localPosition;
|
||||
lastRotation = transform.rotation;
|
||||
localRotation = transform.localRotation;
|
||||
}
|
||||
|
||||
protected virtual void LateUpdate() {
|
||||
if (animatePhysics) return;
|
||||
|
||||
SmoothFollow();
|
||||
}
|
||||
|
||||
// Smooth interpolation of character position. Helps to smooth out hectic rigidbody motion
|
||||
protected virtual void FixedUpdate() {
|
||||
if (!animatePhysics) return;
|
||||
|
||||
SmoothFollow();
|
||||
}
|
||||
|
||||
private void SmoothFollow() {
|
||||
if (smoothFollow) {
|
||||
transform.position = Vector3.Lerp(lastPosition, transform.parent.TransformPoint(localPosition), Time.deltaTime * smoothFollowSpeed);
|
||||
transform.rotation = Quaternion.Lerp(lastRotation, transform.parent.rotation * localRotation, Time.deltaTime * smoothFollowSpeed);
|
||||
} else
|
||||
{
|
||||
transform.localPosition = localPosition;
|
||||
transform.localRotation = localRotation;
|
||||
}
|
||||
|
||||
lastPosition = transform.position;
|
||||
lastRotation = transform.rotation;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 569c0702757374fa699636b2dc4aa1e2
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,40 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
/// <summary>
|
||||
/// Contols animation for a simple Mecanim character
|
||||
/// </summary>
|
||||
public class CharacterAnimationSimple: CharacterAnimationBase {
|
||||
|
||||
public CharacterThirdPerson characterController;
|
||||
public float pivotOffset; // Offset of the rotating pivot point from the root
|
||||
public AnimationCurve moveSpeed; // The moving speed relative to input forward
|
||||
|
||||
private Animator animator;
|
||||
|
||||
protected override void Start() {
|
||||
base.Start();
|
||||
|
||||
animator = GetComponentInChildren<Animator>();
|
||||
}
|
||||
|
||||
public override Vector3 GetPivotPoint() {
|
||||
if (pivotOffset == 0) return transform.position;
|
||||
return transform.position + transform.forward * pivotOffset;
|
||||
}
|
||||
|
||||
// Update the Animator with the current state of the character controller
|
||||
void Update() {
|
||||
float speed = moveSpeed.Evaluate(characterController.animState.moveDirection.z);
|
||||
|
||||
// Locomotion
|
||||
animator.SetFloat("Speed", speed);
|
||||
|
||||
// Movement
|
||||
characterController.Move(characterController.transform.forward * Time.deltaTime * speed, Quaternion.identity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2209dd700c8b64fc28e9cde6ac3286ba
|
||||
timeCreated: 1434698904
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,109 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
/// <summary>
|
||||
/// Contols animation for a third person person controller.
|
||||
/// </summary>
|
||||
public class CharacterAnimationThirdPerson: CharacterAnimationBase {
|
||||
|
||||
public CharacterThirdPerson characterController;
|
||||
[SerializeField] float turnSensitivity = 0.2f; // Animator turning sensitivity
|
||||
[SerializeField] float turnSpeed = 5f; // Animator turning interpolation speed
|
||||
[SerializeField] float runCycleLegOffset = 0.2f; // The offset of leg positions in the running cycle
|
||||
[Range(0.1f,3f)] [SerializeField] float animSpeedMultiplier = 1; // How much the animation of the character will be multiplied by
|
||||
|
||||
protected Animator animator;
|
||||
private Vector3 lastForward;
|
||||
private const string groundedDirectional = "Grounded Directional", groundedStrafe = "Grounded Strafe";
|
||||
private float deltaAngle;
|
||||
private float jumpLeg;
|
||||
private bool lastJump;
|
||||
|
||||
protected override void Start() {
|
||||
base.Start();
|
||||
|
||||
animator = GetComponent<Animator>();
|
||||
|
||||
lastForward = transform.forward;
|
||||
}
|
||||
|
||||
public override Vector3 GetPivotPoint() {
|
||||
return animator.pivotPosition;
|
||||
}
|
||||
|
||||
// Is the Animator playing the grounded animations?
|
||||
public override bool animationGrounded {
|
||||
get {
|
||||
return animator.GetCurrentAnimatorStateInfo(0).IsName(groundedDirectional) || animator.GetCurrentAnimatorStateInfo(0).IsName(groundedStrafe);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the Animator with the current state of the character controller
|
||||
protected virtual void Update() {
|
||||
if (Time.deltaTime == 0f) return;
|
||||
|
||||
animatePhysics = animator.updateMode == AnimatorUpdateMode.AnimatePhysics;
|
||||
|
||||
// Jumping
|
||||
if (characterController.animState.jump) {
|
||||
if (!lastJump)
|
||||
{
|
||||
float runCycle = Mathf.Repeat(animator.GetCurrentAnimatorStateInfo(0).normalizedTime + runCycleLegOffset, 1);
|
||||
float jumpLeg = (runCycle < 0.5f ? 1 : -1) * characterController.animState.moveDirection.z;
|
||||
|
||||
animator.SetFloat("JumpLeg", jumpLeg);
|
||||
}
|
||||
}
|
||||
lastJump = characterController.animState.jump;
|
||||
|
||||
// Calculate the angular delta in character rotation
|
||||
float angle = -GetAngleFromForward(lastForward) - deltaAngle;
|
||||
deltaAngle = 0f;
|
||||
lastForward = transform.forward;
|
||||
angle *= turnSensitivity * 0.01f;
|
||||
angle = Mathf.Clamp(angle / Time.deltaTime, -1f, 1f);
|
||||
|
||||
// Update Animator params
|
||||
animator.SetFloat("Turn", Mathf.Lerp(animator.GetFloat("Turn"), angle, Time.deltaTime * turnSpeed));
|
||||
animator.SetFloat("Forward", characterController.animState.moveDirection.z);
|
||||
animator.SetFloat("Right", characterController.animState.moveDirection.x);
|
||||
animator.SetBool("Crouch", characterController.animState.crouch);
|
||||
animator.SetBool("OnGround", characterController.animState.onGround);
|
||||
animator.SetBool("IsStrafing", characterController.animState.isStrafing);
|
||||
|
||||
if (!characterController.animState.onGround) {
|
||||
animator.SetFloat ("Jump", characterController.animState.yVelocity);
|
||||
}
|
||||
|
||||
if (characterController.doubleJumpEnabled) animator.SetBool("DoubleJump", characterController.animState.doubleJump);
|
||||
characterController.animState.doubleJump = false;
|
||||
|
||||
// the anim speed multiplier allows the overall speed of walking/running to be tweaked in the inspector
|
||||
if (characterController.animState.onGround && characterController.animState.moveDirection.z > 0f) {
|
||||
animator.speed = animSpeedMultiplier;
|
||||
} else {
|
||||
// but we don't want to use that while airborne
|
||||
animator.speed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Call OnAnimatorMove manually on the character controller because it doesn't have the Animator component
|
||||
void OnAnimatorMove() {
|
||||
// For not using root rotation in Turn value calculation
|
||||
Vector3 f = animator.deltaRotation * Vector3.forward;
|
||||
deltaAngle += Mathf.Atan2(f.x, f.z) * Mathf.Rad2Deg;
|
||||
|
||||
if (characterController.fullRootMotion)
|
||||
{
|
||||
characterController.transform.position += animator.deltaPosition;
|
||||
characterController.transform.rotation *= animator.deltaRotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
characterController.Move(animator.deltaPosition, animator.deltaRotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 44963f0d149a94b76a8afd23095c42df
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,118 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
/// <summary>
|
||||
/// The base abstract class for all character controllers, provides common functionality.
|
||||
/// </summary>
|
||||
public abstract class CharacterBase: MonoBehaviour {
|
||||
|
||||
[Header("Base Parameters")]
|
||||
|
||||
[Tooltip("If specified, will use the direction from the character to this Transform as the gravity vector instead of Physics.gravity. Physics.gravity.magnitude will be used as the magnitude of the gravity vector.")]
|
||||
public Transform gravityTarget;
|
||||
|
||||
[Tooltip("Multiplies gravity applied to the character even if 'Individual Gravity' is unchecked.")]
|
||||
public float gravityMultiplier = 2f; // gravity modifier - often higher than natural gravity feels right for game characters
|
||||
|
||||
public float airborneThreshold = 0.6f; // Height from ground after which the character is considered airborne
|
||||
public float slopeStartAngle = 50f; // The start angle of velocity dampering on slopes
|
||||
public float slopeEndAngle = 85f; // The end angle of velocity dampering on slopes
|
||||
public float spherecastRadius = 0.1f; // The radius of sperecasting
|
||||
public LayerMask groundLayers; // The walkable layers
|
||||
|
||||
private PhysicMaterial zeroFrictionMaterial;
|
||||
private PhysicMaterial highFrictionMaterial;
|
||||
protected Rigidbody r;
|
||||
protected const float half = 0.5f;
|
||||
protected float originalHeight;
|
||||
protected Vector3 originalCenter;
|
||||
protected CapsuleCollider capsule;
|
||||
|
||||
public abstract void Move(Vector3 deltaPosition, Quaternion deltaRotation);
|
||||
|
||||
protected Vector3 GetGravity() {
|
||||
if (gravityTarget != null) {
|
||||
return (gravityTarget.position - transform.position).normalized * Physics.gravity.magnitude;
|
||||
}
|
||||
|
||||
return Physics.gravity;
|
||||
}
|
||||
|
||||
protected virtual void Start() {
|
||||
capsule = GetComponent<Collider>() as CapsuleCollider;
|
||||
r = GetComponent<Rigidbody>();
|
||||
|
||||
// Store the collider volume
|
||||
originalHeight = capsule.height;
|
||||
originalCenter = capsule.center;
|
||||
|
||||
// Physics materials
|
||||
zeroFrictionMaterial = new PhysicMaterial();
|
||||
zeroFrictionMaterial.dynamicFriction = 0f;
|
||||
zeroFrictionMaterial.staticFriction = 0f;
|
||||
zeroFrictionMaterial.frictionCombine = PhysicMaterialCombine.Minimum;
|
||||
zeroFrictionMaterial.bounciness = 0f;
|
||||
zeroFrictionMaterial.bounceCombine = PhysicMaterialCombine.Minimum;
|
||||
|
||||
highFrictionMaterial = new PhysicMaterial();
|
||||
|
||||
// Making sure rigidbody rotation is fixed
|
||||
r.constraints = RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezeRotationY | RigidbodyConstraints.FreezeRotationZ;
|
||||
}
|
||||
|
||||
// Spherecast from the root to find ground height
|
||||
protected virtual RaycastHit GetSpherecastHit() {
|
||||
Vector3 up = transform.up;
|
||||
Ray ray = new Ray (r.position + up * airborneThreshold, -up);
|
||||
RaycastHit h = new RaycastHit();
|
||||
h.point = transform.position - transform.transform.up * airborneThreshold;
|
||||
h.normal = transform.up;
|
||||
|
||||
Physics.SphereCast(ray, spherecastRadius, out h, airborneThreshold * 2f, groundLayers);
|
||||
return h;
|
||||
}
|
||||
|
||||
// Gets angle around y axis from a world space direction
|
||||
public float GetAngleFromForward(Vector3 worldDirection) {
|
||||
Vector3 local = transform.InverseTransformDirection(worldDirection);
|
||||
return Mathf.Atan2 (local.x, local.z) * Mathf.Rad2Deg;
|
||||
}
|
||||
|
||||
// Rotate a rigidbody around a point and axis by angle
|
||||
protected void RigidbodyRotateAround(Vector3 point, Vector3 axis, float angle) {
|
||||
Quaternion rotation = Quaternion.AngleAxis(angle, axis);
|
||||
Vector3 d = transform.position - point;
|
||||
r.MovePosition(point + rotation * d);
|
||||
r.MoveRotation(rotation * transform.rotation);
|
||||
}
|
||||
|
||||
// Scale the capsule collider to 'mlp' of the initial value
|
||||
protected void ScaleCapsule (float mlp) {
|
||||
if (capsule.height != originalHeight * mlp) {
|
||||
capsule.height = Mathf.MoveTowards (capsule.height, originalHeight * mlp, Time.deltaTime * 4);
|
||||
capsule.center = Vector3.MoveTowards (capsule.center, originalCenter * mlp, Time.deltaTime * 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the collider to high friction material
|
||||
protected void HighFriction() {
|
||||
capsule.material = highFrictionMaterial;
|
||||
}
|
||||
|
||||
// Set the collider to zero friction material
|
||||
protected void ZeroFriction() {
|
||||
capsule.material = zeroFrictionMaterial;
|
||||
}
|
||||
|
||||
// Get the damper of velocity on the slopes
|
||||
protected float GetSlopeDamper(Vector3 velocity, Vector3 groundNormal) {
|
||||
float angle = 90f - Vector3.Angle(velocity, groundNormal);
|
||||
angle -= slopeStartAngle;
|
||||
float range = slopeEndAngle - slopeStartAngle;
|
||||
return 1f - Mathf.Clamp(angle / range, 0f, 1f);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2869ec4c764fa4c24b4c2b1654fd316d
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,470 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
/// <summary>
|
||||
/// Third person character controller. This class is based on the ThirdPersonCharacter.cs of the Unity Exmaple Assets.
|
||||
/// </summary>
|
||||
public class CharacterThirdPerson : CharacterBase {
|
||||
|
||||
// Is the character always rotating to face the move direction or is he strafing?
|
||||
[System.Serializable]
|
||||
public enum MoveMode {
|
||||
Directional,
|
||||
Strafe
|
||||
}
|
||||
|
||||
// Animation state
|
||||
public struct AnimState {
|
||||
public Vector3 moveDirection; // the forward speed
|
||||
public bool jump; // should the character be jumping?
|
||||
public bool crouch; // should the character be crouching?
|
||||
public bool onGround; // is the character grounded
|
||||
public bool isStrafing; // should the character always rotate to face the move direction or strafe?
|
||||
public float yVelocity; // y velocity of the character
|
||||
public bool doubleJump;
|
||||
}
|
||||
|
||||
[Header("References")]
|
||||
public CharacterAnimationBase characterAnimation; // the animation controller
|
||||
public UserControlThirdPerson userControl; // user input
|
||||
public CameraController cam; // Camera controller (optional). If assigned will update the camera in LateUpdate only if character moves
|
||||
|
||||
[Header("Movement")]
|
||||
public MoveMode moveMode; // Is the character always rotating to face the move direction or is he strafing?
|
||||
public bool smoothPhysics = true; // If true, will use interpolation to smooth out the fixed time step.
|
||||
public float smoothAccelerationTime = 0.2f; // The smooth acceleration of the speed of the character (using Vector3.SmoothDamp)
|
||||
public float linearAccelerationSpeed = 3f; // The linear acceleration of the speed of the character (using Vector3.MoveTowards)
|
||||
public float platformFriction = 7f; // the acceleration of adapting the velocities of moving platforms
|
||||
public float groundStickyEffect = 4f; // power of 'stick to ground' effect - prevents bumping down slopes.
|
||||
public float maxVerticalVelocityOnGround = 3f; // the maximum y velocity while the character is grounded
|
||||
public float velocityToGroundTangentWeight = 0f; // the weight of rotating character velocity vector to the ground tangent
|
||||
|
||||
[Header("Rotation")]
|
||||
public bool lookInCameraDirection; // should the character be looking in the same direction that the camera is facing
|
||||
public float turnSpeed = 5f; // additional turn speed added when the player is moving (added to animation root rotation)
|
||||
public float stationaryTurnSpeedMlp = 1f; // additional turn speed added when the player is stationary (added to animation root rotation)
|
||||
|
||||
[Header("Jumping and Falling")]
|
||||
public bool smoothJump = true; // If true, adds jump force over a few fixed time steps, not in a single step
|
||||
public float airSpeed = 6f; // determines the max speed of the character while airborne
|
||||
public float airControl = 2f; // determines the response speed of controlling the character while airborne
|
||||
public float jumpPower = 12f; // determines the jump force applied when jumping (and therefore the jump height)
|
||||
public float jumpRepeatDelayTime = 0f; // amount of time that must elapse between landing and being able to jump again
|
||||
public bool doubleJumpEnabled;
|
||||
public float doubleJumpPowerMlp = 1f;
|
||||
|
||||
[Header("Wall Running")]
|
||||
|
||||
public LayerMask wallRunLayers; // walkable vertical surfaces
|
||||
public float wallRunMaxLength = 1f; // max duration of a wallrun
|
||||
public float wallRunMinMoveMag = 0.6f; // the minumum magnitude of the user control input move vector
|
||||
public float wallRunMinVelocityY = -1f; // the minimum vertical velocity of doing a wall run
|
||||
public float wallRunRotationSpeed = 1.5f; // the speed of rotating the character to the wall normal
|
||||
public float wallRunMaxRotationAngle = 70f; // max angle of character rotation
|
||||
public float wallRunWeightSpeed = 5f; // the speed of blending in/out the wall running effect
|
||||
|
||||
[Header("Crouching")]
|
||||
public float crouchCapsuleScaleMlp = 0.6f; // the capsule collider scale multiplier while crouching
|
||||
|
||||
/// <summary>
|
||||
/// Enable this while playing an animation that should be driven 100% by root motion, such as climbing walls
|
||||
/// </summary>
|
||||
public bool fullRootMotion { get; set; }
|
||||
|
||||
public bool onGround { get; private set; }
|
||||
public AnimState animState = new AnimState();
|
||||
|
||||
protected Vector3 moveDirection; // The current move direction of the character in Strafe move mode
|
||||
private Animator animator;
|
||||
private Vector3 normal, platformVelocity, platformAngularVelocity;
|
||||
private RaycastHit hit;
|
||||
private float jumpLeg, jumpEndTime, forwardMlp, groundDistance, lastAirTime, stickyForce;
|
||||
private Vector3 wallNormal = Vector3.up;
|
||||
private Vector3 moveDirectionVelocity;
|
||||
private float wallRunWeight;
|
||||
private float lastWallRunWeight;
|
||||
private float fixedDeltaTime;
|
||||
private Vector3 fixedDeltaPosition;
|
||||
private Quaternion fixedDeltaRotation = Quaternion.identity;
|
||||
private bool fixedFrame;
|
||||
private float wallRunEndTime;
|
||||
private Vector3 gravity;
|
||||
private Vector3 verticalVelocity;
|
||||
private float velocityY;
|
||||
private bool doubleJumped;
|
||||
private bool jumpReleased;
|
||||
|
||||
// Use this for initialization
|
||||
protected override void Start () {
|
||||
base.Start();
|
||||
|
||||
animator = GetComponent<Animator>();
|
||||
if (animator == null) animator = characterAnimation.GetComponent<Animator>();
|
||||
|
||||
wallNormal = -gravity.normalized;
|
||||
onGround = true;
|
||||
animState.onGround = true;
|
||||
|
||||
if (cam != null) cam.enabled = false;
|
||||
}
|
||||
|
||||
void OnAnimatorMove() {
|
||||
Move (animator.deltaPosition, animator.deltaRotation);
|
||||
}
|
||||
|
||||
// When the Animator moves
|
||||
public override void Move(Vector3 deltaPosition, Quaternion deltaRotation) {
|
||||
// Accumulate delta position, update in FixedUpdate to maintain consitency
|
||||
fixedDeltaTime += Time.deltaTime;
|
||||
fixedDeltaPosition += deltaPosition;
|
||||
fixedDeltaRotation *= deltaRotation;
|
||||
}
|
||||
|
||||
void FixedUpdate() {
|
||||
gravity = fullRootMotion? Vector3.zero: GetGravity();
|
||||
|
||||
verticalVelocity = V3Tools.ExtractVertical(r.velocity, gravity, 1f);
|
||||
velocityY = verticalVelocity.magnitude;
|
||||
if (Vector3.Dot(verticalVelocity, gravity) > 0f) velocityY = -velocityY;
|
||||
|
||||
// Smoothing out the fixed time step
|
||||
r.interpolation = smoothPhysics? RigidbodyInterpolation.Interpolate: RigidbodyInterpolation.None;
|
||||
characterAnimation.smoothFollow = smoothPhysics;
|
||||
|
||||
// Move
|
||||
MoveFixed(fixedDeltaPosition);
|
||||
|
||||
fixedDeltaTime = 0f;
|
||||
fixedDeltaPosition = Vector3.zero;
|
||||
|
||||
r.MoveRotation(transform.rotation * fixedDeltaRotation);
|
||||
fixedDeltaRotation = Quaternion.identity;
|
||||
|
||||
Rotate();
|
||||
|
||||
GroundCheck (); // detect and stick to ground
|
||||
|
||||
// Friction
|
||||
if (userControl.state.move == Vector3.zero && groundDistance < airborneThreshold * 0.5f) HighFriction();
|
||||
else ZeroFriction();
|
||||
|
||||
bool stopSlide = !fullRootMotion && onGround && userControl.state.move == Vector3.zero && r.velocity.magnitude < 0.5f && groundDistance < airborneThreshold * 0.5f;
|
||||
|
||||
// Individual gravity
|
||||
if (gravityTarget != null) {
|
||||
r.useGravity = false;
|
||||
|
||||
if (!stopSlide) r.AddForce(gravity);
|
||||
}
|
||||
|
||||
if (stopSlide) {
|
||||
r.useGravity = false;
|
||||
r.velocity = Vector3.zero;
|
||||
} else if (gravityTarget == null) r.useGravity = true;
|
||||
|
||||
if (onGround) {
|
||||
// Jumping
|
||||
animState.jump = Jump();
|
||||
jumpReleased = false;
|
||||
doubleJumped = false;
|
||||
} else {
|
||||
if (!userControl.state.jump) jumpReleased = true;
|
||||
|
||||
//r.AddForce(gravity * gravityMultiplier);
|
||||
if (jumpReleased && userControl.state.jump && !doubleJumped && doubleJumpEnabled) {
|
||||
jumpEndTime = Time.time + 0.1f;
|
||||
animState.doubleJump = true;
|
||||
|
||||
Vector3 jumpVelocity = userControl.state.move * airSpeed;
|
||||
r.velocity = jumpVelocity;
|
||||
r.velocity += transform.up * jumpPower * doubleJumpPowerMlp;
|
||||
doubleJumped = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Scale the capsule colllider while crouching
|
||||
ScaleCapsule(userControl.state.crouch? crouchCapsuleScaleMlp: 1f);
|
||||
|
||||
fixedFrame = true;
|
||||
}
|
||||
|
||||
protected virtual void Update() {
|
||||
// Fill in animState
|
||||
animState.onGround = onGround;
|
||||
animState.moveDirection = GetMoveDirection();
|
||||
animState.yVelocity = Mathf.Lerp(animState.yVelocity, velocityY, Time.deltaTime * 10f);
|
||||
animState.crouch = userControl.state.crouch;
|
||||
animState.isStrafing = moveMode == MoveMode.Strafe;
|
||||
}
|
||||
|
||||
protected virtual void LateUpdate() {
|
||||
if (cam == null) return;
|
||||
|
||||
cam.UpdateInput();
|
||||
|
||||
if (!fixedFrame && r.interpolation == RigidbodyInterpolation.None) return;
|
||||
|
||||
// Update camera only if character moves
|
||||
cam.UpdateTransform(r.interpolation == RigidbodyInterpolation.None? Time.fixedDeltaTime: Time.deltaTime);
|
||||
|
||||
fixedFrame = false;
|
||||
}
|
||||
|
||||
private void MoveFixed(Vector3 deltaPosition) {
|
||||
// Process horizontal wall-running
|
||||
WallRun();
|
||||
|
||||
Vector3 velocity = fixedDeltaTime > 0f? deltaPosition / fixedDeltaTime: Vector3.zero;
|
||||
|
||||
// Add velocity of the rigidbody the character is standing on
|
||||
if (!fullRootMotion)
|
||||
{
|
||||
velocity += V3Tools.ExtractHorizontal(platformVelocity, gravity, 1f);
|
||||
|
||||
if (onGround)
|
||||
{
|
||||
// Rotate velocity to ground tangent
|
||||
if (velocityToGroundTangentWeight > 0f)
|
||||
{
|
||||
Quaternion rotation = Quaternion.FromToRotation(transform.up, normal);
|
||||
velocity = Quaternion.Lerp(Quaternion.identity, rotation, velocityToGroundTangentWeight) * velocity;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Air move
|
||||
//Vector3 airMove = new Vector3 (userControl.state.move.x * airSpeed, 0f, userControl.state.move.z * airSpeed);
|
||||
Vector3 airMove = V3Tools.ExtractHorizontal(userControl.state.move * airSpeed, gravity, 1f);
|
||||
velocity = Vector3.Lerp(r.velocity, airMove, Time.deltaTime * airControl);
|
||||
}
|
||||
|
||||
if (onGround && Time.time > jumpEndTime && !r.isKinematic)
|
||||
{
|
||||
r.velocity = r.velocity - transform.up * stickyForce * Time.deltaTime;
|
||||
}
|
||||
|
||||
// Vertical velocity
|
||||
Vector3 verticalVelocity = V3Tools.ExtractVertical(r.velocity, gravity, 1f);
|
||||
Vector3 horizontalVelocity = V3Tools.ExtractHorizontal(velocity, gravity, 1f);
|
||||
|
||||
if (onGround)
|
||||
{
|
||||
if (Vector3.Dot(verticalVelocity, gravity) < 0f)
|
||||
{
|
||||
verticalVelocity = Vector3.ClampMagnitude(verticalVelocity, maxVerticalVelocityOnGround);
|
||||
}
|
||||
}
|
||||
|
||||
r.velocity = horizontalVelocity + verticalVelocity;
|
||||
} else
|
||||
{
|
||||
r.velocity = velocity;
|
||||
}
|
||||
|
||||
// Dampering forward speed on the slopes (Not working since Unity 2017.2)
|
||||
//float slopeDamper = !onGround? 1f: GetSlopeDamper(-deltaPosition / Time.deltaTime, normal);
|
||||
//forwardMlp = Mathf.Lerp(forwardMlp, slopeDamper, Time.deltaTime * 5f);
|
||||
forwardMlp = 1f;
|
||||
}
|
||||
|
||||
// Processing horizontal wall running
|
||||
private void WallRun() {
|
||||
bool canWallRun = CanWallRun();
|
||||
|
||||
// Remove flickering in and out of wall-running
|
||||
if (wallRunWeight > 0f && !canWallRun) wallRunEndTime = Time.time;
|
||||
if (Time.time < wallRunEndTime + 0.5f) canWallRun = false;
|
||||
|
||||
wallRunWeight = Mathf.MoveTowards(wallRunWeight, (canWallRun? 1f: 0f), Time.deltaTime * wallRunWeightSpeed);
|
||||
|
||||
if (wallRunWeight <= 0f) {
|
||||
// Reset
|
||||
if (lastWallRunWeight > 0f) {
|
||||
Vector3 frw = V3Tools.ExtractHorizontal(transform.forward, gravity, 1f);
|
||||
transform.rotation = Quaternion.LookRotation(frw, -gravity);
|
||||
wallNormal = -gravity.normalized;
|
||||
}
|
||||
}
|
||||
|
||||
lastWallRunWeight = wallRunWeight;
|
||||
|
||||
if (wallRunWeight <= 0f) return;
|
||||
|
||||
// Make sure the character won't fall down
|
||||
if (onGround && velocityY < 0f) r.velocity = V3Tools.ExtractHorizontal(r.velocity, gravity, 1f);
|
||||
|
||||
// transform.forward flattened
|
||||
Vector3 f = V3Tools.ExtractHorizontal(transform.forward, gravity, 1f);
|
||||
|
||||
// Raycasting to find a walkable wall
|
||||
RaycastHit velocityHit = new RaycastHit();
|
||||
velocityHit.normal = -gravity.normalized;
|
||||
Physics.Raycast(onGround? transform.position: capsule.bounds.center, f, out velocityHit, 3f, wallRunLayers);
|
||||
|
||||
// Finding the normal to rotate to
|
||||
wallNormal = Vector3.Lerp(wallNormal, velocityHit.normal, Time.deltaTime * wallRunRotationSpeed);
|
||||
|
||||
// Clamping wall normal to max rotation angle
|
||||
wallNormal = Vector3.RotateTowards(-gravity.normalized, wallNormal, wallRunMaxRotationAngle * Mathf.Deg2Rad, 0f);
|
||||
|
||||
// Get transform.forward ortho-normalized to the wall normal
|
||||
Vector3 fW = transform.forward;
|
||||
Vector3 nW = wallNormal;
|
||||
Vector3.OrthoNormalize(ref nW, ref fW);
|
||||
|
||||
// Rotate from upright to wall normal
|
||||
transform.rotation = Quaternion.Slerp(Quaternion.LookRotation(f, -gravity), Quaternion.LookRotation(fW, wallNormal), wallRunWeight);
|
||||
}
|
||||
|
||||
// Should the character be enabled to do a wall run?
|
||||
private bool CanWallRun() {
|
||||
if (fullRootMotion) return false;
|
||||
if (Time.time < jumpEndTime - 0.1f) return false;
|
||||
if (Time.time > jumpEndTime - 0.1f + wallRunMaxLength) return false;
|
||||
if (velocityY < wallRunMinVelocityY) return false;
|
||||
if (userControl.state.move.magnitude < wallRunMinMoveMag) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get the move direction of the character relative to the character rotation
|
||||
private Vector3 GetMoveDirection() {
|
||||
switch(moveMode) {
|
||||
case MoveMode.Directional:
|
||||
moveDirection = Vector3.SmoothDamp(moveDirection, new Vector3(0f, 0f, userControl.state.move.magnitude), ref moveDirectionVelocity, smoothAccelerationTime);
|
||||
moveDirection = Vector3.MoveTowards(moveDirection, new Vector3(0f, 0f, userControl.state.move.magnitude), Time.deltaTime * linearAccelerationSpeed);
|
||||
return moveDirection * forwardMlp;
|
||||
case MoveMode.Strafe:
|
||||
moveDirection = Vector3.SmoothDamp(moveDirection, userControl.state.move, ref moveDirectionVelocity, smoothAccelerationTime);
|
||||
moveDirection = Vector3.MoveTowards(moveDirection, userControl.state.move, Time.deltaTime * linearAccelerationSpeed);
|
||||
return transform.InverseTransformDirection(moveDirection);
|
||||
}
|
||||
|
||||
return Vector3.zero;
|
||||
}
|
||||
|
||||
// Rotate the character
|
||||
protected virtual void Rotate() {
|
||||
if (gravityTarget != null) r.MoveRotation (Quaternion.FromToRotation(transform.up, transform.position - gravityTarget.position) * transform.rotation);
|
||||
if (platformAngularVelocity != Vector3.zero) r.MoveRotation (Quaternion.Euler(platformAngularVelocity) * transform.rotation);
|
||||
|
||||
float angle = GetAngleFromForward(GetForwardDirection());
|
||||
|
||||
if (userControl.state.move == Vector3.zero) angle *= (1.01f - (Mathf.Abs(angle) / 180f)) * stationaryTurnSpeedMlp;
|
||||
|
||||
// Rotating the character
|
||||
//RigidbodyRotateAround(characterAnimation.GetPivotPoint(), transform.up, angle * Time.deltaTime * turnSpeed);
|
||||
r.MoveRotation(Quaternion.AngleAxis(angle * Time.deltaTime * turnSpeed, transform.up) * r.rotation);
|
||||
}
|
||||
|
||||
// Which way to look at?
|
||||
private Vector3 GetForwardDirection() {
|
||||
bool isMoving = userControl.state.move != Vector3.zero;
|
||||
|
||||
switch (moveMode) {
|
||||
case MoveMode.Directional:
|
||||
if (isMoving) return userControl.state.move;
|
||||
return lookInCameraDirection? userControl.state.lookPos - r.position: transform.forward;
|
||||
case MoveMode.Strafe:
|
||||
if (isMoving) return userControl.state.lookPos - r.position;
|
||||
return lookInCameraDirection? userControl.state.lookPos - r.position: transform.forward;
|
||||
}
|
||||
|
||||
return Vector3.zero;
|
||||
}
|
||||
|
||||
protected virtual bool Jump() {
|
||||
// check whether conditions are right to allow a jump:
|
||||
if (!userControl.state.jump) return false;
|
||||
if (userControl.state.crouch) return false;
|
||||
if (!characterAnimation.animationGrounded) return false;
|
||||
if (Time.time < lastAirTime + jumpRepeatDelayTime) return false;
|
||||
|
||||
// Jump
|
||||
onGround = false;
|
||||
jumpEndTime = Time.time + 0.1f;
|
||||
|
||||
Vector3 jumpVelocity = userControl.state.move * airSpeed;
|
||||
jumpVelocity += transform.up * jumpPower;
|
||||
|
||||
if (smoothJump)
|
||||
{
|
||||
StopAllCoroutines();
|
||||
StartCoroutine(JumpSmooth(jumpVelocity - r.velocity));
|
||||
} else
|
||||
{
|
||||
r.velocity = jumpVelocity;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Add jump velocity smoothly to avoid puppets launching to space when unpinned during jump acceleration
|
||||
private IEnumerator JumpSmooth(Vector3 jumpVelocity)
|
||||
{
|
||||
int steps = 0;
|
||||
int stepsToTake = 3;
|
||||
while (steps < stepsToTake)
|
||||
{
|
||||
r.AddForce((jumpVelocity) / stepsToTake, ForceMode.VelocityChange);
|
||||
steps++;
|
||||
yield return new WaitForFixedUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
// Is the character grounded?
|
||||
private void GroundCheck () {
|
||||
Vector3 platformVelocityTarget = Vector3.zero;
|
||||
platformAngularVelocity = Vector3.zero;
|
||||
float stickyForceTarget = 0f;
|
||||
|
||||
// Spherecasting
|
||||
hit = GetSpherecastHit();
|
||||
|
||||
//normal = hit.normal;
|
||||
normal = transform.up;
|
||||
//groundDistance = r.position.y - hit.point.y;
|
||||
groundDistance = Vector3.Project(r.position - hit.point, transform.up).magnitude;
|
||||
|
||||
// if not jumping...
|
||||
bool findGround = Time.time > jumpEndTime && velocityY < jumpPower * 0.5f;
|
||||
|
||||
if (findGround) {
|
||||
bool g = onGround;
|
||||
onGround = false;
|
||||
|
||||
// The distance of considering the character grounded
|
||||
float groundHeight = !g? airborneThreshold * 0.5f: airborneThreshold;
|
||||
|
||||
//Vector3 horizontalVelocity = r.velocity;
|
||||
Vector3 horizontalVelocity = V3Tools.ExtractHorizontal(r.velocity, gravity, 1f);
|
||||
|
||||
float velocityF = horizontalVelocity.magnitude;
|
||||
|
||||
if (groundDistance < groundHeight) {
|
||||
// Force the character on the ground
|
||||
stickyForceTarget = groundStickyEffect * velocityF * groundHeight;
|
||||
|
||||
// On moving platforms
|
||||
if (hit.rigidbody != null) {
|
||||
platformVelocityTarget = hit.rigidbody.GetPointVelocity(hit.point);
|
||||
platformAngularVelocity = Vector3.Project(hit.rigidbody.angularVelocity, transform.up);
|
||||
}
|
||||
|
||||
// Flag the character grounded
|
||||
onGround = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Interpolate the additive velocity of the platform the character might be standing on
|
||||
platformVelocity = Vector3.Lerp(platformVelocity, platformVelocityTarget, Time.deltaTime * platformFriction);
|
||||
if (fullRootMotion) stickyForce = 0f;
|
||||
|
||||
stickyForce = stickyForceTarget;//Mathf.Lerp(stickyForce, stickyForceTarget, Time.deltaTime * 5f);
|
||||
|
||||
// remember when we were last in air, for jump delay
|
||||
if (!onGround) lastAirTime = Time.time;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d8f8cb876d2c742a9a5d9bfa03990ada
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,141 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
// The simplest multi-purpose locomotion controller for demo purposes. Can use root motion, simple procedural motion or the CharacterController
|
||||
public class SimpleLocomotion : MonoBehaviour {
|
||||
|
||||
// The character rotation mode
|
||||
[System.Serializable]
|
||||
public enum RotationMode {
|
||||
Smooth,
|
||||
Linear
|
||||
}
|
||||
|
||||
[Tooltip("The component that updates the camera.")]
|
||||
public CameraController cameraController;
|
||||
|
||||
[Tooltip("Acceleration of movement.")]
|
||||
public float accelerationTime = 0.2f;
|
||||
|
||||
[Tooltip("Turning speed.")]
|
||||
public float turnTime = 0.2f;
|
||||
|
||||
[Tooltip("If true, will run on left shift, if not will walk on left shift.")]
|
||||
public bool walkByDefault = true;
|
||||
|
||||
[Tooltip("Smooth or linear rotation.")]
|
||||
public RotationMode rotationMode;
|
||||
|
||||
[Tooltip("Procedural motion speed (if not using root motion).")]
|
||||
public float moveSpeed = 3f;
|
||||
|
||||
// Is the character grounded (using very simple y < something here for simplicity's sake)?
|
||||
public bool isGrounded { get; private set; }
|
||||
|
||||
private Animator animator;
|
||||
private float speed;
|
||||
private float angleVel;
|
||||
private float speedVel;
|
||||
private Vector3 linearTargetDirection;
|
||||
private CharacterController characterController;
|
||||
|
||||
void Start() {
|
||||
animator = GetComponent<Animator>();
|
||||
characterController = GetComponent<CharacterController>();
|
||||
cameraController.enabled = false;
|
||||
}
|
||||
|
||||
void Update() {
|
||||
// Very basic planar method, should use collision events
|
||||
isGrounded = transform.position.y < 0.1f;
|
||||
|
||||
Rotate();
|
||||
Move();
|
||||
}
|
||||
|
||||
void LateUpdate() {
|
||||
// Update the camera last
|
||||
cameraController.UpdateInput();
|
||||
cameraController.UpdateTransform();
|
||||
}
|
||||
|
||||
private void Rotate() {
|
||||
if (!isGrounded) return;
|
||||
|
||||
// Updating the rotation of the character
|
||||
Vector3 inputVector = GetInputVector();
|
||||
if (inputVector == Vector3.zero) return;
|
||||
|
||||
Vector3 forward = transform.forward;
|
||||
|
||||
switch(rotationMode) {
|
||||
case RotationMode.Smooth:
|
||||
Vector3 targetDirection = cameraController.transform.rotation * inputVector;
|
||||
|
||||
float angleForward = Mathf.Atan2(forward.x, forward.z) * Mathf.Rad2Deg;
|
||||
float angleTarget = Mathf.Atan2(targetDirection.x, targetDirection.z) * Mathf.Rad2Deg;
|
||||
|
||||
// Smoothly rotating the character
|
||||
float angle = Mathf.SmoothDampAngle(angleForward, angleTarget, ref angleVel, turnTime);
|
||||
transform.rotation = Quaternion.AngleAxis(angle, Vector3.up);
|
||||
|
||||
break;
|
||||
case RotationMode.Linear:
|
||||
Vector3 inputVectorRaw = GetInputVectorRaw();
|
||||
if (inputVectorRaw != Vector3.zero) linearTargetDirection = cameraController.transform.rotation * inputVectorRaw;
|
||||
|
||||
forward = Vector3.RotateTowards(forward, linearTargetDirection, Time.deltaTime * (1f /turnTime), 1f);
|
||||
forward.y = 0f;
|
||||
transform.rotation = Quaternion.LookRotation(forward);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void Move() {
|
||||
// Speed interpolation
|
||||
float speedTarget = walkByDefault? (Input.GetKey(KeyCode.LeftShift)? 1f: 0.5f): (Input.GetKey(KeyCode.LeftShift)? 0.5f: 1f);
|
||||
speed = Mathf.SmoothDamp(speed, speedTarget, ref speedVel, accelerationTime);
|
||||
|
||||
// Moving the character by root motion
|
||||
float s = GetInputVector().magnitude * speed;
|
||||
animator.SetFloat("Speed", s);
|
||||
|
||||
// Procedural motion if we don't have root motion
|
||||
bool proceduralMotion = !animator.hasRootMotion && isGrounded;
|
||||
|
||||
if (proceduralMotion) {
|
||||
Vector3 move = transform.forward * s * moveSpeed;
|
||||
|
||||
if (characterController != null) {
|
||||
characterController.SimpleMove(move);
|
||||
} else {
|
||||
transform.position += move * Time.deltaTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reads the Input to get the movement direction.
|
||||
private Vector3 GetInputVector() {
|
||||
Vector3 d = new Vector3(
|
||||
Input.GetAxis("Horizontal"),
|
||||
0f,
|
||||
Input.GetAxis("Vertical")
|
||||
);
|
||||
|
||||
d.z += Mathf.Abs(d.x) * 0.05f;
|
||||
d.x -= Mathf.Abs(d.z) * 0.05f;
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
private Vector3 GetInputVectorRaw() {
|
||||
return new Vector3(
|
||||
Input.GetAxisRaw("Horizontal"),
|
||||
0f,
|
||||
Input.GetAxisRaw("Vertical")
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eb82cec62d812495d878b167e9cdf49c
|
||||
timeCreated: 1434633542
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,55 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
/// <summary>
|
||||
/// User input for an AI controlled character controller.
|
||||
/// </summary>
|
||||
public class UserControlAI : UserControlThirdPerson {
|
||||
|
||||
public Transform moveTarget;
|
||||
public float stoppingDistance = 0.5f;
|
||||
public float stoppingThreshold = 1.5f;
|
||||
public Navigator navigator;
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
base.Start();
|
||||
|
||||
navigator.Initiate(transform);
|
||||
}
|
||||
|
||||
protected override void Update () {
|
||||
float moveSpeed = walkByDefault? 0.5f: 1f;
|
||||
|
||||
// If using Unity Navigation
|
||||
if (navigator.activeTargetSeeking)
|
||||
{
|
||||
navigator.Update(moveTarget.position);
|
||||
state.move = navigator.normalizedDeltaPosition * moveSpeed;
|
||||
}
|
||||
// No navigation, just move straight to the target
|
||||
else
|
||||
{
|
||||
Vector3 direction = moveTarget.position - transform.position;
|
||||
float distance = direction.magnitude;
|
||||
|
||||
Vector3 normal = transform.up;
|
||||
Vector3.OrthoNormalize(ref normal, ref direction);
|
||||
|
||||
float sD = state.move != Vector3.zero ? stoppingDistance : stoppingDistance * stoppingThreshold;
|
||||
|
||||
state.move = distance > sD ? direction * moveSpeed : Vector3.zero;
|
||||
state.lookPos = moveTarget.position;
|
||||
}
|
||||
}
|
||||
|
||||
// Visualize the navigator
|
||||
void OnDrawGizmos()
|
||||
{
|
||||
if (navigator.activeTargetSeeking) navigator.Visualize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c65b1ab317b6940d29112cc6fa332c1d
|
||||
timeCreated: 1438773513
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,63 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
/// <summary>
|
||||
/// User input for a third person character controller.
|
||||
/// </summary>
|
||||
public class UserControlThirdPerson : MonoBehaviour {
|
||||
|
||||
// Input state
|
||||
public struct State {
|
||||
public Vector3 move;
|
||||
public Vector3 lookPos;
|
||||
public bool crouch;
|
||||
public bool jump;
|
||||
public int actionIndex;
|
||||
}
|
||||
|
||||
public bool walkByDefault; // toggle for walking state
|
||||
public bool canCrouch = true;
|
||||
public bool canJump = true;
|
||||
|
||||
public State state = new State(); // The current state of the user input
|
||||
|
||||
protected Transform cam; // A reference to the main camera in the scenes transform
|
||||
|
||||
protected virtual void Start () {
|
||||
// get the transform of the main camera
|
||||
cam = Camera.main.transform;
|
||||
}
|
||||
|
||||
protected virtual void Update () {
|
||||
// read inputs
|
||||
state.crouch = canCrouch && Input.GetKey(KeyCode.C);
|
||||
state.jump = canJump && Input.GetButton("Jump");
|
||||
|
||||
float h = Input.GetAxisRaw("Horizontal");
|
||||
float v = Input.GetAxisRaw("Vertical");
|
||||
|
||||
// calculate move direction
|
||||
Vector3 move = cam.rotation * new Vector3(h, 0f, v).normalized;
|
||||
|
||||
// Flatten move vector to the character.up plane
|
||||
if (move != Vector3.zero) {
|
||||
Vector3 normal = transform.up;
|
||||
Vector3.OrthoNormalize(ref normal, ref move);
|
||||
state.move = move;
|
||||
} else state.move = Vector3.zero;
|
||||
|
||||
bool walkToggle = Input.GetKey(KeyCode.LeftShift);
|
||||
|
||||
// We select appropriate speed based on whether we're walking by default, and whether the walk/run toggle button is pressed:
|
||||
float walkMultiplier = (walkByDefault ? walkToggle ? 1 : 0.5f : walkToggle ? 0.5f : 1);
|
||||
|
||||
state.move *= walkMultiplier;
|
||||
|
||||
// calculate the head look target position
|
||||
state.lookPos = transform.position + cam.forward * 100f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bc555ffe423d44c2f983615b1af3cef4
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user