- Home /
Issue with ScreenToWorldPoint
So, ive been trying to set up a tank game with a top down camera view (the game is still 3D). I want to write a script to let me point the turret towards the mouse. The camera has a script to keep folowing the tank but it is not attached to the tank gameObject itself
I am also not sure whether the script should be attached to the turret or the camera
the compiler keeps sending the same Error
Assets\Scripts\TowerControl.cs(8,12): error CS0246: The type or namespace name 'cam_Main' could not be found (are you missing a using directive or an assembly reference?)
this is my script so far, I haven't had much luck though :/
using UnityEngine;
// continuously point turret at mouse
public class TowerControl : MonoBehaviour {
public cam_Main.ScreenToWorldPoint target;
void Update()
{
//Rotate the turret every frame so it keeps looking at the target
TankFree_Tower.transform.LookAt(target);
// Same as above, but setting the worldUp parameter to Vector3.left turns the camera on its side
TankFree_Tower.transform.LookAt(target, Vector3.left);
}
}
Answer by Luis_Gan · Apr 29, 2020 at 08:50 PM
Something like this? (Attach the script to the tower)
public Camera mainCamera;
void Update()
{
Vector3 position = mainCamera.ScreenToViewportPoint(Input.mousePosition);
transform.LookAt(position);
}
that wont work though, because you would have to put the main camera variable on the tower, and the tower is not a camera (see error) \/
UnassignedReferenceException: The variable mainCamera of TowerControl has not been assigned. You probably need to assign the mainCamera variable of the TowerControl script in the inspector.
Set the camera tag to $$anonymous$$ainCamera and it will work.
private Camera mainCamera;
void Start()
{
mainCamera = Camera.main;
}
void Update()
{
Vector3 position = mainCamera.ScreenToViewportPoint(Input.mousePosition);
transform.LookAt(position, Vector3.up);
}
Wait, i'm sorry, something got jacked up. if you could please reply your latest comment to this message, something got messed up
mainCamera.ScreenToViewportPoint(Input.mousePosition);
transform.LookAt(position);
This will not behave correctly. ScreenToViewportPoint converts simply a mouse position between (0,0) and (Screen.width, Screen.height) to the range of (0,0) - (1,1)
If you then just use this as the argument for transform.LookAt()
the object will always rotate to look at world positions between (0,0,0) and (1,1,0), and not around the tank. At the very least you actually need to transform the mouse position into a range of (-1,-1) to (1,1) to properly offer all 360° directions, as (0,0) - (1,1) will only provide the top-right 90° corner of possible direction vectors.
Answer by Isstanger · Apr 29, 2020 at 08:30 PM
This is hurting my brain, way more than I thought it would
Answer by Fuzzel_ · Jun 01, 2020 at 09:32 PM
If you want to have the tank look at your mouse, with a top-down perspective, I assume you want to the tank to rotate only on the y-axis towards the mouse, and that the camera is looking directly down onto the world with a 90-degree angle.
Given that the camera is directly looking down onto the tank, and is always centred on the tank, you can simply take the mouse position: Mouse.current.position.ReadValues()
/ Input.mousePosition
(depending on if you are using the new input system or not) and subtract the centre screen position: new Vector2(Screen.width/2, Screen.height/2)
With this direction vector, you can either create a new rotation with Quaternion.LookRotation()
, or use transform.LookAt()
public class LookAtMouse : MonoBehaviour
{
private readonly Vector2 screenCenter = new Vector2(Screen.width/2.0f, Screen.height/2.0f);
private void Update()
{
Vector2 mousePosition = Mouse.current.position.ReadValue(); // Input.mousePosition in the old input system
Vector2 directionToMouse = (mousePosition - screenCenter).normalized;
transform.rotation = Quaternion.LookRotation(new Vector3(directionToMouse.x, 0, directionToMouse.y), Vector3.up);
// - or -
transform.LookAt(transform.position + new Vector3(directionToMouse.x, 0, directionToMouse.y));
}
}
If you want to have a camera that may be at an angle, the solution becomes a bit more involved because you want to calculate the position of the mouse in your world, or rather, you want to calculate the world position of the point your mouse points at.
This can be done with a raycast, which would also support 3d models that are sticking out from a flat surface, but a faster approach that only considers the flat "floor" can be achieved by calculating a vector from your camera into the world to where you mouse is pointing at and then calculating the intersection with the "floor plane", to get the world position of the point your mouse is pointing at. With this you can either do transform.LookAt()
or, similar to the code above, subtract the tanks world position to get the direction vector from your tank to the world position of the point your mouse is pointing at and do Quaternion.LookRotation()
.
If you are interested in that because the camera might not always be centred on the tank or might not always look down at the tank at a 90-degree angle, I'll happy to provide you with some code about the more complex solution I just described.