How to determine speed of swipe on a horizontal scrollview? - unity3d

I'm making my own horizontal scroll view the app will be some thing like facebook which contain the homepage , friends , notification,etc.
I want to move between pages on swipe: I considered the difference on moving position to be the criteria to determine if I move to the next page or I still in the current page . it worked well but I also found on facebook if the swipe is fast it will move to next page.
So, The question now how to determine if the swipe is fast or not?

Store the start position of the swipe. When the swipe has ended, get the end position and total time elapsed since the touch began. You can then figure out how far over what time the swipe was executed, getting the "velocity" of the swipe.
Some example code:
float swipevelocity;
Vector2 touchBeginPos, touchEndPos;
float touchTime;
bool isTouching;
void Update()
{
if (//..touchstarted)
TouchBegin();
else if (//..touchended)
TouchEnd();
if (isTouching)
touchTime += Time.deltaTime;
}
void TouchBegin()
{
touchBeginPos = touch.position;
isTouching = true;
touchTime = 0; //reset touchtime
}
void TouchEnd()
{
touchEndPos = touch.position;
isTouching = false; // stop touch timer
swipevelocity = Vector2.distance(touchBeginPos, touchEndPos) / touchTime;
}
You can then set some criteria like minimum distance and minimum velocity needed to change pages.

Related

How to allow raycasting when the player is at a certain distance from object?

I've implemented opening drawers/doors features on my game but the issue I'm facing is that when The player opens a drawer, it gets pushed back so the drawer has some room to be opened. sometimes it jitters when pushed back.
Physics.Raycast(mainCamera.transform.position, mainCamera.transform.forward, out hit, 3f);
if (hit.transform)
{
interactiveObjects = hit.transform.GetComponent<InteractiveObjects>();
}
else
{
lookObject = null;
interactiveObjects = null;
}
if (Open)
{
if (interactiveObjects)
{
interactiveObjects.OnOpen();
}
}
I'm using raycast to open the drawer. Is there a way to only allow the raycasting, when the player is not too close to the drawer? so it doesn't get pushed back by the drawer.
You can check the distance after doing the raycast. If the distance is within the tolerable range, execute the rest of your code.
if (Physics.Raycast(mainCamera.transform.position, mainCamera.transform.forward, out hit, 3f))
{
if (hit.distance >= minDistance)
{
// Code to execute when range is acceptable
}
else
{
Debug.Log("Player is too close to object!");
}
}
The distance used above does not take into account the height difference between the hit point and the camera. You can get a much more consistent distance by setting the y component of both vectors equal before getting the distance.
var cameraPos = mainCamera.transform.position;
cameraPos.y = hit.point.y;
var distance = Vector3.Distance(hit.point, cameraPos);

Distance moved by XR-controller in Unity

I have been making a script in Unity that measures how far a player has moved in the real world using XRNodes like this for example with the right hand:
InputTracking.GetLocalPosition(XRNode.RightHand)
at the start of the movement and then comparing it to the end position
Now I would like to get the distance moved, even if the player moved around in a circle.
Is the a method to do this with XRNodes? Measuring total distance moved during play?
Yes, well, you could just simply sum it up every frame like
// Stores the overall moved distance
private float totalMovedDistance;
// flag to start and stop tracking
// Could also use a Coroutine if that fits you better
private bool track;
// Store position of last frame
private Vector3 lastPos;
public void BeginTrack()
{
// reset total value
totalMovedDistance = 0;
// store first position
lastPos = InputTracking.GetLocalPosition(XRNode.RightHand);
// start tracking
track = true;
}
public void EndTrack()
{
// stop tracking
track = false;
// whatever you want to do with the total distance now
Debug.Log($"Total moved distance in local space: {totalMovedDistance}", this);
}
private void Update()
{
// If not tracking do nothing
if(!track) return;
// get current controller position
var currentPos = InputTracking.GetLocalPosition(XRNode.RightHand);
// Get distance moved since last frame
var thisFrameDistance = Vector3.Distance(currentPos, lastPos);
// sum it up to the total value
totalMovedDistance += thisFrameDistance;
// update the last position
lastPos = currentPos;
}

In Unity, how to detect if window is being resized and if window has stopped resizing

I wanted my UI to not resize when user is still resizing the game (holding click in the window border) and only when the user has released the mouse the resize event will trigger.
I have tried to achieve it on Unity but so far I only able to detect windows size change, which my script checked every 0.5 second and if detected change it will resize the UI. But of course resizing everything caused a heavy lag, so resizing every 0.5 second is not a good option but resizing every 1 second is not a good idea either because 1 second is considered too long.
The question might be too broad but I have specified the problem as small as possible, how do I detect if user is still resizing the window? And how do I detect if user has stopped resizing the window (stop holding click at window border)?
You can't tell when someone stops dragging a window, unless you want to code a low level solution for ever desktop environment and every operating system.
Here's what worked for me with any MonoBehavior class, using the OnRectTransformDimensionsChange event:
public class StackOverflow : MonoBehaviour
{
private const float TimeBetweenScreenChangeCalculations = 0.5f;
private float _lastScreenChangeCalculationTime = 0;
private void Awake()
{
_lastScreenChangeCalculationTime = Time.time;
}
private void OnRectTransformDimensionsChange()
{
if (Time.time - _lastScreenChangeCalculationTime < TimeBetweenScreenChangeCalculations)
return;
_lastScreenChangeCalculationTime = Time.time;
Debug.Log($"Window dimensions changed to {Screen.width}x{Screen.height}");
}
}
I have some good news - sort of.
When the user resizes the window on Mac or PC,
Unity will AUTOMATICALLY re-layout everything.
BUT in fact ONLY when the user is "finished" resizing the Mac/PC window.
I believe that is what the OP is asking for - so the good news, what the OP is asking for is quite automatic.
However. A huge problem in Unity is Unity does not smoothly resize elements as the user is dragging the mouse to expand the Mac/PC window.
I have never found a solution to that problem. (A poor solution often mentioned is to check the size of the window every frame; that seems to be about the only approach.)
Again interestingly, what the OP mentions
" ..and if window has stopped resizing .."
is automatically done in Unity; in fact do nothing to achieve that.
I needed something like this for re generating a line chart, but as it has too many elements, it would be heavy to do it on every update, so I came up with this, which for me worked well:
public class ToRunOnResize : MonoBehaviour
{
private float screenWidth;
private bool screenStartedResizing = false;
private int updateCounter = 0;
private int numberOfUpdatesToRunXFunction = 15; // The number of frames you want your function to run after, (usually 60 per second, so 15 would be .25 seconds)
void Start()
{
screenWidth = Screen.width; // Identifies the screen width
}
private void Update()
{
if (Screen.width != screenWidth) // This will be run and repeated while you resize your screen
{
updateCounter = 0; // This will set 0 on every update, so the counter is reset until you release the resizing.
screenStartedResizing = true; // This lets the application know when to start counting the # of updates after you stopped resizing.
screenWidth = Screen.width;
}
if (screenStartedResizing)
{
updateCounter += 1; // This will count the updates until it gets to the numberOfUpdatesToRunXFunction
}
if (updateCounter == numberOfUpdatesToRunXFunction && screenStartedResizing)
{ // Finally we make the counter stop and run the code, in my case I use it for re-rendering a line chart.
screenStartedResizing = false;
// my re-rendering code...
// my re-rendering code...
}
}
}

Terminate drag while mouse is still down

Imagine some standard Unity UI ScrollView. You grab it with your mouse and start dragging it so it is scrolling with your mouse. How do I programmatically make it stop scrolling while mouse button is still down? Is there any way to make ScrollRect think that user is released mouse button?
Quite old question, but I found exactly this same problem and no clean solution. My problem was to have scrollRect with items which I can scroll left/right but when user select one item and drag it up then scrollRect should cancel scrolling and allow user to drag item up. I achieved this by temporary setting ScrollRect.enable to false, and after few ms set it back to true.
Here is part of mu code which do this. Maybe somebody find this useful.
void Update()
{
if (state == DragState.Started) {
dragStart = Input.mousePosition;
state = DragState.Continued;
}
if (state == DragState.Continued) {
Vector3 pos = Input.mousePosition;
if (pos.y - dragStart.y > 80) {
scrollRect.enabled = false;
state = DragState.None;
Invoke("ReenableScroll", 0.01f);
}
}
}
private void ReenableScroll() {
scrollRect.enabled = true;
}
Its not easy to make the EventSystem think something has happend while it hasn't. I believe its much easier to implement your own ScrollRect logic and parse the mouse input yourself
You can call ScrollRect's OnEndDrag() method with artificial PointerEventData.
var forceEndDragData = new PointerEventData(EventSystem.current)
{
button = PointerEventData.InputButton.Left
};
_scrollRect.OnEndDrag(forceEndDragData);

How to make animation position start from last position

How to implement an animation in Unity relative to the last position. Normally when an animation is implemented in Unity each loop starts from the same position. I want to implement an animation relative to the last position of the animated object to avoid using forces or math calculations.
How I figured it out:
Unity Animation relative to last position without looping
This code solves the problem regarding animations based on last relative position. In this example, each time we press Fire1 a box will be animated to move from X = 0 to X = 10 Using the animation will help us to provide richer transitions and smooth movements based on curves without the problem of looping.
The idea is to have the animated object inside an empty parent so the animation of the object will be based into local position.
When the animation is finished we update the object and its parent location to match in the last position.
If you have any doubts please ask.
#pragma strict
/**
* Animation in Unity Relative to last position without looping
* #autor Knskank3
* http://stackoverflow.com/users/1287772/knskan3
* 04/09/2014
**/
/*
This code solves the problem regarding animations based on last relative ImagePosition
In this example, each time we press Fire1 a box will be animated to move from X = 0 to X = 10
Using the animation will help us to provide richer transitions and smooth movements based on curves
without the problem of looping
*/
// This var will determine if the animation is started
public var animation_started : boolean = false;
// This var will determine if the animation is finished
public var animation_finished : boolean = true;
function Update () {
// if user triggers Fire1
if( Input.GetButtonUp('Fire1')){
// initialize the flags
animation_started = true;
animation_finished = false;
// Start the animation
// this animation moves the box from local X = 0 to X = 10 using a curve to deaccelerate
animation.Play("boxanim");
}
}
/* This function is trigger at the end of the animation */
public function animationFinished() : void {
animation_finished = true;
}
/*
At the end of the frame if the animation is finished
we update the position of the parent to the last position of the child
and set the position of the child to zero inside the parent.
*/
function LateUpdate () {
// if the animation is finished and it was started
if(animation_finished && animation_started) {
// set the flag
animation_started = false;
// update the parent position
transform.parent.position = transform.position;
// update the box position to zero inside the parent
transform.localPosition = Vector3.zero;
}
}