@@ -0,0 +1,257 @@
using System;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;
using UnityStandardAssets.Utility;
using Random = UnityEngine.Random;

namespace UnityStandardAssets.Characters.FirstPerson
{
[RequireComponent(typeof (CharacterController))]
[RequireComponent(typeof (AudioSource))]
public class FirstPersonController : MonoBehaviour
{
[SerializeField] private bool m_IsWalking;
[SerializeField] private float m_WalkSpeed;
[SerializeField] private float m_RunSpeed;
[SerializeField] [Range(0f, 1f)] private float m_RunstepLenghten;
[SerializeField] private float m_JumpSpeed;
[SerializeField] private float m_StickToGroundForce;
[SerializeField] private float m_GravityMultiplier;
[SerializeField] private MouseLook m_MouseLook;
[SerializeField] private bool m_UseFovKick;
[SerializeField] private FOVKick m_FovKick = new FOVKick();
[SerializeField] private bool m_UseHeadBob;
[SerializeField] private CurveControlledBob m_HeadBob = new CurveControlledBob();
[SerializeField] private LerpControlledBob m_JumpBob = new LerpControlledBob();
[SerializeField] private float m_StepInterval;
[SerializeField] private AudioClip[] m_FootstepSounds; // an array of footstep sounds that will be randomly selected from.
[SerializeField] private AudioClip m_JumpSound; // the sound played when character leaves the ground.
[SerializeField] private AudioClip m_LandSound; // the sound played when character touches back on ground.

private Camera m_Camera;
private bool m_Jump;
private float m_YRotation;
private Vector2 m_Input;
private Vector3 m_MoveDir = Vector3.zero;
private CharacterController m_CharacterController;
private CollisionFlags m_CollisionFlags;
private bool m_PreviouslyGrounded;
private Vector3 m_OriginalCameraPosition;
private float m_StepCycle;
private float m_NextStep;
private bool m_Jumping;
private AudioSource m_AudioSource;

// Use this for initialization
private void Start()
{
m_CharacterController = GetComponent<CharacterController>();
m_Camera = Camera.main;
m_OriginalCameraPosition = m_Camera.transform.localPosition;
m_FovKick.Setup(m_Camera);
m_HeadBob.Setup(m_Camera, m_StepInterval);
m_StepCycle = 0f;
m_NextStep = m_StepCycle/2f;
m_Jumping = false;
m_AudioSource = GetComponent<AudioSource>();
m_MouseLook.Init(transform , m_Camera.transform);
}


// Update is called once per frame
private void Update()
{
RotateView();
// the jump state needs to read here to make sure it is not missed
if (!m_Jump)
{
m_Jump = CrossPlatformInputManager.GetButtonDown("Jump");
}

if (!m_PreviouslyGrounded && m_CharacterController.isGrounded)
{
StartCoroutine(m_JumpBob.DoBobCycle());
PlayLandingSound();
m_MoveDir.y = 0f;
m_Jumping = false;
}
if (!m_CharacterController.isGrounded && !m_Jumping && m_PreviouslyGrounded)
{
m_MoveDir.y = 0f;
}

m_PreviouslyGrounded = m_CharacterController.isGrounded;
}


private void PlayLandingSound()
{
m_AudioSource.clip = m_LandSound;
m_AudioSource.Play();
m_NextStep = m_StepCycle + .5f;
}


private void FixedUpdate()
{
float speed;
GetInput(out speed);
// always move along the camera forward as it is the direction that it being aimed at
Vector3 desiredMove = transform.forward*m_Input.y + transform.right*m_Input.x;

// get a normal for the surface that is being touched to move along it
RaycastHit hitInfo;
Physics.SphereCast(transform.position, m_CharacterController.radius, Vector3.down, out hitInfo,
m_CharacterController.height/2f);
desiredMove = Vector3.ProjectOnPlane(desiredMove, hitInfo.normal).normalized;

m_MoveDir.x = desiredMove.x*speed;
m_MoveDir.z = desiredMove.z*speed;


if (m_CharacterController.isGrounded)
{
m_MoveDir.y = -m_StickToGroundForce;

if (m_Jump)
{
m_MoveDir.y = m_JumpSpeed;
PlayJumpSound();
m_Jump = false;
m_Jumping = true;
}
}
else
{
m_MoveDir += Physics.gravity*m_GravityMultiplier*Time.fixedDeltaTime;
}
m_CollisionFlags = m_CharacterController.Move(m_MoveDir*Time.fixedDeltaTime);

ProgressStepCycle(speed);
UpdateCameraPosition(speed);
}


private void PlayJumpSound()
{
m_AudioSource.clip = m_JumpSound;
m_AudioSource.Play();
}


private void ProgressStepCycle(float speed)
{
if (m_CharacterController.velocity.sqrMagnitude > 0 && (m_Input.x != 0 || m_Input.y != 0))
{
m_StepCycle += (m_CharacterController.velocity.magnitude + (speed*(m_IsWalking ? 1f : m_RunstepLenghten)))*
Time.fixedDeltaTime;
}

if (!(m_StepCycle > m_NextStep))
{
return;
}

m_NextStep = m_StepCycle + m_StepInterval;

PlayFootStepAudio();
}


private void PlayFootStepAudio()
{
if (!m_CharacterController.isGrounded)
{
return;
}
// pick & play a random footstep sound from the array,
// excluding sound at index 0
int n = Random.Range(1, m_FootstepSounds.Length);
m_AudioSource.clip = m_FootstepSounds[n];
m_AudioSource.PlayOneShot(m_AudioSource.clip);
// move picked sound to index 0 so it's not picked next time
m_FootstepSounds[n] = m_FootstepSounds[0];
m_FootstepSounds[0] = m_AudioSource.clip;
}


private void UpdateCameraPosition(float speed)
{
Vector3 newCameraPosition;
if (!m_UseHeadBob)
{
return;
}
if (m_CharacterController.velocity.magnitude > 0 && m_CharacterController.isGrounded)
{
m_Camera.transform.localPosition =
m_HeadBob.DoHeadBob(m_CharacterController.velocity.magnitude +
(speed*(m_IsWalking ? 1f : m_RunstepLenghten)));
newCameraPosition = m_Camera.transform.localPosition;
newCameraPosition.y = m_Camera.transform.localPosition.y - m_JumpBob.Offset();
}
else
{
newCameraPosition = m_Camera.transform.localPosition;
newCameraPosition.y = m_OriginalCameraPosition.y - m_JumpBob.Offset();
}
m_Camera.transform.localPosition = newCameraPosition;
}


private void GetInput(out float speed)
{
// Read input
float horizontal = CrossPlatformInputManager.GetAxis("Horizontal");
float vertical = CrossPlatformInputManager.GetAxis("Vertical");

bool waswalking = m_IsWalking;

#if !MOBILE_INPUT
// On standalone builds, walk/run speed is modified by a key press.
// keep track of whether or not the character is walking or running
m_IsWalking = !Input.GetKey(KeyCode.LeftShift);
#endif
// set the desired speed to be walking or running
speed = m_IsWalking ? m_WalkSpeed : m_RunSpeed;
m_Input = new Vector2(horizontal, vertical);

// normalize input if it exceeds 1 in combined length:
if (m_Input.sqrMagnitude > 1)
{
m_Input.Normalize();
}

// handle speed change to give an fov kick
// only if the player is going to a run, is running and the fovkick is to be used
if (m_IsWalking != waswalking && m_UseFovKick && m_CharacterController.velocity.sqrMagnitude > 0)
{
StopAllCoroutines();
StartCoroutine(!m_IsWalking ? m_FovKick.FOVKickUp() : m_FovKick.FOVKickDown());
}
}


private void RotateView()
{
m_MouseLook.LookRotation (transform, m_Camera.transform);
}


private void OnControllerColliderHit(ControllerColliderHit hit)
{
Rigidbody body = hit.collider.attachedRigidbody;
//dont move the rigidbody if the character is on top of it
if (m_CollisionFlags == CollisionFlags.Below)
{
return;
}

if (body == null || body.isKinematic)
{
return;
}
body.AddForceAtPosition(m_CharacterController.velocity*0.1f, hit.point, ForceMode.Impulse);
}
}
}
@@ -0,0 +1,55 @@
using System;
using UnityEngine;
using UnityStandardAssets.Utility;

namespace UnityStandardAssets.Characters.FirstPerson
{
public class HeadBob : MonoBehaviour
{
public Camera Camera;
public CurveControlledBob motionBob = new CurveControlledBob();
public LerpControlledBob jumpAndLandingBob = new LerpControlledBob();
public RigidbodyFirstPersonController rigidbodyFirstPersonController;
public float StrideInterval;
[Range(0f, 1f)] public float RunningStrideLengthen;

// private CameraRefocus m_CameraRefocus;
private bool m_PreviouslyGrounded;
private Vector3 m_OriginalCameraPosition;


private void Start()
{
motionBob.Setup(Camera, StrideInterval);
m_OriginalCameraPosition = Camera.transform.localPosition;
// m_CameraRefocus = new CameraRefocus(Camera, transform.root.transform, Camera.transform.localPosition);
}


private void Update()
{
// m_CameraRefocus.GetFocusPoint();
Vector3 newCameraPosition;
if (rigidbodyFirstPersonController.Velocity.magnitude > 0 && rigidbodyFirstPersonController.Grounded)
{
Camera.transform.localPosition = motionBob.DoHeadBob(rigidbodyFirstPersonController.Velocity.magnitude*(rigidbodyFirstPersonController.Running ? RunningStrideLengthen : 1f));
newCameraPosition = Camera.transform.localPosition;
newCameraPosition.y = Camera.transform.localPosition.y - jumpAndLandingBob.Offset();
}
else
{
newCameraPosition = Camera.transform.localPosition;
newCameraPosition.y = m_OriginalCameraPosition.y - jumpAndLandingBob.Offset();
}
Camera.transform.localPosition = newCameraPosition;

if (!m_PreviouslyGrounded && rigidbodyFirstPersonController.Grounded)
{
StartCoroutine(jumpAndLandingBob.DoBobCycle());
}

m_PreviouslyGrounded = rigidbodyFirstPersonController.Grounded;
// m_CameraRefocus.SetFocusPoint();
}
}
}
@@ -0,0 +1,73 @@
using System;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;

namespace UnityStandardAssets.Characters.FirstPerson
{
[Serializable]
public class MouseLook
{
public float XSensitivity = 2f;
public float YSensitivity = 2f;
public bool clampVerticalRotation = true;
public float MinimumX = -90F;
public float MaximumX = 90F;
public bool smooth;
public float smoothTime = 5f;


private Quaternion m_CharacterTargetRot;
private Quaternion m_CameraTargetRot;


public void Init(Transform character, Transform camera)
{
m_CharacterTargetRot = character.localRotation;
m_CameraTargetRot = camera.localRotation;
}


public void LookRotation(Transform character, Transform camera)
{
float yRot = CrossPlatformInputManager.GetAxis("Mouse X") * XSensitivity;
float xRot = CrossPlatformInputManager.GetAxis("Mouse Y") * YSensitivity;

m_CharacterTargetRot *= Quaternion.Euler (0f, yRot, 0f);
m_CameraTargetRot *= Quaternion.Euler (-xRot, 0f, 0f);

if(clampVerticalRotation)
m_CameraTargetRot = ClampRotationAroundXAxis (m_CameraTargetRot);

if(smooth)
{
character.localRotation = Quaternion.Slerp (character.localRotation, m_CharacterTargetRot,
smoothTime * Time.deltaTime);
camera.localRotation = Quaternion.Slerp (camera.localRotation, m_CameraTargetRot,
smoothTime * Time.deltaTime);
}
else
{
character.localRotation = m_CharacterTargetRot;
camera.localRotation = m_CameraTargetRot;
}
}


Quaternion ClampRotationAroundXAxis(Quaternion q)
{
q.x /= q.w;
q.y /= q.w;
q.z /= q.w;
q.w = 1.0f;

float angleX = 2.0f * Mathf.Rad2Deg * Mathf.Atan (q.x);

angleX = Mathf.Clamp (angleX, MinimumX, MaximumX);

q.x = Mathf.Tan (0.5f * Mathf.Deg2Rad * angleX);

return q;
}

}
}
@@ -0,0 +1,264 @@
using System;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;

namespace UnityStandardAssets.Characters.FirstPerson
{
[RequireComponent(typeof (Rigidbody))]
[RequireComponent(typeof (CapsuleCollider))]
public class RigidbodyFirstPersonController : MonoBehaviour
{
[Serializable]
public class MovementSettings
{
public float ForwardSpeed = 8.0f; // Speed when walking forward
public float BackwardSpeed = 4.0f; // Speed when walking backwards
public float StrafeSpeed = 4.0f; // Speed when walking sideways
public float RunMultiplier = 2.0f; // Speed when sprinting
public KeyCode RunKey = KeyCode.LeftShift;
public float JumpForce = 30f;
public AnimationCurve SlopeCurveModifier = new AnimationCurve(new Keyframe(-90.0f, 1.0f), new Keyframe(0.0f, 1.0f), new Keyframe(90.0f, 0.0f));
[HideInInspector] public float CurrentTargetSpeed = 8f;

#if !MOBILE_INPUT
private bool m_Running;
#endif

public void UpdateDesiredTargetSpeed(Vector2 input)
{
if (input == Vector2.zero) return;
if (input.x > 0 || input.x < 0)
{
//strafe
CurrentTargetSpeed = StrafeSpeed;
}
if (input.y < 0)
{
//backwards
CurrentTargetSpeed = BackwardSpeed;
}
if (input.y > 0)
{
//forwards
//handled last as if strafing and moving forward at the same time forwards speed should take precedence
CurrentTargetSpeed = ForwardSpeed;
}
#if !MOBILE_INPUT
if (Input.GetKey(RunKey))
{
CurrentTargetSpeed *= RunMultiplier;
m_Running = true;
}
else
{
m_Running = false;
}
#endif
}

#if !MOBILE_INPUT
public bool Running
{
get { return m_Running; }
}
#endif
}


[Serializable]
public class AdvancedSettings
{
public float groundCheckDistance = 0.01f; // distance for checking if the controller is grounded ( 0.01f seems to work best for this )
public float stickToGroundHelperDistance = 0.5f; // stops the character
public float slowDownRate = 20f; // rate at which the controller comes to a stop when there is no input
public bool airControl; // can the user control the direction that is being moved in the air
}


public Camera cam;
public MovementSettings movementSettings = new MovementSettings();
public MouseLook mouseLook = new MouseLook();
public AdvancedSettings advancedSettings = new AdvancedSettings();


private Rigidbody m_RigidBody;
private CapsuleCollider m_Capsule;
private float m_YRotation;
private Vector3 m_GroundContactNormal;
private bool m_Jump, m_PreviouslyGrounded, m_Jumping, m_IsGrounded;


public Vector3 Velocity
{
get { return m_RigidBody.velocity; }
}

public bool Grounded
{
get { return m_IsGrounded; }
}

public bool Jumping
{
get { return m_Jumping; }
}

public bool Running
{
get
{
#if !MOBILE_INPUT
return movementSettings.Running;
#else
return false;
#endif
}
}


private void Start()
{
m_RigidBody = GetComponent<Rigidbody>();
m_Capsule = GetComponent<CapsuleCollider>();
mouseLook.Init (transform, cam.transform);
}


private void Update()
{
RotateView();

if (CrossPlatformInputManager.GetButtonDown("Jump") && !m_Jump)
{
m_Jump = true;
}
}


private void FixedUpdate()
{
GroundCheck();
Vector2 input = GetInput();

if ((Mathf.Abs(input.x) > float.Epsilon || Mathf.Abs(input.y) > float.Epsilon) && (advancedSettings.airControl || m_IsGrounded))
{
// always move along the camera forward as it is the direction that it being aimed at
Vector3 desiredMove = cam.transform.forward*input.y + cam.transform.right*input.x;
desiredMove = Vector3.ProjectOnPlane(desiredMove, m_GroundContactNormal).normalized;

desiredMove.x = desiredMove.x*movementSettings.CurrentTargetSpeed;
desiredMove.z = desiredMove.z*movementSettings.CurrentTargetSpeed;
desiredMove.y = desiredMove.y*movementSettings.CurrentTargetSpeed;
if (m_RigidBody.velocity.sqrMagnitude <
(movementSettings.CurrentTargetSpeed*movementSettings.CurrentTargetSpeed))
{
m_RigidBody.AddForce(desiredMove*SlopeMultiplier(), ForceMode.Impulse);
}
}

if (m_IsGrounded)
{
m_RigidBody.drag = 5f;

if (m_Jump)
{
m_RigidBody.drag = 0f;
m_RigidBody.velocity = new Vector3(m_RigidBody.velocity.x, 0f, m_RigidBody.velocity.z);
m_RigidBody.AddForce(new Vector3(0f, movementSettings.JumpForce, 0f), ForceMode.Impulse);
m_Jumping = true;
}

if (!m_Jumping && Mathf.Abs(input.x) < float.Epsilon && Mathf.Abs(input.y) < float.Epsilon && m_RigidBody.velocity.magnitude < 1f)
{
m_RigidBody.Sleep();
}
}
else
{
m_RigidBody.drag = 0f;
if (m_PreviouslyGrounded && !m_Jumping)
{
StickToGroundHelper();
}
}
m_Jump = false;
}


private float SlopeMultiplier()
{
float angle = Vector3.Angle(m_GroundContactNormal, Vector3.up);
return movementSettings.SlopeCurveModifier.Evaluate(angle);
}


private void StickToGroundHelper()
{
RaycastHit hitInfo;
if (Physics.SphereCast(transform.position, m_Capsule.radius, Vector3.down, out hitInfo,
((m_Capsule.height/2f) - m_Capsule.radius) +
advancedSettings.stickToGroundHelperDistance))
{
if (Mathf.Abs(Vector3.Angle(hitInfo.normal, Vector3.up)) < 85f)
{
m_RigidBody.velocity = Vector3.ProjectOnPlane(m_RigidBody.velocity, hitInfo.normal);
}
}
}


private Vector2 GetInput()
{

Vector2 input = new Vector2
{
x = CrossPlatformInputManager.GetAxis("Horizontal"),
y = CrossPlatformInputManager.GetAxis("Vertical")
};
movementSettings.UpdateDesiredTargetSpeed(input);
return input;
}


private void RotateView()
{
//avoids the mouse looking if the game is effectively paused
if (Mathf.Abs(Time.timeScale) < float.Epsilon) return;

// get the rotation before it's changed
float oldYRotation = transform.eulerAngles.y;

mouseLook.LookRotation (transform, cam.transform);

if (m_IsGrounded || advancedSettings.airControl)
{
// Rotate the rigidbody velocity to match the new direction that the character is looking
Quaternion velRotation = Quaternion.AngleAxis(transform.eulerAngles.y - oldYRotation, Vector3.up);
m_RigidBody.velocity = velRotation*m_RigidBody.velocity;
}
}


/// sphere cast down just beyond the bottom of the capsule to see if the capsule is colliding round the bottom
private void GroundCheck()
{
m_PreviouslyGrounded = m_IsGrounded;
RaycastHit hitInfo;
if (Physics.SphereCast(transform.position, m_Capsule.radius, Vector3.down, out hitInfo,
((m_Capsule.height/2f) - m_Capsule.radius) + advancedSettings.groundCheckDistance))
{
m_IsGrounded = true;
m_GroundContactNormal = hitInfo.normal;
}
else
{
m_IsGrounded = false;
m_GroundContactNormal = Vector3.up;
}
if (!m_PreviouslyGrounded && m_IsGrounded && m_Jumping)
{
m_Jumping = false;
}
}
}
}
@@ -0,0 +1,196 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 5
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: RollerBallGrey
m_Shader: {fileID: 45, guid: 0000000000000000f000000000000000, type: 0}
m_ShaderKeywords: _LIGHTMAPPING_BAKED _LIGHTMAPPING_STATIC_LIGHTMAPS _UVPRIM_UV1
_UVSEC_UV1
m_LightmapFlags: 0
m_CustomRenderQueue: -1
m_SavedProperties:
serializedVersion: 2
m_TexEnvs:
data:
first:
name: _MainTex
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _BumpMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _DetailNormalMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _ParallaxMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _OcclusionMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _EmissionMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _DetailMask
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _DetailAlbedoMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _Occlusion
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _MetallicGlossMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _SpecGlossMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Floats:
data:
first:
name: _Cutoff
second: .5
data:
first:
name: _AlphaTestRef
second: .5
data:
first:
name: _SrcBlend
second: 1
data:
first:
name: _DstBlend
second: 0
data:
first:
name: _Parallax
second: .0199999996
data:
first:
name: _ZWrite
second: 1
data:
first:
name: _Glossiness
second: .349999994
data:
first:
name: _BumpScale
second: 1
data:
first:
name: _OcclusionStrength
second: 1
data:
first:
name: _DetailNormalMapScale
second: 1
data:
first:
name: _UVSec
second: 0
data:
first:
name: _EmissionScaleUI
second: 1
data:
first:
name: _Mode
second: 0
data:
first:
name: _Metallic
second: 0
data:
first:
name: _Lightmapping
second: 0
data:
first:
name: _EmissionScale
second: 1
data:
first:
name: _DetailAlbedoMultiplier
second: 2
data:
first:
name: _UVPrim
second: 0
data:
first:
name: _DetailMode
second: 0
m_Colors:
data:
first:
name: _EmissionColor
second: {r: 0, g: 0, b: 0, a: 1}
data:
first:
name: _Color
second: {r: .498039216, g: .498039216, b: .498039216, a: 1}
data:
first:
name: _SpecColor
second: {r: .551470578, g: .551470578, b: .551470578, a: 1}
data:
first:
name: _EmissionColorUI
second: {r: 0, g: 0, b: 0, a: 1}
data:
first:
name: _EmissionColorWithMapUI
second: {r: 1, g: 1, b: 1, a: 1}
data:
first:
name: _SpecularColor
second: {r: .0588235259, g: .0588235259, b: .0588235259, a: 1}
@@ -0,0 +1,191 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 4
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: RollerBallWhite
m_Shader: {fileID: 45, guid: 0000000000000000f000000000000000, type: 0}
m_ShaderKeywords: _LIGHTMAPPING_BAKED _LIGHTMAPPING_STATIC_LIGHTMAPS _UVPRIM_UV1
_UVSEC_UV1
m_CustomRenderQueue: -1
m_SavedProperties:
serializedVersion: 2
m_TexEnvs:
data:
first:
name: _MainTex
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _BumpMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _DetailNormalMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _EmissionMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _ParallaxMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _Occlusion
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _SpecGlossMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _DetailMask
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _DetailAlbedoMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _OcclusionMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _MetallicGlossMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Floats:
data:
first:
name: _AlphaTestRef
second: .5
data:
first:
name: _Lightmapping
second: 0
data:
first:
name: _SrcBlend
second: 1
data:
first:
name: _DstBlend
second: 0
data:
first:
name: _Parallax
second: .0199999996
data:
first:
name: _ZWrite
second: 1
data:
first:
name: _Glossiness
second: .200000003
data:
first:
name: _BumpScale
second: 1
data:
first:
name: _OcclusionStrength
second: 1
data:
first:
name: _DetailNormalMapScale
second: 1
data:
first:
name: _UVSec
second: 0
data:
first:
name: _Mode
second: 0
data:
first:
name: _EmissionScaleUI
second: 1
data:
first:
name: _Metallic
second: 0
data:
first:
name: _EmissionScale
second: 1
data:
first:
name: _DetailAlbedoMultiplier
second: 2
data:
first:
name: _UVPrim
second: 0
data:
first:
name: _DetailMode
second: 0
m_Colors:
data:
first:
name: _EmissionColor
second: {r: 0, g: 0, b: 0, a: 1}
data:
first:
name: _Color
second: {r: 1, g: 1, b: 1, a: 1}
data:
first:
name: _SpecularColor
second: {r: .0588235259, g: .0588235259, b: .0588235259, a: 1}
data:
first:
name: _EmissionColorUI
second: {r: 0, g: 0, b: 0, a: 1}
data:
first:
name: _EmissionColorWithMapUI
second: {r: 1, g: 1, b: 1, a: 1}
data:
first:
name: _SpecColor
second: {r: .235294119, g: .235294119, b: .235294119, a: 1}
Binary file not shown.
@@ -0,0 +1,130 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &100000
GameObject:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
serializedVersion: 4
m_Component:
- 4: {fileID: 400000}
- 33: {fileID: 3300000}
- 23: {fileID: 2300000}
- 135: {fileID: 13500000}
- 54: {fileID: 5400000}
- 114: {fileID: 11400000}
- 114: {fileID: 11400002}
m_Layer: 9
m_Name: RollerBall
m_TagString: Player
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &400000
Transform:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 100000}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 5.40025711, y: -3.13121223, z: -.992190003}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0
--- !u!23 &2300000
MeshRenderer:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 100000}
m_Enabled: 1
m_CastShadows: 1
m_ReceiveShadows: 1
m_Materials:
- {fileID: 2100000, guid: 6fd099d339b4ae34692c8258e4f87531, type: 2}
m_SubsetIndices:
m_StaticBatchRoot: {fileID: 0}
m_UseLightProbes: 0
m_ReflectionProbeUsage: 1
m_ProbeAnchor: {fileID: 0}
m_ScaleInLightmap: 1
m_PreserveUVs: 0
m_ImportantGI: 0
m_AutoUVMaxDistance: .5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_SortingLayerID: 0
m_SortingOrder: 0
--- !u!33 &3300000
MeshFilter:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 100000}
m_Mesh: {fileID: 4300052, guid: d05d496cb4f43c14e80630addd23652e, type: 3}
--- !u!54 &5400000
Rigidbody:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 100000}
serializedVersion: 2
m_Mass: 1
m_Drag: .100000001
m_AngularDrag: 1
m_UseGravity: 1
m_IsKinematic: 0
m_Interpolate: 0
m_Constraints: 0
m_CollisionDetection: 0
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 100000}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: e004fefca5c7ba44d9c5ffd46fdee2ed, type: 3}
m_Name:
m_EditorClassIdentifier:
m_MovePower: 5
m_UseTorque: 1
m_MaxAngularVelocity: 25
m_JumpPower: 4
--- !u!114 &11400002
MonoBehaviour:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 100000}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: daa7e0829bc72c94babd728cc0466196, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!135 &13500000
SphereCollider:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 100000}
m_Material: {fileID: 13400000, guid: 52baaeb214519f347a35cf0edfd262ff, type: 2}
m_IsTrigger: 0
m_Enabled: 1
serializedVersion: 2
m_Radius: .5
m_Center: {x: 0, y: 0, z: 0}
--- !u!1001 &100100000
Prefab:
m_ObjectHideFlags: 1
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 0}
m_Modifications: []
m_RemovedComponents: []
m_ParentPrefab: {fileID: 0}
m_RootGameObject: {fileID: 100000}
m_IsPrefabParent: 1
@@ -0,0 +1,15 @@
The RollerBall prefab is a very simple controllable example which is designed to be used as-is. Just drop the prefab into your scene and you're good to go. It's designed as a minimal demonstration of using our Cross Platform Input scripts, and to demonstrate the way we've chosen to separate the input from the mechanics of the controller, so that you're free to swap in other input styles or AI controls.

The ball converts its input to camera-relative motion, so it works fine with any of the camera rigs provided - even the CCTV Camera Rig!

The simplest way to get started with the rolling ball controller is to:

1) Start with a suitable scene. There ought to be enough flat ground to roll around on.

2) Place the "RollerBall" prefab in the scene.

3) Place a camera rig in the scene, from the Cameras folder.

4) If present, delete the "Main Camera" that exists in new scenes by default. The camera rigs contain their own camera, so you don't need the default camera.

There are a number of simple adjustable settings on the Ball allowing you to change the handling and jump power. For more information, see the comments in the script.
@@ -0,0 +1,47 @@
using System;
using UnityEngine;

namespace UnityStandardAssets.Vehicles.Ball
{
public class Ball : MonoBehaviour
{
[SerializeField] private float m_MovePower = 5; // The force added to the ball to move it.
[SerializeField] private bool m_UseTorque = true; // Whether or not to use torque to move the ball.
[SerializeField] private float m_MaxAngularVelocity = 25; // The maximum velocity the ball can rotate at.
[SerializeField] private float m_JumpPower = 2; // The force added to the ball when it jumps.

private const float k_GroundRayLength = 1f; // The length of the ray to check if the ball is grounded.
private Rigidbody m_Rigidbody;


private void Start()
{
m_Rigidbody = GetComponent<Rigidbody>();
// Set the maximum angular velocity.
GetComponent<Rigidbody>().maxAngularVelocity = m_MaxAngularVelocity;
}


public void Move(Vector3 moveDirection, bool jump)
{
// If using torque to rotate the ball...
if (m_UseTorque)
{
// ... add torque around the axis defined by the move direction.
m_Rigidbody.AddTorque(new Vector3(moveDirection.z, 0, -moveDirection.x)*m_MovePower);
}
else
{
// Otherwise add force in the move direction.
m_Rigidbody.AddForce(moveDirection*m_MovePower);
}

// If on the ground and jump is pressed...
if (Physics.Raycast(transform.position, -Vector3.up, k_GroundRayLength) && jump)
{
// ... add force in upwards.
m_Rigidbody.AddForce(Vector3.up*m_JumpPower, ForceMode.Impulse);
}
}
}
}
@@ -0,0 +1,69 @@
using System;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;

namespace UnityStandardAssets.Vehicles.Ball
{
public class BallUserControl : MonoBehaviour
{
private Ball ball; // Reference to the ball controller.

private Vector3 move;
// the world-relative desired move direction, calculated from the camForward and user input.

private Transform cam; // A reference to the main camera in the scenes transform
private Vector3 camForward; // The current forward direction of the camera
private bool jump; // whether the jump button is currently pressed


private void Awake()
{
// Set up the reference.
ball = GetComponent<Ball>();


// get the transform of the main camera
if (Camera.main != null)
{
cam = Camera.main.transform;
}
else
{
Debug.LogWarning(
"Warning: no main camera found. Ball needs a Camera tagged \"MainCamera\", for camera-relative controls.");
// we use world-relative controls in this case, which may not be what the user wants, but hey, we warned them!
}
}


private void Update()
{
// Get the axis and jump input.

float h = CrossPlatformInputManager.GetAxis("Horizontal");
float v = CrossPlatformInputManager.GetAxis("Vertical");
jump = CrossPlatformInputManager.GetButton("Jump");

// calculate move direction
if (cam != null)
{
// calculate camera relative direction to move:
camForward = Vector3.Scale(cam.forward, new Vector3(1, 0, 1)).normalized;
move = (v*camForward + h*cam.right).normalized;
}
else
{
// we use world-relative directions in the case of no main camera
move = (v*Vector3.forward + h*Vector3.right).normalized;
}
}


private void FixedUpdate()
{
// Call the Move function of the ball controller
ball.Move(move, jump);
jump = false;
}
}
}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.

Large diffs are not rendered by default.

Binary file not shown.

Large diffs are not rendered by default.

Binary file not shown.

Large diffs are not rendered by default.

Binary file not shown.

Large diffs are not rendered by default.

Binary file not shown.

Large diffs are not rendered by default.

Binary file not shown.

Large diffs are not rendered by default.

Binary file not shown.

Large diffs are not rendered by default.

Binary file not shown.

Large diffs are not rendered by default.

Binary file not shown.

Large diffs are not rendered by default.

Binary file not shown.

Large diffs are not rendered by default.

Binary file not shown.

Large diffs are not rendered by default.

Binary file not shown.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

@@ -0,0 +1,194 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 4
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: EthanGrey
m_Shader: {fileID: 45, guid: 0000000000000000f000000000000000, type: 0}
m_ShaderKeywords: _LIGHTMAPPING_STATIC_LIGHTMAPS _NORMALMAP _UVPRIM_UV1 _UVSEC_UV1
m_CustomRenderQueue: -1
m_SavedProperties:
serializedVersion: 2
m_TexEnvs:
data:
first:
name: _MainTex
second:
m_Texture: {fileID: 2800000, guid: 0ca09a4614a0daa44ba043de90181896, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _BumpMap
second:
m_Texture: {fileID: 2800000, guid: 3b5b7be0f2332c24f89a2af018daa62d, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _DetailNormalMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _EmissionMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _ParallaxMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _Occlusion
second:
m_Texture: {fileID: 2800000, guid: 4e2f32e9a1fefc24092337ae061f3dbc, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _SpecGlossMap
second:
m_Texture: {fileID: 2800000, guid: c6093d6055cd6a44ebf0637f17fca0e8, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _DetailMask
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _DetailAlbedoMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _Cube
second:
m_Texture: {fileID: 8900000, guid: 6c5668bb9f9669342bfdd3eaddebb56b, type: 2}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _OcclusionMap
second:
m_Texture: {fileID: 2800000, guid: 4e2f32e9a1fefc24092337ae061f3dbc, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Floats:
data:
first:
name: _Shininess
second: .413138449
data:
first:
name: _AlphaTestRef
second: .5
data:
first:
name: _Lightmapping
second: 0
data:
first:
name: _SrcBlend
second: 1
data:
first:
name: _DstBlend
second: 0
data:
first:
name: _Parallax
second: .0199999996
data:
first:
name: _ZWrite
second: 1
data:
first:
name: _Glossiness
second: .150000006
data:
first:
name: _BumpScale
second: 1
data:
first:
name: _OcclusionStrength
second: 1
data:
first:
name: _DetailNormalMapScale
second: 1
data:
first:
name: _UVSec
second: 0
data:
first:
name: _Mode
second: 0
data:
first:
name: _EmissionScaleUI
second: 1
data:
first:
name: _EmissionScale
second: 1
data:
first:
name: _DetailAlbedoMultiplier
second: 2
data:
first:
name: _UVPrim
second: 0
data:
first:
name: _DetailMode
second: 0
m_Colors:
data:
first:
name: _EmissionColor
second: {r: 0, g: 0, b: 0, a: .99999994}
data:
first:
name: _Color
second: {r: .498039216, g: .498039216, b: .498039216, a: 1}
data:
first:
name: _SpecularColor
second: {r: .242647052, g: .242647052, b: .242647052, a: 1}
data:
first:
name: _EmissionColorUI
second: {r: 0, g: 0, b: 0, a: 1}
data:
first:
name: _EmissionColorWithMapUI
second: {r: 1, g: 1, b: 1, a: 1}
data:
first:
name: _SpecColor
second: {r: .0980392173, g: .0980392173, b: .0980392173, a: 1}
data:
first:
name: _ReflectColor
second: {r: 1, g: 1, b: 1, a: .5}
@@ -0,0 +1,194 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 4
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: EthanWhite
m_Shader: {fileID: 45, guid: 0000000000000000f000000000000000, type: 0}
m_ShaderKeywords: _LIGHTMAPPING_STATIC_LIGHTMAPS _NORMALMAP _UVPRIM_UV1 _UVSEC_UV1
m_CustomRenderQueue: -1
m_SavedProperties:
serializedVersion: 2
m_TexEnvs:
data:
first:
name: _MainTex
second:
m_Texture: {fileID: 2800000, guid: 0ca09a4614a0daa44ba043de90181896, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _BumpMap
second:
m_Texture: {fileID: 2800000, guid: 3b5b7be0f2332c24f89a2af018daa62d, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _DetailNormalMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _EmissionMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _ParallaxMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _Occlusion
second:
m_Texture: {fileID: 2800000, guid: 4e2f32e9a1fefc24092337ae061f3dbc, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _SpecGlossMap
second:
m_Texture: {fileID: 2800000, guid: c6093d6055cd6a44ebf0637f17fca0e8, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _DetailMask
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _DetailAlbedoMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _Cube
second:
m_Texture: {fileID: 8900000, guid: 6c5668bb9f9669342bfdd3eaddebb56b, type: 2}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _OcclusionMap
second:
m_Texture: {fileID: 2800000, guid: 4e2f32e9a1fefc24092337ae061f3dbc, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Floats:
data:
first:
name: _Shininess
second: .413138449
data:
first:
name: _AlphaTestRef
second: .5
data:
first:
name: _Lightmapping
second: 0
data:
first:
name: _SrcBlend
second: 1
data:
first:
name: _DstBlend
second: 0
data:
first:
name: _Parallax
second: .0199999996
data:
first:
name: _ZWrite
second: 1
data:
first:
name: _Glossiness
second: .150000006
data:
first:
name: _BumpScale
second: 1
data:
first:
name: _OcclusionStrength
second: 1
data:
first:
name: _DetailNormalMapScale
second: 1
data:
first:
name: _UVSec
second: 0
data:
first:
name: _Mode
second: 0
data:
first:
name: _EmissionScaleUI
second: 1
data:
first:
name: _EmissionScale
second: 1
data:
first:
name: _DetailAlbedoMultiplier
second: 2
data:
first:
name: _UVPrim
second: 0
data:
first:
name: _DetailMode
second: 0
m_Colors:
data:
first:
name: _EmissionColor
second: {r: 0, g: 0, b: 0, a: .99999994}
data:
first:
name: _Color
second: {r: 1, g: 1, b: 1, a: 1}
data:
first:
name: _SpecularColor
second: {r: .242647052, g: .242647052, b: .242647052, a: 1}
data:
first:
name: _EmissionColorUI
second: {r: 0, g: 0, b: 0, a: 1}
data:
first:
name: _EmissionColorWithMapUI
second: {r: 1, g: 1, b: 1, a: 1}
data:
first:
name: _SpecColor
second: {r: .0980392173, g: .0980392173, b: .0980392173, a: 1}
data:
first:
name: _ReflectColor
second: {r: 1, g: 1, b: 1, a: .5}
Binary file not shown.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

@@ -0,0 +1,52 @@
using System;
using UnityEngine;

namespace UnityStandardAssets.Characters.ThirdPerson
{
[RequireComponent(typeof (NavMeshAgent))]
[RequireComponent(typeof (ThirdPersonCharacter))]
public class AICharacterControl : MonoBehaviour
{
public NavMeshAgent agent { get; private set; } // the navmesh agent required for the path finding
public ThirdPersonCharacter character { get; private set; } // the character we are controlling
public Transform target; // target to aim for

// Use this for initialization
private void Start()
{
// get the components on the object we need ( should not be null due to require component so no need to check )
agent = GetComponentInChildren<NavMeshAgent>();
character = GetComponent<ThirdPersonCharacter>();

agent.updateRotation = false;
agent.updatePosition = true;
}


// Update is called once per frame
private void Update()
{
if (target != null)
{
agent.SetDestination(target.position);



// use the values to move the character
character.Move(agent.desiredVelocity, false, false);
}
else
{
// We still need to call the character's move function, but we send zeroed input as the move param.
character.Move(Vector3.zero, false, false);
}

}


public void SetTarget(Transform target)
{
this.target = target;
}
}
}
@@ -0,0 +1,225 @@
using UnityEngine;

namespace UnityStandardAssets.Characters.ThirdPerson
{
[RequireComponent(typeof(Rigidbody))]
[RequireComponent(typeof(CapsuleCollider))]
[RequireComponent(typeof(Animator))]
public class ThirdPersonCharacter : MonoBehaviour
{
[SerializeField] float m_MovingTurnSpeed = 360;
[SerializeField] float m_StationaryTurnSpeed = 180;
[SerializeField] float m_JumpPower = 12f;
[Range(1f, 4f)][SerializeField] float m_GravityMultiplier = 2f;
[SerializeField] float m_RunCycleLegOffset = 0.2f; //specific to the character in sample assets, will need to be modified to work with others
[SerializeField] float m_MoveSpeedMultiplier = 1f;
[SerializeField] float m_AnimSpeedMultiplier = 1f;
[SerializeField] float m_GroundCheckDistance = 0.1f;

Rigidbody m_Rigidbody;
Animator m_Animator;
bool m_IsGrounded;
float m_OrigGroundCheckDistance;
const float k_Half = 0.5f;
float m_TurnAmount;
float m_ForwardAmount;
Vector3 m_GroundNormal;
float m_CapsuleHeight;
Vector3 m_CapsuleCenter;
CapsuleCollider m_Capsule;
bool m_Crouching;


void Start()
{
m_Animator = GetComponent<Animator>();
m_Rigidbody = GetComponent<Rigidbody>();
m_Capsule = GetComponent<CapsuleCollider>();
m_CapsuleHeight = m_Capsule.height;
m_CapsuleCenter = m_Capsule.center;

m_Rigidbody.constraints = RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezeRotationY | RigidbodyConstraints.FreezeRotationZ;
m_OrigGroundCheckDistance = m_GroundCheckDistance;
}


public void Move(Vector3 move, bool crouch, bool jump)
{

// convert the world relative moveInput vector into a local-relative
// turn amount and forward amount required to head in the desired
// direction.
if (move.magnitude > 1f) move.Normalize();
move = transform.InverseTransformDirection(move);
CheckGroundStatus();
move = Vector3.ProjectOnPlane(move, m_GroundNormal);
m_TurnAmount = Mathf.Atan2(move.x, move.z);
m_ForwardAmount = move.z;

ApplyExtraTurnRotation();

// control and velocity handling is different when grounded and airborne:
if (m_IsGrounded)
{
HandleGroundedMovement(crouch, jump);
}
else
{
HandleAirborneMovement();
}

ScaleCapsuleForCrouching(crouch);
PreventStandingInLowHeadroom();

// send input and other state parameters to the animator
UpdateAnimator(move);
}


void ScaleCapsuleForCrouching(bool crouch)
{
if (m_IsGrounded && crouch)
{
if (m_Crouching) return;
m_Capsule.height = m_Capsule.height / 2f;
m_Capsule.center = m_Capsule.center / 2f;
m_Crouching = true;
}
else
{
Ray crouchRay = new Ray(m_Rigidbody.position + Vector3.up * m_Capsule.radius * k_Half, Vector3.up);
float crouchRayLength = m_CapsuleHeight - m_Capsule.radius * k_Half;
if (Physics.SphereCast(crouchRay, m_Capsule.radius * k_Half, crouchRayLength))
{
m_Crouching = true;
return;
}
m_Capsule.height = m_CapsuleHeight;
m_Capsule.center = m_CapsuleCenter;
m_Crouching = false;
}
}

void PreventStandingInLowHeadroom()
{
// prevent standing up in crouch-only zones
if (!m_Crouching)
{
Ray crouchRay = new Ray(m_Rigidbody.position + Vector3.up * m_Capsule.radius * k_Half, Vector3.up);
float crouchRayLength = m_CapsuleHeight - m_Capsule.radius * k_Half;
if (Physics.SphereCast(crouchRay, m_Capsule.radius * k_Half, crouchRayLength))
{
m_Crouching = true;
}
}
}


void UpdateAnimator(Vector3 move)
{
// update the animator parameters
m_Animator.SetFloat("Forward", m_ForwardAmount, 0.1f, Time.deltaTime);
m_Animator.SetFloat("Turn", m_TurnAmount, 0.1f, Time.deltaTime);
m_Animator.SetBool("Crouch", m_Crouching);
m_Animator.SetBool("OnGround", m_IsGrounded);
if (!m_IsGrounded)
{
m_Animator.SetFloat("Jump", m_Rigidbody.velocity.y);
}

// calculate which leg is behind, so as to leave that leg trailing in the jump animation
// (This code is reliant on the specific run cycle offset in our animations,
// and assumes one leg passes the other at the normalized clip times of 0.0 and 0.5)
float runCycle =
Mathf.Repeat(
m_Animator.GetCurrentAnimatorStateInfo(0).normalizedTime + m_RunCycleLegOffset, 1);
float jumpLeg = (runCycle < k_Half ? 1 : -1) * m_ForwardAmount;
if (m_IsGrounded)
{
m_Animator.SetFloat("JumpLeg", jumpLeg);
}

// the anim speed multiplier allows the overall speed of walking/running to be tweaked in the inspector,
// which affects the movement speed because of the root motion.
if (m_IsGrounded && move.magnitude > 0)
{
m_Animator.speed = m_AnimSpeedMultiplier;
}
else
{
// don't use that while airborne
m_Animator.speed = 1;
}
}


void HandleAirborneMovement()
{
// apply extra gravity from multiplier:
Vector3 extraGravityForce = (Physics.gravity * m_GravityMultiplier) - Physics.gravity;
m_Rigidbody.AddForce(extraGravityForce);

m_GroundCheckDistance = m_Rigidbody.velocity.y < 0 ? m_OrigGroundCheckDistance : 0.01f;
}


void HandleGroundedMovement(bool crouch, bool jump)
{
// check whether conditions are right to allow a jump:
if (jump && !crouch && m_Animator.GetCurrentAnimatorStateInfo(0).IsName("Grounded"))
{
// jump!
m_Rigidbody.velocity = new Vector3(m_Rigidbody.velocity.x, m_JumpPower, m_Rigidbody.velocity.z);
m_IsGrounded = false;
m_Animator.applyRootMotion = false;
m_GroundCheckDistance = 0.1f;
}
}

void ApplyExtraTurnRotation()
{
// help the character turn faster (this is in addition to root rotation in the animation)
float turnSpeed = Mathf.Lerp(m_StationaryTurnSpeed, m_MovingTurnSpeed, m_ForwardAmount);
transform.Rotate(0, m_TurnAmount * turnSpeed * Time.deltaTime, 0);
}


public void OnAnimatorMove()
{
// we implement this function to override the default root motion.
// this allows us to modify the positional speed before it's applied.
if (m_IsGrounded && Time.deltaTime > 0)
{
Vector3 v = (m_Animator.deltaPosition * m_MoveSpeedMultiplier) / Time.deltaTime;

// we preserve the existing y part of the current velocity.
v.y = m_Rigidbody.velocity.y;
m_Rigidbody.velocity = v;
}
}


void CheckGroundStatus()
{
RaycastHit hitInfo;
#if UNITY_EDITOR
// helper to visualise the ground check ray in the scene view
Debug.DrawLine(transform.position + (Vector3.up * 0.1f), transform.position + (Vector3.up * 0.1f) + (Vector3.down * m_GroundCheckDistance));
#endif
// 0.1f is a small offset to start the ray from inside the character
// it is also good to note that the transform position in the sample assets is at the base of the character
if (Physics.Raycast(transform.position + (Vector3.up * 0.1f), Vector3.down, out hitInfo, m_GroundCheckDistance))
{
m_GroundNormal = hitInfo.normal;
m_IsGrounded = true;
m_Animator.applyRootMotion = true;
}
else
{
m_IsGrounded = false;
m_GroundNormal = Vector3.up;
m_Animator.applyRootMotion = false;
}
}
}
}
@@ -0,0 +1,75 @@
using System;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;

namespace UnityStandardAssets.Characters.ThirdPerson
{
[RequireComponent(typeof (ThirdPersonCharacter))]
public class ThirdPersonUserControl : MonoBehaviour
{
private ThirdPersonCharacter m_Character; // A reference to the ThirdPersonCharacter on the object
private Transform m_Cam; // A reference to the main camera in the scenes transform
private Vector3 m_CamForward; // The current forward direction of the camera
private Vector3 m_Move;
private bool m_Jump; // the world-relative desired move direction, calculated from the camForward and user input.


private void Start()
{
// get the transform of the main camera
if (Camera.main != null)
{
m_Cam = Camera.main.transform;
}
else
{
Debug.LogWarning(
"Warning: no main camera found. Third person character needs a Camera tagged \"MainCamera\", for camera-relative controls.");
// we use self-relative controls in this case, which probably isn't what the user wants, but hey, we warned them!
}

// get the third person character ( this should never be null due to require component )
m_Character = GetComponent<ThirdPersonCharacter>();
}


private void Update()
{
if (!m_Jump)
{
m_Jump = CrossPlatformInputManager.GetButtonDown("Jump");
}
}


// Fixed update is called in sync with physics
private void FixedUpdate()
{
// read inputs
float h = CrossPlatformInputManager.GetAxis("Horizontal");
float v = CrossPlatformInputManager.GetAxis("Vertical");
bool crouch = Input.GetKey(KeyCode.C);

// calculate move direction to pass to character
if (m_Cam != null)
{
// calculate camera relative direction to move:
m_CamForward = Vector3.Scale(m_Cam.forward, new Vector3(1, 0, 1)).normalized;
m_Move = v*m_CamForward + h*m_Cam.right;
}
else
{
// we use world-relative directions in the case of no main camera
m_Move = v*Vector3.forward + h*Vector3.right;
}
#if !MOBILE_INPUT
// walk speed multiplier
if (Input.GetKey(KeyCode.LeftShift)) m_Move *= 0.5f;
#endif

// pass all parameters to the character control script
m_Character.Move(m_Move, crouch, m_Jump);
m_Jump = false;
}
}
}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@@ -0,0 +1,27 @@
In the ThirdPersonCharacter folder you'll find two ready-made character prefabs, which are used in the ThirdPersonCharacter sample scenes. These prefabs demonstrate how you can use the ThirdPersonCharacters scripts and animations we've included, including an AI-controlled variant which is able to walk towards a specified target, or follow a waypoint-based route.

The simplest way to get started setting up your own character is to take our ThirdPersonCharacter and replace the art with your own model. To do so, make sure you've imported your own rigged model with a Humanoid avatar, then follow these steps:

1) Start with a suitable scene. There ought to be enough flat ground to walk around on.

2) Place the "ThirdPersonCharacter" prefab in the scene.

3) Unfold the ThirdPersonCharacter hierarchy in the hierarchy window, and delete the "Ethan" child object.

4) Place your own character model as a child of the ThirdPersonCharacter, in place of Ethan.

5) Make sure your character model's position in the inspector is set to zero on X and Z, and that it's Y position is appropriately adjusted so that your character's feet are at the same position as the ThirdPersonCharacter GameObject. (if you find it easier, you could add your character first before deleting Ethan, so that you can use Ethan's feet as a guide for where your character's feet should be)

7) Hit play, and try controlling your character!

You'll probably want to add a camera rig so that the camera follows the character as it runs off. See the Camera Rig guidelines for instructions on how to do that.

The ThirdPersonCharacter script exposes a number of properties which determine the jump power, the amount of control while in air, and various other speed and behaviour modifiers. For more detail about each setting, see the comments in the script.

The ThirdPersonUserControl script takes input from the "CrossPlatformInput" class included in the sample assets, however if you're not targeting mobile or prefer to use a different system to read input, you can simply use Unity's built-in Input class in place of CrossPlatformInput. For more information, see the CrossPlatformInput guidelines.

The sample scenes provided works on standalone and also include cross platform touch controls which are set up and ready to publish to mobile.

The ThirdPersonAIControl component can be added instead of the user control component, allowing the character to be AI controlled. This relies on a NavMeshAgent to pathfind the way to the target. The NavMeshAgent should be a child object of the Character, as demonstrated in the AI Character Prefab provided. If you want to create your own AI characters, you can follow the steps above, but start with the AI prefab we provided.


@@ -0,0 +1,32 @@

Importing the CrossPlatformInput package adds a menu item to Unity, "CrossPlatformInput", which allows you to enable or disable the CrossPlatformInput in the editor. You must enable the CrossPlatformInput in order to see the control rigs in the editor, and to start using Unity Remote to control your game.

The CrossPlatformInput sample assets contains two main sections.

1) The folder of prefabs provide a variety of ready-to-use "MobileControlRigs". Each control rig is suitable for a different purpose, and each implements the touch or tilt-based equivalent of some of the default standalone axes or buttons. These are ready to drop into your scene, and to use them you simply need to read the axes via the CrossPlatformInput class, rather than Unity's regular Input class.

2) The set of scripts provided are the scripts we used to put together the control rigs prefabs. They provide a simplified way of reading basic mobile input, such as tilt, taps and swipe gestures. They are designed so that various mobile controls can be read in the same way as regular Unity axes and buttons. You can use these scripts to build your own MobileControlRigs.



For example the Car control rig feeds the tilt input of the mobile device to the "Horizontal" axis, and has an accelerator and brake touch button which are fed as a pair into the "Vertical" axis. These are virtual equivalents of the real "Horizontal" and "Vertical" axes defined in Unity's Input Manager.

Therefore when you read CrossPlatformInput.GetAxis("Horizontal"), you will either get the "real" input value - if your build target is non-mobile, or the value from the mobile control rig - if your build target is set to a mobile platform.

The CrossPlatformInput scripts and prefabs are provided together as an example of how you can implement a cross-platform control solution in Unity. They also allow us to provide our other sample scenes in a form that can be published as standalone or to mobile targets with no modification.

To use the CrossPlatformInput, you need to drop a "Mobile Control Rig" into your scene (or create your own), and then make calls to CrossPlatformInput functions, referring to the axes and buttons that the Rig implements.

When reading input from the CrossPlatformInput class, the values returned will be taken either from Unity's Input Manager settings, or from the mobile-specific controls set up, depending on which build target you have selected.

The CrossPlatformInput class is designed to be called instead of Unity's own Input class, and so mirrors certain parts of the Input API - specifically the functions relating to Axes and Buttons:
GetAxis, GetAxisRaw
GetButton, GetButtonDown, GetButtonUp

Notes for coders:
This package sets two compiler define symbols. One is always set automatically, the other is optionally set from a menu item.

Importing the "CrossPlatformInput" package will automatically add a compiler define symbol, "CROSS_PLATFORM_INPUT". This enables the CrossPlatformInput functions defined in some of the other Sample Asset packages (such as the Characters, Planes, etc). Without this symbol defined, those packages use Unity's regular Input class, which means they can be imported alone and still work without the CrossPlatformInput package.

The optional define (which is set by default, but can be disabled using the "Mobile Input" menu), is "MOBILE_INPUT". This causes the MobileControlRigs to become active when a mobile build target is selected. It also enables certain mobile-specific control nuances in some of the packages, which make more sense when the character or vehicle is being controlled using mobile input (such as auto-leveling the character's look direction). This define is optional because some developers prefer to use standalone input methods instead of the Unity Remote app, when testing mobile apps in the editor's play mode.