In my 2D unity mobile game, when I touch and pull the ball it shows up a lineRenderer from the ball through the way I pull there is no problem with that but if I touch to screen while the ball is dynamic (before it stopped) the new lineRenderer take (0,0) point as the center instead of the location of the ball.
This is how it works properly when I touch the screen while the ball is not moving
This is the problematic version line renderer starts from the point (0,0) instead of the ball
void Update()
{
if (Input.touchCount > 0 && !hasMoved)
{
touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Began)
{
dragStart();
}
if (touch.phase == TouchPhase.Moved)
{
Dragging();
}
if (touch.phase == TouchPhase.Ended)
{
DragRelease();
}
}
}
void dragStart()
{
dragStartposition = transform.position;
dragStartposition.z = 0;
gostergeLine.positionCount = 1;
gostergeLine.SetPosition(0,transform.position);
}
void Dragging()
{
Vector3 draggingPos = Camera.main.ScreenToWorldPoint(touch.position);
draggingPos.z = 0;
gostergeLine.positionCount = 2;
gostergeLine.SetPosition(1, draggingPos);
}
void DragRelease()
{
gostergeLine.positionCount = 0;
Vector3 dragReleasePos = Camera.main.ScreenToWorldPoint(touch.position);
dragReleasePos.z = 0;
Vector3 forceVec = dragStartposition - dragReleasePos;
forcePower = forceVec.magnitude;
if(forcePower > 45)
{
topRb.velocity = forceVec * 45;
}
else
{
topRb.velocity = forceVec * forcePower;
}
}
Even though it does not read my touch while the ball is moving (!hasmoved); if I touch the screen before it stopped, the new linerenderer shows up in wrong direction.
Update
is called every frame.
The TouchPhase.Began
is only true in the very first frame of a touch -> your ball was moving then so you ignored it
Now you continue touching so eventually TouchPhase.Moved
is true at some point
=> Since the ball stopped in the meantime you now call Dragging
without having called dragStart
before.
You could make sure that the other cases are only called at all if dragStart
was actually called first.
You could e.g. use a nullable
private Vector2? dragStartposition;
and then check for it in
void Dragging()
{
if(dragStartposition == null) return;
...
}
and also reset it in
void DragRelease()
{
if(dragStartposition == null) return;
...
Vector3 forceVec = dragStartposition.Value - dragReleasePos;
...
dragStartposition = null;
}
This way if a touch started to early it doesn't trigger the other methods, only if one started after the ball has stopped.
There is still a pitfall though with multiple touches
=> I would also use exactly one touch only
if(Input.touchCount == 1 && !hasMoved)