-
Notifications
You must be signed in to change notification settings - Fork 349
Expand file tree
/
Copy pathPlayerController.cs
More file actions
246 lines (202 loc) · 6.87 KB
/
PlayerController.cs
File metadata and controls
246 lines (202 loc) · 6.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : GravityObject {
// Exposed variables
[Header ("Movement settings")]
public float walkSpeed = 8;
public float runSpeed = 14;
public float jumpForce = 20;
public float vSmoothTime = 0.1f;
public float airSmoothTime = 0.5f;
public float stickToGroundForce = 8;
public float jetpackForce = 10;
public float jetpackDuration = 2;
public float jetpackRefuelTime = 2;
public float jetpackRefuelDelay = 2;
[Header ("Mouse settings")]
public float mouseSensitivityMultiplier = 1;
public float maxMouseSmoothTime = 0.3f;
public Vector2 pitchMinMax = new Vector2 (-40, 85);
public InputSettings inputSettings;
[Header ("Other")]
public float mass = 70;
public LayerMask walkableMask;
public Transform feet;
// Private
Rigidbody rb;
Ship spaceship;
float yaw;
float pitch;
float smoothYaw;
float smoothPitch;
float smoothYawOld;
float yawSmoothV;
float pitchSmoothV;
Vector3 targetVelocity;
Vector3 cameraLocalPos;
Vector3 smoothVelocity;
Vector3 smoothVRef;
bool isGrounded;
// Jetpack
bool usingJetpack;
float jetpackFuelPercent = 1;
float lastJetpackUseTime;
CelestialBody referenceBody;
Camera cam;
bool readyToFlyShip;
bool debug_playerFrozen;
Animator animator;
void Awake () {
cam = GetComponentInChildren<Camera> ();
cameraLocalPos = cam.transform.localPosition;
spaceship = FindObjectOfType<Ship> ();
InitRigidbody ();
animator = GetComponentInChildren<Animator> ();
inputSettings.Begin ();
}
void InitRigidbody () {
rb = GetComponent<Rigidbody> ();
rb.interpolation = RigidbodyInterpolation.Interpolate;
rb.useGravity = false;
rb.isKinematic = false;
rb.mass = mass;
}
void Update () {
if (Time.timeScale == 0) {
return;
}
HandleInput();
// Refuel jetpack
if (Time.time - lastJetpackUseTime > jetpackRefuelDelay) {
jetpackFuelPercent = Mathf.Clamp01 (jetpackFuelPercent + Time.deltaTime / jetpackRefuelTime);
}
// Handle animations
float currentSpeed = smoothVelocity.magnitude;
float animationSpeedPercent = (currentSpeed <= walkSpeed) ? currentSpeed / walkSpeed / 2 : currentSpeed / runSpeed;
animator.SetBool ("Grounded", isGrounded);
animator.SetFloat ("Speed", animationSpeedPercent);
}
void HandleInput()
{
HandleEditorInput();
// Look input
yaw += Input.GetAxisRaw ("Mouse X") * inputSettings.mouseSensitivity / 10 * mouseSensitivityMultiplier;
pitch -= Input.GetAxisRaw ("Mouse Y") * inputSettings.mouseSensitivity / 10 * mouseSensitivityMultiplier;
pitch = Mathf.Clamp (pitch, pitchMinMax.x, pitchMinMax.y);
float mouseSmoothTime = Mathf.Lerp (0.01f, maxMouseSmoothTime, inputSettings.mouseSmoothing);
smoothPitch = Mathf.SmoothDampAngle (smoothPitch, pitch, ref pitchSmoothV, mouseSmoothTime);
smoothYawOld = smoothYaw;
smoothYaw = Mathf.SmoothDampAngle (smoothYaw, yaw, ref yawSmoothV, mouseSmoothTime);
// Movement input
isGrounded = IsGrounded ();
Vector3 input = new Vector3 (Input.GetAxisRaw ("Horizontal"), 0, Input.GetAxisRaw ("Vertical"));
bool running = Input.GetKey (KeyCode.LeftShift);
targetVelocity = transform.TransformDirection (input.normalized) * ((running) ? runSpeed : walkSpeed);
smoothVelocity = Vector3.SmoothDamp (smoothVelocity, targetVelocity, ref smoothVRef, (isGrounded) ? vSmoothTime : airSmoothTime);
}
void HandleMovement () {
if (!debug_playerFrozen && Time.timeScale > 0) {
cam.transform.localEulerAngles = Vector3.right * smoothPitch;
transform.Rotate (Vector3.up * Mathf.DeltaAngle (smoothYawOld, smoothYaw), Space.Self);
}
//bool inWater = referenceBody
if (isGrounded) {
if (Input.GetKeyDown (KeyCode.Space)) {
rb.AddForce (transform.up * jumpForce, ForceMode.VelocityChange);
isGrounded = false;
} else {
// Apply small downward force to prevent player from bouncing when going down slopes
rb.AddForce (-transform.up * stickToGroundForce, ForceMode.VelocityChange);
}
} else {
// Press (and hold) spacebar while above ground to engage jetpack
if (Input.GetKeyDown (KeyCode.Space)) {
usingJetpack = true;
}
}
if (usingJetpack && Input.GetKey (KeyCode.Space) && jetpackFuelPercent > 0) {
lastJetpackUseTime = Time.time;
jetpackFuelPercent -= Time.deltaTime / jetpackDuration;
rb.AddForce (transform.up * jetpackForce, ForceMode.Acceleration);
} else {
usingJetpack = false;
}
}
bool IsGrounded () {
// Sphere must not overlay terrain at origin otherwise no collision will be detected
// so rayRadius should not be larger than controller's capsule collider radius
const float rayRadius = .3f;
const float groundedRayDst = .2f;
bool grounded = false;
if (referenceBody) {
var relativeVelocity = rb.velocity - referenceBody.velocity;
// Don't cast ray down if player is jumping up from surface
if (relativeVelocity.y <= jumpForce * .5f) {
RaycastHit hit;
Vector3 offsetToFeet = (feet.position - transform.position);
Vector3 rayOrigin = rb.position + offsetToFeet + transform.up * rayRadius;
Vector3 rayDir = -transform.up;
grounded = Physics.SphereCast (rayOrigin, rayRadius, rayDir, out hit, groundedRayDst, walkableMask);
}
}
return grounded;
}
void FixedUpdate () {
if (Time.timeScale == 0) {
return;
}
HandleMovement();
CelestialBody[] bodies = NBodySimulation.Bodies;
Vector3 gravityOfNearestBody = Vector3.zero;
float nearestSurfaceDst = float.MaxValue;
// Gravity
foreach (CelestialBody body in bodies) {
float sqrDst = (body.Position - rb.position).sqrMagnitude;
Vector3 forceDir = (body.Position - rb.position).normalized;
Vector3 acceleration = forceDir * Universe.gravitationalConstant * body.mass / sqrDst;
rb.AddForce (acceleration, ForceMode.Acceleration);
float dstToSurface = Mathf.Sqrt (sqrDst) - body.radius;
// Find body with strongest gravitational pull
if (dstToSurface < nearestSurfaceDst) {
nearestSurfaceDst = dstToSurface;
gravityOfNearestBody = acceleration;
referenceBody = body;
}
}
// Rotate to align with gravity up
Vector3 gravityUp = -gravityOfNearestBody.normalized;
transform.rotation = Quaternion.FromToRotation (transform.up, gravityUp) * transform.rotation;
// Move
rb.MovePosition (rb.position + smoothVelocity * Time.fixedDeltaTime);
}
void HandleEditorInput () {
if (Application.isEditor) {
if (Input.GetKeyDown (KeyCode.O)) {
Debug.Log ("Debug mode: Toggle freeze player");
debug_playerFrozen = !debug_playerFrozen;
}
}
}
public void SetVelocity (Vector3 velocity) {
rb.velocity = velocity;
}
public void ExitFromSpaceship () {
cam.transform.parent = transform;
cam.transform.localPosition = cameraLocalPos;
smoothYaw = 0;
yaw = 0;
smoothPitch = cam.transform.localEulerAngles.x;
pitch = smoothPitch;
}
public Camera Camera {
get {
return cam;
}
}
public Rigidbody Rigidbody {
get {
return rb;
}
}
}