276 lines
9.1 KiB
C#
276 lines
9.1 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.InputSystem;
|
|
|
|
public class Player : Manager<Player>
|
|
{
|
|
public float ThrustForce = 10; // in m/s^2
|
|
public float SteeringFactor = 10.0f;
|
|
public float UprightMultiplier = 10.0f;
|
|
public float DragForce = 0.75f;
|
|
|
|
public AnimationCurve SlopeDragCurve;
|
|
|
|
public Vector3 horizontalVelocity = Vector2.zero;
|
|
|
|
private BoxCollider BenchBoxCollider;
|
|
|
|
[SerializeField]
|
|
private ParticleSystem thrusterParticleSystemLeft;
|
|
|
|
[SerializeField]
|
|
private ParticleSystem thrusterParticleSystemRight;
|
|
|
|
public ParticleSystem Explosion;
|
|
|
|
[SerializeField]
|
|
private float dynamiteCountdownStart = 3.0f;
|
|
|
|
private float dynamiteCountDown;
|
|
|
|
private bool disableInput = false;
|
|
|
|
public float DynamiteCountDown => dynamiteCountDown;
|
|
|
|
public float Fuel = 1.0f;
|
|
public float FuelConsumptionPerSecond = 0.01f;
|
|
public float FuelConsumptionPerSecondBase = 0.01f;
|
|
|
|
private float score = 0.0f;
|
|
public float Score => score;
|
|
|
|
public LayerMask RayLayerMask;
|
|
|
|
|
|
IEnumerator SecondDelayInterval()
|
|
{
|
|
while(true)
|
|
{
|
|
|
|
yield return new WaitForSeconds(1.0f);
|
|
|
|
if(dynamiteCountDown > 0)
|
|
{
|
|
if(horizontalVelocity.magnitude < 0.1f)
|
|
{
|
|
dynamiteCountDown -= 1.0f;
|
|
AudioManager.Instance.GetAudioSource(AudioClip.CountdownBeep).Play();
|
|
}
|
|
else
|
|
{
|
|
dynamiteCountDown = dynamiteCountdownStart;
|
|
}
|
|
}
|
|
|
|
if(dynamiteCountDown <= 0)
|
|
{
|
|
disableInput = true;
|
|
dynamiteCountDown = 0;
|
|
|
|
if(GameStateManager.Instance.GameState == GameState.Play)
|
|
{
|
|
Debug.Log("GameStateChange => Play => GameOver");
|
|
GameStateManager.Instance.SetGameState(GameState.GameOver);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private AudioSource audioSourceSledge;
|
|
private AudioSource audioSourceSpin;
|
|
private AudioSource audioSourceRoar;
|
|
|
|
protected void Start()
|
|
{
|
|
GameStateManager.Instance.OnGameStateChangedEvent.AddListener(OnGameStateChanged);
|
|
|
|
BenchBoxCollider = GetComponentInChildren<BoxCollider>();
|
|
|
|
dynamiteCountDown = dynamiteCountdownStart;
|
|
|
|
audioSourceSpin = AudioManager.Instance.GetAudioSource(AudioClip.TurbineSpin);
|
|
audioSourceRoar = AudioManager.Instance.GetAudioSource(AudioClip.TurbineRoar);
|
|
audioSourceSledge = AudioManager.Instance.GetAudioSource(AudioClip.SnowSlideSledge);
|
|
}
|
|
|
|
public void OnGameStateChanged(GameState newState, GameState oldState)
|
|
{
|
|
Debug.Log("OnGameStateChanged "+newState);
|
|
if(newState == GameState.Play)
|
|
{
|
|
StartCoroutine(SecondDelayInterval());
|
|
}
|
|
}
|
|
|
|
protected void OnDestroy()
|
|
{
|
|
GameStateManager.Instance.OnGameStateChangedEvent.RemoveListener(OnGameStateChanged);
|
|
}
|
|
|
|
void FixedUpdate()
|
|
{
|
|
var gamepad = Gamepad.current;
|
|
|
|
float throttle = 0;
|
|
float steering = 0;
|
|
|
|
Vector3 localVelocity = this.transform.InverseTransformDirection(horizontalVelocity);
|
|
|
|
if(!disableInput)
|
|
{
|
|
throttle += (Keyboard.current.wKey.ReadValue()) + (Keyboard.current.sKey.ReadValue() * -1.0f);
|
|
steering += (Keyboard.current.dKey.ReadValue()) + (Keyboard.current.aKey.ReadValue() * -1.0f);
|
|
|
|
if(gamepad != null)
|
|
{
|
|
float throttleR = gamepad.rightTrigger.ReadValue();
|
|
float throttleL = gamepad.leftTrigger.ReadValue() * -1.0f;
|
|
throttle += throttleL + throttleR;
|
|
steering += gamepad.leftStick.ReadValue().x;
|
|
if(Vector3.Dot(Vector3.forward, localVelocity) < -0.1f)
|
|
steering *= -1.0f;
|
|
}
|
|
}
|
|
|
|
|
|
audioSourceRoar.volume = Mathf.Abs(throttle) * 0.75f;
|
|
audioSourceRoar.pitch = 1.05f;
|
|
|
|
audioSourceSledge.volume = Mathf.Clamp(horizontalVelocity.magnitude, 0.0f, 1.0f);
|
|
|
|
Fuel -= (Mathf.Abs(throttle) * FuelConsumptionPerSecond + FuelConsumptionPerSecondBase) * Time.fixedDeltaTime;
|
|
if(Fuel <= 0)
|
|
{
|
|
Fuel = 0;
|
|
disableInput = true;
|
|
}
|
|
|
|
|
|
if(disableInput)
|
|
{
|
|
audioSourceSpin.volume = 0.0f;
|
|
audioSourceRoar.volume = 0.0f;
|
|
}
|
|
|
|
float baseEmission = disableInput ? 0 : 0.1f;
|
|
thrusterParticleSystemLeft.emissionRate = (baseEmission + (1.0f - baseEmission) * (throttle - steering * -1.0f)) * 300.0f;
|
|
thrusterParticleSystemRight.emissionRate = (baseEmission + (1.0f - baseEmission) * (throttle - steering)) * 300.0f;
|
|
|
|
this.transform.Rotate(this.transform.up, steering * SteeringFactor * Time.fixedDeltaTime, Space.World);
|
|
Vector3 forward = this.transform.forward;
|
|
Vector3 horizontalForward = Vector3.Scale(new Vector3(1.0f, 0.0f, 1.0f), forward);
|
|
|
|
score = Mathf.Round(this.transform.position.z * 1000.0f) / 1000.0f;
|
|
|
|
horizontalVelocity += this.transform.forward * throttle * ThrustForce * Time.fixedDeltaTime;
|
|
|
|
horizontalVelocity -= horizontalVelocity * DragForce * Time.fixedDeltaTime;
|
|
|
|
UIManagerGame.Instance.Fuel = Fuel;
|
|
UIManagerGame.Instance.CountdownSeconds = (int)dynamiteCountDown;
|
|
UIManagerGame.Instance.Score = score;
|
|
|
|
this.transform.position += horizontalVelocity;
|
|
|
|
float OFFSET = 0.5f;
|
|
|
|
int OFFSET_COUNT_X = 4;
|
|
int OFFSET_COUNT_Y = 4;
|
|
|
|
// TODO: Find better way to smoothly slide across the terrain without bump distortions
|
|
|
|
int TOTAL_OFFSET_COUNT = OFFSET_COUNT_X * OFFSET_COUNT_Y;
|
|
|
|
Vector3[] floorRaycastOffsets = new Vector3[TOTAL_OFFSET_COUNT];
|
|
|
|
for(int x=0;x<OFFSET_COUNT_X; x++)
|
|
{
|
|
for(int y=0;y<OFFSET_COUNT_Y; y++)
|
|
{
|
|
float offsetX = ((2.0f / (OFFSET_COUNT_X-1)) * x) - 1.0f;
|
|
float offsetY = ((2.0f / (OFFSET_COUNT_Y-1)) * y) - 1.0f;
|
|
Vector3 offset = Vector3.up * OFFSET + Vector3.Scale((BenchBoxCollider.size / 2), new Vector3(offsetX, 0.0f, offsetY));
|
|
floorRaycastOffsets[x*OFFSET_COUNT_X+y] = offset;
|
|
}
|
|
}
|
|
|
|
Vector3[] floorRaycastHitOffsets = new Vector3[TOTAL_OFFSET_COUNT];
|
|
Vector3 averageNormal = Vector3.zero;
|
|
Vector3 averagePosition = Vector3.zero;
|
|
|
|
int hitCount = 0;
|
|
for(int n=0;n<floorRaycastHitOffsets.Length;n++)
|
|
{
|
|
Vector3 offset = floorRaycastOffsets[n];
|
|
RaycastHit hitInfo;
|
|
bool raycastHit = Physics.Raycast(this.transform.TransformPoint(offset), -this.transform.up, out hitInfo, 1000.0f, RayLayerMask.value);
|
|
if(raycastHit)
|
|
{
|
|
hitCount++;
|
|
floorRaycastHitOffsets[n] = hitInfo.point;
|
|
averageNormal += hitInfo.normal;
|
|
averagePosition += hitInfo.point;
|
|
}
|
|
}
|
|
|
|
averageNormal *= (1.0f / hitCount);
|
|
averagePosition *= (1.0f / hitCount);
|
|
|
|
if(hitCount == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Vector3 right = Vector3.Cross(averageNormal, this.transform.forward);
|
|
Quaternion rot = Quaternion.AngleAxis(90.0f, right);
|
|
|
|
Quaternion newRot = this.transform.rotation;
|
|
newRot.SetLookRotation(rot * averageNormal, averageNormal);
|
|
this.transform.rotation = newRot;
|
|
|
|
this.transform.position = averagePosition + this.transform.up * 1.0f;
|
|
|
|
Vector3 slope = Quaternion.AngleAxis(90.0f, Vector3.Cross(Vector3.up, averageNormal).normalized) * averageNormal;
|
|
float slopeMagnitude = Vector3.Scale(averageNormal, new Vector3(1.0f, 0.0f, 1.0f)).magnitude;
|
|
horizontalVelocity += slope.normalized * Physics.gravity.magnitude * Time.fixedDeltaTime * 0.1f * SlopeDragCurve.Evaluate(slopeMagnitude);
|
|
|
|
|
|
Debug.DrawRay(this.transform.position, slope, Color.yellow);
|
|
Debug.DrawRay(this.transform.position, horizontalForward, Color.green);
|
|
Debug.DrawRay(this.transform.position, rot * averageNormal, Color.red);
|
|
Debug.DrawRay(this.transform.position, averageNormal, Color.blue);
|
|
Debug.DrawRay(this.transform.position, right, Color.magenta);
|
|
}
|
|
|
|
protected void OnTriggerEnter(Collider collider)
|
|
{
|
|
Obstacle o = collider.gameObject.GetComponent<Obstacle>();
|
|
if(o != null)
|
|
{
|
|
o.OnHit(this.gameObject);
|
|
|
|
if(o.HitRecoilForce != 0.0f)
|
|
{
|
|
this.horizontalVelocity += -(collider.transform.position - this.transform.position).normalized * o.HitRecoilForce;
|
|
}
|
|
|
|
this.Fuel -= o.DamageOnHit;
|
|
}
|
|
|
|
PickupItem pu = collider.gameObject.GetComponent<PickupItem>();
|
|
if(pu != null && pu.PickedUp == false)
|
|
{
|
|
this.Fuel += pu.Fuel;
|
|
|
|
if(this.Fuel > 1.0f)
|
|
this.Fuel = 1.0f;
|
|
|
|
pu.OnPickup();
|
|
|
|
if(disableInput)
|
|
disableInput = false;
|
|
}
|
|
}
|
|
}
|