3 scripting questions that I've got on my mind for a long time

Solved by @TheEdgyDev and @rek_kie

So I’ve got several questions on my mind for a long time…

  1. Difference between synchronously and asynchronously in scripting?

  2. Sometimes I see some codes like this:

if (isTrue) then
   --// Do something
end

What are the brackets used for?

  1. Any tips on how to make your own wait system? (I heard using wait() is super bad)
2 Likes

People who parenthesize their expressions in conditions typically come from a background where past programming languages they’ve learned require it. Some also have grown so close to that syntax that they prefer it. In the end, it doesn’t change the semantics of the code. In fact, when writing idiomatic Lua, parenthesizing your expressions needlessly is discouraged.

Don’t make your own wait system, just use the appropriate method for yielding your code. Designing your own wait system is just one more level of headache that’s meaningless; don’t try to reinvent the wheel, just use the right wheels for the right car.

Qualifying the issues with wait, check out this wonderful post explaining various complications with wait: Avoiding wait() and why

Synchronous code means that each computation is executed, and then the next computation happens, all in a linear fashion. Asynchronous code means that multiple operations can occur without having to wait for the past operation to resolve. Of course, you can make certain asynchronous operations only happen once another one succeeds.

There’s some pretty quick answers into otherwise extensive topics; for some more detailed discussions consult a search engine near you, lol.

1 Like

So synchronously is basically like 1 script and asynchronously is like running multiple coroutines?

And the brackets inside if is just a decoration stuff but doesn’t change anything?

1 Like

In essence, yes. Coroutine support in Lua is Lua’s solution to asynchronous programming and, simplified, scripts are essentially synchronous in most applications; statements are computed in order.

  1. Synchronous scripting, which is just normal scripting, is where for each line of code, the line before it has to be completed for it to run. This is where the lines are going one by one until they reach the end. This is sometimes bad in some cases because sometimes if a line is yielding, it’d yield the entire script when you don’t want it to and need something else to run, which brings us to:
  • Asynchronous scripting: Running multiple threads using either coroutines or spawn. This is running “more than one script at the same time.” This is useful when you want multiple functions/code or whatever that would yield at some point running concurrently without interrupting each other or the entire script.
  1. I’m not completely sure, but I’m pretty sure the brackets are used to compile a bunch of conditions to get 1 true or false result. I’m probably wrong about this one though

  2. Use RunService to make a more accurate and reliable wait system using Heartbeat, which fires every frame and doesn’t block anything from rendering like RenderStepped does since it fires after physics calculations.

It’s as simple as this:

local rs = game:GetService(“RunService”)

local wait = function(t)
    t = t or 1/30
    local now = tick()
    repeat rs.Heartbeat:Wait() until tick() - now >= t
end
1 Like

I have marked your post as the solution.

Thanks!

1 Like

Thanks as well, I’ll post your and @TheEdgyDev 's pist on the topic instead since I can’t mark 2 solutions

While your definitions are correct, you mislabeled them; your definition of synchronous should be asynchronous and vice versa.

This solution falls prone to the same errors as wait when t <= 1/30.

Oh, oops lmao I’ll fix it right now. Thanks

I am also curious about this part. Can I get a deeper explanation if you don’t mind?

Alright I guess I am not doing custom waits due to the complications, but ok I get it about synchronously and asynchronously on your post

Sure thing, I’ll add the link explaining these issues to my original post as well:

I found this custom wait in one of the post’s replies. This is accurate down to a single frame, which is more than enough for what you’d usually need.

Edit: My method that I wrote earlier is exactly the same as this, a lot of people use that too…

Both are accurate down to a single frame. (1/60)

local Heartbeat = game:GetService("RunService").Heartbeat

local function wait(n)
  local elapsed = 0
  while elapsed < n do
    elapsed = elapsed+Heartbeat:Wait()
  end
  return elapsed
end

Actually, the method I wrote is about the best you can get. It is accurate down to a single frame which is (1/60), compared to the regular wait()’s 1/30 minimum. A lot of people use some form of this method (like what I wrote above), which is just using Heartbeat or Stepped

This was the main bottleneck. If you wanted it to be as quick as possible, make the default time 0 so it’s essentially an alias for RunService.Heartbeat:Wait()

Bruh. So that’s what you meant, lol.

There’s nothing wrong with the code and it still does what I said it does, but you are right. You can change that line to

t = t or rs.Heartbeat:Wait()

Usually I never use wait() at all, I usually use wait(n), but what you said is a smarter way to design it in case I ever want to wait() as fast as possible without having to specify a value less than 1/30

1 Like