VR Development Framework
v 1.0.0
 All Classes Namespaces Functions Variables Enumerations Enumerator Properties Events Pages
AVR_Ray.cs
1 using System.Collections;
2 using System.Collections.Generic;
3 using UnityEngine;
4 
5 namespace AVR.Core {
6  /// <summary>
7  /// Base class for a ray. A ray is always cast in transform.forward direction of the object it is attatched to.
8  /// Rays of this type do not collide with any objects and pass through everything.
9  /// Use AVR_SolidRay if collisions are required.
10  /// </summary>
11  [AVR.Core.Attributes.DocumentationUrl("class_a_v_r_1_1_core_1_1_a_v_r___ray.html")]
12  [RequireComponent(typeof(LineRenderer))]
13  public class AVR_Ray : AVR_Component
14  {
15  //// ENUMS =====================================================================================================
16  public enum RayMode { STRAIGHT, PROJECTILE_MOTION } //TODO: Implement Bezier, Sine, etc etc
17 
18 
19  //// MEMBERS ===================================================================================================
20 
21  [Header("Shape")]
22  /// <summary> What type of ray should be used </summary>
23  public RayMode mode = RayMode.STRAIGHT;
24 
25  // These only concern rays of mode=PROJECTILE
26  /// <summary> How many vertices per unit distance to use for projectile motion ray </summary>
27  [AVR.Core.Attributes.ConditionalHideInInspector("mode", ((int)RayMode.PROJECTILE_MOTION), invertCondition: true)]
28  public int proj_resolution = 3;
29 
30  /// <summary> Max. amount of vertices to use for projectile motion ray </summary>
31  [AVR.Core.Attributes.ConditionalHideInInspector("mode", ((int)RayMode.PROJECTILE_MOTION), invertCondition: true)]
32  public float proj_max_verts = 150;
33 
34  /// <summary> Starting velocity of the projectile motion </summary>
35  [AVR.Core.Attributes.ConditionalHideInInspector("mode", ((int)RayMode.PROJECTILE_MOTION), invertCondition: true)]
36  [Range(0.5f, 6.0f)]
37  public float proj_velocity = 3;
38 
39  [Header("Settings")]
40  /// <summary> Hide or show the ray immediately on Awake() </summary>
41  public bool start_hidden = true;
42  /// <summary> Maximum length of the ray </summary>
43  public float max_length = 25;
44  /// <summary> Will restrict the length of the ray along the xz-Plane to a given value. </summary>
45  public float max_horizontal_distance = 10;
46  /// <summary> Will restrict the minium angle of the Ray with the y-Axis. </summary>
47  public float min_y_angle = 0;
48 
49  // Private / Protected:
50  protected LineRenderer lr;
51  protected bool _hidden;
52  protected Vector3[] positions = new Vector3[0];
53  protected Vector3 RayForward = Vector3.forward;
54 
55  /// <summary> Is this ray visible </summary>
56  public bool isVisible {
57  get { return !_hidden; }
58  }
59 
60  /// <summary> Is this ray hidden </summary>
61  public bool isHidden {
62  get { return _hidden; }
63  }
64 
65 
66  //// METHODS ===================================================================================================
67 
68  protected override void Awake()
69  {
70  base.Awake();
71 
72  if(!lr) lr = GetComponent<LineRenderer>();
73  if(!lr) {
74  AVR_DevConsole.error("AVR_Ray object "+gameObject.name+" has no LineRenderer attatched!");
75  }
76  if(start_hidden) hide(); else show();
77  UpdateRay();
78  }
79 
80  protected virtual void Update() {
81  UpdateRay(); //This ray needs continous updating
82  }
83 
84  /// <summary> Updates the ray. Called from Monobehaviour.Update() </summary>
85  protected virtual void UpdateRay() {
86  if(isHidden) return;
87 
88  // This paragraph deals with the min_y_angle parameter.
89  /// An brief explanation on the math done here:
90  /// Say alpha is the angle between RayForward and the y-axis. We want a minium alpha of 30°.
91  /// Basic trigonometry tells us, that alpha >= 30° is equivalent with RayForward.y <= cos(30°).
92  /// Consequently, RayForward.y will be clamped to exaclty cos(30°). What remains is setting the xz vector accordingly.
93  /// Since the whole vector is normalized, the hypotenuse is 1. So pythagoras => 1^2 = |RayForward.xz|^2 + Rayforward.y^2
94  /// As a result, the length of RayForward.xz is equal to |RayForward.xz| = sqrt(1-RayForward.y^2)
95  /// And since RayForward.y = cos(30°): |RayForward.xz| = sqrt(1-cos(30°)^2) = sin(30°)
96  /// And this is what we do here. If the condition is violated, we set y=0, then multiply the normalized vector with sin(alpha)
97  /// and finally set y to cos(alpha).
98  RayForward = transform.forward;
99  float ang = Mathf.Deg2Rad * min_y_angle;
100  if(RayForward.y > Mathf.Cos(ang)) {
101  RayForward.y = 0;
102  RayForward = RayForward.normalized * Mathf.Sin(ang);
103  RayForward.y = Mathf.Cos(ang);
104  }
105 
106  switch (mode)
107  {
108  // Straight beam
109  case RayMode.STRAIGHT: {
110  UpdateStraightRay();
111  break;
112  }
113 
114  // Parabolic projectile motion, affected by gravity
115  case RayMode.PROJECTILE_MOTION: {
116  UpdateProjectileRay();
117  break;
118  }
119  default: {
120  AVR.Core.AVR_DevConsole.warn("RayMode type of AVR_Ray object "+gameObject.name+" has not been implemented.");
121  break;
122  }
123  }
124  }
125 
126  /// <summary> Updates a ray with mode==STRAIGHT </summary>
127  protected virtual void UpdateStraightRay() {
128  // Make sure we only have 2 positions
129  if (positions.Length != 2) positions = new Vector3[2];
130 
131  // Se which condition determines the endpoint, max_length or max_horizontal_distance. Semi-TODO: This seems like an unelegant solution. Find a better one.
132  Vector3 dest = RayForward * max_length;
133  if(new Vector2(dest.x, dest.z).magnitude > max_horizontal_distance){
134  dest *= max_horizontal_distance / Mathf.Max(new Vector2(dest.x, dest.z).magnitude, 0.0001f);
135  }
136 
137  // Initialize between here & max_length
138  this.positions[0] = transform.position;
139  this.positions[1] = transform.position + dest;
140 
141  // Set line
142  lr.useWorldSpace = true;
143  lr.positionCount = 2;
144  lr.SetPositions(positions);
145  }
146 
147  /// <summary> Updates a ray with mode==PROJECTILE </summary>
148  protected virtual void UpdateProjectileRay() {
149  List<Vector3> posl = new List<Vector3>();
150 
151  for (int i = 0; i < proj_max_verts; i++)
152  {
153  float dist = (float)i / proj_resolution;
154 
155  Vector3 dest = RayForward * dist;
156 
157  // Add new vertex to line
158  posl.Add(transform.position + dest - Vector3.up * (dist * dist) / (proj_velocity * proj_velocity));
159 
160  // Check if we're within distance limitations. NOTE: We are only restricting distance in the direction of transform.forward, not up or down.
161  if (dist >= max_length) break;
162 
163  if (new Vector2(dest.x, dest.z).magnitude > max_horizontal_distance) break;
164  }
165 
166  this.positions = posl.ToArray();
167  lr.useWorldSpace = true;
168  lr.positionCount = posl.Count;
169  lr.SetPositions(this.positions);
170  }
171 
172  /// <summary> Hides the ray. A ray is not updated while hidden. </summary>
173  public virtual void hide() {
174  setHidden(true);
175  }
176 
177  /// <summary> Shows the ray. A ray is not updated while hidden. </summary>
178  public virtual void show() {
179  setHidden(false);
180  }
181 
182  /// <summary>
183  /// Set the hidden status of the ray
184  /// </summary>
185  /// <param name="hidden">True to hide, false to show</param>
186  public virtual void setHidden(bool hidden) {
187  _hidden = hidden;
188  lr.enabled = !hidden;
189  }
190 #if AVR_NET
191  [HideInInspector]
193  public bool synchronizeHidden = false;
194 
195  [Unity.Netcode.ServerRpc(RequireOwnership = false)]
196  private void syncServerRpc(InternalState state)
197  {
198  m_ReplicatedState.Value = state;
199  }
200 
201  private void sync()
202  {
203  if (!synchronizeHidden) return;
204  if (IsOwner)
205  {
206  InternalState state = new InternalState();
207  state.FromReference(this);
208  }
209  else
210  {
211  m_ReplicatedState.Value.ApplyState(this);
212  }
213  }
214 
215  private readonly Unity.Netcode.NetworkVariable<InternalState> m_ReplicatedState = new Unity.Netcode.NetworkVariable<InternalState>(Unity.Netcode.NetworkVariableReadPermission.Everyone, new InternalState());
216 
217  private struct InternalState : IInternalState<AVR_Ray>
218  {
219  public bool Hidden;
220 
221  public void FromReference(AVR_Ray reference)
222  {
223  Hidden = reference.isHidden;
224  }
225 
226  public void ApplyState(AVR_Ray reference)
227  {
228  reference.setHidden(Hidden);
229  }
230 
231  public void NetworkSerialize<T>(Unity.Netcode.BufferSerializer<T> serializer) where T : Unity.Netcode.IReaderWriter
232  {
233  serializer.SerializeValue(ref Hidden);
234  }
235  }
236 #endif
237  }
238 }
override void Awake()
Definition: AVR_Ray.cs:68
LineRenderer lr
Definition: AVR_Ray.cs:50
Base class for a ray. A ray is always cast in transform.forward direction of the object it is attatch...
Definition: AVR_Ray.cs:13
Makes a property of an object only show in the Network-behaviour window. Also works for private/prote...
virtual void UpdateRay()
Updates the ray. Called from Monobehaviour.Update()
Definition: AVR_Ray.cs:85
Sets the documentation html file inside of Packages/com.avr.core/Documentation/html of a given class...
virtual void UpdateStraightRay()
Updates a ray with mode==STRAIGHT
Definition: AVR_Ray.cs:127
virtual void setHidden(bool hidden)
Set the hidden status of the ray
Definition: AVR_Ray.cs:186
virtual void UpdateProjectileRay()
Updates a ray with mode==PROJECTILE
Definition: AVR_Ray.cs:148
Allows for simple hiding of properties in the UnityEditor depending on certain conditions. For instance, in the following example the "type" field will only be displayed in the inspector if the "tracking" field is set to true:
virtual void hide()
Hides the ray. A ray is not updated while hidden.
Definition: AVR_Ray.cs:173
Base class for all arc-vr components. A component is typically a Monobehaviour that represents a virt...
virtual void show()
Shows the ray. A ray is not updated while hidden.
Definition: AVR_Ray.cs:178
virtual void Update()
Definition: AVR_Ray.cs:80