Created
August 21, 2022 08:50
-
-
Save DraconInteractive/c264172b3095a7f31a78c819c808de9d to your computer and use it in GitHub Desktop.
Basic logic flow for VR Bow mechanic
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
public class Arrow : MonoBehaviour | |
{ | |
[Header("Main")] | |
public Transform tip; | |
public float movementSpeed; | |
public float ttl = 5; | |
public float dropRate; | |
[Header("Aim Assist")] | |
public float pathCorrectionBase; | |
float pathCorrection; | |
private float velocityCorrection; | |
[Space] | |
public GameObject[] activateOnLaunch; | |
protected Coroutine launchR; | |
protected bool launched; | |
protected Vector3 velocity; | |
protected BowTarget target; | |
// Called on 'proper' notch release from BowModule | |
public virtual void Launch(float power, BowTarget target, float correctionMult = 0, float velocityCorrectionMult = 0.1f) | |
{ | |
// Apply slight starting rotation depending on aim assist. Makes further assistance less noticeable | |
if (target != null) | |
{ | |
Quaternion targetRot = Quaternion.LookRotation((target.transform.position - transform.position).normalized, Vector3.up); | |
transform.rotation = Quaternion.Lerp(transform.rotation, targetRot, correctionMult); | |
} | |
// Setup values for assistance | |
if (correctionMult != 0) | |
{ | |
pathCorrection = pathCorrectionBase * correctionMult; | |
velocityCorrection = velocityCorrectionMult; | |
} | |
// Release from nock, and set arrow speed | |
transform.SetParent(null); | |
movementSpeed *= power; | |
// Start controlling arrow, set state and turn on any useful objects | |
launchR = StartCoroutine(LaunchRoutine(target)); | |
launched = true; | |
foreach (GameObject go in activateOnLaunch) | |
{ | |
go.SetActive(true); | |
} | |
} | |
// Post-launch arrow control | |
protected virtual IEnumerator LaunchRoutine(BowTarget _target) | |
{ | |
target = _target; | |
// ttl = time to live. Therefore: while (still alive) | |
while (ttl > 0) | |
{ | |
ttl -= Time.deltaTime; | |
// Update last tip pos | |
Vector3 tipPos_last = transform.position; | |
// Increase drop rate. Gravity is accelleration so this replicates that | |
dropRate += dropRate * Time.deltaTime; | |
// Calculate base arrow movement vector | |
Vector3 delta = transform.forward * movementSpeed + Vector3.down * dropRate; | |
delta *= Time.deltaTime; | |
// Update velocity, apply movement | |
velocity = delta; | |
transform.position += delta; | |
// Update rotation to face velocity (needed for drop) | |
transform.rotation = Quaternion.LookRotation(delta.normalized, Vector3.up); | |
// If targetting, adjust rotation towards target | |
if (target != null) | |
{ | |
// Use target velocity to get better prediction of required target position | |
Vector3 targetPos = target.transform.position + target.Velocity * velocityCorrection; | |
Vector3 targetDir = targetPos - transform.position; | |
transform.rotation = Quaternion.RotateTowards(transform.rotation, Quaternion.LookRotation(targetDir.normalized, Vector3.up), pathCorrection * Time.deltaTime); | |
} | |
// Check if arrow has hit anything this frame | |
DetectHit(tipPos_last); | |
yield return null; | |
} | |
// After time to live runs out, destroy arrow | |
Destroy(this.gameObject); | |
yield break; | |
} | |
// Check between last frame and this frame whether arrow hit something | |
protected virtual void DetectHit(Vector3 tipPos) | |
{ | |
// Cast ray from arrow tip position in direction of velocity | |
Ray ray = new Ray(tipPos, velocity.normalized); | |
RaycastHit hit; | |
// If obstacle detected, try to get target component and forward to hit function | |
if (Physics.Raycast(ray, out hit, velocity.magnitude)) | |
{ | |
BowTarget t = hit.transform.GetComponent<BowTarget>(); | |
BaseHit(hit, t); | |
} | |
} | |
protected virtual void BaseHit(RaycastHit hit, BowTarget t) | |
{ | |
// Get vector from base of arrow / nock to tip of arrow | |
Vector3 tipDelta = tip.position - transform.position; | |
// Make sure the arrow actually launched before it hit anything | |
if (launched) | |
{ | |
// Move arrow so that the tip is embedded in the hit point (looks cooler) | |
transform.position = hit.point - (tipDelta * 0.95f); | |
// If we hit a BowTarget, forward on the results | |
if (t != null) | |
{ | |
t.Hit(tip.position, velocity); | |
} | |
// Stop the movement handling routine | |
StopCoroutine(launchR); | |
// Destroy this in 3 seconds. With no LaunchRoutine, TTL is disabled. | |
// This is nicer since it gives the player a chance to see the arrow properly in the target before it disappears | |
Destroy(this.gameObject, 3); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment