I am trying to create a little game where I can select a position on my screen(within a panel area) using touch(Touch.position, etc.). Once I have this touch, I am trying to throw an object from a stationary position to the current touch location. I am having trouble being able to convert my touch.position into a Transform from which I can target the object to be thrown. My code hasn't worked for me thus far. I am more than likely suffering from an issue with not knowing what I don't know. Thank you for your time.
public int[] distanceToThrow;
public int[] objectToThrow;
public GameObject object;
public Transform throwOrigin;
public float throwingAngle;
public float gravity;
public Transform throwPointPos;
public Transform throwDestination;
public float flightSpeed;
void Update()
{
if (throwTimer > 0)
{
throwTimer -= Time.deltaTime;
Debug.Log("Timer at: " + throwTimer);
// Using a single touch as control - Letholor
if (Input.touchCount > 0)
{
Touch touch = Input.GetTouch(0);
Vector3 touchPos = new Vector3(touch.position.x, touch.position.y, 0);
Debug.Log("You are touching at position: " + touchPos);
Ray ray = theCamera.ScreenPointToRay(touchPos);
RaycastHit hitResult;
Physics.Raycast(ray, out hitResult);
Vector3 throwDestination = hitResult.point;
Debug.Log("Throw destination is " + throwDestination);
Throw();
}
}
}
public void Throw() {
if (throwTimer > 0)
{
Debug.Log("Cooling down.");
return;
}
throwTimer = throwResetTimer;
Debug.Log("Throwing to " + throwDestination);
Instantiate(object, throwOrigin.position, throwOrigin.rotation);
}
Touch.position is a screen position. You need to convert it into a world position in order to determine the target coordinates. Here's my suggestion:
Step 1: Use Camera.ScreenPointToRay to get a world-coordinate ray.
Vector3 touchPos = new Vector3 (touch.position.x, touch.position.y, 0);
Ray ray = Camera.ScreenPointToRay(touchPos);
You can imagine this being like a "laser sight" from the camera to the touched position.
Step 2: Use Physics.Raycast to cast the ray and get the target coordinates.
RaycastHit hitResult;
Physics.Raycast(ray, out hitResult);
Note that this will only work if the player touches a physics collider. If you want the player to be able to throw the ball at "empty space", you will need to create some invisible walls (that obviously should be set to not collide with the ball) so the raycast has something to hit. Preferably, place the invisible wall at or near your intended maximum throwing range for the player, and parent it to the camera so that you get predictable behaviour.
Step 3: hitResult now has your target position!
Vector3 targetLocation = hitResult.point;
There's another problem with your code, though. Currently, it will fire one bomb every Update as long as the player keeps their finger on the screen. That's a lotta bombs. There are multiple ways to fix this, but I suggest a simple cooldown timer:
float maxCooldown = 1f;
float cooldownTimer = 0f;
void Update()
{
if (cooldownTimer > 0) cooldownTimer -= Time.deltaTime;
[the rest of your update code goes here]
}
public void Throw()
{
//silently return without throwing, if the cooldown has not expired
if (cooldownTimer > 0)
return;
//safe to throw - set cooldown to max
cooldownTimer = maxCooldown;
[the rest of your throw code goes here]
}
Hope that helps!
Edit: After looking at your new code, a few things need fixing.
You want to decrement the timer when throwTimer > 0, and process the touch when throwTimer <= 0. So keep the decrement instruction where it is, and put the rest of the Update() code either OUTSIDE the if statement, or in an else block. It won't work otherwise.
My mistake: Camera.ScreenPointToRay is not a static method, so you should be using Camera.main.ScreenPointToRay.
throwDestination should be a Vector3, but you've declared it wrongly as a Transform at the start of the program, and redeclared it as a Vector3 in Update(). To fix this, you have two options:
a. Declare ThrowDestination as a Vector3, not a Transform, at the start of your program, and don't re-declare it.
b. Declare ThrowDestination as a local variable, don't declare it at the start of your script, and pass it directly to Throw() as an argument. This is what I've done in the code below.
I believe "object" is a reserved word; you can't call your projectile "object". Call it bomb, or projectile, or something else. In the sample code I'm calling it "projectile".
You've instantiated the object in Throw(), but it doesn't have a velocity and doesn't know its destination. We can fix this later; for now, you probably want to make sure the Debug.Log shows you a reasonable position for your throw destination.
void Update()
{
if (throwTimer > 0)
{
throwTimer -= Time.deltaTime;
Debug.Log("Timer at: " + throwTimer);
}
// Using a single touch as control - Letholor
else if (Input.touchCount > 0)
{
Touch touch = Input.GetTouch(0);
Vector3 touchPos = new Vector3(touch.position.x, touch.position.y, 0);
Debug.Log("You are touching at position: " + touchPos);
Ray ray = Camera.main.ScreenPointToRay(touchPos);
RaycastHit hitResult;
Physics.Raycast(ray, out hitResult);
Vector3 throwDestination = hitResult.point;
Debug.Log("Throw destination is " + throwDestination);
Throw(throwDestination);
}
}
public void Throw(Vector3 throwDestination) {
if (throwTimer > 0)
{
Debug.Log("Cooling down.");
return;
}
throwTimer = throwResetTimer;
Debug.Log("Throwing to " + throwDestination);
Instantiate(projectile, throwOrigin.position, throwOrigin.rotation);
}
Here's the updated code. Hope it helps.