How to do a Slow Time Effect for Player Feedback in Godot 3.0

Published by Jan Heaney on

How to do a Slow Time Effect for Player Feedback in Godot 3.0


Howdy! I am rk, and this is Game Endeavor. Slowing time is effective when you want to
emphasize an attack. It adds an extra layer of polish to your games,
and also serves as more feedback to the player. In this tutorial I will be showing you how
you can implement a slow time effect in your Godot games, which I will be using whenever
the player takes damage. Let’s go ahead and get started. We’re going to be adjusting the engine’s
time_scale to achieve the slow motion affect. This will adjusts the rate of the in-game
clock, which affects things such as timers, tweens, and the delta parameters of the process
methods. This means we will not be able to use a tween
node effectively, so we’re going to have to do our own easing calculations. To do this, we’re going to need to store
a few variables. Once we change the engine’s time_scale,
we’re always going to ease back to 1. So for readability I will create a constant
named END_VALUE, and set it as 1. We’ll be using the _process method for our
easing logic, but we only want it to process whenever the effect is active. So we’ll create a boolean variable called
is_active which we’ll use to check for this. I’ll go ahead and set it to false. We also need to know when we started the tweening
and how long it’s going to last for. So I’ll create two variables. One named _time_start and the other _duration_ms. We’ll be working in milliseconds, hence
the ms. And finally, we need to know what the time_scale
was when we started the easing. This will be what we set it to when the effect
starts, and will determine the strength of the effect. I will store this in a variable named _start_value. We’ll begin by creating the start method. This is what we’ll call whenever we want
to initiate the effect. It’ll need two parameters. Duration being the time that the effect will
last in seconds. And strength being a value between 0 and 1,
which will determine what we set the engine’s time_scale to before easing back to normal
speed. The main purpose of the start method is to
store some information we’ll need for the tweening and then initiate the effect. So first we’ll get the current number of
milliseconds that have passed since the game has launched by calling the method OS.get_ticks_msec
and store it in our _time_start variable. We’ll use this later to determine how long
the effect has been running. Since we’re working in milliseconds, we’ll
translate the duration variable to milliseconds by multiplying it by 1000 and then storing
it in our duration_ms variable. And then we’ll set the _start_value to 1
– strength. I do these translations for simplicity’s
sake when you’re calling these methods from outside of the script. It makes more sense to me to choose the strength
rather than choosing what to set the time_scale to. But this is a personal preference of mine. Free to do whatever is comfortable to you. And then to initiate the effect, we’ll set
Engine.time_scale to our start value immediately. This will give the effect of the game slowing
instantly, which will be what adds emphasis if you’re using this to convey impact. And then we’ll set is_active to true, so
that it knows to do our easing logic in our _process method. And that is it for our start method. Now we need to handle the processing logic. So we’ll create our _process method. And in it, we’ll use an if statement to
check if is_active is true. If it is, then we’ll get the current time
by subtracting time_start from another call to OS.get_ticks_msec and store it in a variable
named current_time. And with this we have all the information
we need to create our own easing function. I’ve included two links in the description. One to a page full of easing equations and
another to a cheat sheet that shows you how the tweens look. The latter being extremely useful in general,
I reference it all the time. Feel free to browse these and find whichever
tween you would like to use for this effect. I will be using an ease in with a circular
transition. To me, this tween goes great with this effect
because it has a long hang time. Which will provide plenty of emphasis and
allow the player a moment to think and plan. And then suddenly it snaps back to the end
value. With this decided, we’ll go ahead and create
a method to process this equation. It will need the current time, the start value,
the end value, and the duration. Which for simplicity sake we will refer to
as t, b, c, and d as it is on the equation site. And to spare you the horrors of listening
to me trying to read this equation, I’ll just leave it up for you to read on your own. With that done we will return to our _process
method and make a call to our easing function, giving it the variables that it needs, and
storing the result in a variable named value. And right quick before setting the time_scale,
we’re going to make a check to see if the current_time is greater than or equal to duration_ms. If it is, then the effect has ended, so we
will set is_active to false. We also need to make sure that the time_scale
returns to normal, so we will set value to END_VALUE. And finally, we set Engine.time_scale to value. With this done, we simply make a call to the
start method anywhere within our game. I will be connecting my player’s “damaged”
signal directly to the _start method as demonstrated here. You could also use this with a lesser strength
value whenever the player damages an enemy. This is sometimes done in shooter games to
make the player feel more powerful. Thank you for watching and I hope you enjoyed
it. If you did, then be sure to join the sub club
and let me know what you thought. I post a new video at least once a week, so
be sure to come back. There are links to my Twitter and Discord
in the description below if you’re interested. I would love to hear from you, whether it
be feedback, suggestions, or topics you would like for me to cover in the future. And until next time, y’all take it easy.


15 Comments

brianuptagrafft · September 27, 2018 at 2:39 pm

Very nice, concise and clearly spoken. Keep up the good work!

Aquaified · October 2, 2018 at 1:53 pm

Immediately subbed, all other tutorial creators should take notes from you.

Game Endeavor · October 3, 2018 at 2:07 pm

There's a teeny tiny easily fixable bug discovered after I made this tutorial. Check the description for details.

Drakibble · November 1, 2018 at 2:38 pm

Thank you so much! I can't wait to try this for my game. Amazing work, I can't wait to see more tutorials from you!

Lan SJ · February 28, 2019 at 10:20 am

Very awesome, quick and concise… I have a slight fever now but I was still able to pick up your logic with 1 watch.

Brad Yalo · April 14, 2019 at 4:01 pm

Please make more videos.

Brad Yalo · April 17, 2019 at 11:14 am

How can you emit a particle(explosion) then que.free it on

kanethornwyrd · April 21, 2019 at 2:38 am

gizma is closed :/

meme life · April 24, 2019 at 8:38 am

What if i wanted to slow evre thing except my player.
Cool video

WKS Art · April 27, 2019 at 1:01 am

can you make a tutorial on how to make an ease in ease out for button animations? like sliding down from the top of the screen and out of the screen. I cant jam any ideas on how to manipulate button animations

CHAITANYA chinu · June 16, 2019 at 8:35 pm

I m getting an error…it says invalid operand int & nil in operator '/'. * done I found the error

Its The Alpha · June 17, 2019 at 8:31 am

Nice tutorial! Does this effect change the number of physics process done a second? is it still 60 or will it change with the time scale?

Peter W Hansen · August 28, 2019 at 9:35 am

is there a way to speed up time

Ric · October 7, 2019 at 3:16 pm

Oh man, you have the BEST tutorials!! I was wondering how to do a slow motion effect and this was (as usual) SO USEFUL!

unfor5unately itsumeea · October 15, 2019 at 5:02 pm

or you could just do this is you're really lazy .

if (condition):
Engine.time_scale = 0.1
else:
Engine.time_scale = 1

Leave a Reply

Your email address will not be published. Required fields are marked *