So I would put all the cars together inside a Folder or something, place the script you provided inside ServerScriptService or the Folder and do it like that?
Also, where you are setting up a function that makes sense but removing a function; how does that work?:
local function onInstanceRemoved(car : Model)
-- Validate car
-- Clean up stored connections
end
Finally, you have shown me what the separate script would look like but how would I connect that to each script inside each vehicle model? Would I still keep .Heartbeat or how would that work?
You can put the script inside ServerScriptService, but the car models can be in different folders since they are obtained through tags and CollectionService.
onInstanceRemoved() fires when a tag is removed from an instance. This is often used for cleaning up resources to prevent memory leaks.
The code sample for GetInstanceRemovedSignal shows an example of cleaning up connections when a tag is removed.
I’ll provide an example for what you can do:
First, define vehicleCooldown(car) and respawnCar(car) such that they respawn the car specified in the parameter.
Next, in onInstanceAdded(car), create and store the connections to vehicleCooldown(car), like how the the code sample in GetInstanceAddedSignal did with .Touched.
The connections can be:
Do you think using a ModuleScript, where you’d require the ModuleScript from each script inside each vehicle model, would be a more effective approach than compared with using CollectionService, since this sounds more complicated, even though it seems like it might achieve pretty much the same result, which is to reduce the duplication of code in each vehicle model separately?
I think it’s more effective to use a single script to set up the vehicles. CollectionService is a way of retrieving all vehicle in the DataModel in a single script.
The functionality of the ModuleScript in my post was for extra configuration of the vehicle (ex: different cooldown seconds), not for storing general functions like respawnCar().
I meant just using a ModuleScript in general and having it being required in each vehicle model, rather than using CollectionService, entirely. Would there be any advantage of doing this or is there a more rewarding advantage of going down the CollectionService route, even though it could potentially become more complicated whilst achieving similar results, or not?:
I would avoid placing scripts containing functions in each models because it would be harder to manage than if we used CollectionService.
(see the post on CollectionService, section 2. Using CollectionService)
I’ve developed with JToH Tower Creation Kit, which currently uses a ModuleScript for each type of scripted obby mechanism.
When updating the kit, it is quite difficult to convert all of these mechanisms into the newest version. Through CollectionService, you will only need to update a single script to convert the mechanisms.
Yeah I meant the entire script placed in each vehicle model; sorry, I did not make it clear enough. The code I provided in this topic only includes the function connected to the .Heartbeat, but I was thinking of placing the entire script inside a ModuleScript, (including the .Heartbeat connected to the vehicleCooldown() function), and just requiring it in every vehicle model that needs it, instead of doing them separately which could cause greater performance issues, because I would be independently using .Heartbeat in each vehicle script, or is that not how this would work?:
The performance of using .Heartbeat for separate vehicle scripts won’t differ much from using .Heartbeat for each vehicle in a single script.
I only suggested CollectionService because it avoids the use of identical scripts that could be hard to manage in the future.
You could read more about the advantages of using CollectionService in the links attached to the previous posts.
That is what would happen also, if you required the ModuleScript containing the same code, and required it in every script that’s inside every vehicle model and not using CollectionService entirely or; since this seems to be more complex when you could just do it that way, unless there is an advantage of using CollectionService instead?:
Overall, it could just be a preference, but there’s a slight advantage with using CollectionService.
Here are the two methods that we mentioned:
With Scripts in each vehicle model requiring a single ModuleScript, the DataModel will contain multiple Scripts inside Models and a single ModuleScript inside ServerStorage or ReplicatedStorage.
With CollectionService, you would put a single Script in ServerScriptService or StartPlayerScripts, and perhaps an additional ModuleScript to organize the functions.
Comparing the two methods, you’ll see that:
The first method requires more Scripts than the second method.
This creates more Instances, which could be difficult and messy to work with.
Since the Scripts in the first method are placed in Models, they will only run on the server side of the client-server model once the model is parented to Workspace. You can’t run client-sided scripts since they only run in certain containers.
The Script used in the second method can be ran from both the server and client side of the client-server model, allowing for client-sided scripting.
In the case of respawning vehicles, you won’t need to do client-sided scripting.
Overall, using CollectionService reduces the number of Script instances (which improves manageability and possibly performance), and it allows similar objects to function both on the server and the client side of the client-server model.
Also, using CollectionService wouldn’t make things more complex. You could let the examples in the documentation for CollectionService guide you through ways to use the service.
I am only accessing the server side as you know. Therefore, there is less of a reason to use CollectionService and rather to use a single ModuleScript instead? In theory if I am using a ModuleScript and requiring it in every script inside every vehicle model, I’d only be using one script of which I could edit from instead of having separate scripts?
However, I assume that there must be some advantage to using either of these because there must be some performance improvements, if your using the same code all in one place?
Yes, you would only be editing one script, but there’s just the tiny issue of having extra, identical Script instances that require the ModuleScript.
Also, with CollectionService, you could do :AddTag() or :RemoveTag() to dynamically add or remove a vehicle, which is a feature that the ModuleScript method can’t provide easily.
As mentioned in ModuleScripts: “Having multiple copies of a function is disastrous when you need to change that behavior.”
The improvement in manageability is already an advantage, even though there’s little impact in performance.
True, I still have an issue even when I do use a ModuleScript. I tested 32 cars and moved them all at once and they took a while to respawn. So in terms of performance; that hasn’t really been improved at all for in which case, I could still use CollectionService on my current implementation of requiring the ModuleScript into every vehicle model that needs it?
I still feel like using CollectionService would eventually become unnecessarily complicated though, because I don’t necessarily have to have the vehicles already spawned in, especially because I am trying to use so many vehicle models at once when I could simply leave it up to the user to have to spawn them in. I’m only using .Heartbeat for when the vehicles are already spawned in for users to drive in and when they are pushed out of place they would respawn, so maybe I should have it up to the user to spawn the vehicles in, therefore no need for the use of .Heartbeat anymore or trying ways to increase the game’s performance in light of this?
When cars are moved, there’s a cooldown before cars are respawned.
Do you mean that time, or do you mean the car takes a while to load?
You can try debug-printing when vehicles start to load to see if all vehicles start reloading at the same time.
From the respawn code posted before, I see that you created a new clone of the car model.
Wouldn’t it be better to just reposition the old car and remove the car’s AssemblyLinearVelocity?
Also, in the code, I see that you used :SetPrimaryPartCFrame. SetPrimaryPartCFrame is a deprecated function that is superseded by PivotTo, so I suggest using the latter instead.
When new vehicles are added, it would fire the GetInstanceAddedSignal event to set up the vehicle functions, so you wouldn’t need to worry about vehicles being spawned in later.
You could also remove the functions by just calling :RemoveTag on the vehicle model.
If you feel like using .Heartbeat has a significant drawback on the game’s performance, it’s okay to consider letting players spawn in the vehicles themselves.
Like the cooldown takes a while to start if they are all moved at once, resulting in all of them taking longer to respawn back into their original spawning positions. That’s without using CollectionService at this point, of course.
I think it could be a result of the elapsedTime >= 1 condition that forces vehicleCooldown() to run only once per second.
You can remove that throttle condition if you want to immediately detect movement in car positions, and instead use a debounce-like system.
Definitely not a good idea to be making new while true loops 30 times a second, so make sure your code can’t do that.
If you only need one while true loop to be running at a time, you can do something like this:
local connection
local function newConnection()
if connection then connection:Disconnect() connection = nil end
connection = heartbeat:Connect(vehicleCooldown)
end
-- Then for your while loop, do something like this:
if not inCooldown and not cancelCooldown then
connection:Disconnect() -- stops the heartbeat from calling vehicleCooldown() more
while CooldownValue > 0 and respawnInProgress do
-- Inside code
task.wait(1) -- Wait for one second
-- Inside code
end
newConnection() -- allows heartbeat to call vehicleCooldown() more
Also, you have a comment that says
--sets respawning progress to true
But you don’t set that debounce to true. If you set that debounce to true there, that’s an alternative way to stop that loop from being created a million times.
Using heartbeat for every vehicle is fine, the main thing is how expensive the function heartbeat is running is.
While loops are mainly only bad practice when you’re using a zero wait time, but they’re pretty good when you don’t need to do something really fast. Your case is a great example of somewhere a while task.wait(1) loop would be good. (Instead of doing stuff 30 times a second, it’s simplier to do it one time a second if applicable.)
If I were you, I would get a table of all the cars (through collection service, parenting them all to the same folder, etc) then in one single while task.wait(1) loop I would update all of them. I would then store the other states as attributes (cooldown canceled, etc) (or more ideally in a data structure to avoid replication, though it’s really negligible b|c they only update once a second).