Idicator arrow flips upside down when player is below certain y axis. SOLVED!!!
I have been banging my head up against the wall for about a week now on how to resolve the indicator arrow flipping upside down when I drop below certain y axis during gameplay. I am fairly new to coding so please do go easy on me. Below is a copy of the code I am using that is attached to the objects that I want to identify. This works great until dropping below the y level. I have tried raising terrain to no avail. My landings are also all above 0. My player object is a ball with a camera attached to it which is the same camera (Main Camera) that I am using for this code. Thanks in advance for your help!
using UnityEngine; using System.Collections;
public class Newoffscreen : MonoBehaviour {
//Attach this class to the GameObject you want the arrow to be pointing at.
public Texture2D icon; //The icon. Preferably an arrow pointing upwards.
public float iconSize = 50f;
[HideInInspector]
public GUIStyle gooey; //GUIStyle to make the box around the icon invisible. Public so that everything has the default stats.
Vector2 indRange;
float scaleRes = Screen.width / 500; //The width of the screen divided by 500. Will make the GUI automatically
//scale with varying resolutions.
Camera cam;
bool visible; //Whether or not the object is visible in the camera.
void Start () {
visible = GetComponent<MeshRenderer> ().isVisible;
cam = Camera.main; //Don't use Camera.main in a looping method, its very slow, as Camera.main actually
//does a GameObject.Find for an object tagged with MainCamera.
indRange.x = Screen.width - (Screen.width / 6);//this makes the indicator not stack
indRange.y = Screen.height - (Screen.height / 7);//this makes the indicator not stack
indRange /= 6.5f; //this keeps indicator close to center of screen
gooey.normal.textColor = new Vector4 (0, 0, 0, 0); //Makes the box around the icon invisible.
}
void OnGUI () {
if (!visible) {
Vector3 dir = transform.position - cam.transform.position;
dir = Vector3.Normalize (dir);
//dir.y *= -1f;
Vector2 indPos = new Vector2 (indRange.x * dir.x, indRange.y * dir.y);
indPos = new Vector2 ((Screen.width / 2) + indPos.x,
(Screen.height / 2) + indPos.y);
Vector3 pdir = transform.position - cam.ScreenToWorldPoint(new Vector3(indPos.x, indPos.y,
transform.position.z));
pdir = Vector3.Normalize(pdir);
float angle = Mathf.Atan2(pdir.x , pdir.y) * Mathf.Rad2Deg;
GUIUtility.RotateAroundPivot(angle, indPos); //Rotates the GUI. Only rotates GUI drawn after the rotate is called, not before.
GUI.Box (new Rect (indPos.x, indPos.y, iconSize, iconSize), icon,gooey);
GUIUtility.RotateAroundPivot(0, indPos); //Rotates GUI back to the default so that GUI drawn after is not rotated.
}
}
void OnBecameInvisible() {
visible = false;
}
//Turns off the indicator if object is onscreen.
void OnBecameVisible() {
visible = true;
}
UPATED:
After a little research and a lot of hours. I found a solution to this issue. Thanks to this post from Andeeeee back in 2009: https://forum.unity3d.com/threads/an-icon-pointing-to-an-offscreen-enemy.32075/
What I did was change the Vector3 dir to this.
Vector3 dir = cam.transform.InverseTransformPoint (transform.position); dir.y = 0.0f; dir.Normalize ();
That took the y factor out of the arrow rotation, or zeroed it out I should say.
Then I changed the Vector2 inPos to this:
Vector2 indPos = new Vector2 (indRange.x - dir.x,indRange.y - dir.z); indPos = new Vector2 (Screen.width / 2 + indPos.x, 100 + indPos.y);
In which as you can see the dir.y is replaced with dir.z.
Last but not least to keep the angle right I changed its y value to z also like this:
float angle = Mathf.Atan2(pdir.x , pdir.z) * Mathf.Rad2Deg;
You might have to adjust things to fit your needs but this should be a great start for everyone looking for this answer. Hope this helps out!