I am working on a 3D space combat game where I have first and third person cameras. For the third person camera, it is slightly above and behind the ship. When the ship changes direction, the camera points in that direction, similar to Star Wars Battlefront II space combat. The question is how to provide accurate aiming with crosshairs. Raycasting won’t work because you have to lead shots so hit moving targets.
The problem with your setup is triangulation.
The orange hex represents the screen…that is the start of the ray into the 3D space. The blue triangle is the ship or gun or spawn point that you need to point to fire the projectile. Given a ray, there are an infinite number of places along the ray that the ship/gun/point can be aimed, and how you solve it will depend on your game.
If most of the action happens around a certain distance in front of the ship, then you can just pick a distance along the ray for the aiming to take place. You can use Camera.ScreenToWorldPoint(). The ‘Z’ parameter of the passed Vector3 will be the distance in front of the camera plane to calculate the point.
If your targets can be at greatly varying distances then you will need to pick an object to use to calculate the distance. You can find the nearest object to the mouse position by using Camera.WorldToScreenPoint() to convert each potential target a screen coordinate. You can then find the target with the least distance to the mouse position. The distance between the camera and that target is a good approximation to use for the distance in your Camera.WorldToScreenPoint() calculation.
If you need a more accurate calculation, then you can use Unity’s mathematical Plane and use Plane.Raycast() against that plane. A mathematical plane is constructed using a point and a normal to the plane. For your geometry here, you would construct the plane using the point of the target and the ‘forward’ of the camera.
well i think there is a fundamental difficulty in aiming accurately from a third person camera. i’ve seen some game that had a target reticule that would guess the distance to the target and then adjust accordingly… it wasn’t great but worked ok. also if your camera is close enough to directly behind the ship and they are exactly aligned, then a cross-hairs in the middle of your camera would work for relatively distant targets, and close ones you would just have to know to aim above them.
so basically the only things i can think of are the automatic distance-adjusting sight, and the fixed on the camera one that you manually compensate for.
I’ve had the exact same problem. The “player camera” is raised above and behind my spaceship so any targeting reticule in the screenspace would be misleading.
I solved it by having a “Targeting camera” setup inline with the space ship. Set “Clear Flags” to “Depth Only” and “Culling Mask” to “Nothing”. Both cameras are set up via a script to orbit the ship when the mouse moves but the player camera orbits a point above the ship and the targeting camera orbits the actual ship. Viewing through the Targeting camera would mean that the targeting would be accurate but the ship would always obscure the target.
I then created a Canvas element with the render mode set to “world space”, the Canvas is set to a “UI” layer and finally the Canvas is set as a child of the Targeting camera. The canvas contains the targeting reticule right in the middle. Now when the Targeting camera moves the reticule exists in the world space and moves aswell with the Targeting camera, the ship and the targeting reticule all inline at all times.
Currently, if you set the player camera to include the “UI” layer then you’ll see the offset reticule on the screen. However the reticule will cut through objects as it exists in world space. To solve this the final step is to create another Camera as a child of the player camera. Set “Clear Flags” to “Depth Only” and “Culling Mask” to “UI” layer. Give it a “depth” higher than the player camera and finally remove the UI layer from player camera’s Culling Mask.
The reticule will now be onscreen all the time as expected and will always point to the target correctly.