Is RunService.Heartbeat more efficient than while wait() do?

No that wouldn’t work, since your event will fire once per change. The point isn’t to use a new variable for the speed tween - you would do something like this:

local BodyVelocity = script.Parent.BodyVelocity
local speed_Tween
VehicleSeat.Changed:Connect(function()
    if VehicleSeat.Throttle == 1 then
        speed_Tween = TweeService:Create(BodyVelocity.velocity, TweenInfo.new(0.05), maxspeed.Value)
        speed_Tween:Play()
        script.Parent.Left.Value = false
		script.Parent.Right.Value = false
        script.Parent.Driving.Value = true
    end
end)

I’ve just included a short snippet, but the idea is you are Tweening the bodyvelocity itself, not a variable placeholder and applying it as you would in a loop. It’s a different way to do it and probably more efficient.

Edit: Forgot to add the play() thing.

2 Likes

Wouldn’t I need to stop/play the tween?

1 Like

Yes your logic at the beginning is fine, I’m just showing you how the tween part would work for one of your states. I didn’t want to rewrite the work you already did that was correct.

1 Like

got this error message

DriveSeat.Drive:47: attempt to index global 'maxspeed' (a number value)

i believe that its because the velocity is a vector3 and the maxspeed value is not?

Yes that’s what it is. Do you have a Vector3 for it that you would use otherwise?

1 Like

idk what the max vector3 value is, since steer also affects the speed of it via speed on another axis.

even just doing value1 still yields the issue that i can’t index maxspeed.Value

This is what I think would be the setup. Try it out and see if it works. I’ve taken your maxspeed and applied it to the CFrame that you are using for the direction.

-- Edit 3: Ignore the other edits, final version (I hope)
local TweenService = game:GetService("TweenService")
local speed_Tween
local BodyVelocity = script.Parent.BodyVelocity
VehicleSeat.Changed:Connect(function()
	if speed_Tween ~= nil then
		speed_Tween:Stop()
		speed_Tween = nil
	end	
	if VehicleSeat.Throttle == 1 then
		speed_Tween = TweenService:Create(BodyVelocity, TweenInfo.new(0.05), {Velocity = maxspeed.Value * script.Parent.CFrame.lookVector})
		speed_Tween:Play()
		script.Parent.Driving.Value = true
		script.Parent.Left.Value = false
		script.Parent.Right.Value = false
	elseif VehicleSeat.Throttle == 0 then
        speed_Tween = TweenService:Create(BodyVelocity, TweenInfo.new(0.05), {Velocity = Vector3.new(0,0,0)})		
        speed_Tween:Play()
		script.Parent.Driving.Value = false
		script.Parent.Left.Value = false
		script.Parent.Right.Value = false
	elseif VehicleSeat.Throttle == -1 then
        speed_Tween = TweenService:Create(BodyVelocity, TweenInfo.new(0.05), {Velocity = -maxspeed.Value * script.Parent.CFrame.lookVector})		
        speed_Tween:Play()
		script.Parent.Driving.Value = false
		script.Parent.Left.Value = false
		script.Parent.Right.Value = false
	end
end)
1 Like

now it just says Unable to cast value to Object

Edit:

I think I realized why it isn’t working. Sorry for messing this up. It should look like this when you apply a velocity Tween:

local Part = script.Parent
.
.
.
        speed_Tween = TweenService:Create(Part, TweenInfo.new(0.05), {Velocity = Vector3.new(0,0,0)})
.
.
.

Apparently you reference the object, and in the last argument you would reference the property you are tweening. This would also apply for BodyVelocity. Example:

local BodyVel = script.Parent.BodyVelocity
.
.
.
        speed_Tween = TweenService:Create(BodyVel, TweenInfo.new(0.05), {Velocity = Vector3.new(0,0,0)})
.
.
.

Again, so sorry for mixing this up. Now I feel like an idiot for running around in circles and taking you with me D:

1 Like

If you think about this based on player reaction time, you want the boat to be responsive. I somewhat disagree that looping like this is wasteful, simply because it’s important that you do not add too much delay. Anything above 0.1 seconds for controls is cutting it close because a lot of people have reaction times less than that, and generally I’ve found that looping about 50%-75% of a player’s reaction time yields better feeling controls, so I’d disagree that wait() is wasteful in this situation.

wait() is not necessarily more or less expensive than heartbeat, after all both are simply activating the execution of code, and wait does so through yielding, while Heartbeat, being an event, creates a new thread (this could be seen as more expensive, however you can connect thousands of events and never run into issues since this isn’t particularly very expensive).

I would actually very much so suggest using Heartbeat none the less. Heartbeat runs immediately before every physics step, while waiting will mean you are completely out of sync with heartbeat. An example of how sync issues can cause problems comes up with monitors. If your computer is sending visual data to the monitor when the monitor is not ready to display, you can introduce slight tearing or the appearance of low FPS which may not even be noticeable, and similarly you can introduce unexpected results in controls, which while subtle, I’ve found to effect my experience somewhat.

Here are some important things about Heartbeat and Stepped: Heartbeat runs before physics, so making position or physics changes on Heartbeat will yield expected results. Stepped runs after physics, but before anything is replicated to clients. This has very strange implications on what clients will see when changing physics on Stepped, for example, the position of a part can appear completely different than where it is when physics are taking place causing the appearance of extreme lag when none is present, but Stepped is particularly useful if you’re looking to do that in the first place, as well as being a useful marker to know when physics calculations end.

Finally, if you do in fact want to slow down input, you can actually combine both a wait call and sync with physics:

-- Controller loop
wait(0.1) -- Slow down!
RunService.Heartbeat:Wait() -- This will wait at most one frame longer, however, now you're fully synced with physics so when things get replicated after Stepped fires shortly after things can appear much more accurate to players
-- Some physics stuff

Also side note: TweenService now uses Heartbeat anyway, so using Tweens and Changed events with a tweened object is effectively the same as using Heartbeat with the extra overhead of replication and property changes in general. Rather than Tweening an object, you can use TweenService:GetValue() instead on a Heartbeat loop or connection as a nice optimization that additionally yields less overall clutter.

5 Likes

How would a sample code similar to the original look with this then?

No worries, you have been extremely helpful, and taught me something I had no idea about until now!

1 Like

Well, you can do it either two ways, through an event connection or just a while loop with Heartbeat:Wait(). GetValue accepts all of the info that a normal Tween makes, other than the actual value types to tween. CFrames and vectors both offer Lerp functions you can use for this.

local elapsedTime = 0
local tweenTime = 1 -- Example time
-- On Heartbeat:
elapsedTime = elapsedTime + heartbeatStep
local newAlpha = TweenService:GetValue(elapsedTime/tweenTime, Enum.EasingStyle.Circular, Enum.EasingDirection.Out) -- Example values, all must be specified
local newCFrame = cframe1:Lerp(cframe2, newAlpha) -- Essentially what is done internally by TweenService

if elapsedTime >= tweenTime then
    break -- Or disconnect
end
2 Likes

Would using the original code I posted suffice as well?

I think it looks pretty decent to me. It could use a little work in some areas, however I really only see a few minor things here and there that aren’t really going to hurt you too much.

1 Like

(and @tralalah)

Could you guys help me here? Having issues wth Tweening in my Boat script

Use non-expensive events when possible, so both methods are BAD.
Try to have an event that fires only when needed.

What is your solution, preferably using one of the many :Tween() posts above?

Possibly, or could use connected events for steer and throttle.

1 Like

Does anyone know how to check if the speed changed, like an event that does this?, Otherwise ima have to use heartbeat im guessing because im adjusting the steering angle of a car based off of vehicle seat velocity