I am currently trying to implement a wheel shaped menu for an android game.
The menu should rotate when the user moves his finger up or down the y axis of his screen.
Swipe up --> rotate counter clockwise
Swipe down --> rotate clockwise
I am able to rotate the menu via touch input, but the problem is the following:
Every time the finger touches the display, the rotation is reset.
E.g. You can swipe up, the menu rotates and stays in place. But when you want to swipe up again to rotate even further, the rotation resets and starts over.
I guess the problem is very simple, but I tried a lot of stuff and nothing ever changes.
My code:
class{
// ...
void Update(){
if(Input.touches.Length > 0 && Input.GetTouch(0).phase == TouchPhase.Moved){
transform.rotation *= Quaternion.AngleAxis(Input.GetTouch(0).deltaPosition.y, Vector3.forward);
}
}
}
Thanks in advance!
You need a variable to store the current rotation and simply add the change in angle each update.
public float angle;
void Update() {
if ( Input.touches.Length > 0 && Input.GetTouch(0).phase == TouchPhase.Moved ) {
angle += Input.GetTouch(0).deltaPosition.y;
transform.rotation *= Quaternion.AngleAxis( angle, Vector3.forward );
}
}
Related
So I have this code in my LateUpdate function attached to my camera gameObject. I'm trying to rotate around a unity default cube as if it was an orbit. I have got the motion right but I'm not able to clamp the value... Here's the code.
if (Input.GetMouseButtonDown(0))
{
mInitialPosition = Input.mousePosition.x;
}
if (Input.GetMouseButton(0))
{
mChangedPosition = Input.mousePosition.x;
float difference = mChangedPosition - mInitialPosition;
if (mChangedPosition < mInitialPosition || mChangedPosition > mInitialPosition)
{
Rotation(-difference);
}
}
private void Rotation(float inDifference)
{
if (transform.eulerAngles.y < 60f && transform.eulerAngles.y > -60f)
{
transform.RotateAround(mTargetToRotateAround.position, transform.up, inDifference * Time.deltaTime);
}
}
Im tried to clamp the value this way as mathf.clamp dint seem to work out for me... So here i am telling it to do the rotation function responsible for the rotation to happen only when camera-y rotation is below 60f and above -60f. But the rotation behaves super weird and i am super confused. So I did a bit of research on what value does the camera transform show outside in inspector window. Then i realized it was euler angles and not quaternion. Now i changed my code to euler but when i debug.log the value of camera.transform.eulerangles.y the value goes from 0 to 360. But in inspector the y value when reaching less than 0 starts printing -1 and so but in debug it shows 360,359 and so on.
How to get the exact rotation value that there printed in inspector so I can clamp my camera accordingly?
Or is there any way to clamp my camera dont want it to go more that 60 degrees on both left and right!
I have a sphere in that is moving foward and I need it to follow my finger smoothly when it swipes on the screen but only in the x axis.
I trying to make the exact movent like Rolling Sky, Color Road
The ball Should follow my finger when it swipes in the x axis and move smoothly.
Just like in the games I mention before.
I try OnMouseDrag and a lot of ways but it dont work correctly beacuse it dont dont follow the finger or it dont move while finger is swiping.
From what I understand, it seems you want to get the position of the user's finger and move the ball accordingly?
You could achieve this with Touch.position
Example:
private void Update()
{
Touch touch = Input.GetTouch(0); // Get the touch data for the first finger
Vector2 position = touch.position; // Get the position in screen-space
Vector3 worldPosition = Camera.main.ScreenToWorldPoint(position); // Convert the position to world space
Vector3 ballPosition = ball.transform.position;
ball.transform.position = new Vector3(worldPosition.x, ballPosition.y, ballPosition.z); // Move the ball
}
I think you should handle the input separately from the sphere.
Put this on a script to detect the swiping on the screen.
bool inputBegan = false;
Vector2 beganPosition;
void Update()
{
if (!inputBegan && Input.GetMouseButtonDown (0))
{
inputBegan = true;
beganPosition = Input.mousePosition;
}
else if (inputBegan && Input.GetMouseButtonUp (0))
{
//If you want a threshold you need to change this comparison
if (beganPosition.x > Input.mousePosition)
{
MoveBallLeft ();
}
else
{
MoveBallRight ();
}
inputBegan = false;
}
}
The movement of the balls you can achieve it adding or substracting Vector2.right * movingDistance to the sphere Transform if you want it to teleport or making the sphere move slowly using a targetPosition and currentPosition and each Update cycle add a little bit of transform distance.
I solved it doing this and setting the variable NavigationMultiplier to 10000
I am trying to create a player movement along the x-axis based on finger position.
What I need to Happen: Not multi-Touch. I want it so a player can put a single finger down and grab that position. Then check to see if the player dragged finger along screen on x-axis and move player left or right based off where they dragged finger from first touch.
So if they touch the screen and if drag left: move left by speed and if it changes to drag right move right by speed.
Any help would be Awesome.
The easiest way would be to stored first touch position and then compare the X with that position:
public class PlayerMover : MonoBehaviour
{
/// Movement speed units per second
[SerializeField]
private float speed;
/// X coordinate of the initial press
// The '?' makes the float nullable
private float? pressX;
/// Called once every frame
private void Update()
{
// If pressed with one finger
if(Input.GetMouseButtonDown(0))
pressX = Input.touches[0].position.x;
else if (Input.GetMouseButtonUp(0))
pressX = null;
if(pressX != null)
{
float currentX = Input.touches[0].position.x;
// The finger of initial press is now left of the press position
if(currentX < pressX)
Move(-speed);
// The finger of initial press is now right of the press position
else if(currentX > pressX)
Move(speed);
// else is not required as if you manage (somehow)
// move you finger back to initial X coordinate
// you should just be staying still
}
}
`
/// Moves the player
private void Move(float velocity)
{
transform.position += Vector3.right * velocity * Time.deltaTime;
}
}
WARNING: this solution will only work for devices with touch input available (because of Input.touches use).
using the code #programmer provided in this answer: Detect swipe gesture direction
You can easily detect the direction you are swiping/dragging. Replace the Debug
void OnSwipeLeft()
{
Debug.Log("Swipe Left");
}
void OnSwipeRight()
{
Debug.Log("Swipe Right");
}
With functions that move your character. If you use RigidBody to move your character you can use https://docs.unity3d.com/ScriptReference/Rigidbody.MovePosition.html. If its a normal object, you can move it by tweaking the transform.position.
If you need more information on how to move rigidbody\normal objects let me know what type of game you have and more details on how you set up the player.
I am trying to get touch controls to work for iOS, the result i want is drag left to move left, drag right to move right and tap to jump. At the moment the functions do work but what happens is if i don't want to jump and just want to drag the character will jump first as soon as touch the screen. Is there a way i can get the result i want i have added my code below. I want the first touch to just register for the drag and when the player lifts and then taps or maybe double taps the character will jump. Thanks in advance.
//Mobile Touch Drag Controls
{
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
// Get movement of the finger since last frame
Vector2 touchDeltaPosition = Input.GetTouch(0).deltaPosition;
// Move object across X plane
transform.Translate(touchDeltaPosition.x * speed, 0, 0);
}
}
////Mobile Touch To Jump
{
if (Input.GetMouseButtonDown(0))
{
transform.Translate(Vector3.up * jumpForce * Time.deltaTime, Space.World);
}
When the button goes down, there is no way to know what the player wants to do. You should jump when the finger goes up instead.
An easy solution is to use a boolean to know if the player has moved before the finger was released. If yes, you don't want to jump
public class PlayerController // Or whatever name your class has
{
private bool _moved;
private void Update()
{
//Mobile Touch Drag Controls
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
// Get movement of the finger since last frame
Vector2 touchDeltaPosition = Input.GetTouch(0).deltaPosition;
// Move object across X plane
transform.Translate(touchDeltaPosition.x * speed, 0, 0);
_moved = true; // Remember that the player moved
}
////Mobile Touch To Jump
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Ended)
{
if(!_moved) // Only jump if we didnt move
{
transform.Translate(Vector3.up * jumpForce * Time.deltaTime, Space.World);
}
_moved = false;
}
}
}
I assume this code goes in your update function. This will work fine but here is a more elegant solution in case you want to try it:
Your class can implement IDragHandler and IEndDragHandler (among others, look for all possibilities that extend IEventSystemHandler)
When you implement these, you can override functions that get called when the user touches the screen, such as public void OnDrag(PointerEventData eventData)
With this you don't have to use the Update function anymore
I have a class below that I attach to a object in order to make it rotate around its pivot. I sent the pivot of the sprite via the inspector.
This works exactly how I want it too, BUT the issue I am having is that whenever I touch and drag it, and then touch and drag it again, it snaps to a new position.
What I would like for it to do is, when it is rotated and then rotated again, the sprite stays in its same rotation and not snap to a new position and I would like the angle of the sprite to be reset to 0. The next then is that I want the angle to continually rotate. So if I rotate it in the positive direction, the angle should keep increasing in the positive direction and not change..Such as 0---> 360 ----> 720 -----> etc, etc. And then when the mouse is released, the sprite stays in the same position but the angle is now set back to 0. And then when clicked again to rotate, it rotates from that exact position.
Here is my code thus far which works well for rotating, but I would like to modify it to achieve the above scenario. Any help with this?
public class Steering : MonoBehaviour {
float prevAngle,wheelAngle,wheelNewAngle = 0;
public SpriteRenderer sprite;
void Start () {
}
void Update () {
}
public float GetAngle(){
return wheelAngle;
}
void OnMouseDrag(){
Vector3 mouse_pos = Input.mousePosition;
Vector3 player_pos = Camera.main.WorldToScreenPoint(this.transform.position);
mouse_pos.x = mouse_pos.x - player_pos.x;
mouse_pos.y = mouse_pos.y - player_pos.y;
wheelNewAngle = Mathf.Atan2 (mouse_pos.y, mouse_pos.x) * Mathf.Rad2Deg;
if (Input.mousePosition.x > sprite.bounds.center.x) {
wheelAngle += wheelNewAngle - prevAngle;
} else {
wheelAngle -= wheelNewAngle - prevAngle;
}
this.transform.rotation = Quaternion.Euler (new Vector3(0, 0, wheelAngle));
Debug.Log (wheelAngle);
prevAngle = wheelNewAngle;
}
void OnMouseUp(){
prevAngle = wheelNewAngle;
wheelAngle = 0;
}
}
By angle of the sprite, do you mean the rotation? I'm not sure how the position is changing if there's nothing in your code doing that. Does it always move to the same position? I'm having a little trouble visualizing how your system is supposed to look but I hope this helps.
It looks like you might want to store the previous mouse position so you can get the relative amount to rotate each frame.
At the top:
Vector3 prevMousePos = Vector3.zero;
This method will help get the position when the player pressed:
void OnMouseDown(){
prevMousePos = Input.mousePosition;
}
Then in OnMouseDrag() get the difference between the two mouse positions to get the relative position (if you moved the mouse left, right, up, or down since pressing):
Vector3 mouseDiff = Input.mousePosition - prevMousePos;
With this it will use the relative mouse position after pressing instead of the current one, which should smooth things out.