Adventure Game Studio

AGS Support => Advanced Technical Forum => Topic started by: subspark on Sat 01/12/2007 04:12:08

Title: General Purpose Smooth Scrolling Module
Post by: subspark on Sat 01/12/2007 04:12:08
Dear AGS'ers, AGS is in need of a decent general purpose smooth scrolling module. At first I though scrolling the viewport would be easy, it wasn't. I had to visit several topics in order to get a specific and messy solution. The reality is, we all need a module that can be activated in room scripts for introductions and cut scenes.

A simple line like:
ScrollViewport(left,easing, blocking, 91 pixels);
or:
ScrollCharacter(up,easing, blocking, 12 pixels);
even:
ScrollGUI(up right,easing, blocking, 20 pixels);

...should give an indication as to the simplicity and control needed.

Can somebody please put the whole scrolling thing to rest with a decent module for the new AGS 3.0?
With all due respect to Chris, simple 'one line' control over scrolling could have been a standard AGS feature a long while ago, but it's now come time for the community to do it ourselves.  :)

Anyone keen?

Cheers,
Paul.
Title: Re: General Purpose Smooth Scrolling Module
Post by: monkey0506 on Sat 01/12/2007 05:09:46
What exactly would be the purposes of the ScrollCharacter and ScrollGUI functions? Should ScrollCharacter make the Character walk up the 12 pixels, or should the Character float up?

A Viewport scrolling module wouldn't be that difficult, and it could even be set up with enumerated values like:

eScrollUp,
eScrollDown,
eScrollLeft,
eScrollRight,
eScrollUpLeft,
eScrollUpRight,
eScrollDownLeft,
eScrollDownRight


Also I don't understand the purpose of the easing parameter. Presumably a function like this you would pass SPEED and AMOUNT parameters and every game loop it would scroll SPEED units in the specified direction up to AMOUNT pixels. This is what you're looking for, yes?
Title: Re: General Purpose Smooth Scrolling Module
Post by: subspark on Sat 01/12/2007 07:57:05
Characters and Objects would float yes.

Easing is a pretty common term. It basically means instead of a linear movement from point A to point B, its more like a 90 degree S curve. (If you've ever done 3D animation?)
The scrolling motion slows down (eases into) the stop position and eases out from a stationary position into movement. This could mean a mere 3 extra frames to slow down sharp stopping and starting.

Its all been done before http://www.adventuregamestudio.co.uk/yabb/index.php?topic=25937.0 (http://www.adventuregamestudio.co.uk/yabb/index.php?topic=25937.0) and http://www.adventuregamestudio.co.uk/yabb/index.php?topic=31187.msg401225#msg401225 (http://www.adventuregamestudio.co.uk/yabb/index.php?topic=31187.msg401225#msg401225)
however none of these solutions are as simple as typing a single line of code into a room script. Theres no reason it shouldn't or can't be that simple and every reason it should be.

I'm not a programmer but I do hope that somebody can create this module for the community. In my opinion, its something that once created, we won't do without it.

Cheers,
Paul.
Title: Re: General Purpose Smooth Scrolling Module
Post by: Khris on Sat 01/12/2007 17:41:08
Here's easing using sine & cosine:

enum EaseType {
  eEaseIn,
  eEaseOut,
  eNoEasing
};

int Scroll(int min, int middle, int max, EaseType easing) {
  if (min==max) return 0;
  float part=IntToFloat(middle-min)/IntToFloat(max-min);
  if (part<0.0) part=0.0;
  if (part>1.0) part=1.0;
  if (easing==eEaseIn) part=Maths.Sin(part*Maths.Pi/2.0);
  if (easing==eEaseOut) part=1.0-Maths.Cos(part*Maths.Pi/2.0);
  return FloatToInt(part*IntToFloat(max-min))+min;
}


Use it like:
  int c;
  while (c<100) {
    gStatusline.SetPosition(0, Scroll(0, c, 100, eEaseOut));
    Wait(1);
    c++;
  }

tested, working

Note that in the case of easing out, the end speed is not 1 but Pi/2 (~1.57).
Title: Re: General Purpose Smooth Scrolling Module
Post by: subspark on Sun 02/12/2007 08:08:44
As I said I'm no programmer. Could you give me a little reference as to where to put this code?
I imagine the main bit goes in repetedly_execute_always?
In any case, I couldn't get it to work.

Do I have any control over the scroll direction with this script, btw?
I don't understand what does what so your going to have to be more specific with me.  :)

Thanks,
Paul.
Title: Re: General Purpose Smooth Scrolling Module
Post by: Khris on Sun 02/12/2007 15:24:38
The first bit goes at the top of the global script. You can move the enum's definition into the script header if you want.
If you want to access Scroll() from your room scripts, you need to import the function in the header:
// inside script header, below enum definition
import int Scroll(int min, int middle, int max, EaseType easing);


The second bit demonstrates the use; the while loop makes c go from 0 to 99, Scroll() is called with 0 and 99 as from-value and to-value and c as the intermediate position.
The fourth param sets the type of easing; if it's set to eNoEasing, Scroll() will simply return the unchanged intermediate value.
If easing is set to eEaseIn or eEaseOut, the intermediate value is adjusted to reflect acceleration or deceleration.
That's all Scroll() does; the actual movement has to be done using a loop.
So the direction of the scrolling can be anything you like.
If you get my code to work, put "99-" in front of "Scroll(..." to reverse the direction.

(I'm working on an adjusted function that'll use a factor to scale the speed.)
Title: Re: General Purpose Smooth Scrolling Module
Post by: subspark on Sun 02/12/2007 20:48:33
Hmm, still doesn't work. I'm actually trying to scroll the viewport here so the line gStatusline doesn't apply.
The code I have is SetViewport(0, Scroll(0, c, 100, eEaseOut)); but this doesn't work either.
Any ideas?

QuoteI'm working on an adjusted function that'll use a factor to scale the speed.
Brilliant! I'm looking forward to trying it out.

Thanks for this, Khris. Your a champ!  ;)

Edit: Whats eEaseOut and how would you use it? This doesn't make sense.
The whole purpose of easing is that it does the ease out on the start of scrolling and the ease in at the end to smooth out the sharp transition.
Based on your example, I don't understand how one would write the eEase in command for the end of the animation.
Does this mean I have to write two separate lines of code to control each half of the scrolling movement? Point A = eEaseOut line and point B = eEaseIn line?  ???

Cheers,
Paul.
Title: Re: General Purpose Smooth Scrolling Module
Post by: theatrx on Tue 04/12/2007 06:12:18
Quote from: KhrisMUC on Sat 01/12/2007 17:41:08
Here's easing using sine & cosine:

enum EaseType {
  eEaseIn,
  eEaseOut,
  eNoEasing
};

int Scroll(int min, int middle, int max, EaseType easing) {
  if (min==max) return 0;
  float part=IntToFloat(middle-min)/IntToFloat(max-min);
  if (part<0.0) part=0.0;
  if (part>1.0) part=1.0;
  if (easing==eEaseIn) part=Maths.Sin(part*Maths.Pi/2.0);
  if (easing==eEaseOut) part=1.0-Maths.Cos(part*Maths.Pi/2.0);
  return FloatToInt(part*IntToFloat(max-min))+min;
}


Use it like:
  int c;
  while (c<100) {
    gStatusline.SetPosition(0, Scroll(0, c, 100, eEaseOut));
    Wait(1);
    c++;
  }

tested, working

Note that in the case of easing out, the end speed is not 1 but Pi/2 (~1.57).

Sometimes I look at your coding and think... Damn!  What was he on to come up with that elegantly simple solution.  Good work.  Steve
Title: Re: General Purpose Smooth Scrolling Module
Post by: subspark on Tue 04/12/2007 08:14:57
Care to share with us how you got it working, Steve?

I'm still not sure what your eEaseOut does, Khris.
Cheers,
Paul.
Title: Re: General Purpose Smooth Scrolling Module
Post by: Khris on Tue 04/12/2007 22:06:55
Here's a graphical representation of what the function does:

(http://i208.photobucket.com/albums/bb259/khrismuc/_expl_ease.png)

The x-axis represents time, the y-axis represents location. Thus, the slope of the graph represents the speed.

Standard scrolling is done using the blue line. Even movement at a constant speed.
The red line represents easing in; the movement starts out fast and slows gradually down to zero.
The green line represents easing out; the movement starts very slow and gradually gains speed.

The starting/ending speed is ~1.57; unfortunately, this can't be changed by simply including a factor in the function params.
Pi/2 isn't very convenient to handle so I've changed the function to use x² instead, resulting in a starting/ending speed of 2:

int Scroll(int min, int middle, int max, EaseType easing) {
  if (min==max) return 0;
  float part=IntToFloat(middle-min)/(IntToFloat(max-min));
  if (part<0.0) part=0.0;
  if (part>1.0) part=1.0;
  if (easing==eEaseIn) part=-1.0*(part-1.0)*(part-1.0)+1.0;
  if (easing==eEaseOut) part=part*part;
  return FloatToInt((part*IntToFloat(max-min)))+min;
}


To make the status line accelerate from 0-100, then move steadily to 200, use code like this:
    int c, y;
    while (c<299) {
      if (c<200) {
        y=Scroll(0, c, 200, eEaseOut)/2;
      }
      else y=c-100;
      Wait(1);
      gStatusline.SetPosition(0, y);
      c++;
    }
Title: Re: General Purpose Smooth Scrolling Module
Post by: subspark on Tue 04/12/2007 22:36:00
Interesting. Ultimately I would like to know how to work through your code to achieve this:

(http://www.shuugouteki.net/paul/Development/transition_curve.jpg)
I'm aiming for easing in general. So smooth out from point A to smooth in to point B.

Paul.
Title: Re: General Purpose Smooth Scrolling Module
Post by: Khris on Tue 04/12/2007 22:50:47
To achieve this you don't even have to use any conversions, you can directly use both versions one after another:
    int c, y;
    while (c<199) {
      if (c<100) y=Scroll(0, c, 99, eEaseOut);
      else       y=Scroll(100, c, 99, eEaseIn);
      Wait(1);
      gStatusline.SetPosition(0, y);
      c++;
    }
Title: Re: General Purpose Smooth Scrolling Module
Post by: subspark on Tue 04/12/2007 23:22:15
I'm with you now. However when using it with SetViewport the screen jumps to the value rather than performing any scrolling at all.
I've adjusted the code like this:


function room_AfterFadeIn()
{
  Wait(80);
    int c, y;
    while (c<199) {
      if (c<100) y=Scroll(0, c, 99, eEaseOut);
      else       y=Scroll(100, c, 99, eEaseIn);
      Wait(1);
      SetViewport(0, y);
      c++;
    }
  ReleaseViewport();

  FadeObjectIn_NoBlock(oLocationTime,0, -15); // Paracosmo City 2083
  cNarrator.ChangeRoom(3, 120, 0);
}


Am I missing something somewhere?

Cheers,
Paul.
Title: Re: General Purpose Smooth Scrolling Module
Post by: Khris on Tue 04/12/2007 23:54:38
Oh, I forgot to change something. The 99 in the eEaseIn line was supposed to be a 199.

Use this:
function room_AfterFadeIn()
{
  Wait(80);
  int c, y;
  while (c<200) {
    if (c<100) y=Scroll(0, c, 100, eEaseOut);
    else       y=Scroll(100, c, 200, eEaseIn);
    SetViewport(0, y);
    Wait(1);
    c++;
  }
  ReleaseViewport();

  FadeObjectIn_NoBlock(oLocationTime,0, -15); // Paracosmo City 2083
  cNarrator.ChangeRoom(3, 120, 0);
}
Title: Re: General Purpose Smooth Scrolling Module
Post by: subspark on Wed 05/12/2007 03:13:22
Hmm. It compiles and launches fine however it still jumps without scrolling. I wonder if its something in my global script. I've tried searching through my scripts looking for bugs but nothing is immediately obvious. Boy, either I'm really stupid, or I'm missing the obvious.  :-[

Cheers,
Paul.
Title: Re: General Purpose Smooth Scrolling Module
Post by: Khris on Wed 05/12/2007 03:36:36
When I tried your code, the first, accelerating scroll worked fine. The second one didn't due to the 99.
The corrected code is tested and worked for me; the 320x400 screen scrolled nicely from top to bottom.
Title: Re: General Purpose Smooth Scrolling Module
Post by: subspark on Wed 05/12/2007 06:28:25
Hmmm. Let me see what I am doing wrong. I must have some conflicting code in my game somewhere. I did use two different methods before I tried yours so there might still be some left over code.
I can't believe how simple your function is, btw. I'm astounded that smooth scrolling can be done with merely a few lines of code. Thats pretty impressive to me, man.

Paul.

EDIT: Ahah! Top to bottom you say. Thats where my error is. I was wondering why it never worked at all. I'm actually trying to go from right to left. It makes sense now. This must be pretty simple to do so I'll have a play around.

Thanks Khris.
Title: Re: General Purpose Smooth Scrolling Module
Post by: subspark on Wed 05/12/2007 07:22:37
Ive tried everything! I can't seem to get it to scroll in the direction I want. I want it to scroll 91 pixels to the left. This is what I have so far:
function room_AfterFadeIn()
{
  Wait(80);
    int c, x;
    while (c>0) {
      if (c>45) x=Scroll(91, c, 46, eEaseOut);
      else       x=Scroll(45, c, 0, eEaseIn);
      Wait(1);
      SetViewport(x, 0);
      c++;
    }
  Wait(100);
  ReleaseViewport();

  FadeObjectIn_NoBlock(oLocationTime,0, -15); // Paracosmo City 2083
  cNarrator.ChangeRoom(3, 120, 0);
}


I know I'm somewhat there.

Cheers,
Paul.
Title: Re: General Purpose Smooth Scrolling Module
Post by: monkey0506 on Wed 05/12/2007 07:37:26
int Scroll(int min, int middle, int max, EaseType easing) {
  if (min==max) return 0;
  float part=IntToFloat(middle-min)/(IntToFloat(max-min));
  if (part<0.0) part=0.0;
  if (part>1.0) part=1.0;
  if (easing==eEaseIn) part=-1.0*(part-1.0)*(part-1.0)+1.0;
  if (easing==eEaseOut) part=part*part;
  return FloatToInt((part*IntToFloat(max-min)))+min;
}

function room_AfterFadeIn()
{
  Wait(80);
    int c, x;
    while (c>0) {
      if (c>45) x=Scroll(91, c, 46, eEaseOut);
      else       x=Scroll(45, c, 0, eEaseIn);
      Wait(1);
      SetViewport(x, 0);
      c++;
    }
  Wait(100);
  ReleaseViewport();

  FadeObjectIn_NoBlock(oLocationTime,0, -15); // Paracosmo City 2083
  cNarrator.ChangeRoom(3, 120, 0);
}


I'm not sure, but I think you may have meant c < 45 instead of c > 45. Without actually seeing it in motion, the numbers I calculated aren't really meaning much to me right now.

Please forgive me if I'm completely wrong here. My toe and head are experiencing reasonable amounts of discomfort right now and my brain could just be floating off elsewhere... ::)
Title: Re: General Purpose Smooth Scrolling Module
Post by: subspark on Wed 05/12/2007 07:42:31
Thanks monkey. I already tried that actually. That time it didn't even pop to the left side.  :)

Paul.
Title: Re: General Purpose Smooth Scrolling Module
Post by: Khris on Wed 05/12/2007 14:53:24
Quote from: subspark on Wed 05/12/2007 07:22:37I want it to scroll 91 pixels to the left.

In that case you have to set c to 91 before the loop, then decrement it inside:

function room_AfterFadeIn()
{
  Wait(80);
  int x;
  int c=91;              // set starting coord
  while (c>=0) {    // end at 0, not 1
    if (c>45) x=Scroll(91, c, 46, eEaseOut);
    else       x=Scroll(45, c, 0, eEaseIn);
    SetViewport(x, 0);
    Wait(1);
    c--;          // decrement c
  }
  Wait(100);
  ReleaseViewport();

  FadeObjectIn_NoBlock(oLocationTime,0, -15); // Paracosmo City 2083
  cNarrator.ChangeRoom(3, 120, 0);
}
Title: Re: General Purpose Smooth Scrolling Module
Post by: subspark on Wed 05/12/2007 22:19:26
Ahh darn it. I was going to try that but got sidetracked and tried something else.
Thanks a bunch, Khris.

Paul.
Title: Re: General Purpose Smooth Scrolling Module
Post by: Ali on Fri 07/12/2007 21:16:30
I have just uploaded a module version of the code you linked to on the first post. I don't know how it compares to the code posted by KrisMUC, but it should work without any code in room scripts:

http://www.adventuregamestudio.co.uk/yabb/index.php?topic=33142.0 (http://www.adventuregamestudio.co.uk/yabb/index.php?topic=33142.0)

Title: Re: General Purpose Smooth Scrolling Module
Post by: subspark on Sat 08/12/2007 03:34:05
Fantastic Ali. Congrats.
This will come in handy. I think the addition of smooth scrolling paralax is a necessary one. I'll be more than happy to help you with the paralax layers in your module thread.

Cheers,
Paul.