Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Developing a first person controller for Unity3D with UniRx: Part 1
using UnityEngine;
using UniRx;
using UniRx.Triggers;
// NOTE: Unity won't actually let you put two MonoBehaviours in one file.
// They're both listed here just for convenience.
namespace Assets.Scripts.v1 {
public class InputsV1 : MonoBehaviour {
// Singleton.
public static InputsV1 Instance { get; private set; }
public IObservable<Vector2> Movement { get; private set; }
public IObservable<Vector2> Mouselook { get; private set; }
private void Awake() {
Instance = this;
// Hide the mouse cursor and lock it in the game window.
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
// Movement inputs tick on FixedUpdate
Movement = this.FixedUpdateAsObservable()
.Select(_ => {
var x = Input.GetAxis("Horizontal");
var y = Input.GetAxis("Vertical");
return new Vector2(x, y).normalized;
});
// Mouse look ticks on Update
Mouselook = this.UpdateAsObservable()
.Select(_ => {
var x = Input.GetAxis("Mouse X");
var y = Input.GetAxis("Mouse Y");
return new Vector2(x, y);
});
}
}
[RequireComponent(typeof(CharacterController))]
public class PlayerControllerV1 : MonoBehaviour {
public float walkSpeed = 5f;
[Range(-90, 0)]
public float minViewAngle = -60f; // How much can the user look down (in degrees)
[Range(0, 90)]
public float maxViewAngle = 60f; // How much can the user look up (in degrees)
private CharacterController character;
private Camera view;
private void Awake() {
character = GetComponent<CharacterController>();
view = GetComponentInChildren<Camera>();
}
private void Start() {
var inputs = InputsV1.Instance;
// Handle movement input (WASD-style).
inputs.Movement
.Where(v => v != Vector2.zero) // We can ignore this if movement is zero.
.Subscribe(inputMovement => {
// Calculate velocity (direction * speed).
var inputVelocity = inputMovement * walkSpeed;
// Translate 2D velocity into 3D player coordinates.
var playerVelocity =
inputVelocity.x * transform.right + // x (+/-) corresponds to strafe right/left
inputVelocity.y * transform.forward; // y (+/-) corresponds to forward/back
// Apply movement.
var distance = playerVelocity * Time.fixedDeltaTime;
character.Move(distance);
}).AddTo(this);
// Handle mouse input (free mouse look).
inputs.Mouselook
.Where(v => v != Vector2.zero) // We can ignore this if mouse look is zero.
.Subscribe(inputLook => {
// Translate 2D mouse input into euler angle rotations.
// inputLook.x rotates the character around the vertical axis (with + being right)
var horzLook = inputLook.x * Time.deltaTime * Vector3.up;
transform.localRotation *= Quaternion.Euler(horzLook);
// inputLook.y rotates the camera around the horizontal axis (with + being up)
var vertLook = inputLook.y * Time.deltaTime * Vector3.left;
var newQ = view.transform.localRotation * Quaternion.Euler(vertLook);
// We have to flip the signs and positions of min/max view angle here because the math
// uses the contradictory interpretation of our angles (+/- is down/up).
view.transform.localRotation = ClampRotationAroundXAxis(newQ, -maxViewAngle, -minViewAngle);
}).AddTo(this);
}
// Ripped straight out of the Standard Assets MouseLook script. (This should really be a standard function...)
private static Quaternion ClampRotationAroundXAxis(Quaternion q, float minAngle, float maxAngle) {
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, minAngle, maxAngle);
q.x = Mathf.Tan(0.5f * Mathf.Deg2Rad * angleX);
return q;
}
}
}
@TokyoDan

This comment has been minimized.

Copy link

TokyoDan commented Aug 2, 2016

To the inputs.MouseLook Observer part of PlayerControllerV1 I had to multiply inputLook.x and inputLook.y by 100.0f to get any movement from the mouse input.

@yunspace

This comment has been minimized.

Copy link

yunspace commented Jan 14, 2017

Yep @TokyoDan's work around worked for me as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.