How do I zoom in/out?(scroll to)

Get help using Construct 2

Post » Sun Feb 15, 2015 6:07 am

Hello everyone, I need help making this feature for my game. I want the camera to scroll to the player and smoothly zoom out when the player is in the center of the layout. When the player is near the edges I want the camera to smoothly zoom in.

Here is an example:
https://www.dropbox.com/s/7w1bj114lua62o8/zoom.png?dl=0


Can anyone help me make this mechanic?

Thanks in advance
B
9
S
2
G
1
Posts: 98
Reputation: 1,933

Post » Sun Feb 15, 2015 11:08 am

Hey ThunderLion, :)

One way you might do this is by changing the zoom level based on the player's distance from the center of the layout.
You can get the distance between points with C2's built-in distance() function.

e.g. Below is the distance from the center of the layout to the player:
distance( layoutWidth / 2 , layoutHeight / 2 , Player.X , Player.Y )
let's call this "playerDistance".

Below is the distance from the center of the layout to a corner of the layout, (the max possible distance from the center):
distance( 0 , 0 , layoutWidth / 2 , layoutHeight / 2 )
let's call this "maxDistance".

If the layout is 1000 x 1000 pixels, then the farthest you can get from the middle is 500 px at the middle of a layout edge, and about 700 px in the layout corner.
(The 700 in this case comes from distance( 0 , 0 , 1000 , 1000 ) ~= 707 ~= 700.)

So the maxDistance would be about 700.

Thus, your playerDistance value is going to range from 0 (when the player is in the middle) to 700 (when the player is in the corner), roughly.

So, if you divide your playerDistance by maxDistance, you get a result that ranges from 0 to 1. (i.e. 0/700 to 700/700)
Lets call this "normalizedDistance".

You can set your zoom level to 100 + ( 100 * normalizedDistance )

With the player in the center of the layout, that expression becomes:
zoom = 100 + ( 100 * 0 ) ... = 100 + ( 0 ) ... = 100

With the player in the corner of the layout, that expression becomes:
zoom = 100 + ( 100 * 1 ) ... = 100 + ( 100 ) ... = 200

This means your zoom level will smoothly go from 100% to 200%, as the player goes from the center to the corner of the level.

So the final formula would be:
zoom = 100 + ( 100 * ( distance( layoutWidth / 2 , layoutHeight / 2 , Player.X , Player.Y ) / distance( 0 , 0 , layoutWidth / 2 , layoutHeight / 2 ) ) )

Thinking of it in terms of the intermediate variables I described above, the expression evaluates as follows:
zoom = 100 + ( 100 * ( distance( layoutWidth / 2 , layoutHeight / 2 , Player.X , Player.Y ) / distance( 0 , 0 , layoutWidth / 2 , layoutHeight / 2 ) ) )
zoom = 100 + ( 100 * ( playerDistance / maxDistance ) )
zoom = 100 + ( 100 * ( normalizedDistance ) )
zoom = Some number ranging from 100 to 200 depending on the player's distance from the center of the layout.
B
24
S
15
G
8
Posts: 314
Reputation: 5,751

Post » Sun Feb 15, 2015 10:11 pm

@fisholith Thanks, I really appreciate your help.
B
9
S
2
G
1
Posts: 98
Reputation: 1,933

Post » Mon Feb 16, 2015 12:51 pm

No problem. :)
B
24
S
15
G
8
Posts: 314
Reputation: 5,751

Post » Mon Feb 16, 2015 2:26 pm

From the top of my head, If you have a square layout, you could perhaps use the scaling.


Every Tick
set layoutscale = lerp(layoutscale, 1 - (distance(layoutwidth/2,layoutheight/2,player.x,player.y) / layoutwidth), 1*dt)

This can be applied to layers too.

Near the same as fisholith said, but with lerping (smoothing) and easily applied :)
Who dares wins
B
50
S
10
G
10
Posts: 1,728
Reputation: 12,875

Post » Tue Feb 17, 2015 6:10 am

Good suggestion @Lennaert, :)

I don't know if you're familiar with lerp() @ThunderLion, but Lennaert is using it in his formula above to smooth out changes in the layoutScale over time.
"lerp()" is a super handy function, which I'll try to explain a bit below. It can be found in the System's expressions in the math section, or you can just type "lerp()" in an expression.



lerp()
The lerp() function helps you pick numbers between a starting value and an ending value.
So lerp() answers the following kind of question...

Suppose you're on a road, starting at the 300 mile marker, and you're travelling to the 400 mile marker.
Once you've travelled 50% of the way to your destination, what mile marker are you standing next to?
Well, 50% of the way from 300 to 400, you'd be right in between them at 350.

lerp( start , end , percentage )
(The percentage in this case is expressed as 0 to 1, instead of 0% to 100%)

lerp( 300 , 400 , 0.50 ) returns 350.



Here are some examples:

e.g. Some different percentages.
lerp( 300 , 400 , 0.75 ) = 375
lerp( 300 , 400 , 1.00 ) = 400
lerp( 300 , 400 , 0.00 ) = 300

e.g. Starting with a big number and ending at a small one.
lerp( 400 , 300 , 0.75 ) = 325

e.g. Some different values.
lerp( 3 , 4 , 0.50 ) = 3.5
lerp( -10 , 10 , 0.50 ) = 0
lerp( -10 , 10 , 0.25 ) = -5
lerp( -10 , 10 , 0.75 ) = 5

e.g. Percentages outside the 0to 1 range.
Using a percentage larger than 1.0, (i.e. larger than 100%), returns a number as if you overshot your destination and just kept travelling at the same speed.
lerp( 300 , 400 , 1.50 ) = 450
lerp( 300 , 400 , 2.00 ) = 500
lerp( 300 , 400 , -0.50 ) = 250
lerp( 300 , 400 , -0.75 ) = 225
lerp( 300 , 400 , -1.00 ) = 200



Using lerp() to smooth out a value over time
In lennaert's example, he's using the lerp() function to make the layoutScale value change over time smoothly, from the value it currently is, to the value it currently should be.

Suppose that layoutScale is currently 1, but you've moved to the corner, so it currently should be 2.
If we want layoutScale to smoothly move from it's current value to a target value, instead of just setting it directly to the target value (not smooth), we can move it part way to the target value every tick.

Let's move layoutScale's current value half way to the target value each tick.
(A little fast, but it makes the example numbers easier to follow.)

So we should expect to see the following, if we start at "1" and head for a target of "2".

Tick 0: layoutScale = 1.00
Tick 1: layoutScale = 1.50
Tick 2: layoutScale = 1.75
Tick 3: layoutScale = 1.875
etc...

We get closer and closer to 2 every tick.
How can we use lerp() to do this?

Every tick: Set layoutScale to lerp( layoutScale , 2 , 0.5 ).

The first tick layoutScale will get set from 1 to 1.5.
On the second tick layoutScale will get set from 1.5 to 1.75.
etc...

The only problem with the above lerp() is that we don't want the target to always be "2", so we can replace it with the formula that tells us what the zoom should currently be based on player position in the layout.

Every tick: Set layoutScale to lerp( layoutScale , layoutScaleTargetValue , 0.5 ).

If you want the approach speed to be slower you can use a smaller percentage.
Every tick: Set layoutScale to lerp( layoutScale , layoutScaleTargetValue , 0.1).



Frame (tick) rate independence
So far so good, but notice that the speed we approach the target value is partly dependant on the number of ticks.
With an approach rate of 50%, after 2 ticks we're 75% of the way to the destination. The problem is, it doesn't matter if we are playing the game at 30 ticks (frames) per second or 120 ticks per second, it always takes 2ticks.

Imagine we use a small approach rate percentage, so that the value transition takes 60 ticks to get all the way (99.9%) to the destination, If the game runs at 60 ticks per second, the transition will take 1 second, but if the game runs at 30 ticks per second, the transition will take 2 seconds, because the transition still takes 60 ticks, and now the ticks are occurring half as often.

What we need is a way to double the lerp()'s approach percentage, when the time between ticks doubles, (e.g. when the game slows down due to CPU load).
We need to make the approach percentage proportional to the time between ticks.

Fortunately, Construct gives us a variable "dt" (delta time) which gives us the time between the current tick and the last tick, in seconds, which is exactly what we need.

So we just multiply the approach percentage by dt, to get the tick rate proportionality we're looking for.

Every tick: Set layoutScale to lerp( layoutScale , layoutScaleTargetValue , 0.5 * dt ).

Remember though that "dt" is tick time in seconds, so at 60 ticks per second dt will usually be about 1/60 ~= 0.0167, which is a smallish number. So you may need to compensate by adjusting the constant part of your original approach percentage, (i.e. the "0.5" in our case).
B
24
S
15
G
8
Posts: 314
Reputation: 5,751


Return to How do I....?

Who is online

Users browsing this forum: Desatento and 1 guest