Unity smooth touch x coordinate - c#

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.

Related

How can I refactor my 2d unity movement script to resolve the behavioral issues I have?

Below is the code I've written for my 2D movement:
void HandleInput()
{
float verticalMoveAmount = Input.GetAxis("Vertical") * playerSpeed * Time.deltaTime;
float horizontalMoveAmount = Input.GetAxis("Horizontal") * playerSpeed * Time.deltaTime;
if (facingRight)
{
transform.Translate(horizontalMoveAmount, verticalMoveAmount, 0);
}
else
{
transform.Translate(-horizontalMoveAmount, verticalMoveAmount, 0);
}
if (horizontalMoveAmount > 0 && !facingRight)
{
Flip();
}
else if (horizontalMoveAmount < 0 && facingRight)
{
Flip();
}
if (Input.GetKeyDown(KeyCode.Space) && hasBall)
{
Shoot();
}
}
void Flip()
{
facingRight = !facingRight;
transform.Rotate(0f, 180f, 0f);
}
I have the below problems though:
I have a Cinemachine virtual camera following the player around. However, whenever the player changes direction they vanish from the camera view. I think this is something to do with the Flip(), but I don't know why or how to fix it.
The if statement for if facingRight where I have to use negative movement on the horizontal axis, this feels like a really poor way to handle it, but if I don't do that I can't move left when the player changes directions to the left. Is there a better way I can do this?
Thank you in advance.
To 1) my guess is that since you rotate the object by 180° you are looking at the backface of it -> it is not being rendered due to backface culling.
To 2) since you rotate the object by 180° it's local coordinate system is now pointing in the other direction. Note that by default Transform.Translate works in the local coordinate system. If you want to rather use global axes then simply pass in
transform.Translate(horizontalMoveAmount, verticalMoveAmount, 0, Space.World);
In general simply assuming you are using a SpriteRenderer which is the most common thing for 2D games you should rather use the property SpriteRenderer.flipX and not rotate your object at all. This would solve both issues at the same time
So together your code could be simply
public SpriteRenderer spriteRenderer;
void HandleInput()
{
var input = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
// ensure that diagonal movement isn't faster
input = Vector2.ClampMagnitude(input, 1f);
var movement = input * playerSpeed * Time.deltaTime;
transform.Translate(movement, Space.World);
// basically the same now as
//transform.position += movement;
if (input.x != 0)
{
spriteRenderer.flipX = input.x < 0;
}
if (hasBall && Input.GetKeyDown(KeyCode.Space))
{
Shoot();
}
}

I'm using Unity C# and Whenever I press down my finger to control the ball, the ball slows down how do I prevent that?

my ball slows down when I press the screen, which is making the game go very slowly, When I let go the ball starts speeding up again because of gravity.
{
private Vector3 touchPosition;
private Rigidbody2D rb;
private Vector3 direction;
private float moveSpeed = 10;
// Use this for initialization
private void Start()
{
rb = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
private void Update()
{
if (Input.touchCount > 0)
{
Touch touch = Input.GetTouch(0);
touchPosition = Camera.main.ScreenToWorldPoint(touch.position);
touchPosition.z = 0;
direction = (touchPosition - transform.position);
rb.velocity = new Vector2(direction.x, 0) * moveSpeed;
if (touch.phase == TouchPhase.Ended)
rb.velocity = Vector2.zero;
}
}
}
Each time you press the button, you're telling the RigidBody you want the y velocity to be 0, essentially stopping to ball from falling.
Try this instead:
private void Update ( )
{
if ( Input.touchCount > 0 )
{
Touch touch = Input.GetTouch ( 0 );
touchPosition = Camera.main.ScreenToWorldPoint ( touch.position );
touchPosition.z = 0;
direction = ( touchPosition - transform.position );
var v = rb.velocity;
v.x = direction.x * moveSpeed;
rb.velocity = v;
if ( touch.phase == TouchPhase.Ended )
rb.velocity = Vector2.zero;
}
}
Or, you could even just get the x component in the first place with:
var x = touchPosition.x - transform.position.x;
rb.velocity = new Vector2 ( x, rb.velocity.y );
Either way should do the trick. The second is slightly more performant.
If you are looking to maintaining the current velocity of the object(horizontaly), then
rb.velocity = new Vector2(direction.normalized.x* rb.velocity.x, 0);
You are currently resetting the velocity of the object to the movement speed to its basic speed (and the distance between your finger, which I dont believe you want). In addition, it is unclear if you have vertical movement with the 0 in y, which will stop the object's vertical movement. If you do you need the vertical movement to be maintain, you need to replace 0 with rb.velocity.y.
rb.velocity = new Vector2(direction.normalized.x* rb.velocity.x * moveSpeed, rb.velocity.y );
or
rb.velocity = new Vector2(direction.normalized.x * moveSpeed,1)* rb.velocity;

unity player moving on the x axis with the finger does not work

Hey I'm developing an android game with unity its in 3d and the main point is that you are a square which you have to move on the x-Axis. I want that the player can place his finger wherever he wants and swipe left or right (still touching the display) and the distance between the positions where he starts touching and where he is now the square should move right or left. When the player is not touching it should not move at the x-Axis. I did this but my code has a problem when I release my finger and touch again without moving right or left the square deflects to one side very fast. Of course when the finger not move the square shouldn't move.
Picture for better understand
// My Code
public class PlayerMovement : MonoBehaviour
{
void FixedUpdate()
{
// move the player constantly forward
transform.position += Vector3.forward * Time.deltaTime * speed;
if (Input.touchCount > 0)
{
touch = Input.GetTouch(0);
// the current finger position
touchedPosMoved = Camera.main.ScreenToWorldPoint(new Vector3(touch.position.x, touch.position.y, 10));
switch (touch.phase)
{
case TouchPhase.Began:
// get finger position when touch start
touchedPosBegan = Camera.main.ScreenToWorldPoint(new Vector3(touch.position.x, touch.position.y, 10));
startX = transform.position.x;
break;
case TouchPhase.Moved:
// claculate the distance between start and curent position of the finger
differenz = Mathf.Abs(touchedPosBegan.x - touchedPosMoved.x);
if (touchedPosBegan.x > touchedPosMoved.x)
{
differenz = differenz * -1;
}
break;
}
// Move player at the X-axis
Vector3 idk = new Vector3((startX + differenz) * 8, transform.position.y, transform.position.z);
gameObjectStart = new Vector3(startX, transform.position.y, transform.position.z);
transform.position = Vector3.Lerp(gameObjectStart, idk, Time.deltaTime * 2);
}
}
}
Does anyone know the problem or has another solution for my to move the player as described above
Here I find a better code without these problems I hope this can help other programmers ;)
private void FixedUpdate()
{
transform.position += Vector3.forward * Time.deltaTime * speed;
if (Input.touchCount > 0)
{
touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Moved)
{
transform.position = new Vector3(
transform.position.x + touch.deltaPosition.x * multiplier,
transform.position.y,
transform.position.z + touch.deltaPosition.y * multiplier);
}
}
}

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);
}

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

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;
}

Categories