Files
aibis-dream/Assets/Shapes/Samples/Assets/Scripts/FpsController.cs
T
2025-05-07 15:07:44 +08:00

185 lines
5.6 KiB
C#

using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Rendering;
namespace Shapes {
[Serializable]
public class Decayer {
public float decaySpeed;
public float magnitude;
public AnimationCurve curve;
[NonSerialized] public float value;
[NonSerialized] public float valueInv;
[NonSerialized] public float t;
public void SetT( float v ) => t = v;
public void Update() {
t = Mathf.Max( 0, ( t - decaySpeed * Time.deltaTime ) );
float tEval = curve.keys.Length > 0 ? curve.Evaluate( 1f - t ) : t;
value = tEval * magnitude;
valueInv = ( 1f - tEval ) * magnitude;
}
}
[ExecuteAlways]
public class FpsController : ImmediateModeShapeDrawer {
// components
public Transform head;
public Camera cam;
public Crosshair crosshair;
public ChargeBar chargeBar;
public AmmoBar ammoBar;
public Compass compass;
public Transform crosshairTransform;
[Header( "Player Movement" )] [Range( 0.8f, 1f )] public float smoof = 0.99f;
public float moveSpeed = 1f;
public float lookSensitivity = 1f;
float yaw;
float pitch;
Vector2 moveInput = Vector2.zero;
Vector3 moveVel = Vector3.zero;
[Header( "Sidebar Style" )] [Range( 0f, ShapesMath.TAU / 2 )] public float ammoBarAngularSpanRad;
[Range( 0, 0.05f )] public float ammoBarOutlineThickness = 0.1f;
[Range( 0, 0.2f )] public float ammoBarThickness;
[Range( 0, 0.2f )] public float ammoBarRadius;
[Header( "Animation" )] [Range( 0f, 0.3f )] public float fireSidebarRadiusPunchAmount = 0.1f;
public AnimationCurve shakeAnimX = AnimationCurve.Constant( 0, 1, 0 );
public AnimationCurve shakeAnimY = AnimationCurve.Constant( 0, 1, 0 );
void Awake() {
if( Application.isPlaying == false )
return;
InputFocus = true;
StartCoroutine( FixedSteps() );
}
// called by the ImmediateModeShapeDrawer base type
public override void DrawShapes( Camera cam ) {
if( cam != this.cam ) // only draw in the player camera
return;
using( Draw.Command( cam ) ) {
Draw.ZTest = CompareFunction.Always; // to make sure it draws on top of everything like a HUD
Draw.Matrix = crosshairTransform.localToWorldMatrix; // draw it in the space of crosshairTransform
Draw.BlendMode = ShapesBlendMode.Transparent;
Draw.LineGeometry = LineGeometry.Flat2D;
crosshair.DrawCrosshair();
float radiusPunched = ammoBarRadius + fireSidebarRadiusPunchAmount * crosshair.fireDecayer.value;
ammoBar.DrawBar( this, radiusPunched );
chargeBar.DrawBar( this, radiusPunched );
compass.DrawCompass( head.transform.forward );
}
}
IEnumerator FixedSteps() {
while( true ) {
FixedUpdateManual();
yield return new WaitForSeconds( 0.01f ); // 100 fps
}
}
public static void DrawRoundedArcOutline( Vector2 origin, float radius, float thickness, float outlineThickness, float angStart, float angEnd ) {
// inner / outer
float innerRadius = radius - thickness / 2;
float outerRadius = radius + thickness / 2;
const float aaMargin = 0.01f;
Draw.Arc( origin, innerRadius, outlineThickness, angStart - aaMargin, angEnd + aaMargin );
Draw.Arc( origin, outerRadius, outlineThickness, angStart - aaMargin, angEnd + aaMargin );
// rounded caps
Vector2 originBottom = origin + ShapesMath.AngToDir( angStart ) * radius;
Vector2 originTop = origin + ShapesMath.AngToDir( angEnd ) * radius;
Draw.Arc( originBottom, thickness / 2, outlineThickness, angStart, angStart - ShapesMath.TAU / 2 );
Draw.Arc( originTop, thickness / 2, outlineThickness, angEnd, angEnd + ShapesMath.TAU / 2 );
}
public Vector2 GetShake( float speed, float amp ) {
float shakeVal = ShapesMath.Frac( Time.time * speed );
float shakeX = shakeAnimX.Evaluate( shakeVal );
float shakeY = shakeAnimY.Evaluate( shakeVal );
return new Vector2( shakeX, shakeY ) * amp;
}
bool InputFocus {
get => !Cursor.visible;
set {
Cursor.lockState = value ? CursorLockMode.Locked : CursorLockMode.None;
Cursor.visible = !value;
}
}
void FixedUpdateManual() {
if( Application.isPlaying == false )
return;
if( InputFocus ) {
Vector3 right = head.right;
Vector3 forward = head.forward;
forward.y = 0;
moveVel += ( moveInput.y * forward + moveInput.x * right ) * ( Time.fixedDeltaTime * moveSpeed );
}
transform.position += moveVel * Time.deltaTime; // move
moveVel *= smoof; // decelerate
}
void Update() {
if( Application.isPlaying == false )
return;
crosshair.UpdateCrosshairDecay();
chargeBar.UpdateCharge();
if( InputFocus ) {
// mouselook
yaw += Input.GetAxis( "Mouse X" ) * lookSensitivity;
pitch -= Input.GetAxis( "Mouse Y" ) * lookSensitivity;
pitch = Mathf.Clamp( pitch, -90, 90 );
head.localRotation = Quaternion.Euler( pitch, yaw, 0f );
chargeBar.isCharging = Input.GetMouseButton( 1 ); // rmb
if( Input.GetKey( KeyCode.R ) )
ammoBar.Reload();
// actions
if( Input.GetMouseButtonDown( 0 ) && ammoBar.HasBulletsLeft ) {
// Fire
ammoBar.Fire();
crosshair.Fire();
Ray ray = new Ray( head.position, head.forward );
if( Physics.Raycast( ray, out RaycastHit hit ) && hit.collider.gameObject.name == "Enemy" )
crosshair.FireHit();
}
// move input
moveInput = Vector2.zero;
void DoInput( KeyCode key, Vector2 dir ) {
if( Input.GetKey( key ) )
moveInput += dir;
}
DoInput( KeyCode.W, Vector2.up );
DoInput( KeyCode.S, Vector2.down );
DoInput( KeyCode.D, Vector2.right );
DoInput( KeyCode.A, Vector2.left );
// leave focus mode stuff
if( Input.GetKeyDown( KeyCode.Escape ) )
InputFocus = false;
} else if( Input.GetMouseButtonDown( 0 ) ) {
InputFocus = true;
}
}
}
}