Using 2D gui pointer to point to game objects in 3d space

Hi Unity community,

I’ve been running into problems with an pointer/icon system that is part of the HUD for a game I’m working on…here’s what I want it to do:

-Pointer has to appear on the screen and rotate to point to tagged game objects when the player is within a certain proximity to that game object.

-Within the pointer there is space to display an icon that provides the player with relevant information about the game object (for example, a particle system that is part of a fire on the map that represents danger to the player causes a small fire icon to appear on top of the pointer graphic. These symbols are stored in a .ttf.

I have been using camera.WorldToScreenPoint (gameObject.position) to get the coordinates of the game object into 2d coordinates that my pointer system can use.

What I am unsure about is how to take those coordinates and rotate my pointer to guide the player to the game object.

Can anyone here provide help? I can post the code I’ve been working with if necessary.

cz2isq

Is your pointer in a static position on the screen, or is it a free cursor?

The pointer icon itself is static, yes. But it is free to rotate around to point to the game objects.

Sounds neat!
since its position is static, you might be able to ‘cheat’ in a way:

make the pointer a game object instead of a GUI element, create it as a child of the camera and self-illuminated, with the z-axis aligned in its point direction.

if you create an empty game object at the designated point of interest on the screen and the same relative plane, you can use the ‘lookat’ options to have the pointer rotate to it, or Lerp it as you see fit.

You could feasibly apply priority tags or names to the game objects as they are created, allowing the pointer to go to the most important one, or the most recent, or even either one based on user preferences.

Not really sure I know what you mean. The pointer is really just an imported .png. I already have the tagged game objects on my 3d terrain that I want it to point to.

Where are these lookat and Lerp options? Newbie here…

Here’s the code I’ve been attempting to use to get the pointer to rotate…

var customLabel: GUIStyle;
var pointer : Texture2D;
var textFieldString = "A";   //textFieldString is the .ttf where the symbols are supposed to be accessed from
var rotator:float;
rotator = 90.0;

function OnGUI () {
GUIUtility.RotateAroundPivot(rotator, Vector2(Screen.width-50, Screen.height -60));
       
       GUI.depth = 3;
       GUI.Label (Rect (Screen.width-84, Screen.height -105,80,80),  pointer);
       
GUIUtility.RotateAroundPivot(-rotator, Vector2(Screen.width-82, Screen.height -50));
       GUI.depth = 1;
       GUI.Label (Rect (Screen.width-100, Screen.height -90,100,100), textFieldString, customLabel);
}
function Update () {
var screenPos = camera.WorldToScreenPoint (gameObject.position);
print ("target is " + screenPos.x + " pixels from the left");
}

// where gameObject can be changed to whenever I need to change the symbols from the .ttf

I’m an amateur myself; I certainly haven’t started fiddling with the GUIutility operations, you may be on to something there.

Here’s a rudimentary example of the 3D pointer at work:
http://www.archonium.com/pointer_sample.html

It is set to point at the light source.

and the project file:

http://www.archonium.com/pointer_sample.zip
(open the “sample” scene)

it uses this script (along with standard FPS walker scripts):

var trigger_object: Transform;
var camera_object: GameObject; 
private var target_created = false;
private var target : GameObject;

function LateUpdate () {

	var screenPos = camera_object.camera.WorldToScreenPoint (trigger_object.position);
	if (!target_created){   //should probably put this in Start()		
		target = GameObject.CreatePrimitive(PrimitiveType.Sphere);
        target_created = true;
        target.transform.localScale = Vector3(0.01, 0.01, 0.01);
        Destroy(target.collider); 
	}
	else //set the sphere position to right where the screen point is.
	   	target.transform.position = camera_object.camera.ScreenToWorldPoint (Vector3 (screenPos[0],screenPos[1],0.35));
	
	    	
	//tell the peg to turn towards the sphere
	transform.LookAt(target.transform);
	

}

That script is placed on the “peg”, a sphere set at the pivot point for the pointer. The pointer itself is a child of that object. You could get by with a single object if the axis is properly placed.

a target is generated in world-space based on the screen-space of the position of the light source, directly in front of the camera, along with the pointer, which targets it with LookAt.

I used a cone pointer here because LookAt will cause some rotation around its forward axis that would be very evident with a 2D pointer.

I used a sphere as a target in this example instead of an empty game object to illustrate the method better. The sphere appearing to hover over the light is actually very small and right in front of the camera, on nearly the same plane as the pointer that targets it. These are both within the collider of the camera.

This method has its limitations, and as you can see there is a slight issue when the target object is directly on or behind the camera, but it’s fairly simple so good to work with for a start, I feel, and these can probably be solved with a few simple “If target is this close do this” and “if target is not visible” sort of things.

LookAt: Unity - Scripting API: Transform.LookAt

You may also want to take a glance at Quaternions; Quaternion.Lerp, and
Quaternion.FromToRotation;

A.A.Slayden - that pointer example is exactly what I was after. I’m taking a look at the code now. Thanks very much for the assistance and I’ll let you know how it turns out.

cz2isq

I can’t get this to work as you described…I can send you a link to my assets folder in a PM if you are willing to take a look at the level…

But that example you posted does exactly what I want it to do…I just can’t get it to play nicely with my project.

cz2isq

Sure throw it at me, I’ll see if I can lend a hand

OK, sent you a PM

bumping to see if there are any fresh ideas on this…

Does the WorldToScreenPoint work for you? If it does then you have a position on the same plane as your camera to point at. If you calculate the vector that points from your pointer to this position (objectsScreenPos - pointerPos). Take the x and y of this (so 2D) and use it with Atan2 to calculate the angle in radians that this line is.
Something like:

Vector3 direction = (objectsRelativeScreenPos - transform.position).normalized;

float angleRad = Mathf.Atan2(direction.y, direction.x);
float angleDeg = angleRad * 57.2957795f;
transform.localEularAngles = new Vector3(0, 0, angleDeg);

and that should work. Make sure you use y then x with the Atan2 function, and you can convert from radians to degrees in another way if you prefer.

While I am here though, I am having some trouble doing this myself. I am trying to do something similar except I want my marker to move, basically being constrained by the edges of the screen. I can get it bound by the screen easy enough. My problem is converting the world space of the object to some screen space. My main camera is at an angle looking down at the ground (about a 48 degree angle) and it moves to follow the player. The HUD camera is at 0,0,0 and faces straight along the z axis (so no rotation) and is an orthographic camera. I can’t seem to translate an enemies position from world space to a position on this same plane. Basically I am just moving the marker directly towards this position without letting it leave the screen (and ideally I want it to vanish when the enemy enters the main cameras frustum).

If anyone has any ideas on this that would be awesome.

Adsy.

Edit

Just noticed the date the last entry was posted. I may be a little late on this one lol.

1 Like