Author Topic: Scrolling  (Read 19484 times)

Nico91

  • Guest
Re: Scrolling
« Reply #30 on: September 23, 2012, 02:30:41 am »
Yes, sorry i added it quickly. Now i added the comments.  I need the recoil in this code can you Add it?
« Last Edit: September 23, 2012, 02:46:07 am by Nico91 »

Nico91

  • Guest
Re: Scrolling
« Reply #31 on: September 23, 2012, 09:01:31 am »
I added recoil
« Last Edit: January 10, 2013, 06:50:59 am by Nico91 »

jjsanchezramirez

  • Guest
Re: Scrolling
« Reply #32 on: September 23, 2012, 09:56:35 am »
Your recoil doesn't work well. You must divide by a constant value to make it feel "smooth". If you just add a constant value, it tends to look weird.

Tell me, what exactly is the purpose of h?

Nico91

  • Guest
Re: Scrolling
« Reply #33 on: September 23, 2012, 10:50:03 am »
I know, it isn't perfect but it is a good compromise. if you can improve it I'm very grateful, however, it is semple  decrease the speed, h mesure the times that the function is called. OnTimer is called 30 times per second, so h increases by 30 every second, putting if (h% 2 == 0) means that the if statement is called 15 times per second, h%3==0 means 10 time per second.

jjsanchezramirez

  • Guest
Re: Scrolling
« Reply #34 on: September 24, 2012, 12:20:19 am »
It's still not perfect, but it's working. It's definitely a WOP, so please note the code is incomplete.

Code: [Select]
/* Copyright 2012 Juan José Sánchez Ramírez

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

   Author Juan José Sánchez Ramírez
   Version 1.1
*/

#ifndef DYNAMIC_SCROLLER
#define DYNAMIC_SCROLLER

int nOldX;
int nOldY;
int nNewX;
int nNewY;

int nTouchId;
int nTouchEvent;

int i;

// This function will be called when a scroller is activated
int OnTouch(int id, int event, int x, int y)
{
// Get the ID of the container
nTouchId = id;

// Get the event of the container
nTouchEvent = event;

// Record initial coordinates when pressed down
if (event == 1)
{
nOldX = x;
nOldY = y;
nNewX = x;
nNewY = y;
}

// Record new coordinates when moving
if (event == 2)
{
nNewX = x;
nNewY = y;
}

// Erase coordinates when released
if (event == 3)
{
nOldX = 0;
nOldY = 0;
nNewX = 0;
nNewY = 0;
}

return id;
}

// This function approximates a container to it's target position.
void SlideContainer(int container, int targetX, int targetY, int speed)
{
/* To approximate the container, we're going to do the following:

   1. We get the container's x and y positions on the screen.
   2. If the value is less than the target value, we substract the
      value from the target value. If the value is more than the
  target value, we substract the target value from the value.
   3. We divide the difference by the speed.
   4. If the result equals 0, we make it equal to 1.
   5. If the value is less than the target value, we add the result
      to the value. If the value is more than the target value, we
  substract the result from the value.
   6. Finally, we set the container's position to our x and y values.
*/

int x = ContainerGetx(container);
int y = ContainerGety(container);

if (x < targetX)
{
int n = (targetX - x) / speed;
if (n == 0) n = 1;
x += n;
}
else if (x > targetX)
{
int n = (x - targetX) / speed;
if (n == 0) n = 1;
x -= n;
}

if (y < targetY)
{
int n = (targetY - y) / speed;
if (n == 0) n = 1;
y += n;
}
else if (y > targetY)
{
int n = (y - targetY) / speed;
if (n == 0) n = 1;
y -= n;
}

ContainerSetxy(container, x, y);
}

// This class creates a simple scroller for containers
class DynamicScroller
{
/* A scroller lets a container slide upon a portion of the screen.
   It's designed to move containers that are too big for the screen,
   both vertically and horizontally, but it can be modified to move
   smaller objects too, such as sliders. This can be achieved by
   modifying minimum and maximum ranges, using the SetMinX, SetMinY,
   SetMaxX, and SetMaxY functions, or alternatively, using the
   SetBoundaries function, which modifies all of these values at once.

   The scroller uses the following components:

   1. A container which contains all of the elements in the scroller.
   2. A touch component which must be at least the size of the
      entire container, which records the drag and drop actions.
   3. An ID number that allows to differentiate among scrollers,
      since all scrollers use the same OnTouch function.
   
   The recoil component uses the following variables:

   1. Elasticity, defined here as the property of an object to return
      to its original state after a stress. In this particular context,
  elasticity can be thought of as how fast the container returns to
  its position.
 
  Note: The lower the value, the higher the elasticity!

   2. Compliance, defined here as the inverse of elasticity. In this
      particular context, compliance can be thought of as the resistance
  of a container to move out of position.

  Note: The higher the value, the higher the compliance!
*/

private:

int m_nContainer;
int m_nTouch;

int m_nX;
int m_nY;

int m_nMinX;
int m_nMinY;

int m_nMaxX;
int m_nMaxY;

int m_nCompliance;
int m_nElasticity;

int m_nSpeedX;
int m_nSpeedY;

int m_anTouchX[10000];
int m_anTouchY[10000];

bool m_bHorizontalScroll;
bool m_bVerticalScroll;

bool m_bRecoil;
bool m_bFriction;

public:

// Constructor
DynamicScroller()
{

}

// This function initiates the scroller and all of its components
void Init(int& container, int x, int y, int touchWidth, int touchHeight, int id)
{
m_nContainer = container;
m_nTouch = TouchAdd(container, x, y, touchWidth, touchHeight, OnTouch, id);

m_nX = ContainerGetx(container);
m_nY = ContainerGety(container);

m_nMinX = x-touchWidth+320;
m_nMinY = y-touchHeight+480;

m_nMaxX = 0;
m_nMaxY = 0;

m_nCompliance = 10;
m_nElasticity = 2;

m_nSpeedX = 0;
m_nSpeedY = 0;

m_bHorizontalScroll = true;
m_bVerticalScroll = true;

m_bRecoil = true;
m_bFriction = false;
}

// This function updates the scroller
void Update()
{
/* To update the scroller we're going to:

   1. Check if the x coordinate has changed. If it has, and
      if horizontal scrolling is allowed, move the container.
  If the container is out of bounds, and recoil is allowed,
  move the container using compliance. If the container is
  out of bounds, and recoil is not allowed, move the
  container within bounds.

   2. Repeat for the y coordinate.

   3. If nothing has changed, then make the scroller x and y
      coordinates equal to the container's coordinates. This
  is necessary to start scrolling again. If the container
  is out of bounds, slide the container within bounds using
  elasticty.
*/

if (nOldX != nNewX && m_bHorizontalScroll)
{
ContainerSetx(m_nContainer, m_nX+nNewX-nOldX);

if (ContainerGetx(m_nContainer) < m_nMinX)
{
if (m_bRecoil)
ContainerSetx(m_nContainer, m_nMinX-(m_nMinX-(m_nX+nNewX-nOldX))/m_nCompliance);
else
ContainerSetx(m_nContainer, m_nMinX);
}

if (ContainerGetx(m_nContainer) > m_nMaxX)
{
if (m_bRecoil)
ContainerSetx(m_nContainer, m_nMaxX-(m_nMaxX-(m_nX+nNewX-nOldX))/m_nCompliance);
else
ContainerSetx(m_nContainer, m_nMaxX);
}
}

if (nOldY != nNewY && m_bVerticalScroll)
{
ContainerSety(m_nContainer, m_nY+nNewY-nOldY);

if (ContainerGety(m_nContainer) < m_nMinY)
{
if (m_bRecoil)
ContainerSety(m_nContainer, m_nMinY-(m_nMinY-(m_nY+nNewY-nOldY))/m_nCompliance);
else
ContainerSety(m_nContainer, m_nMinY);
}

if (ContainerGety(m_nContainer) > m_nMaxY)
{
if (m_bRecoil)
ContainerSety(m_nContainer, m_nMaxY-(m_nMaxY-(m_nY+nNewY-nOldY))/m_nCompliance);
else
ContainerSety(m_nContainer, m_nMaxY);
}
}

if (nOldX == nNewX && nOldY == nNewY)
{
m_nX = ContainerGetx(m_nContainer);
m_nY = ContainerGety(m_nContainer);

if (m_nX < m_nMinX)
SlideContainer(m_nContainer, m_nMinX, m_nY, m_nElasticity);
if (m_nY < m_nMinY)
SlideContainer(m_nContainer, m_nX, m_nMinY, m_nElasticity);
if (m_nX > m_nMaxX)
SlideContainer(m_nContainer, m_nMaxX, m_nY, m_nElasticity);
if (m_nY > m_nMaxY)
SlideContainer(m_nContainer, m_nX, m_nMaxY, m_nElasticity);
}

if (nTouchEvent == 1)
{
i = -1;
m_bFriction = false;
}

if (nTouchEvent == 2)
{
i++;
m_anTouchY[i] = nNewY;
}

if (nTouchEvent == 3)
{
if ((m_anTouchY[i] > m_anTouchY[i-1] &&
m_anTouchY[i] - m_anTouchY[i-1] > 1) ||
(m_anTouchY[i] < m_anTouchY[i-1] &&
m_anTouchY[i-1] - m_anTouchY[i] > 1))
m_bFriction = true;

m_nSpeedY = m_anTouchY[i-1] - m_anTouchY[i];

if (m_nSpeedY >= 10)
m_nSpeedY = 10;
if (m_nSpeedY <= -10)
m_nSpeedY = -10;
}

if (m_bFriction)
{
if (m_bVerticalScroll)
{
m_nY -= m_nSpeedY;
ContainerSety(m_nContainer, m_nY);
}

if (m_nSpeedY > 0)
m_nSpeedY--;
if (m_nSpeedY < 0)
m_nSpeedY++;

if (m_nSpeedY == 0)
m_bFriction = false;
}

nTouchEvent = -1;
}

// This function sets the minimum x range
void SetMinX(int x)
{
m_nMinX = x;
}

// This function sets the minimum y range
void SetMinY(int y)
{
m_nMinY = y;
}

// This function sets the maximum x range
void SetMaxX(int x)
{
m_nMaxX = x;
}

// This function sets the maximum y range
void SetMaxY(int y)
{
m_nMaxY = y;
}

// This function sets the minimum and maximum x and y ranges
void SetBoundaries(int minX, int minY, int maxX, int maxY)
{
SetMinX(minX);
SetMinY(minY);
SetMaxX(maxX);
SetMaxY(maxY);
}

// This function sets the horizontal scroll
void SetHorizontalScroll(bool flag)
{
m_bHorizontalScroll = flag;
}

// This function sets the vertical scroll
void SetVerticalScroll(bool flag)
{
m_bVerticalScroll = flag;
}

// This function sets the recoil
void SetRecoil(bool flag)
{
m_bRecoil = flag;
}
};

#endif

jjsanchezramirez

  • Guest
Re: Scrolling
« Reply #35 on: September 24, 2012, 12:22:57 am »
By the way, it's currently not supporting multiple containers. It's an issue with the nTouchId variable. I'll fix it soon.

jjsanchezramirez

  • Guest
Re: Scrolling
« Reply #36 on: September 24, 2012, 03:48:34 am »
This is what you've all been waiting for. Elasticity and friction in a single container. It works with other multiple containers. It's very easy to use.

This could use better comments, but it's done and it works beautifully. Haven't encountered any errors in the programming so far. I'm still worried about the compatibility issues when using more than two containers. Please let me know if you experience any problems.

Finally, I should thank Nico91, who wrote the original friction code.

That is to say, DragonFireSDK officially has scrolling components.

DynamicScroller.h
Code: [Select]
/* Copyright 2012 Juan José Sánchez Ramírez

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

   Author Juan José Sánchez Ramírez
   Co-author Nico91 at www.DragonFireSDK.net/forums
   Version 2.0
*/

#ifndef DYNAMIC_SCROLLER
#define DYNAMIC_SCROLLER

int nOldX;
int nOldY;
int nNewX;
int nNewY;

int nTouchId;
int nTouchEvent;

// This function will be called when a scroller is activated
int OnTouch(int id, int event, int x, int y)
{
// Get the ID of the container
nTouchId = id;

// Get the event of the container
nTouchEvent = event;

// Record initial coordinates when pressed down
if (event == 1)
{
nOldX = x;
nOldY = y;
nNewX = x;
nNewY = y;
}

// Record new coordinates when moving
if (event == 2)
{
nNewX = x;
nNewY = y;
}

// Erase coordinates when released
if (event == 3)
{
nOldX = 0;
nOldY = 0;
nNewX = 0;
nNewY = 0;
}

return id;
}

// This function approximates a container to it's target position.
void SlideContainer(int container, int targetX, int targetY, int speed)
{
/* To approximate the container, we're going to do the following:

   1. We get the container's x and y positions on the screen.
   2. If the value is less than the target value, we substract the
      value from the target value. If the value is more than the
  target value, we substract the target value from the value.
   3. We divide the difference by the speed.
   4. If the result equals 0, we make it equal to 1.
   5. If the value is less than the target value, we add the result
      to the value. If the value is more than the target value, we
  substract the result from the value.
   6. Finally, we set the container's position to our x and y values.
*/

int x = ContainerGetx(container);
int y = ContainerGety(container);

if (x < targetX)
{
int n = (targetX - x) / speed;
if (n == 0) n = 1;
x += n;
}
else if (x > targetX)
{
int n = (x - targetX) / speed;
if (n == 0) n = 1;
x -= n;
}

if (y < targetY)
{
int n = (targetY - y) / speed;
if (n == 0) n = 1;
y += n;
}
else if (y > targetY)
{
int n = (y - targetY) / speed;
if (n == 0) n = 1;
y -= n;
}

ContainerSetxy(container, x, y);
}

// This class creates a simple scroller for containers
class DynamicScroller
{
/* A scroller lets a container slide upon a portion of the screen.
   It's designed to move containers that are too big for the screen,
   both vertically and horizontally, but it can be modified to move
   smaller objects too, such as sliders. This can be achieved by
   modifying minimum and maximum ranges, using the SetMinX, SetMinY,
   SetMaxX, and SetMaxY functions, or alternatively, using the
   SetBoundaries function, which modifies all of these values at once.

   The scroller uses the following components:

   1. A container which contains all of the elements in the scroller.
   2. A touch component which must be at least the size of the
      entire container, which records the drag and drop actions.
   3. An ID number that allows to differentiate among scrollers,
      since all scrollers use the same OnTouch function.
   
   The recoil component uses the following variables:

   1. Elasticity, defined here as the property of an object to return
      to its original state after a stress. In this particular context,
  elasticity can be thought of as how fast the container returns to
  its position.
 
  Note: The lower the value, the higher the elasticity!

   2. Compliance, defined here as the inverse of elasticity. In this
      particular context, compliance can be thought of as the resistance
  of a container to move out of position.

  Note: The higher the value, the higher the compliance!
   
   The friction component uses the following variables:

   1. Max Speed, defined here as the maximum sliding speed between two
      bodies, independent of the acceleration.

   2. Friction Coefficient, defined here as an empirical property of the
      containers which describes the force of friction between two bodies
  and the force pressing them together. For example, ice on steel has
  a low coefficient of friction, while rubber on pavement has a high
  coefficient of friction.

  Note: The higher the value, the higher the coefficient!
*/

private:

int m_nContainer;
int m_nTouch;

int m_nX;
int m_nY;

int m_nMinX;
int m_nMinY;

int m_nMaxX;
int m_nMaxY;

int m_nCompliance;
int m_nElasticity;

int m_nSpeedX;
int m_nSpeedY;

int m_nMaxSpeed;
int m_nFrictionCoef;

int i;

int m_anTouchX[10000];
int m_anTouchY[10000];

bool m_bHorizontalScroll;
bool m_bVerticalScroll;

bool m_bRecoil;
bool m_bFriction;

bool m_bHorizontalSliding;
bool m_bVerticalSliding;

public:

// Constructor
DynamicScroller()
{

}

// This function initiates the scroller and all of its components
void Init(int& container, int x, int y, int touchWidth, int touchHeight, int id)
{
m_nContainer = container;
m_nTouch = TouchAdd(container, x, y, touchWidth, touchHeight, OnTouch, id);

m_nX = ContainerGetx(container);
m_nY = ContainerGety(container);

m_nMinX = x-touchWidth+320;
m_nMinY = y-touchHeight+480;

m_nMaxX = 0;
m_nMaxY = 0;

m_nCompliance = 10;
m_nElasticity = 2;

m_nSpeedX = 0;
m_nSpeedY = 0;

m_nMaxSpeed = 10;
m_nFrictionCoef = 2;

m_bHorizontalScroll = true;
m_bVerticalScroll = true;

m_bRecoil = true;
m_bFriction = true;

m_bHorizontalSliding = false;
m_bVerticalSliding = false;
}

// This function updates the scroller
void Update()
{
/* To update the scroller we're going to:

   1. Check if the x coordinate has changed. If it has, and
      if horizontal scrolling is allowed, move the container.
  If the container is out of bounds, and recoil is allowed,
  move the container using compliance. If the container is
  out of bounds, and recoil is not allowed, move the
  container within bounds.

   2. Repeat for the y coordinate.

   3. If nothing has changed, then make the scroller x and y
      coordinates equal to the container's coordinates. This
  is necessary to start scrolling again. If the container
  is out of bounds, slide the container within bounds using
  elasticty.

   4. If friction is allowed, depending on the Touch Id, gather
      speed and acceleration data. If there is acceleration and
  the acceleration surpasses the coefficient of friction,
  then use the last recorded speed. Activate scrolling.

   5. Substract the speed from the current coordinate, depending
      if it's vertical or horizontal scrolling. Then terminate
  scrolling. If the container is out of boundes, slide the
  container within bounds using elasticity and set the speed
  to zero.
*/

if (nOldX != nNewX && m_bHorizontalScroll)
{
ContainerSetx(m_nContainer, m_nX+nNewX-nOldX);

if (ContainerGetx(m_nContainer) < m_nMinX)
{
if (m_bRecoil)
ContainerSetx(m_nContainer, m_nMinX-(m_nMinX-(m_nX+nNewX-nOldX))/m_nCompliance);
else
ContainerSetx(m_nContainer, m_nMinX);
}

if (ContainerGetx(m_nContainer) > m_nMaxX)
{
if (m_bRecoil)
ContainerSetx(m_nContainer, m_nMaxX-(m_nMaxX-(m_nX+nNewX-nOldX))/m_nCompliance);
else
ContainerSetx(m_nContainer, m_nMaxX);
}
}

if (nOldY != nNewY && m_bVerticalScroll)
{
ContainerSety(m_nContainer, m_nY+nNewY-nOldY);

if (ContainerGety(m_nContainer) < m_nMinY)
{
if (m_bRecoil)
ContainerSety(m_nContainer, m_nMinY-(m_nMinY-(m_nY+nNewY-nOldY))/m_nCompliance);
else
ContainerSety(m_nContainer, m_nMinY);
}

if (ContainerGety(m_nContainer) > m_nMaxY)
{
if (m_bRecoil)
ContainerSety(m_nContainer, m_nMaxY-(m_nMaxY-(m_nY+nNewY-nOldY))/m_nCompliance);
else
ContainerSety(m_nContainer, m_nMaxY);
}
}

if (nOldX == nNewX && nOldY == nNewY)
{
m_nX = ContainerGetx(m_nContainer);
m_nY = ContainerGety(m_nContainer);

if (m_nX < m_nMinX)
SlideContainer(m_nContainer, m_nMinX, m_nY, m_nElasticity);
if (m_nY < m_nMinY)
SlideContainer(m_nContainer, m_nX, m_nMinY, m_nElasticity);
if (m_nX > m_nMaxX)
SlideContainer(m_nContainer, m_nMaxX, m_nY, m_nElasticity);
if (m_nY > m_nMaxY)
SlideContainer(m_nContainer, m_nX, m_nMaxY, m_nElasticity);
}

if (m_bFriction)
{
if (nTouchEvent == 1)
{
i = 0;
m_bHorizontalSliding = false;
m_bVerticalSliding = false;
}

if (nTouchEvent == 2)
{
i++;
m_anTouchX[i] = nNewX;
m_anTouchY[i] = nNewY;
}

if (nTouchEvent == 3)
{
if ((m_anTouchX[i] > m_anTouchX[i-1] && m_anTouchX[i] - m_anTouchX[i-1] > m_nFrictionCoef) ||
(m_anTouchX[i] < m_anTouchX[i-1] && m_anTouchX[i-1] - m_anTouchX[i] > m_nFrictionCoef))
m_bHorizontalSliding = true;

if ((m_anTouchY[i] > m_anTouchY[i-1] && m_anTouchY[i] - m_anTouchY[i-1] > m_nFrictionCoef) ||
(m_anTouchY[i] < m_anTouchY[i-1] && m_anTouchY[i-1] - m_anTouchY[i] > m_nFrictionCoef))
m_bVerticalSliding = true;

m_nSpeedX = m_anTouchX[i-1] - m_anTouchX[i];
m_nSpeedY = m_anTouchY[i-1] - m_anTouchY[i];

if (m_nSpeedX >= m_nMaxSpeed)
m_nSpeedX = m_nMaxSpeed;

if (m_nSpeedX <= -m_nMaxSpeed)
m_nSpeedX = -m_nMaxSpeed;

if (m_nSpeedY >= m_nMaxSpeed)
m_nSpeedY = m_nMaxSpeed;

if (m_nSpeedY <= -m_nMaxSpeed)
m_nSpeedY = -m_nMaxSpeed;

nTouchEvent = -1;
}

if (m_bHorizontalSliding && m_bHorizontalScroll)
{
m_nX -= m_nSpeedX;

if (m_nX < m_nMinX)
m_nSpeedX = 0;

if (m_nX > m_nMaxX)
m_nSpeedX = 0;

ContainerSetx(m_nContainer, m_nX);

if (m_nSpeedX > 0)
m_nSpeedX--;

if (m_nSpeedX < 0)
m_nSpeedX++;

if (m_nSpeedX == 0)
m_bHorizontalSliding = false;
}

if (m_bVerticalSliding && m_bVerticalScroll)
{
m_nY -= m_nSpeedY;

if (m_nY < m_nMinY)
m_nSpeedY = 0;

if (m_nY > m_nMaxY)
m_nSpeedY = 0;

ContainerSety(m_nContainer, m_nY);

if (m_nSpeedY > 0)
m_nSpeedY--;

if (m_nSpeedY < 0)
m_nSpeedY++;

if (m_nSpeedY == 0)
m_bVerticalSliding = false;
}
}
}

// This function sets the minimum x range
void SetMinX(int x)
{
m_nMinX = x;
}

// This function sets the minimum y range
void SetMinY(int y)
{
m_nMinY = y;
}

// This function sets the maximum x range
void SetMaxX(int x)
{
m_nMaxX = x;
}

// This function sets the maximum y range
void SetMaxY(int y)
{
m_nMaxY = y;
}

// This function sets the minimum and maximum x and y ranges
void SetBoundaries(int minX, int minY, int maxX, int maxY)
{
SetMinX(minX);
SetMinY(minY);
SetMaxX(maxX);
SetMaxY(maxY);
}

// This function sets the horizontal scroll
void SetHorizontalScroll(bool flag)
{
m_bHorizontalScroll = flag;
}

// This function sets the vertical scroll
void SetVerticalScroll(bool flag)
{
m_bVerticalScroll = flag;
}

// This function sets the recoil
void SetRecoil(bool flag)
{
m_bRecoil = flag;
}

// This function sets the friction
void SetFriction(bool flag)
{
m_bFriction = flag;
}
};

#endif

App.cpp
Code: [Select]
/* Copyright 2012 Juan José Sánchez Ramírez

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

   Author Juan José Sánchez Ramírez
   Version 1.0
*/

#include "DragonFireSDK.h"
#include "DynamicScroller.h"

DynamicScroller dynamicScroller;
DynamicScroller sliderDynamicScroller;

int nContainer;
int nSliderContainer;
int nGUIContainer;

int nFont;

// This function will be called when a button is pressed
int OnButton(int id)
{
return id;
}

// This function marks the beginning of program execution
void AppMain()
{
nContainer = ContainerAdd(0, 0, 0);
nSliderContainer = ContainerAdd(nContainer, 50, 165);
nGUIContainer = ContainerAdd(0, 0, 0);

nFont = FontAdd("Arial", "Regular", 20, 0x000000);

ViewAdd(0, "Images/Background.png", 0, 0);

// Initiate scroller 320x720, ID 0, horizontal scroll false
dynamicScroller.Init(nContainer, 0, 0, 320, 720, 0);
dynamicScroller.SetHorizontalScroll(false);

// Populate container
ButtonAdd(nContainer, "Images/RoundedButton", 8, 80, OnButton, 0);
TextAdd(nContainer, 24, 91, "Button", nFont);

ButtonAdd(nContainer, "Images/RoundedButton", 8, 595, OnButton, 1);
TextAdd(nContainer, 24, 606, "Another button", nFont);

ViewAdd(nContainer, "Images/Slider.png", 50, 165);

// Initiate scroller 25x26, ID 1, vertical scroll false
sliderDynamicScroller.Init(nSliderContainer, 0, 0, 25, 26, 1);
sliderDynamicScroller.SetVerticalScroll(false);
sliderDynamicScroller.SetBoundaries(50, 165, 246, 165);

// Populate slider container
ViewAdd(nSliderContainer, "Images/Handle.png", 0, 0);

// GUI elements
ViewAdd(nGUIContainer, "Images/TopBar.png", 0, 0);
ViewAdd(nGUIContainer, "Images/Navigator.png", 0, 20);
ViewAdd(nGUIContainer, "Images/Toolbar.png", 0, 436);
}

// This function is called whenever the app terminates
void AppExit()
{

}

// This function is called 30 times per second
void OnTimer()
{
if (nTouchEvent == 2)
{
if (nTouchId == 0)
dynamicScroller.Update();
else if (nTouchId == 1)
sliderDynamicScroller.Update();
}
else
{
dynamicScroller.Update();
sliderDynamicScroller.Update();
}
}

xabaras

  • Guest
Re: Scrolling
« Reply #37 on: September 24, 2012, 05:36:35 am »
Argh... i've uploaded my new app on the appstore a few days ago... i would have added friction very very willingly...   :)
Thank you  jj and nico... it works very well... and it works on the device too.
I'll sure add it in some update of the app (even if it probably will never be published...  ???)

good job!

Nico91

  • Guest
Re: Scrolling
« Reply #38 on: September 24, 2012, 05:47:56 am »
Great job jj. Can you Add friction and recoil to my code for zoom in a photo?

http://dragonfiresdk.net/forum/index.php?topic=293.0

« Last Edit: September 24, 2012, 05:49:51 am by Nico91 »

jjsanchezramirez

  • Guest
Re: Scrolling
« Reply #39 on: September 24, 2012, 10:57:39 am »
I don't have a device as of the moment, so I can't test the zoom function. Anyhow, what do you mean adding friction and recoil?

Nico91

  • Guest
Re: Scrolling
« Reply #40 on: September 24, 2012, 11:24:33 am »
You don't have to test the zoom, i need only the friction and the recoil when you move the image.

jjsanchezramirez

  • Guest
Re: Scrolling
« Reply #41 on: September 24, 2012, 12:24:26 pm »
Perhaps if we modify the DynamicScroller.h code to use an image instead of a container. I'm not entirely sure this would work. I'd try it myself but I'm a bit swamped with work right now.

jjsanchezramirez

  • Guest
Re: Scrolling
« Reply #42 on: September 24, 2012, 08:45:56 pm »
So this is the newest and probably final version of the dynamic scroller for containers. I added a momentum variable which increases the time it takes for a sliding container to stop. The bigger the momentum, the longer it takes to stop. Everything is explained in detail in the comments. So far, it works just fine.

Please let me know if you see any bugs.

Code: [Select]
/* Copyright 2012 Juan José Sánchez Ramírez

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

   Author Juan José Sánchez Ramírez
   Co-author Nico91 at www.dragonfiresdk.net/forums
   Version 2.1
*/

#ifndef DYNAMIC_SCROLLER
#define DYNAMIC_SCROLLER

int nOldX;
int nOldY;
int nNewX;
int nNewY;

int nTouchId;
int nTouchEvent;

// This function will be called when a scroller is activated
int OnTouch(int id, int event, int x, int y)
{
// Get the ID of the container
nTouchId = id;

// Get the event of the container
nTouchEvent = event;

// Record initial coordinates when pressed down
if (event == 1)
{
nOldX = x;
nOldY = y;
nNewX = x;
nNewY = y;
}

// Record new coordinates when moving
if (event == 2)
{
nNewX = x;
nNewY = y;
}

// Erase coordinates when released
if (event == 3)
{
nOldX = 0;
nOldY = 0;
nNewX = 0;
nNewY = 0;
}

return id;
}

// This function approximates a container to it's target position.
void SlideContainer(int container, int targetX, int targetY, int speed)
{
/* To approximate the container, we're going to do the following:

   1. We get the container's x and y positions on the screen.
   2. If the value is less than the target value, we substract the
      value from the target value. If the value is more than the
  target value, we substract the target value from the value.
   3. We divide the difference by the speed.
   4. If the result equals 0, we make it equal to 1.
   5. If the value is less than the target value, we add the result
      to the value. If the value is more than the target value, we
  substract the result from the value.
   6. Finally, we set the container's position to our x and y values.
*/

int x = ContainerGetx(container);
int y = ContainerGety(container);

if (x < targetX)
{
int n = (targetX - x) / speed;
if (n == 0) n = 1;
x += n;
}
else if (x > targetX)
{
int n = (x - targetX) / speed;
if (n == 0) n = 1;
x -= n;
}

if (y < targetY)
{
int n = (targetY - y) / speed;
if (n == 0) n = 1;
y += n;
}
else if (y > targetY)
{
int n = (y - targetY) / speed;
if (n == 0) n = 1;
y -= n;
}

ContainerSetxy(container, x, y);
}

// This class creates a simple scroller for containers
class DynamicScroller
{
/* A scroller lets a container slide upon a portion of the screen.
   It's designed to move containers that are too big for the screen,
   both vertically and horizontally, but it can be modified to move
   smaller objects too, such as sliders. This can be achieved by
   modifying minimum and maximum ranges, using the SetMinX, SetMinY,
   SetMaxX, and SetMaxY functions, or alternatively, using the
   SetBoundaries function, which modifies all of these values at once.

   The scroller uses the following components:

   1. A container which contains all of the elements in the scroller.
   2. A touch component which must be at least the size of the
      entire container, which records the drag and drop actions.
   3. An ID number that allows to differentiate among scrollers,
      since all scrollers use the same OnTouch function.
   
   The recoil component uses the following variables:

   1. Elasticity, defined here as the property of an object to return
      to its original state after a stress. In this particular context,
  elasticity can be thought of as how fast the container returns to
  its position.
 
  Note: The lower the value, the higher the elasticity!

   2. Compliance, defined here as the inverse of elasticity. In this
      particular context, compliance can be thought of as the resistance
  of a container to move out of position.

  Note: The higher the value, the higher the compliance!
   
   The friction component uses the following variables:

   1. Max Speed, defined here as the maximum sliding speed between two
      bodies, independent of the acceleration.

   2. Friction Coefficient, defined here as an empirical property of the
      containers which describes the force of friction between two bodies
  and the force pressing them together. For example, ice on steel has
  a low coefficient of friction, while rubber on pavement has a high
  coefficient of friction.

   3. Momentum, defined here as the property of containers to continue
      moving until stopped by a force of friction. The greater the
  momentum of a container, the stronger the force of friction that
  is required to stop the container.
*/

private:

int m_nContainer;
int m_nTouch;

int m_nX;
int m_nY;

int m_nMinX;
int m_nMinY;

int m_nMaxX;
int m_nMaxY;

int m_nCompliance;
int m_nElasticity;

int m_nSpeedX;
int m_nSpeedY;

int m_nMaxSpeed;
int m_nFrictionCoef;
int m_nMomentum;

int i;
int j;

int m_anTouchX[10000];
int m_anTouchY[10000];

bool m_bHorizontalScroll;
bool m_bVerticalScroll;

bool m_bRecoil;
bool m_bFriction;

bool m_bHorizontalSliding;
bool m_bVerticalSliding;

public:

// Constructor
DynamicScroller()
{

}

// This function initiates the scroller and all of its components
void Init(int& container, int x, int y, int touchWidth, int touchHeight, int id)
{
m_nContainer = container;
m_nTouch = TouchAdd(container, x, y, touchWidth, touchHeight, OnTouch, id);

m_nX = ContainerGetx(container);
m_nY = ContainerGety(container);

m_nMinX = x-touchWidth+320;
m_nMinY = y-touchHeight+480;

m_nMaxX = 0;
m_nMaxY = 0;

m_nCompliance = 10;
m_nElasticity = 2;

m_nSpeedX = 0;
m_nSpeedY = 0;

m_nMaxSpeed = 40;
m_nFrictionCoef = 2;
m_nMomentum = 3;

m_bHorizontalScroll = true;
m_bVerticalScroll = true;

m_bRecoil = true;
m_bFriction = true;

m_bHorizontalSliding = false;
m_bVerticalSliding = false;
}

// This function updates the scroller
void Update()
{
/* To update the scroller we're going to:

   1. Check if the x coordinate has changed. If it has, and
      if horizontal scrolling is allowed, move the container.
  If the container is out of bounds, and recoil is allowed,
  move the container using compliance. If the container is
  out of bounds, and recoil is not allowed, move the
  container within bounds.

   2. Repeat for the y coordinate.

   3. If nothing has changed, then make the scroller x and y
      coordinates equal to the container's coordinates. This
  is necessary to start scrolling again. If the container
  is out of bounds, slide the container within bounds using
  elasticty.

   4. If friction is allowed, and if pressing down, set horizontal
      and vertical sliding off; if moving, store the x and y
  coordinates in an array; if pressing up, check if there is
  vertical or horizontal acceleration and if the acceleration
  surpasses the coefficient of friction. If there is, set
  sliding on.
   
   5. Vertical and horizontal speed is calculated as the last
      recorded x and y coordinates minus the next to last recorded
  coordinates. If speed exceeds maximum speed, set speed to
  maximum speed.

   6. If horizontal sliding is on, and  if horizontal scrolling is
      allowed, substract the horizontal speed from the x coordinate.
  If the coordinate is out of bounds, set the speed to zero.
  Move the container horizontally. If the frame count is divisble
  by the momentum, and if speed is greater than zero, substract
  one from the speed, thus creating friction. If the speed is
  equal to zero, set horizontal sliding off.

   7. Repeat for vertical sliding.
*/

if (nOldX != nNewX && m_bHorizontalScroll)
{
ContainerSetx(m_nContainer, m_nX+nNewX-nOldX);

if (ContainerGetx(m_nContainer) < m_nMinX)
{
if (m_bRecoil)
ContainerSetx(m_nContainer, m_nMinX-(m_nMinX-(m_nX+nNewX-nOldX))/m_nCompliance);
else
ContainerSetx(m_nContainer, m_nMinX);
}

if (ContainerGetx(m_nContainer) > m_nMaxX)
{
if (m_bRecoil)
ContainerSetx(m_nContainer, m_nMaxX-(m_nMaxX-(m_nX+nNewX-nOldX))/m_nCompliance);
else
ContainerSetx(m_nContainer, m_nMaxX);
}
}

if (nOldY != nNewY && m_bVerticalScroll)
{
ContainerSety(m_nContainer, m_nY+nNewY-nOldY);

if (ContainerGety(m_nContainer) < m_nMinY)
{
if (m_bRecoil)
ContainerSety(m_nContainer, m_nMinY-(m_nMinY-(m_nY+nNewY-nOldY))/m_nCompliance);
else
ContainerSety(m_nContainer, m_nMinY);
}

if (ContainerGety(m_nContainer) > m_nMaxY)
{
if (m_bRecoil)
ContainerSety(m_nContainer, m_nMaxY-(m_nMaxY-(m_nY+nNewY-nOldY))/m_nCompliance);
else
ContainerSety(m_nContainer, m_nMaxY);
}
}

if (nOldX == nNewX && nOldY == nNewY)
{
m_nX = ContainerGetx(m_nContainer);
m_nY = ContainerGety(m_nContainer);

if (m_nX < m_nMinX)
SlideContainer(m_nContainer, m_nMinX, m_nY, m_nElasticity);
if (m_nY < m_nMinY)
SlideContainer(m_nContainer, m_nX, m_nMinY, m_nElasticity);
if (m_nX > m_nMaxX)
SlideContainer(m_nContainer, m_nMaxX, m_nY, m_nElasticity);
if (m_nY > m_nMaxY)
SlideContainer(m_nContainer, m_nX, m_nMaxY, m_nElasticity);
}

if (m_bFriction)
{
j++;

if (nTouchEvent == 1)
{
i = 0;
m_bHorizontalSliding = false;
m_bVerticalSliding = false;
}

if (nTouchEvent == 2)
{
i++;
m_anTouchX[i] = nNewX;
m_anTouchY[i] = nNewY;
}

if (nTouchEvent == 3)
{
j = 0;

if ((m_anTouchX[i] > m_anTouchX[i-1] && m_anTouchX[i] - m_anTouchX[i-1] > m_nFrictionCoef) ||
(m_anTouchX[i] < m_anTouchX[i-1] && m_anTouchX[i-1] - m_anTouchX[i] > m_nFrictionCoef))
m_bHorizontalSliding = true;

if ((m_anTouchY[i] > m_anTouchY[i-1] && m_anTouchY[i] - m_anTouchY[i-1] > m_nFrictionCoef) ||
(m_anTouchY[i] < m_anTouchY[i-1] && m_anTouchY[i-1] - m_anTouchY[i] > m_nFrictionCoef))
m_bVerticalSliding = true;

m_nSpeedX = m_anTouchX[i-1] - m_anTouchX[i];
m_nSpeedY = m_anTouchY[i-1] - m_anTouchY[i];

if (m_nSpeedX >= m_nMaxSpeed)
m_nSpeedX = m_nMaxSpeed;

if (m_nSpeedX <= -m_nMaxSpeed)
m_nSpeedX = -m_nMaxSpeed;

if (m_nSpeedY >= m_nMaxSpeed)
m_nSpeedY = m_nMaxSpeed;

if (m_nSpeedY <= -m_nMaxSpeed)
m_nSpeedY = -m_nMaxSpeed;

nTouchEvent = -1;
}

if (m_bHorizontalSliding && m_bHorizontalScroll)
{
m_nX -= m_nSpeedX;

if (m_nX < m_nMinX || m_nX > m_nMaxX)
m_nSpeedX = 0;

ContainerSetx(m_nContainer, m_nX);

if (j % m_nMomentum == 0 && m_nSpeedX > 0)
m_nSpeedX--;

if (j % m_nMomentum == 0 && m_nSpeedX < 0)
m_nSpeedX++;

if (m_nSpeedX == 0)
m_bHorizontalSliding = false;
}

if (m_bVerticalSliding && m_bVerticalScroll)
{
m_nY -= m_nSpeedY;

if (m_nY < m_nMinY || m_nY > m_nMaxY)
m_nSpeedY = 0;

ContainerSety(m_nContainer, m_nY);

if (j % m_nMomentum == 0 && m_nSpeedY > 0)
m_nSpeedY--;

if (j % m_nMomentum == 0 && m_nSpeedY < 0)
m_nSpeedY++;

if (m_nSpeedY == 0)
m_bVerticalSliding = false;
}
}
}

// This function sets the minimum x range
void SetMinX(int x)
{
m_nMinX = x;
}

// This function sets the minimum y range
void SetMinY(int y)
{
m_nMinY = y;
}

// This function sets the maximum x range
void SetMaxX(int x)
{
m_nMaxX = x;
}

// This function sets the maximum y range
void SetMaxY(int y)
{
m_nMaxY = y;
}

// This function sets the minimum and maximum x and y ranges
void SetBoundaries(int minX, int minY, int maxX, int maxY)
{
SetMinX(minX);
SetMinY(minY);
SetMaxX(maxX);
SetMaxY(maxY);
}

// This function sets the horizontal scroll
void SetHorizontalScroll(bool flag)
{
m_bHorizontalScroll = flag;
}

// This function sets the vertical scroll
void SetVerticalScroll(bool flag)
{
m_bVerticalScroll = flag;
}

// This function sets the recoil
void SetRecoil(bool flag)
{
m_bRecoil = flag;
}

// This function sets the friction
void SetFriction(bool flag)
{
m_bFriction = flag;
}
};

#endif

jjsanchezramirez

  • Guest
Re: Scrolling
« Reply #43 on: September 26, 2012, 07:42:49 pm »
Small update. Fixed a bug when scrolling out of bounds. It was accelerating when it shouldn't for a split frame. It works perfectly well on the simulator and device. I also tried to tweak the values to make them the most similar to native apps.

Code: [Select]
/* Copyright 2012 Juan José Sánchez Ramírez

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

   Author Juan José Sánchez Ramírez
   Co-author Nico91 at www.dragonfiresdk.net/forums
   Version 2.1.1
*/

#ifndef DYNAMIC_SCROLLER
#define DYNAMIC_SCROLLER

int nOldX;
int nOldY;
int nNewX;
int nNewY;

int nTouchId;
int nTouchEvent;

// This function will be called when a scroller is activated
int OnTouch(int id, int event, int x, int y)
{
// Get the ID of the container
nTouchId = id;

// Get the event of the container
nTouchEvent = event;

// Record initial coordinates when pressed down
if (event == 1)
{
nOldX = x;
nOldY = y;
nNewX = x;
nNewY = y;
}

// Record new coordinates when moving
if (event == 2)
{
nNewX = x;
nNewY = y;
}

// Erase coordinates when released
if (event == 3)
{
nOldX = 0;
nOldY = 0;
nNewX = 0;
nNewY = 0;
}

return id;
}

// This function approximates a container to it's target position.
void SlideContainer(int container, int targetX, int targetY, int speed)
{
/* To approximate the container, we're going to do the following:

   1. We get the container's x and y positions on the screen.
   2. If the value is less than the target value, we substract the
      value from the target value. If the value is more than the
  target value, we substract the target value from the value.
   3. We divide the difference by the speed.
   4. If the result equals 0, we make it equal to 1.
   5. If the value is less than the target value, we add the result
      to the value. If the value is more than the target value, we
  substract the result from the value.
   6. Finally, we set the container's position to our x and y values.
*/

int x = ContainerGetx(container);
int y = ContainerGety(container);

if (x < targetX)
{
int n = (targetX - x) / speed;
if (n == 0) n = 1;
x += n;
}
else if (x > targetX)
{
int n = (x - targetX) / speed;
if (n == 0) n = 1;
x -= n;
}

if (y < targetY)
{
int n = (targetY - y) / speed;
if (n == 0) n = 1;
y += n;
}
else if (y > targetY)
{
int n = (y - targetY) / speed;
if (n == 0) n = 1;
y -= n;
}

ContainerSetxy(container, x, y);
}

// This class creates a simple scroller for containers
class DynamicScroller
{
/* A scroller lets a container slide upon a portion of the screen.
   It's designed to move containers that are too big for the screen,
   both vertically and horizontally, but it can be modified to move
   smaller objects too, such as sliders. This can be achieved by
   modifying minimum and maximum ranges, using the SetMinX, SetMinY,
   SetMaxX, and SetMaxY functions, or alternatively, using the
   SetBoundaries function, which modifies all of these values at once.

   The scroller uses the following components:

   1. A container which contains all of the elements in the scroller.
   2. A touch component which must be at least the size of the
      entire container, which records the drag and drop actions.
   3. An ID number that allows to differentiate among scrollers,
      since all scrollers use the same OnTouch function.
   
   The recoil component uses the following variables:

   1. Elasticity, defined here as the property of an object to return
      to its original state after a stress. In this particular context,
  elasticity can be thought of as how fast the container returns to
  its position.
 
  Note: The lower the value, the higher the elasticity!

   2. Compliance, defined here as the inverse of elasticity. In this
      particular context, compliance can be thought of as the resistance
  of a container to move out of position.

  Note: The higher the value, the higher the compliance!
   
   The friction component uses the following variables:

   1. Max Speed, defined here as the maximum sliding speed between two
      bodies, independent of the acceleration.

   2. Friction Coefficient, defined here as an empirical property of the
      containers which describes the force of friction between two bodies
  and the force pressing them together. For example, ice on steel has
  a low coefficient of friction, while rubber on pavement has a high
  coefficient of friction.

   3. Momentum, defined here as the property of containers to continue
      moving until stopped by a force of friction. The greater the
  momentum of a container, the stronger the force of friction that
  is required to stop the container.
*/

private:

int m_nContainer;
int m_nTouch;

int m_nX;
int m_nY;

int m_nMinX;
int m_nMinY;

int m_nMaxX;
int m_nMaxY;

int m_nCompliance;
int m_nElasticity;

int m_nSpeedX;
int m_nSpeedY;

int m_nMaxSpeed;
int m_nFrictionCoef;
int m_nMomentum;

int i;
int j;

int m_anTouchX[10000];
int m_anTouchY[10000];

bool m_bHorizontalScroll;
bool m_bVerticalScroll;

bool m_bRecoil;
bool m_bFriction;

bool m_bHorizontalSliding;
bool m_bVerticalSliding;

public:

// Constructor
DynamicScroller()
{

}

// This function initiates the scroller and all of its components
void Init(int& container, int x, int y, int touchWidth, int touchHeight, int id)
{
m_nContainer = container;
m_nTouch = TouchAdd(container, x, y, touchWidth, touchHeight, OnTouch, id);

m_nX = ContainerGetx(container);
m_nY = ContainerGety(container);

m_nMinX = x-touchWidth+320;
m_nMinY = y-touchHeight+480;

m_nMaxX = 0;
m_nMaxY = 0;

m_nCompliance = 1;
m_nElasticity = 2;

m_nSpeedX = 0;
m_nSpeedY = 0;

m_nMaxSpeed = 40;
m_nFrictionCoef = 2;
m_nMomentum = 3;

m_bHorizontalScroll = true;
m_bVerticalScroll = true;

m_bRecoil = true;
m_bFriction = true;

m_bHorizontalSliding = false;
m_bVerticalSliding = false;
}

// This function updates the scroller
void Update()
{
/* To update the scroller we're going to:

   1. Check if the x coordinate has changed. If it has, and
      if horizontal scrolling is allowed, move the container.
  If the container is out of bounds, and recoil is allowed,
  move the container using compliance. If the container is
  out of bounds, and recoil is not allowed, move the
  container within bounds.

   2. Repeat for the y coordinate.

   3. If nothing has changed, then make the scroller x and y
      coordinates equal to the container's coordinates. This
  is necessary to start scrolling again. If the container
  is out of bounds, slide the container within bounds using
  elasticty.

   4. If friction is allowed, and if pressing down, set horizontal
      and vertical sliding off; if moving, store the x and y
  coordinates in an array; if pressing up, check if there is
  vertical or horizontal acceleration and if the acceleration
  surpasses the coefficient of friction. If there is, set
  sliding on.
   
   5. Vertical and horizontal speed is calculated as the last
      recorded x and y coordinates minus the next to last recorded
  coordinates. If speed exceeds maximum speed, set speed to
  maximum speed.

   6. If horizontal sliding is on, if horizontal scrolling is allowed,
      and if the coordinate is out of bounds, set the speed to zero.
  Otherwise, substract the horizontal speed from the x coordinate.
  Move the container horizontally. If the frame count is divisble
  by the momentum, and if speed is greater than zero, substract
  one from the speed, thus creating friction. If the speed is
  equal to zero, set horizontal sliding off.

   7. Repeat for vertical sliding.
*/

if (nOldX != nNewX && m_bHorizontalScroll)
{
ContainerSetx(m_nContainer, m_nX+nNewX-nOldX);

if (ContainerGetx(m_nContainer) < m_nMinX)
{
if (m_bRecoil)
ContainerSetx(m_nContainer, m_nMinX-(m_nMinX-(m_nX+nNewX-nOldX))/m_nCompliance);
else
ContainerSetx(m_nContainer, m_nMinX);
}

if (ContainerGetx(m_nContainer) > m_nMaxX)
{
if (m_bRecoil)
ContainerSetx(m_nContainer, m_nMaxX-(m_nMaxX-(m_nX+nNewX-nOldX))/m_nCompliance);
else
ContainerSetx(m_nContainer, m_nMaxX);
}
}

if (nOldY != nNewY && m_bVerticalScroll)
{
ContainerSety(m_nContainer, m_nY+nNewY-nOldY);

if (ContainerGety(m_nContainer) < m_nMinY)
{
if (m_bRecoil)
ContainerSety(m_nContainer, m_nMinY-(m_nMinY-(m_nY+nNewY-nOldY))/m_nCompliance);
else
ContainerSety(m_nContainer, m_nMinY);
}

if (ContainerGety(m_nContainer) > m_nMaxY)
{
if (m_bRecoil)
ContainerSety(m_nContainer, m_nMaxY-(m_nMaxY-(m_nY+nNewY-nOldY))/m_nCompliance);
else
ContainerSety(m_nContainer, m_nMaxY);
}
}

if (nOldX == nNewX && nOldY == nNewY)
{
m_nX = ContainerGetx(m_nContainer);
m_nY = ContainerGety(m_nContainer);

if (m_nX < m_nMinX)
SlideContainer(m_nContainer, m_nMinX, m_nY, m_nElasticity);
if (m_nY < m_nMinY)
SlideContainer(m_nContainer, m_nX, m_nMinY, m_nElasticity);
if (m_nX > m_nMaxX)
SlideContainer(m_nContainer, m_nMaxX, m_nY, m_nElasticity);
if (m_nY > m_nMaxY)
SlideContainer(m_nContainer, m_nX, m_nMaxY, m_nElasticity);
}

if (m_bFriction)
{
j++;

if (nTouchEvent == 1)
{
i = 0;
m_bHorizontalSliding = false;
m_bVerticalSliding = false;
}

if (nTouchEvent == 2)
{
i++;
m_anTouchX[i] = nNewX;
m_anTouchY[i] = nNewY;
}

if (nTouchEvent == 3)
{
j = 0;

if ((m_anTouchX[i] > m_anTouchX[i-1] && m_anTouchX[i] - m_anTouchX[i-1] > m_nFrictionCoef) ||
(m_anTouchX[i] < m_anTouchX[i-1] && m_anTouchX[i-1] - m_anTouchX[i] > m_nFrictionCoef))
m_bHorizontalSliding = true;

if ((m_anTouchY[i] > m_anTouchY[i-1] && m_anTouchY[i] - m_anTouchY[i-1] > m_nFrictionCoef) ||
(m_anTouchY[i] < m_anTouchY[i-1] && m_anTouchY[i-1] - m_anTouchY[i] > m_nFrictionCoef))
m_bVerticalSliding = true;

m_nSpeedX = m_anTouchX[i-1] - m_anTouchX[i];
m_nSpeedY = m_anTouchY[i-1] - m_anTouchY[i];

if (m_nSpeedX >= m_nMaxSpeed)
m_nSpeedX = m_nMaxSpeed;

if (m_nSpeedX <= -m_nMaxSpeed)
m_nSpeedX = -m_nMaxSpeed;

if (m_nSpeedY >= m_nMaxSpeed)
m_nSpeedY = m_nMaxSpeed;

if (m_nSpeedY <= -m_nMaxSpeed)
m_nSpeedY = -m_nMaxSpeed;

nTouchEvent = -1;
}

if (m_bHorizontalSliding && m_bHorizontalScroll)
{
if (m_nX < m_nMinX || m_nX > m_nMaxX)
m_nSpeedX = 0;
else
m_nX -= m_nSpeedX;

ContainerSetx(m_nContainer, m_nX);

if (j % m_nMomentum == 0 && m_nSpeedX > 0)
m_nSpeedX--;

if (j % m_nMomentum == 0 && m_nSpeedX < 0)
m_nSpeedX++;

if (m_nSpeedX == 0)
m_bHorizontalSliding = false;
}

if (m_bVerticalSliding && m_bVerticalScroll)
{
if (m_nY < m_nMinY || m_nY > m_nMaxY)
m_nSpeedY = 0;
else
m_nY -= m_nSpeedY;

ContainerSety(m_nContainer, m_nY);

if (j % m_nMomentum == 0 && m_nSpeedY > 0)
m_nSpeedY--;

if (j % m_nMomentum == 0 && m_nSpeedY < 0)
m_nSpeedY++;

if (m_nSpeedY == 0)
m_bVerticalSliding = false;
}
}
}

// This function sets the minimum x range
void SetMinX(int x)
{
m_nMinX = x;
}

// This function sets the minimum y range
void SetMinY(int y)
{
m_nMinY = y;
}

// This function sets the maximum x range
void SetMaxX(int x)
{
m_nMaxX = x;
}

// This function sets the maximum y range
void SetMaxY(int y)
{
m_nMaxY = y;
}

// This function sets the minimum and maximum x and y ranges
void SetBoundaries(int minX, int minY, int maxX, int maxY)
{
SetMinX(minX);
SetMinY(minY);
SetMaxX(maxX);
SetMaxY(maxY);
}

// This function sets the horizontal scroll
void SetHorizontalScroll(bool flag)
{
m_bHorizontalScroll = flag;
}

// This function sets the vertical scroll
void SetVerticalScroll(bool flag)
{
m_bVerticalScroll = flag;
}

// This function sets the recoil
void SetRecoil(bool flag)
{
m_bRecoil = flag;
}

// This function sets the friction
void SetFriction(bool flag)
{
m_bFriction = flag;
}
};

#endif

zacho

  • Jr. Member
  • **
  • Posts: 81
  • Karma: +2/-0
    • View Profile
Re: Scrolling
« Reply #44 on: October 18, 2012, 03:07:02 pm »
Can you upload the image files you have used in this example, for reference of what the slider looks like?