- Home /
Smoothing camera edge scroll
Hello there,
I run into a problem I have been trying to resolve for days now. I have searched and tried every solution provided on the net, but none of them worked, actually, I was always stuck on the same state.
Now, here is what I am trying to do:
private void EdgeMovement(bool edgeScroll, float scrollSpeed, int screenBorder)
{
mousePosX = Input.mousePosition.x;
mousePosY = Input.mousePosition.y;
if (edgeScroll)
{
if (mousePosX < screenBorder)
{
transform.Translate(Vector3.left * scrollSpeed * Time.deltaTime);
}
if (mousePosX >= Screen.width - screenBorder)
{
transform.Translate(Vector3.right * scrollSpeed * Time.deltaTime);
}
if (mousePosY < screenBorder)
{
transform.Translate(Vector3.back * scrollSpeed * Time.deltaTime);
}
if (mousePosY >= Screen.height - screenBorder)
{
transform.Translate(Vector3.forward * scrollSpeed * Time.deltaTime);
}
}
}
I use this piece of code for edge scrolling the camera. When cursor hits the screen edge, camera moves that way, simple RTS/Classic RPG camera movement. That worked just fine. Now what I want to do is smooth this movement, add some kind of acceleration on edge hit and deceleration on release (like Wasteland 2 have, if some of you guys played it, or other similar games as well I believe).
I have been using Vector3.Lerp for smoothing other camera movements, such as mouse wheel zooming and adjusting "isometric" camera angle from top-down on max zoom-out to 45 degree on full zoom-in (again, like Wasteland 2 have). It worked perfectly. When I tried to do this analogicaly for edge scrolling, it just doesnt work no metter what method I use, I always get the same result - linear movement speed. I have already tried Vector3.Lerp, Slerp, SmoothDamp, everything I found in the net somehow connected with smoothing, nothing worked unfortunately.
Thats why I am asking here, maybe some of you guys would have some good hint on what method to use or what to change.
Thanks in advance.
EDIT:// To show more exactly what I mean by smoothing, please have a look to this short video. https://streamable.com/kmlob
Can you describe in more detail what you mean by "acceleration on edge hit and deceleration on release"? (I haven't played Wasteland 2). Also, how do you interpolate?
I think I would translate by a percentage of how much I am inside the screen border. For example:
if (mousePosX < screenBorder) {
float t = mousePosX / (float)screenBorder;
transform.Translate(Vector3.Left * $$anonymous$$athf.Lerp(0, scrollSpeed * Time.deltaTime, t));
}
// the code is similar for the other branches, just be careful when at positive edges
Alright, I will try to describe it more. $$anonymous$$y current script behaves like: You move the cursor over the edge of the screen, camera starts to move that way, classic RTS camera, I am sure you know it. Now, my problem is that when I actually move cursor over the edge, camera starts moving immediately in constant speed and when I release (a.k.a. move cursor away from edge) it, camera immediately stops. What I want is a little bit of smoothness, as it looks bad as it is. I mentioned Wasteland 2 because it has that little bit of smoothing, which means that camera starts to move with increasing speed until reaching constatnt speed, and when you release the cursor from edge, camera speed is decreasing for a while before stoping.
Tried your code suggestion, no difference though. Thanks for your time anyway.
Video from Wasteland 2 https://streamable.com/kmlob
Now I see what you mean, thanks for the explanation (the video helped a lot).
What I would do is store the current scroll speed in a variable, which you increase when at the border, and decrease when not. Then you multiply your scroll direction with this value, and move your camera that way. Something like this:
[SerializeField] private float maxScrollSpeed;
[SerializeField] private float scrollSpeedAcceleration; // how many seconds it takes to reach max scroll speed
[SerializeField] private int scrollBorderWidth; // how many pixels from the border counts as within scroll region
private float scrollSpeed = 0;
private Vector3 scrollDirection;
private void Update () {
Vector3 currentScrollDirection = Vector3.zero;
mousePosX = Input.mousePosition.x;
if (mousePosX < scrollBorderWidth) { currentScrollDirection += Vector3.left; }
if (mousePoxX > Screen.width - scrollBorderWidth) { currentScrollDirection += Vector3.right; }
mousePosY = Input.mousePosition.y;
if (mousePosY < scrollBorderWidth) { currentScrollDirection += Vector3.back; }
if (mousePoxY > Screen.height - scrollBorderWidth) { currentScrollDirection += Vector3.forward; }
// modify and limit scroll speed - this part controls the acceleration/deceleration
float scrollSpeedChange = scrollSpeedAcceleration * Time.deltaTime;
scrollSpeed += currentScrollDirection != Vector3.zero ? scrollSpeedChange : -scrollSpeedChange;
scrollSpeed = $$anonymous$$athf.Clamp(scrollSpeed, 0, maxScrollSpeed);
// if on border, update the scroll direction
if (currentScrollDirection != Vector3.zero) { scrollDirection = currentScrollDirection; }
// move by direction * speed * time
transform.Translate(scrollDirection * scrollSpeed * Time.deltaTime);
}
Answer by davidcox70 · Apr 10, 2018 at 10:36 AM
Is it that you want your translation to gradually accelerate to full speed and then gradually decelerate to a stop? If so, in your current code, the float value scrollSpeed is what defines the translation speed, so this needs to grow and shrink, rather than be a constant. So you could define a new float called "maxSpeed" and set it to be the fastest speed you want, then;
// define these variables at the beginning;
float maxSpeed =5; // the fastest speed we can go
float accelSpeed=1; // how quick is the acceleration
float decelSpeed=1; //how quickly to slow down;
//when you want to accelerate, use this in the update loop somewhere;
scrollSpeed=Mathf.Lerp(scrollSpeed,maxSpeed,Time.deltaTime*accelSpeed);
// when you want to slow to a stop
scrollSpeed=Mathf.Lerp(scrollSpeed,0,Time.deltaTime*decelSpeed);
Thank you for advice. I tried this, with no success so far, however now it makes more sense to me and your explainaton is exactly what I need to do. I cant quite decide where to put those two last lines from you as I only call above mentioned method in LateUpdate loop, so it doesnt make no sense to put it anywhere around it, it does nothing. Though now I know in what way I gotta think about all this, I will try to figure it out. Thank you so much for a hint. Any further thoughts are welcome of course :D
Ok . try this way of doing it...
// these should be at the beginning of your script somewhere
float maxSpeed =5; // the fastest speed we can go
float accelSpeed=1; // how quick is the acceleration
float decelSpeed=1; //how quickly to slow down;
private void Edge$$anonymous$$ovement(bool edgeScroll, float scrollSpeed, int screenBorder)
{
mousePosX = Input.mousePosition.x;
mousePosY = Input.mousePosition.y;
bool isScrolling=false;
Vector3 scrollDirection;
if (edgeScroll)
{
if (mousePosX < screenBorder)
{
scrollDirection=Vector3.left;
isScrolling=true;
}
if (mousePosX >= Screen.width - screenBorder)
{
scrollDirection=Vector3.right;
isScrolling=true;
}
if (mousePosY < screenBorder)
{
scrollDirection=Vector3.back;
isScrolling=true;
}
if (mousePosY >= Screen.height - screenBorder)
{
scrollDirection=Vector3.forward;
isScrolling=true;
}
if (isScrolling){
// accellerate
scrollSpeed=$$anonymous$$athf.Lerp(scrollSpeed,maxSpeed,Time.deltaTime*accelSpeed);
} else {
//Decellerate
scrollSpeed=$$anonymous$$athf.Lerp(scrollSpeed,0,Time.deltaTime*decelSpeed);
}
// move
transform.Translate(scrollDirection * scrollSpeed * Time.deltaTime);
}
}
just an after thought - I' not sure what your "edgeScroll" boolean needs to do. It might be that you need to move the If block starting with "if (isScrolling)..." to be after the end of the "if (edgeScroll) block. If not, the accelleration and decelleration calculations are not done when edgeScroll is false. Depending on when this is called, it could lead to your player travelling off for ever :-)