I felt that one of Syberia's best technical features was the smooth scrolling movement, the way it sped up and slowed down when following the player character.
The game I'm working on is 640x480 and I feel that implementing this sort of scrolling would make camera movement look nicer in my game.
I feel it's bad etiquette not to make an attempt to code this myself before asking for help, but I'm really not sure how I would go about it. Any thoughts on how I might approach this idea?
Something like this maybe.
You can change the 0.1's to adjust the speed it follows the player.
You'll also probably need to write a initialization function for when a player enter a room.
Top of Global script
bool AutoScroll=true;
float AutoScrollX;
float AutoScrollY;
in function repeatedly_execute_always() , you might have to add this function to the global script as it's not there by default.
Ã, if (AutoScroll)
Ã, {
Ã, Ã, float X;
Ã, Ã, float Y;
Ã, Ã, X=IntToFloat(player.x)-160.0;
Ã, Ã, Y=IntToFloat(player.y)-120.0;
Ã, Ã, AutoScrollX=AutoScrollX+(X-AutoScrollX)*0.1;
Ã, Ã, AutoScrollY=AutoScrollY+(Y-AutoScrollY)*0.1;
Ã, Ã,Â
Ã, Ã, SetViewport(FloatToInt(AutoScrollX,eRoundNearest), FloatToInt(AutoScrollY,eRoundNearest));
Ã, }
Ã,Â
Here's some pseudocode.
Pseudocode because I just typed it off the top of my head and it has a couple of variables that you'll have to set up/apply yourself (characterX, screenCentre).
The idea is that you accelerate the screen scroll up to a maximum speed that decreases when close to the character.
float scrollSpeed = 0.0;
float screenCentre = 160.0;
// rep_ex
float targetScrollSpeed = 5.0; // pixels per second
float slowDownRange = 30.0; // pixels
float scrollOffset = IntToFloat(characterX) - screenCentre;
if (Abs(scrollOffset) < slowDownRange)
{
targetScrollSpeed = (scrollOffset/slowDownRange)*targetScrollSpeed;
}
else
if (scrollOffset < 0.0)
{
targetScrollSpeed = -1.0*targetScrollSpeed;
}
float timeStep = 1.0f/IntToFloat(GetGameSpeed());
scrollSpeed += timeStep*(targetScrollSpeed - scrollSpeed);
screenCentre += FloatToInt(timeStep*scrollSpeed);
// update the viewport here
Thanks guys, this is more than I expected!
I think I understand most of your code Steve, and my screens only scroll horizontally so It seems most useful. My maths isn't great though, so I could do with clarification on a couple of points:
Am I right in thinking I should set screenCentre to half the width of the room? Or should that be the current X position of the viewport?
float scrollSpeed = 0.0;
float screenCentre = 160.0;
// rep_ex
float targetScrollSpeed = 5.0; // pixels per second
float slowDownRange = 30.0; // pixels
float scrollOffset = IntToFloat(characterX) - screenCentre;
if (Abs(scrollOffset) < slowDownRange)
{
Ã, Ã, targetScrollSpeed = (scrollOffset/slowDownRange)*targetScrollSpeed;
}
I think this segment decreases the targetScrollSpeed as scrollOffset enters the slowDown range of 30 pixels near to the player.
else
if (scrollOffset < 0.0)
{
Ã, Ã, targetScrollSpeed = -1.0*targetScrollSpeed;
}
This passage will invert the targetScrollSpeed if the player is to the left of the screen center, I reckon.
float timeStep = 1.0f/IntToFloat(GetGameSpeed());
scrollSpeed += timeStep*(targetScrollSpeed - scrollSpeed);
screenCentre += FloatToInt(timeStep*scrollSpeed);
// update the viewport here
It's this crucial-looking bit I have trouble following I'm afraid. I guess I should use SetViewport, but which variable should I use to set the X position of the viewport?
Thanks again for your help guys!
Yup, screenCentre is the x position of the centre of the viewport.
Ah, that explains why I was having trouble. I was setting screenCentre to the middle of my room. Aside from that I had trouble with this line:
screenCentre += FloatToInt(timeStep*scrollSpeed);
// update the viewport here
screenCentre is a floating point, so AGS won't give it an integer value. Sould I use something like this?
SetViewport (FloatToInt(screenCentre), 0);
Also, the editor didn't like the 'Abs' or '1.0f', but I couldn't tell if they were typos.
Sorry for asking so many questions, but my home computer is without internet so I can't try any of this out until later.
Thanks again!
-Al.
Sounds good.
SetViewport(FloatToInt(screenCentre) - screenWidth/2, 0);
Use 1.0 instead of 1.0f (that's a C-ism).
And I see that AGS doesn't have an abs function. Dang.
Use
if (scrollOffset > -slowDownRange && scrollOffset < slowDownRange)
instead.
It works! It'll take a bit of tweaking to get the speed right but it works. Thanks so much Steve. In case anyone else ever wants to do this the code I used was like this:
// in the universal script header:
float scrollSpeed = 0.0;
float screenCentre = 160.0;
// in repeatedly_execute
float targetScrollSpeed = 5.0; // pixels per second
float slowDownRange = 30.0; // pixels
float scrollOffset = IntToFloat(characterX) - screenCentre;
if (scrollOffset > -slowDownRange && scrollOffset < slowDownRange)
{
targetScrollSpeed = (scrollOffset/slowDownRange)*targetScrollSpeed;
}
else
if (scrollOffset < 0.0)
{
targetScrollSpeed = -1.0*targetScrollSpeed;
}
float timeStep = 1.0/IntToFloat(GetGameSpeed());
scrollSpeed += timeStep*(targetScrollSpeed - scrollSpeed);
screenCentre += (timeStep*scrollSpeed);
SetViewport(FloatToInt(screenCentre) - screenWidth/2, 0);