There are some errors in the logic. You must get firePosition using ViewportToWorldPoint with (0.5, 0.5, hand distance + 3), and handPosition with (mouse pos X, mouse pos Y, hand distance), where hand distance is the distance from camera to hand (variable distFromCam added to the code to define this distance).
While the mouse button is pressed, calculate both, handPosition and firePosition, and when the mouse is released create and shoot the projectile - you must calculate the rotation to create the projectile in the shooting direction. Get a reference to the projectile instantiated and use it to add the shooting force in its forward direction:
...
public GameObject projectilePrefab;
public float distFromCam = 2.0f; // distance from camera to hand
void Update () {
transform.LookAt(target);
if (Input.GetMouseButton(0)) // aim while the mouse button is down
{
firePosition = Camera.main.ViewportToWorldPoint (new Vector3(0.5f, 0.5f, distFromCam+3.0f)); // 3D point at screen center, 3 units ahead hand
handPosition = Camera.main.ScreenToWorldPoint (new Vector3 (Input.mousePosition.x, Input.mousePosition.y, distFromCam));
// draw a debug line just to see what's happening (click Gizmos to see the line)
Debug.DrawLine(handPosition, firePosition, Color.green);
}
if (Input.GetMouseButtonUp(0)) // shoot in last aimed direction when button released
{
Vector3 projDir = firePosition - handPosition; // calculate the projectile direction
// calculate rotation to turn projectile's forward direction to the shooting direction
Quaternion rot = Quaternion.FromToRotation(Vector3.forward, projDir);
// create the projectile in a variable to access its rigidbody...
GameObject projectile = Instantiate (projectilePrefab, handPosition, rot);
// then add force in the projectile's forward direction
projectile.rigidbody.AddForce(projectile.transform.forward * shootForce);
Destroy(projectile, 10); // destroy projectile after 10 seconds
}
}
EDITED: I think you can recycle the projectile forever: create the projectile only once, then bring it to the shooting position when firing again - but you must make the rigidbody forget about the past, or it will continue doing whatever it was doing before (rotating, moving to the old direction, etc.) I suppose it can be done by zeroing the rigidbody velocities.
This is the ecologically correct version of the script above - the projectile is created once and recycled each time you shoot:
...
public GameObject projectilePrefab;
public float distFromCam = 2.0f; // distance from camera to hand
private GameObject projectile; // current projectile
void Update () {
transform.LookAt(target);
if (Input.GetMouseButton(0)) // aim while the mouse button is down
{
firePosition = Camera.main.ViewportToWorldPoint (new Vector3(0.5f, 0.5f, distFromCam+3.0f)); // 3D point at screen center, 3 units ahead hand
handPosition = Camera.main.ScreenToWorldPoint (new Vector3 (Input.mousePosition.x, Input.mousePosition.y, distFromCam));
// draw a debug line just to see what's happening (click Gizmos to see the line)
Debug.DrawLine(handPosition, firePosition, Color.green);
}
if (Input.GetMouseButtonUp(0)) // shoot in last aimed direction when button released
{
Vector3 projDir = firePosition - handPosition; // calculate the projectile direction
// calculate rotation to turn projectile's forward direction to the shooting direction
Quaternion rot = Quaternion.FromToRotation(Vector3.forward, projDir);
// if projectile doesn't still exist, create it
if (!projectile) projectile = Instantiate(projectilePrefab);
// make sure the projectile is active:
projectile.SetActiveRecursively(true);
// bring it to the handPosition and set its rotation
projectile.transform.position = handPosition;
projectile.transform.rotation = rot;
// make rigidbody forget the past by zeroing its velocities
projectile.rigidbody.velocity = Vector3.zero;
projectile.rigidbody.angularVelocity = Vector3.zero;
// then add force in the shooting direction
projectile.rigidbody.AddForce(projDir * shootForce);
}
}
The projectile script usually have code to destroy the projectile when it hits something - for instance:
void OnCollisionEnter(Collision col){
// do the usual projectile stuff - check what was hit, apply damage etc.
// and finally destroy the projectile:
Destroy(gameObject);
}
But if you are recycling the projectile, you must change the code to deactivate it instead:
void OnCollisionEnter(Collision col){
// do the projectile stuff...
// and deactivate the projectile:
gameObject.SetActiveRecursively(false);
}