2011-04-29 4 views
4

스크롤 이벤트에 대해의 스크롤 모멘텀 을 어떻게 계산합니까?스크롤 관성/운동량 계산 중?

끝 부분의 스크롤 시작 부분에 두 개의 타임 스탬프가 있어야한다는 것을 알고 있습니다. 기본적으로 관성없이 스크롤 할 수있는 "축 변경"변수가 있어야합니다.

이 내 현재 코드 스크롤의 종료에 대한 책임 :

if ((type == kMXTEnd || type == kMXTMovedOut) && _isScrolling) 
    { 
     long int finishTime = MXTimestamp(); 
     printf("SCEnd: Ending scroll at %ld\n",finishTime-_beginTime); 

     /* scrollX is the change in X axis */ 
     /* finishTime is time from touch down to touch up */ 

     printf(" * Time: %ld ChangeX: %f\n",finishTime,scrollX); 

     _isScrolling = FALSE; 
     _originalScrollPoint = _scrollPoint; 
    } 

가 그에 대한 "관성 또한"를 산출 할 수 있습니까? 기본 스크롤 값 외에도 스크롤 할 수있는 관성으로 인한 추가 오프셋과 같습니다. 또는 추가 변수를 받아야합니까?

내 UI 툴킷을 작성 중이므로 실제로 필요한 것은 아닙니다.

+0

당신이 사용하는 어떤 GUI 툴킷? intertia는 scolling과 어떤 관련이 있습니까? (이것은 부드러운 스크롤과 터치 스크롤에 사용되는 GUI 효과라는 것을 알고 있습니다.) 이 정보를 제공하여 질문을 향상 시키십시오. 또한 이것은 실제로 C 질문이 아닙니다. 애매 모호하기 때문에 투표 마감. – datenwolf

+1

GUI 툴킷을 사용하지 않고 있습니다. –

답변

5

"최근 축 변경"대기열을 사용하여이를 시뮬레이션 할 수 있습니다.

변경 사항의 마지막 1/2 초를 해당 타임 스탬프와 함께 저장하면 큐가 값 N보다 긴지 (즉, 사용자가 평소보다 빨리 끝까지 드래그 한 경우) 테스트 할 수 있습니다. 지난 반 초 동안 여행 한 총 거리, 즉 속도를 얻을 수있는 거리를 알 수 있습니다.

합리적인 속도로 속도 조정 (예 : 15px/.5 초, 약 25px/초 매핑) 및 모든 가속도 적용 (예 : 위의 예에서는 적절하게 조정 됨, 예 : -20px/초) (시스템에서 가능한 한 빨리 을 처리하십시오.으로 처리하십시오. 이와 함께 과도하게 적용하지 마십시오).

그런 다음 각 틱 (speed+=accel*time_scale)에서 속도를 업데이트 한 후 위치 (position+=speed*time_scale)를 실행하십시오. 속도가 0에 도달하면 (또는 그 이하로 이동하면) 타이머를 종료하십시오.

+0

그래서 모든 이동 이벤트에 대해 포인트를 줄 필요가 있습니까? –

+0

그것이 내가하는 방법입니다. 움직임이 끝나는 시점을 결코 알지 못하기 때문에이 방법을 사용하면 단위 시간 내에 이동 한 거리를 항상 계산할 수있는 충분한 데이터를 유지할 수 있습니다. – Blindy

1

다음과 같이 좋은 결과를 얻었습니다.

각 마우스 끌기 이벤트 (또는 터치 이벤트)에서 속도 (마지막 프레임 이후의 시간으로 나눈 이동량)와 시간 소인을 저장합니다. 마지막 변수 만 필요하므로 변수는 두 가지입니다.

마우스/터치가 해제되면 마지막 타임 스탬프가 최신인지 충분히 확인합니다 (0.3 초 ​​사용). 그렇다면 변수 inertialVelocity를 마지막으로 계산 된 속도로 설정합니다. 그렇지 않으면 사용자가 신중하게 위치를 선택한 경우 스크롤을 방지하기 위해 0으로 설정하십시오.

그런 다음 타이머 나 각 렌더 호출을 통해 렌더링 할 때마다 inertialVelocity * INERTIA_SCROLL_FACTOR (0.9를 사용)로 스크롤하고 inertialVelocity에 INERTIA_ACCELERATION을 곱합니다 (0.98 사용).

임계 값을 추가하면 inertiaVelocity가 너무 작아지면 스크롤이 중지됩니다. 내 렌더링 lib는 좌표로 float를 사용하므로 임계 값으로 1을 사용합니다. 좌표가 적분이라면, 그것은 0으로 떨어집니다.

명심해야 할 점은 inertialVelocity는 방향에 따라 양수 또는 음수 일 수 있다는 것입니다.

그래서, 의사 코드 :

OnMouseMove: 
    inertialVelocity = moveDistance/(now - timeOfLastEvent) 
    timeOfLastEvent = now 

OnMouseUp: 
    if (now - timeSinceLastEvent > 0.3f) 
     inertialVelocity = 0 

OnTimer/OnRender: 
    // timeDelta is needed only when doing this on render events, just to make 
    // it independent of the render speed. It is the time since the previous render 
    scrollPosition += inertialVelocity * INERTIA_SCROLL_FACTOR * timeDelta 
    inertialVelocity *= INERTIA_ACCELERATION * timeDelta 
    // Keep in mind that velocity can be negative as well, hence the abs 
    if (abs(inertialVelocity) < INERTIA_THRESHOLD) 
     inertialVelocity = 0