using System.Collections; using System.Collections.Generic; using System.Text; using UnityEngine; using UnityEngine.XR; public class PlayerController : MonoBehaviour { [Tooltip("The base automatic speed of the player.")] [Range(1f, 3f)] public float speed = 1f; [Tooltip("How sensitive the player rotation is.")] [Range(0, 3f)] public float rotationSensibility = 1f; [Tooltip("How sensitive the player movement is.")] [Range(0, 3f)] public float movementSensibility = 1f; [Tooltip("The menus controller.")] public MenusController menusController; [Tooltip("The game manager.")] public GameManager gameManager; private UdpClientController playerUdpClient; void Awake() { playerUdpClient = new UdpClientController(5000); } void Start() { ApplyPlayerPrefs(); } void Update() { GameStateControl(); WatchPlayerControls(); WatchXRControls(); if (gameManager.isPaused) { return; } if (speed > 0f) AutomaticForwardMovement(speed); CheckForFall(); } private void OnDestroy() { this.playerUdpClient.Close(); } private void GameStateControl() { bool quitGame = Input.GetKeyDown(KeyCode.Escape); bool restartGame = Input.GetKeyDown(KeyCode.R); bool togglePauseGame = Input.GetKeyDown(KeyCode.Space) || Input.GetKeyDown(KeyCode.P); if (XRSettings.isDeviceActive) { InputDevice rightHand = GetXRNode(XRNode.RightHand); bool primaryButtonPressed = false; rightHand.TryGetFeatureValue(CommonUsages.primaryButton, out primaryButtonPressed); bool secondaryButtonPressed = false; rightHand.TryGetFeatureValue(CommonUsages.secondaryButton, out secondaryButtonPressed); bool gripButtonPressed = false; rightHand.TryGetFeatureValue(CommonUsages.gripButton, out gripButtonPressed); quitGame = gripButtonPressed; restartGame = secondaryButtonPressed; togglePauseGame = primaryButtonPressed; } // Quit game if (quitGame) { menusController.LoadScene("StartScene"); } // Restart game if (restartGame) { menusController.LoadScene("MainScene"); } // Toggle pause Game if (togglePauseGame) { bool gameState = gameManager.isPaused; gameManager.PauseGame(!gameState); } } /// <summary> /// Apply all the player preferences /// </summary> private void ApplyPlayerPrefs() { this.speed = PlayerPrefs.GetFloat("Speed", this.speed); this.rotationSensibility = PlayerPrefs.GetFloat("Rotation Sensibility", this.rotationSensibility); this.movementSensibility = PlayerPrefs.GetFloat("Movement Sensibility", this.movementSensibility); } /// <summary> /// Give a constant movement toward the facing direction /// </summary> /// <param name="speed">Movement speed</param> private void AutomaticForwardMovement(float speed) { // Give a constant movement toward the facing direction Vector3 automaticMovement = this.transform.forward; this.transform.position += automaticMovement * Time.deltaTime * speed; } /// <summary> /// Check if the player has fallen. If so, go back to main menu /// </summary> private void CheckForFall() { if (this.transform.position.y < -50) { menusController.LoadScene("StartScene"); } } /// <summary> /// Define the player controls according if there is a connection to the UDP server or not /// </summary> /// <param name="isConnectedToUdpServer">True if the player is connected to the UDP server</param> private void WatchPlayerControls() { if (playerUdpClient.IsConnected()) { PositionManager pm = this.GetComponent<PositionManager>(); float[] newPosition = pm.updatePosition(playerUdpClient?.data); float x = newPosition[0]; float y = newPosition[2]; float z = newPosition[1]; float theta_x = newPosition[3]; float theta_y = newPosition[4] * rotationSensibility; float theta_z = newPosition[5]; StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine($"PositionManager : [x {x}], [y {y}], [z {z}] - [theta_x {theta_x}], [theta_y {theta_y}], [theta_z {theta_z}]"); stringBuilder.AppendLine($"Transform P : [x {this.transform.position.x}], [y {this.transform.position.y}], [z {this.transform.position.z}]"); Vector3 movement = new Vector3(x, 0, z); this.transform.position += movement * Time.deltaTime * movementSensibility; stringBuilder.AppendLine($"Updated Transform P : [x {this.transform.position.x}], [y {this.transform.position.y}], [z {this.transform.position.z}]"); stringBuilder.AppendLine($"Transform R : [x {this.transform.rotation.x}], [y {this.transform.rotation.y}], [z {this.transform.rotation.z}]"); Quaternion newRotation = Quaternion.Euler(theta_x, theta_y, theta_z); this.transform.rotation = newRotation; stringBuilder.AppendLine($"Updated Transform R : [x {this.transform.rotation.x} ], [y {this.transform.rotation.y} ], [z {this.transform.rotation.z}]"); print(stringBuilder.ToString()); } else { // Shift the player with the keyboard, according to the camera facing direction float horizontal = Input.GetAxis("Horizontal"); float vertical = Input.GetAxis("Vertical"); Vector3 movement = this.transform.right * horizontal + this.transform.forward * vertical; this.transform.position += movement * Time.deltaTime * movementSensibility; // Rotate the player with the mouse (horizontal axis only) float mouseX = Input.GetAxis("Mouse X"); Vector3 rotation = this.transform.rotation.eulerAngles; this.transform.rotation = Quaternion.Euler(rotation.x, rotation.y + mouseX * rotationSensibility, rotation.z); } } /// <summary> /// Define the XR controls if the VR headset is active /// </summary> private void WatchXRControls() { if (XRSettings.isDeviceActive) { Camera camera = this.transform.Find("FirstPersonCamera").GetComponent<Camera>(); InputDevice rightHand = GetXRNode(XRNode.RightHand); InputDevice headset = GetXRNode(XRNode.Head); if (!playerUdpClient.IsConnected()) { // Control player with right controller Vector2 primary2DAxisInput; if (rightHand.TryGetFeatureValue(CommonUsages.primary2DAxis, out primary2DAxisInput)) { // Use the x value of the joystick or touchpad to control the rotation float rotationY = primary2DAxisInput.x * 15 * rotationSensibility * Time.deltaTime; // Only y axis is used for the rotation Quaternion newRotation = Quaternion.Euler(0, rotationY, 0); this.transform.rotation *= newRotation; } } // Control camera with headset Quaternion headsetRotation; if (headset.TryGetFeatureValue(CommonUsages.deviceRotation, out headsetRotation)) { camera.transform.localRotation = headsetRotation; } } } /// <summary> /// Get the XR node according to the current platform /// </summary> private InputDevice GetXRNode(XRNode node) { List<InputDevice> devices = new List<InputDevice>(); InputDevices.GetDevicesAtXRNode(node, devices); InputDevice device = devices[0]; return device; } }