Created
October 4, 2019 13:43
-
-
Save verborghs/b0e1e17aec7928b5b3df20f730bf151f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
public class EnvironmentQuery | |
{ | |
private readonly CharacterController _controller; | |
private readonly float _characterRayCastHeight; | |
private readonly float _radius; | |
public EnvironmentQuery(float characterRayCastHeight, float radius) | |
{ | |
_characterRayCastHeight = characterRayCastHeight; | |
_radius = radius; | |
} | |
public Vector3 FindGroundPoint(Vector3 characterCenter) | |
{ | |
var groundLayer = LayerMask.GetMask("Walkable"); | |
Vector3 groundPoint = Vector3.zero; | |
var groundPointRay = new Ray(characterCenter, Vector3.down); | |
if (Physics.SphereCast(groundPointRay, _radius, out var hitInfo, _characterRayCastHeight, groundLayer)) | |
{ | |
groundPoint = hitInfo.point; | |
} | |
return groundPoint; | |
} | |
public Vector3 FindGroundNormal(Vector3 groundPoint, Vector3 characterCenter) | |
{ | |
Vector3 groundNormal = Vector3.up; | |
var groundNormalRay = new Ray(new Vector3(groundPoint.x, characterCenter.y, groundPoint.z), Vector3.down); | |
if (Physics.Raycast(groundNormalRay, out var hitInfo, _characterRayCastHeight)) | |
{ | |
groundNormal = hitInfo.normal; | |
} | |
return groundNormal; | |
} | |
public Collider FindInteractives() | |
{ | |
var halfExtents = new Vector3(_controller.radius * 0.5f, | |
_controller.height / 2.0f, _controller.radius * 1.0f); | |
var forwardOffset = _controller.transform.forward * halfExtents.x; | |
var upOffset = _controller.transform.up * halfExtents.y; | |
var interactiveCenter = _controller.transform.position + forwardOffset + upOffset; | |
var interactiveLayer = LayerMask.GetMask("Interactive"); | |
var interactives = | |
Physics.OverlapBox(interactiveCenter, halfExtents, _controller.transform.rotation, interactiveLayer); | |
if (interactives.Length > 0) | |
return interactives[0]; | |
else | |
{ | |
return null; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
public class Motor | |
{ | |
private readonly CharacterController _controller; | |
private readonly float _jumpHeight; | |
private readonly float _speed; | |
private Vector3 _velocity; | |
public Motor(CharacterController controller, float jumpHeight, float speed) | |
{ | |
_controller = controller; | |
_jumpHeight = jumpHeight; | |
_speed = speed; | |
} | |
public void Begin() | |
{ | |
_velocity = _controller.velocity; | |
} | |
public void Commit() | |
{ | |
_controller.Move(_velocity * Time.deltaTime); | |
} | |
public void ApplyJump() | |
{ | |
//jump impulse | |
_velocity = new Vector3( | |
_velocity.x, | |
Mathf.Sqrt(2 * Physics.gravity.magnitude * _jumpHeight), | |
_velocity.z); | |
} | |
public void ApplyMovement(Vector3 worldDirection, Vector3 groundNormal) | |
{ | |
//calculate ground orientation | |
Vector3 groundTangent = worldDirection; | |
Vector3.OrthoNormalize(ref groundNormal, ref groundTangent); | |
//add movement to velocity | |
_velocity += groundTangent * worldDirection.magnitude * _speed; | |
} | |
public void ApplyGround(Vector3 groundNormal) | |
{ | |
//only keep vertical velocity | |
_velocity = Vector3.Scale(_velocity, new Vector3(0, 1, 0)); | |
//transform velocity into pure velocity along plane. | |
_velocity = Vector3.ProjectOnPlane(_velocity, groundNormal); | |
} | |
public void ApplyGravity() | |
{ | |
//gravity | |
_velocity += Physics.gravity * Time.deltaTime; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using UnityEngine; | |
public class PlayerBehaviour : MonoBehaviour | |
{ | |
public float Speed; | |
public float JumpHeight; | |
private CharacterController _controller; | |
private Camera _camera; | |
private Motor _motor; | |
private EnvironmentQuery _environmentQuery; | |
private const string JoyStickVerticalTemplate = "{0}_Vertical"; | |
private const string JoyStickHorizontalTemplate = "{0}_Horizontal"; | |
void Start() | |
{ | |
_controller = GetComponent<CharacterController>(); | |
_camera = Camera.main; | |
_motor = new Motor(_controller, JumpHeight, Speed); | |
} | |
// Update is called once per frame | |
void Update() | |
{ | |
_motor.Begin(); | |
//Determine the player surface | |
var groundNormal = Vector3.up; | |
var groundPoint = Vector3.zero; | |
var characterCenter = transform.position + _controller.center; | |
groundPoint = _environmentQuery.FindGroundPoint(characterCenter); | |
groundNormal = _environmentQuery.FindGroundNormal(groundPoint, characterCenter); | |
var directionRight = GetJoyStickDirection("RightStick"); | |
var worldDirectionRight = ToWorldSpaceXYPlaneDirection(directionRight); | |
if (IsZeroLengthVector(worldDirectionRight)) | |
{ | |
ApplyRotation(worldDirectionRight); | |
} | |
_motor.ApplyGravity(); | |
var directionLeft = GetJoyStickDirection("LeftStick"); | |
var worldDirectionLeft = ToWorldSpaceXYPlaneDirection(directionRight); | |
if (_controller.isGrounded) | |
{ | |
_motor.ApplyGround(groundNormal); | |
_motor.ApplyMovement(worldDirectionLeft, groundNormal); | |
if (Input.GetButtonDown("A")) | |
{ | |
_motor.ApplyJump(); | |
} | |
else | |
{ | |
if (Input.GetButtonDown("B")) | |
{ | |
var interactive = _environmentQuery.FindInteractives(); | |
if (interactive != null) | |
{ | |
InteractWith(interactive); | |
} | |
} | |
} | |
} | |
_motor.Commit(); | |
} | |
private void ApplyRotation(Vector3 worldDirection) | |
{ | |
Quaternion worldOrientation = Quaternion.LookRotation(worldDirection, Vector3.up); | |
//rotate the player | |
transform.rotation = worldOrientation; | |
} | |
private bool IsZeroLengthVector(Vector3 worldDirectionRight) | |
{ | |
return !Mathf.Approximately(worldDirectionRight.sqrMagnitude, 0.0f); | |
} | |
private void InteractWith(Collider interactive) | |
{ | |
var physics = interactive.GetComponentInParent<Rigidbody>(); | |
Vector3 direction = interactive.transform.position - transform.position; | |
direction.y = 0; | |
physics.AddForce(direction * 8.0f, ForceMode.Impulse); | |
} | |
private Vector2 GetJoyStickDirection(String joyStickName) | |
{ | |
float horizontal = UnityEngine.Input.GetAxis(String.Format(JoyStickHorizontalTemplate, joyStickName)); | |
float vertical = UnityEngine.Input.GetAxis(String.Format(JoyStickVerticalTemplate, joyStickName)); | |
Vector3 direction = new Vector2(horizontal, vertical); | |
return direction.sqrMagnitude > 2 ? direction.normalized : direction; | |
} | |
private Vector3 ToWorldSpaceXYPlaneDirection(Vector2 direction) | |
{ | |
Vector3 cameraForward = Vector3.Scale(_camera.transform.forward, new Vector3(1, 0, 1)).normalized; | |
Vector3 cameraRight = Vector3.Scale(_camera.transform.right, new Vector3(1, 0, 1)).normalized; | |
return cameraRight * direction.x + cameraForward * direction.y; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment