So I was creating a new shop UI, and I was wanting to do use magnitude to pop up the UI whenever the character approached the shop.
HOWEVER
I don’t know if a loop would be efficient or not to continuously check if the player is within the radius. Is there another way around this? I.E a function of some sort?
I’m asking because I want to include the shop script in my main script handler instead of having a separate script.
I’m not 100% sure if this is a better way of doing things, but if you wanted to avoid a loop you could always make a part with a .Touched event. (Look at xZylter’s reply)
I’m not sure which one has better performance but you could use Region3 over magnitude since I guess the benefit is your not checking for every player if they are near the shop but instead running the script for the players found in the Region3.
Well I think having a touch event woumld be needed to make the Region3 loop activate. Since with Region3 you still need to put it in a loop. Just comparing it to .magnitude I think Region3 would create less memory use.
I never confirmed this to be fully true but .magnitude would check for every player in the game which seems inefficient for the purpose of making a shop.
In my opinion I would divide the world into sectors/cities/areas whatever you have in your game. Then iterate through all players every certain period of time for example 5 seconds and assign all players to the areas they are in. Next for example if the shop is in area1 I would be able to iterate over all the players in that area instead of all the players in the game. That loop would be faster, for example 5 times a second and it would use magnitude to determine whether a player is in a shop or not.
This means 5*n operations per second where n is the amount of players in a certain area. This is really nothing in comparison to how much Roblox engine can handle.
Dividing the map into sectors can be used in other parts of the game too.
One more thing. I would handle all the shops in one script.
for area in areas:
for shop in area:
for players in area:
evaluate distance and open shop if player is close enough
But the area system is really an advantage only if you have a big amount of shops and a big map.
Not going to say “you should’ve looked first” because it’s under a technical title, but here, is exactly what you want.
Touch is very reliable. You use touch on a cylinder, but unlike what I’m linking, you instead run a while loop (no need for Runservice:Heartbeat or anything this need not be every frame), that checks magnitude using the distance equation you’d use in school, 2d cartesian magnitude using the X and Z positions (vertical cylinder…ization)
Another solution is to loop through all shops locally on the client, and then if a player is close enough send that information to the server using a RemoteEvent, then the server would make a check to make sure that the player is indeed in the shop (to avoid exploits). This would reduce the amount of operations performed on the server.
Instead of m*n operations where m is the amount of the shops and n is the amount of players you would do checks on the server and the clients would do m operations.
There will only be 1 shop per place, and heres what I was attempting ( but it doesnt work)
local player = game.Players.LocalPlayer
local Char = player.Character
local Humanoid = player.Character
local ShopRegion = game.Workspace.ShopRegion
while wait() do
game.Players:WaitForChild(player.Name).CharacterAdded:wait()
if (Char.HumanoidRootPart.Position - ShopRegion.Position).Magnidtude <= ShopRegion.Size.X/2 then
print("Yeep")
end
end
(ShopRegion being a sphere)
I’m slightly confused on your concept though.
I would do what @TokoNanami if you had a like “Press E to Shop” popup then fireserver after pressing E, else it would just keep Firing the server non stop otherwise.
(Just an idea) Could use a .Touched event that starts a loop and keeps checking if the player is in the radius then if player isnt in radius, break the loop so it therea not a constant loop for all players.
This is not working becuase the script yields until the CharacterAdded event is fired, that’s how wait event method works.
You should be doing
local player = game.Players.LocalPlayer
local ShopRegion = game.Workspace.ShopRegion
local RunService = game:GetService("RunService")
RunService.Stepped:Connect(function()
local Char = player.Character
if Char then
if (Char.HumanoidRootPart.Position - ShopRegion.Position).magnitude <= ShopRegion.Size.X/2 then
print("Yeep")
end
end
end)
I replaced the while wait() do loop with the RunService.Stepped event connection to make it faster and more reliable. Also not Magnidtude but magnitude. What is more, you already have the player in a variable, there’s no need to invoke WaitForChild every iteration.
Wow, I’ve never even heard of RunService.Stepped before lol thanks!
I was wondering why I kept getting errors!
@Deathful huh I never thought about that, so basically what your saying is have a touch function that when touched, the script checks if the player is in the radius and as soon as the player leaves, the checks stop?
Basically yes. Using that would need some kind of special debounce or a boolvalue to make the touched event stop firing after touched and then make it touchable again after leaving the touchable part.
Which also brings to using Touched and TouchEnded >>
This would work but I heard stories of it not being reliable since TouchEnded can fire without leaving the part being touched sometimes. Probably would be fine for a shop though.
Also, for region3, you can use different shapes besides a box if you use EgoMoose’s Rotated Region3 Module.
I think you can check whenever the player is moving using MoveDirection
And check if :DistanceFromCharacter() is less than studs then you would open the shop, elseif it is greater than that studs then you close the shop.