Arrows pointing to offscreen enemy
Hi guys, I'm looking for a good tutorial for how to create arrows that point in the direction of a target offscreen. The arrows would be 2D gui, pointing to 3D objects, and sit just near the edge of the screen.
Is there a tutorial for this, because I think the maths would make my head explode!
I think what I need to do is draw a line to the enemy, and then detect where it touches the edge of the screen, and place my arrow there. But I'm not sure how to do that without complicated mathematics!
Try calculating the angle between the two 3d game objects positions, and then applying that angle to the 2d object? so something like:
float angle = Vector3.Angle(myShip.transform.position, otherShip.transform.position);
would give you the angle
Then something like :
arrow.transform.rotation.eulerAngles = new Vector 3(0, angle, 0);
Just use a fixed size arrow for now to see if you can get that working.
Thanks for the help @azmundai, but your calculation doesn't point the arrow towards the enemy. The angle never becomes a negative, so points mostly upwards.
Answer by Scribe · Aug 29, 2015 at 04:54 PM
You can use the builtin camera methods to get screen point and viewport point, both could be useful depending on the desired outcome, my example uses viewport as it tends to be easier to work with (as it's always between (0, 0) (bottom left) and (1, 1) (top right).
Vector3 screenPos;
Vector2 onScreenPos;
float max;
Camera camera;
void Start(){
camera = Camera.main;
}
void Update () {
screenPos = camera.WorldToViewportPoint(transform.position); //get viewport positions
if(screenPos.x >= 0 && screenPos.x <= 1 && screenPos.y >= 0 && screenPos.y <= 1){
Debug.Log("already on screen, don't bother with the rest!");
return;
}
onScreenPos = new Vector2(screenPos.x-0.5f, screenPos.y-0.5f)*2; //2D version, new mapping
max = Mathf.Max(Mathf.Abs(onScreenPos.x), Mathf.Abs(onScreenPos.y)); //get largest offset
onScreenPos = (onScreenPos/(max*2))+new Vector2(0.5f, 0.5f); //undo mapping
Debug.Log(onScreenPos);
}
Thanks for commenting @Scribe but I'm not sure how this helps. Surely what I need is an angle towards the player, and a location at the edge of the screen to place the arrow. I'm unsure what your mathematics is providing?
The code I posted gets the point at the edge of the screen, which a line would intercept if drawn from the centre of the screen to the target, this does assume the player is always close to the centre of the screen.
oh thanks this helped me finding the anchors value should be.
I am trying to use the script above. Should I just create a GameObject in a UI canvas, attach a cursor image and then attach this script?
Answer by morvi · Aug 19, 2017 at 05:56 PM
Hello,
I just used the code above and it works perfectly fine to me. My problem is, I don't understand, why it works ...especially this line:
onScreenPos = new Vector2(screenPos.x-0.5f, screenPos.y-0.5f)*2; //2D version, new mapping
I tried and tested and made some changes and it turned out it has to be done this way, but since screenPos can have any value, depending on where related to transform.position the viewport currntly is, I don't see how it can work.
I am really going crazy because of this...please help.
Thank you so much in advance
Morvi
This line just transforms the representation of the Viewport-space. Normally values range from: Vector2(0F,0F) to Vector2(1F,1F)
The line "maps" it to: Vector2(-1F,-1F) to Vector2(1F,1F) So e.g. Vector2(0.5F,0.5F) becomes Vector2(0F,0F) and Vector2(0F,0F) becomes Vector2(-1F,-1F)
the max then finds out which of x and y is closer to the edge. It then scales up the vector so that that closer value exactly hits the edge. Afterwards he reverts the mapping to be Vector2(0F,0F) to Vector2(1F,1F) again
You can even make this work in 3D-Space if you invert+forceclamp if the z value is negative
Vector3 viewportPos = cam.WorldToViewportPoint( worldPosition );
bool behindCamera = viewportPos.z < 0F;
if(behindCamera){
//invert vector and clamp
viewportPos = Vector3.one-viewportPos;
viewportPos = ClampToSquare(viewportPos); //above clamping code
}
Your answer
Follow this Question
Related Questions
Dragging object, raycast blocked by object 0 Answers
Quaternion and Direction for DrawRay(Make Object Look At Its Feet, Watch where its going...) 2 Answers
Problem with raycasting towards mouse 0 Answers
Check if player is facing an Object with Tag and set distance away 1 Answer
How can I incorporate a Rotation Towards the Mouse Position into this Script? I Tried. 0 Answers