Skip to content

Instantly share code, notes, and snippets.

@eintopf
Created December 23, 2016 12:00
Show Gist options
  • Save eintopf/b3c4b8780847e63d9733fd84509522fa to your computer and use it in GitHub Desktop.
Save eintopf/b3c4b8780847e63d9733fd84509522fa to your computer and use it in GitHub Desktop.
This class is an addition to the Unity Standard Asset Scripts (need to be imported in your project to get this gist working). This component can be used like the standard asset "First Person Controller", however it moves on the NavMesh (instead of colliders). This can save a lot of setup pain and performance.
using System;
using UnityEngine;
using UnityEngine.AI;
using UnityStandardAssets.Characters.FirstPerson;
using UnityStandardAssets.CrossPlatformInput;
namespace ZKW.PlayerMovement
{
public class NavMeshPlayerMovement : MonoBehaviour
{
private const string noPlayerNavmeshCheckTag = "No Player NavMesh Check";
public Camera cam;
private float yWhileInNoCheckArea;
private bool isInNoCheckArea;
public MouseLook mouseLook = new MouseLook();
public MovementSettings movementSettings = new MovementSettings();
private Transform myTranform;
public bool Running
{
get
{
#if !MOBILE_INPUT
return movementSettings.Running;
#else
return false;
#endif
}
}
private void Start()
{
myTranform = transform;
mouseLook.Init(myTranform, cam.transform);
}
private void Update()
{
RotateView();
var input = GetInput();
if (!(Mathf.Abs(input.x) > float.Epsilon) && !(Mathf.Abs(input.y) > float.Epsilon)) return;
// always move along the camera forward as it is the direction that it being aimed at
var desiredMove = cam.transform.forward*input.y + cam.transform.right*input.x;
desiredMove = Vector3.ProjectOnPlane(desiredMove, Vector3.zero).normalized;
desiredMove.x = desiredMove.x*movementSettings.CurrentTargetSpeed;
desiredMove.z = desiredMove.z*movementSettings.CurrentTargetSpeed;
desiredMove.y = desiredMove.y*movementSettings.CurrentTargetSpeed;
var movement = desiredMove*Time.deltaTime;
if (movement.magnitude == 0) return;
var currPos = myTranform.position;
var desiredPos = currPos + movement;
if (isInNoCheckArea)
desiredPos.y = yWhileInNoCheckArea;
myTranform.position = desiredPos;
if (isInNoCheckArea) return;
movePlayerToNearestNavMeshPosition(desiredPos);
}
private void movePlayerToNearestNavMeshPosition(Vector3 curr)
{
var distance = 0.01f;
var hit = new NavMeshHit();
do
{
NavMesh.SamplePosition(curr, out hit, distance, NavMesh.AllAreas);
distance *= 2f;
} while (!hit.hit);
myTranform.position = hit.position;
}
private void OnTriggerEnter(Collider other)
{
if (other.tag != noPlayerNavmeshCheckTag) return;
isInNoCheckArea = true;
yWhileInNoCheckArea = myTranform.position.y;
}
private void OnTriggerExit(Collider other)
{
if (other.tag == noPlayerNavmeshCheckTag)
isInNoCheckArea = false;
}
private Vector2 GetInput()
{
var 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
mouseLook.LookRotation(transform, cam.transform);
}
[Serializable]
public class MovementSettings
{
public float BackwardSpeed = 4.0f; // Speed when walking backwards
[HideInInspector] public float CurrentTargetSpeed = 8f;
public float ForwardSpeed = 8.0f; // Speed when walking forward
public float JumpForce = 30f;
#if !MOBILE_INPUT
#endif
public KeyCode RunKey = KeyCode.LeftShift;
public float RunMultiplier = 2.0f; // Speed when sprinting
public float StrafeSpeed = 4.0f; // Speed when walking sideways
#if !MOBILE_INPUT
public bool Running { get; private set; }
#endif
public void UpdateDesiredTargetSpeed(Vector2 input)
{
if (input == Vector2.zero) return;
if ((input.x > 0) || (input.x < 0))
CurrentTargetSpeed = StrafeSpeed;
if (input.y < 0)
CurrentTargetSpeed = BackwardSpeed;
if (input.y > 0)
CurrentTargetSpeed = ForwardSpeed;
#if !MOBILE_INPUT
if (Input.GetKey(RunKey))
{
CurrentTargetSpeed *= RunMultiplier;
Running = true;
}
else
{
Running = false;
}
#endif
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment