Input.GetTouch(0).deltaPosition is moving 'faster' on axis - c#

I have a function that moves a sprite relative to the finger position. I mean that the finger can touch any part of the screen and move the player sprite without moving the sprite to the finger position.
The issue that I have is that it's moving the sprite faster than the actual finger position:
Lets say that i have the finger at (0,0) and the sprite at (10,10); I move the finger 10 units on the X axis and I expect the sprite to move at (20,10), but it's actually moving more units than expected. Let's say it moved to (25,10).
I think it's related to the deltaPosition values. Here's the function (the transform in the arguments is the transform of the sprite that I'm moving):
private Vector2 MovePlayerRelativeToFinger(Transform transform)
{
Vector2 position = transform.position;
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
touchPosition = Input.GetTouch(0).deltaPosition;
position = new Vector2((touchPosition.x * Time.deltaTime) + transform.position.x, (touchPosition.y * Time.deltaTime) + transform.position.y);
return position;
}
else
{
return position;
}
}

Change the condition in outer-if statement to
Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Stationary
TouchPhase.Moved will be true during all the Update when the finger in moved and its deltaPosition will have value right from the point movement is started. So it gets added up into a huge value like, say, your touch started from x and you moved to x + 2 within the next Update. deltaPosition will be 2 during this Update. And if you have moved to x + 5 within the next Update, deltaPosition will be 5 instead of 3 as you want it to be.

If things have to be that accurate, try this
if(Input.touchCount > 0 &&Input.GetTouch(0).phase == TouchPhase.Moved) {
newDelta = Input.GetTouch(0).deltaPosition - oldDelta;
position = new Vector2((newDelta.x * Time.deltaTime) + transform.position.x, (newDelta.y * Time.deltaTime) + transform.position.y);
olDelta += Input.GetTouch(0).deltaPosition
return position;
}
Initialize oldDelta to 0

Based on your question, I'm not sure why you are including the time there. Or maybe you are missing the transform to world space? Does this work:
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
return (transform.position + (Vector3)((1.0f/100) * Input.GetTouch(0).deltaPosition));
}
else
{
return transform.position;
}

Related

How can i take only one finger swerve input

My project is a Runner game where character constantly moves forward and if player slides left or right, character moves that position too. But in mobile, if i slide with one finger and touch with my other finger in the mean time, character starts to take 2 inputs and move wrong directions.
This is my code below:
private void Update(){
float newz = transform.position.z + movementSpeed * Time.deltaTime;
float newx = 0, swipeDelta = 0;
if(Input.touchCount == 1 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
swipeDelta = Input.GetTouch(0).deltaPosition.x / Screen.width;
}
newx = transform.position.x + swipeDelta * 5f *Time.deltaTime;
transform.position = new Vector3(newx, transform.position.y, newz);
}
I have set Input.touchCount to 1 because i want it to get only 1 finger input but it did not work. What should i do to make it work with one finger and make it accurate?
From your code it seems that as soon as you touch with second finger it will just not read location of your first finger.
Input.touchCount == 1 in your if statement looks like a problem for me, it means that if statement will only execute if you have a single finger on your screen. if you change it to Input.touchCount > 0 it will execute even if there are more fingers on the screens and should work correctly since you are already only taking one input with Input.GetTouch(0).
private void Update(){
float newz = transform.position.z + movementSpeed * Time.deltaTime;
float newx = 0, swipeDelta = 0;
if(Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
swipeDelta = Input.GetTouch(0).deltaPosition.x / Screen.width;
}
newx = transform.position.x + swipeDelta * 5f *Time.deltaTime;
transform.position = new Vector3(newx, transform.position.y, newz);
}
Changing Input.touchCount == 1 to Input.touchCount > 0 did not solve my problem.
I solved it by adding this line of code in the PlayerController script's Start function:
Input.multiTouchEnabled = false;

How to smooth out 2D rotation in C#?

I'm making a 2D game in Unity and one feature I'm trying to implement is flipping the player if the mouse position is over 90 meaning he is always facing the direction of the mouse.
Vector3 mousePosition = UtilsClass.GetMouseWorldPosition();
Vector3 aimDirection = (mousePosition - transform.position).normalized;
float angle = Mathf.Atan2(aimDirection.y, aimDirection.x) * Mathf.Rad2Deg;
Vector3 aimLocalScale = Vector3.one;
if (angle > 90 || angle < -90)
{
rotate = true;
}
else
{
rotate = false;
}
gameObject.transform.localScale = aimLocalScale;
if (rotate == true)
{
transform.Rotate(0f, 180f, 0f);
}
else
{
transform.Rotate(0f, 0f, 0f);
}
However, one problem I am having is that one, it's very finicky and if you go too fast the player is looking in the wrong direction, and two, if you look straight up, he doesn't know exactly where to look and keeps snapping left and right really fast.
Does anyone know a way to fix this allowing for a smoother more functional flipping?
Try flipping the sprite by adjusting its scale from 1 to -1. Then implement that into a FlipSprite() method and just call it when you want to flip it
So if you want to flip and sprite one approach could be to inverse the localScale of the sprite, like this:
private void FlipSprite()
{
// Multiply the player's x local scale by -1.
Vector3 flippedScale = transform.localScale;
flippedScale.x *= -1;
transform.localScale = flippedScale;
}
I suggest you to keep a boolean variable like isFacingRight to keep tracking the direction the sprite is looking at!
The issue is you use the same rotate threshold for when the character is facing right and left, so when you straddle the threshold he flips a lot and its bad UX for the player.
Solution : make the rotate threshold dynamic so each time the player rotates the threshold gets pushed down.
float thresholdAngle = 90.0f;
change angle > 90 || angle < -90 to
if (angle > thresholdAngle || angle < -1.0f * thresholdAngle)
Then add in
if (rotate == true)
{
transform.Rotate(0f, 180f, 0f);
thresholdAngle = 110.0f;
}
else
{
transform.Rotate(0f, 0f, 0f);
thresholdAngle = 80.0f;
}
I'm not sure which way your character faces first so you may have to swap the thresholdAngle = 110.0f with the threshold = 80.0f;

Move 2D object at constant speed and turn towards touch point

I've been trying for a while to get a 2D player to work kind of like a bullet that is always moving forward (forward being in this case the local X axis for the GameObject, as that's the way that the character is facing) and only changes direction when you touch a point on the screen, in which case it should smoothly start turning towards that point.
One problem I have is that I can't manage to keep the character moving smoothly at a constant speed in the last direction it was facing before, and the other problem that I'm finding is that the character is turning around the wrong axis and instead of rotating based on the Z axis, it's always rotating on the Y axis, which makes the sprite become invisible to the camera.
Here's the code that I have right now:
Vector3 lastTouchPoint;
private void Start()
{
lastTouchPoint = transform.position;
}
void Update()
{
if (Input.touchCount > 0)
{
// The screen has been touched so store the touch
Touch touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Stationary || touch.phase == TouchPhase.Moved)
{
// If the finger is on the screen, move the object smoothly to the touch position
lastTouchPoint = Camera.main.ScreenToWorldPoint(new Vector3(touch.position.x, touch.position.y, 10));
}
}
transform.position = Vector3.Lerp(transform.position, lastTouchPoint, Time.deltaTime);
//Rotate towards point
Vector3 targetDir = lastTouchPoint - transform.position;
transform.LookAt(lastTouchPoint);
}
Thanks in advance!
keep the character moving smoothly at a constant speed
You probably didn't understand what Lerp actually is: This interpolates between the two positions on the given factor where 0 means fully the first position, 1 means fully the last position and e.g. 0.5f would mean in the center between both positions.
This results in faster speeds if the positions are further apart and becomes slower and slower the smaller the distance between both positions becomes. In some cases especially with a factor that small as in your case the object might even never actually reach the target position.
Using this with a dynamic factor of Time.deltaTime makes no sense as this value changes every frame and jitters somewhere around 0,017 (assumin 60 FPS).
You could rather use Vector3.MoveTowards with a fixed constant speed
// set via the Inspector
public float speedInUnitsPerSecond = 1;
...
transform.position = Vector3.MoveTowards(transform.position, lastTouchPoint, Time.deltaTime * speedInUnitsPerSecond);
if you want to keep moving but stop once the touched position is reached.
If you rather wanted to continue moving in the according direction no matter what you could rather store the direction instead of a position and use a straight forward Transform.Translate
// set via the Inspector
public float speedInUnitsPerSecond = 1;
private Vector2 lastDirection;
privtae void Update()
{
...
// If the finger is on the screen, move the object smoothly to the touch position
var touchPosition = Camera.main.ScreenToWorldPoint(new Vector3(touch.position.x, touch.position.y, 10));
lastDirection = (touchPosition - transform.position).normalized;
...
// move with constant speed in the last direction
transform.Translate(lastDirection * Time.deltaTime * speedInUnitsPerSecond);
...
}
the character is turning around the wrong axis and instead of rotating based on the Z axis, it's always rotating on the Y axis
Note that Transform.LookAt has an optional second parameterworldUp which by default is Vector3.up so a rotation around the global Y axis!
Since you rather want a rotation around the Z axis you should pass
transform.LookAt(lastTouchPoint, Vector3.forward);
I don't know your setup ofcourse but also note that
LookAt
Rotates the transform so the forward vector points at worldPosition.
As you describe it it is also possible that you don't want the objects forward vector to point towards the target position but actually rather the objects right (X) vector!
You can do this by rather simply directly setting the transform.right like e.g.
transform.right = (lastTouchPoint - transform.position).normalized;
or
transform.right = lastDirection;
Btw it would actually be enough to set this rotation only once, namely the moment it changes so in
if (touch.phase == TouchPhase.Stationary || touch.phase == TouchPhase.Moved)
{
// If the finger is on the screen, move the object smoothly to the touch position
lastTouchPoint = Camera.main.ScreenToWorldPoint(new Vector3(touch.position.x, touch.position.y, 10));
transform.right = (lastTouchPoint - transform.position).normalized;
}
or
if (touch.phase == TouchPhase.Stationary || touch.phase == TouchPhase.Moved)
{
// If the finger is on the screen, move the object smoothly to the touch position
var touchPosition = Camera.main.ScreenToWorldPoint(new Vector3(touch.position.x, touch.position.y, 10));
lastDirection = (touchPosition - transform.position).normalized;
transform.right = lastDirection;
}
I ended up finding the answer to my own problem using code to rotate smoothly from another post. Here's the code:
Vector3 lastTouchPoint;
Vector3 direction;
Vector3 vectorToTarget;
//Character controller variables
public float moveSpeed = 5f;
public float angularSpeed = 3f;
private void Start()
{
lastTouchPoint = transform.position;
}
void Update()
{
if (Input.touchCount > 0)
{
// The screen has been touched so store the touch
Touch touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Began)
{
// If the finger is on the screen, move the object smoothly to the touch position
lastTouchPoint = Camera.main.ScreenToWorldPoint(new Vector3(touch.position.x, touch.position.y, 10));
direction = lastTouchPoint - transform.position;
vectorToTarget = lastTouchPoint - transform.position;
}
}
transform.position += direction.normalized * moveSpeed * Time.deltaTime;
float angle = Mathf.Atan2(vectorToTarget.y, vectorToTarget.x) * Mathf.Rad2Deg;
Quaternion q = Quaternion.AngleAxis(angle, Vector3.forward);
transform.rotation = Quaternion.Slerp(transform.rotation, q, Time.deltaTime * angularSpeed);
}

unity screen delta to world delta

I want to convert the user touch delta position to delta position of gameobject in the world, is there a util to do that?
//drag
if (duringmove && (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved))
{
Debug.Log("will move " + progressTrans.gameObject.name);
endPos = Camera.main.ScreenToWorldPoint(Input.GetTouch(0).position);
//should convert te deltaPos here
progressTrans.localPosition += Vector3.right * Input.GetTouch(0).deltaPosition.x;
progressTrans.localPosition = new Vector3(Mathf.Clamp(progressTrans.localPosition.x, mostLeft, mostRight), progressTrans.localPosition.y, progressTrans.localPosition.z);
}
Note that I'm building a 2d game using a camera with Orthographic mode
Since it seems your object will not have its transform.position.z changing over time, you can use something like this:
//drag
if (duringmove && (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved))
{
Debug.Log("will move " + progressTrans.gameObject.name);
Vector3 touchPosition = Input.GetTouch(0).position;
touchPosition.z = progressTrans.position.z;
// World touch position
endPos = Camera.main.ScreenToWorldPoint(touchPosition);
// To local position
progressTrans.InverseTransformPoint(endPos);
endPos.x = Mathf.Clamp(endPos.x, mostLeft, mostRight);
endPos.y = progressTrans.localPosition.y;
endPos.z = progressTrans.localPosition.z;
// If you need the delta (to lerp on it, get speed, ...)
Vector3 deltaLocalPosition = endPos - progressTrans.localPosition;
progressTrans.localPosition = endPos;
}
Hope this helps,

Unity smooth touch x coordinate

I have a 2D mobile game and I need touch and drag objects. Here is a script (objects don't move smoothly with this script). I want moving objects at position where is a finger on the that time.
public float speed;
void Update ()
{
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
Vector2 touchDeltaPosition = Input.GetTouch(0).deltaPosition;
transform.Translate(touchDeltaPosition.x * speed, 0, 0);
}
What to do?
Thanks
Kind regards
You should not user speed here as it would give you the exact position without any delay. So try to remove speed like transform.Translate(touchDeltaPosition.x, 0, 0);
UPDATE:
You can also use Vector3.MoveTowards. Give it a try
void Update ()
{
if (Input.touchCount > 0 && Input.GetTouch (0).phase == TouchPhase.Moved) { //pomicanje trake po x-osi na touch screenu
// pokret prsta od zadnjeg frejma
Vector3 touchDeltaPosition = Input.GetTouch (0).deltaPosition;
// Za x-os
transform.position = Vector3.MoveTowards (transform.position, new Vector3 (Mathf.Clamp (touchDeltaPosition.x, -2.5f, 2.5f), transform.position.y, transform.position.z), 1);
}
}
Instead of transform.Translate
It should work nicely.

Categories