using SanAndreasUnity.Behaviours.Vehicles; using SanAndreasUnity.Importing.Animation; using SanAndreasUnity.Utilities; using System.Collections.Generic; using System.Linq; using UnityEngine; using SanAndreasUnity.Net; namespace SanAndreasUnity.Behaviours { [DefaultExecutionOrder(-50)] [RequireComponent(typeof(Ped))] public class PlayerController : MonoBehaviour { public static PlayerController Instance { get { return Ped.Instance != null ? Ped.Instance.GetComponent() : null; } } private Ped m_ped; // Alpha speedometer private const float velTimer = 1 / 4f; private float m_velCounter = velTimer; private Vector3 m_lastPos = Vector3.zero, m_deltaPos = Vector3.zero; private Vector2 _mouseAbsolute; private Vector2 _smoothMouse = Vector2.zero; public Vector2 clampInDegrees = new Vector2(90, 60); public float EnterVehicleRadius { get { return m_ped.EnterVehicleRadius; } } public Vector2 smoothing = new Vector2(10, 10); [SerializeField] private bool m_doSmooth = true; [SerializeField] private bool m_smoothMovement = false; public float CurVelocity { get { return m_deltaPos.magnitude * 3.6f / velTimer; } } private void Awake() { m_ped = GetComponent(); } void OnEnable() { UIManager.onGUI += this.OnGUICustom; } void OnDisable() { UIManager.onGUI -= this.OnGUICustom; } private void OnGUICustom() { if (!m_ped.IsControlledByLocalPlayer) return; if (!Loader.HasLoaded) return; UnityEngine.Profiling.Profiler.BeginSample ("PlayerController gui"); // show that we are in flying state if (m_ped.CurrentState is Peds.States.FlyState) { int height = 25; Rect rect = new Rect(Screen.width - 140, Screen.height - height, 140, height); GUI.Label(rect, "Flying-mode enabled!"); } if (PedManager.Instance.showPedSpeedometer) GUI.Label(GUIUtils.GetCornerRect(ScreenCorner.TopLeft, 100, 25, new Vector2(5, 5)), string.Format("{0:0.0} km/h", m_deltaPos.magnitude * 3.6f / velTimer)); // show current ped state GUI.Label (GUIUtils.GetCornerRect(ScreenCorner.BottomLeft, 250, 50), string.Format("Current ped state: {0}", m_ped.CurrentState != null ? m_ped.CurrentState.GetType().Name : "none") ); UnityEngine.Profiling.Profiler.EndSample(); } private void FixedUpdate() { m_velCounter -= Time.deltaTime; if (m_velCounter <= 0) { Vector3 t = new Vector3(transform.position.x, 0, transform.position.z); m_deltaPos = t - m_lastPos; m_lastPos = t; m_velCounter = velTimer; } } private void Update() { if (!m_ped.IsControlledByLocalPlayer) return; if (!Loader.HasLoaded) return; // reset ped input m_ped.ResetMovementInput (); m_ped.MouseMoveInput = Vector2.zero; m_ped.MouseScrollInput = Vector2.zero; if (!GameManager.CanPlayerReadInput()) return; // states must be read before events, otherwise callback functions for events will not have access // to states (they will always be unpressed/reset, because we did a reset above) this.ReadStates (); this.ReadEvents (); } void ReadStates() { CustomInput customInput = CustomInput.Instance; this.ReadCameraInput (); m_ped.MouseScrollInput = Input.mouseScrollDelta; m_ped.IsAimOn = customInput.GetButton ("RightClick"); m_ped.IsFireOn = customInput.GetButton ("LeftClick"); m_ped.IsJumpOn = customInput.GetButton ("Jump"); Vector3 inputMove = Vector3.zero; if (m_smoothMovement) inputMove = new Vector3 (customInput.GetAxis ("Horizontal"), 0f, customInput.GetAxis ("Vertical")); else inputMove = new Vector3 (customInput.GetAxisRaw ("Horizontal"), 0f, customInput.GetAxisRaw ("Vertical")); if (inputMove.sqrMagnitude > 0f) { inputMove.Normalize(); if (customInput.GetButton ("Walk")) m_ped.IsWalkOn = true; else if (customInput.GetButton ("Sprint")) m_ped.IsSprintOn = true; else m_ped.IsRunOn = true; } if (m_ped.Camera != null) m_ped.Movement = m_ped.Camera.transform.TransformVector (inputMove).normalized; else m_ped.Movement = inputMove.normalized; if (m_ped.Movement.sqrMagnitude > float.Epsilon) { // only assign heading if there is any movement - we don't want the heading to be zero vector m_ped.Heading = m_ped.Movement; } } void ReadEvents() { CustomInput customInput = CustomInput.Instance; if (customInput.GetButtonDown ("LeftClick")) m_ped.OnFireButtonPressed (); if (customInput.GetButtonDown ("RightClick")) m_ped.OnAimButtonPressed (); if (customInput.GetKeyDown (KeyCode.Q)) m_ped.OnPreviousWeaponButtonPressed(); else if (customInput.GetKeyDown (KeyCode.E)) m_ped.OnNextWeaponButtonPressed(); if (customInput.GetButtonDown("Use")) m_ped.OnSubmitPressed (); if (customInput.GetButtonDown("Jump")) m_ped.OnJumpButtonPressed (); if (customInput.GetKeyDown(KeyCode.C)) m_ped.OnCrouchButtonPressed (); if (customInput.GetKeyDown (KeyCode.T)) m_ped.OnFlyButtonPressed(); if (customInput.GetKeyDown (KeyCode.R)) m_ped.OnFlyThroughButtonPressed(); } private void ReadCameraInput () { CustomInput customInput = CustomInput.Instance; if (GameManager.CanPlayerReadInput()) { // rotate camera // FIXME: Camera rotation should be done by ped's current state. We should only assign mouse move input. var mouseDelta = new Vector2(customInput.GetAxisRaw("Mouse X"), customInput.GetAxisRaw("Mouse Y")); var rightAnalogDelta = new Vector2(customInput.GetAxisRaw("Joystick X"), customInput.GetAxisRaw("Joystick Y")); Vector2 totalMouseDelta = mouseDelta + rightAnalogDelta; totalMouseDelta = Vector2.Scale (totalMouseDelta, GameManager.Instance.cursorSensitivity); m_ped.MouseMoveInput = totalMouseDelta; if (m_doSmooth) { _smoothMouse.x = Mathf.Lerp (_smoothMouse.x, totalMouseDelta.x, 1f / smoothing.x); _smoothMouse.y = Mathf.Lerp (_smoothMouse.y, totalMouseDelta.y, 1f / smoothing.y); _mouseAbsolute += _smoothMouse; } else { _mouseAbsolute += totalMouseDelta; } if (clampInDegrees.y > 0) _mouseAbsolute.y = Mathf.Clamp(_mouseAbsolute.y, -clampInDegrees.y, clampInDegrees.y); } } private void OnDrawGizmosSelected() { if (null == m_ped) return; Gizmos.color = Color.white; // draw enter vehicle radius Gizmos.DrawWireSphere(transform.position, EnterVehicleRadius); // find closest vehicle in entering range var vehicles = FindObjectsOfType() .Where(x => Vector3.Distance(transform.position, x.FindClosestSeatTransform(transform.position).position) < EnterVehicleRadius) .OrderBy(x => Vector3.Distance(transform.position, x.FindClosestSeatTransform(transform.position).position)).ToArray(); foreach (var vehicle in vehicles) { // draw all seats foreach (var seat in vehicle.Seats) { Gizmos.color = Color.red; Gizmos.DrawWireSphere(seat.Parent.position, 0.1f); } // draw closest seat var closestSeat = vehicle.FindClosestSeat(transform.position); if (closestSeat != Vehicle.SeatAlignment.None) { var closestSeatTransform = vehicle.GetSeatTransform(closestSeat); Gizmos.color = Color.green; Gizmos.DrawWireSphere(closestSeatTransform.position, 0.1f); Gizmos.DrawLine(transform.position, closestSeatTransform.position); } break; } } } }