Created
August 21, 2022 09:08
-
-
Save DraconInteractive/02b32e8ee54731b695e9463ed3be3bc5 to your computer and use it in GitHub Desktop.
Basic logic 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; | |
using System.Collections.Generic; | |
using UnityEngine; | |
using UnityEngine.Events; | |
public class BowTarget : MonoBehaviour | |
{ | |
// Collection / context pattern | |
public static List<BowTarget> All = new List<BowTarget>(); | |
// Rigidbody reference. Usually on target, experimenting with having it on attached objects | |
public Rigidbody rb; | |
// Vector difference between last frame and this frame. Used for aim assist prediction | |
public Vector3 Velocity; | |
// Same as arrow, time to live | |
public float destroyTTL; | |
// Toggle for whether to attempt to apply force on hit | |
public bool usePhysics; | |
// How much force to apply | |
public float hitForce; | |
// Prefab to be spawned on arrow hit | |
public GameObject hitFXPrefab; | |
// Scene functions for hit and destroy. Mainly for rapid prototyping, should be changed to delegates / events | |
public UnityEvent onHit; | |
public UnityEvent onDestroy; | |
// Reference to position on last frame | |
private Vector3 lastPos; | |
// Helper functions | |
// First is dot product comparing arrow forward and arrow direction to target (used to find best target) | |
public float Dot(Vector3 arrowPos, Vector3 arrowForward) => Vector3.Dot((transform.position - arrowPos).normalized, arrowForward); | |
// Second is finding the closest target to point. Used for ricochet | |
public static BowTarget ClosestTo(Vector3 point, List<BowTarget> previous = null) | |
{ | |
if (previous == null) | |
{ | |
previous = new List<BowTarget>(); | |
} | |
float dist = Mathf.Infinity; | |
BowTarget output = null; | |
foreach (var target in All) | |
{ | |
if (previous.Contains(target)) | |
{ | |
continue; | |
} | |
float d = Vector3.Distance(target.transform.position, point); | |
if (d < dist) | |
{ | |
dist = d; | |
output = target; | |
} | |
} | |
return output; | |
} | |
// Enable / Disable for context control | |
private void OnEnable() | |
{ | |
All.Add(this); | |
} | |
private void OnDisable() | |
{ | |
All.Remove(this); | |
} | |
// Useful event | |
private void OnDestroy() | |
{ | |
onDestroy?.Invoke(); | |
} | |
// Update velocity and last pos | |
private void Update() | |
{ | |
Velocity = transform.position - lastPos; | |
lastPos = transform.position; | |
} | |
// Useful for quickly populating the component when placed in scene. | |
// Can be overriding by dragging in a different rigidbody | |
private void OnValidate() | |
{ | |
if (rb == null) | |
{ | |
rb = GetComponent<Rigidbody>(); | |
} | |
} | |
// Called by arrow on hit. | |
public virtual void Hit(Vector3 point, Vector3 impulse) | |
{ | |
// Call scene event | |
onHit?.Invoke(); | |
// Create FX prefab, point it in the direction the arrow came | |
if (hitFXPrefab != null) | |
{ | |
Instantiate(hitFXPrefab, point, Quaternion.LookRotation(-impulse), this.transform); | |
} | |
// If should apply force, do so. Apply at position to get cool results | |
if (usePhysics && rb != null) | |
{ | |
rb.AddForceAtPosition(impulse * hitForce, point); | |
} | |
// If TTL is 0, target will remain after hit. Else it will destroy after being hit. | |
if (destroyTTL != 0) | |
{ | |
Destroy(this.gameObject, destroyTTL); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment