Making floating parts that goes up and down

local CS = game:GetService("CollectionService")


while true do
	task.wait()

	for i, v in CS:GetTagged("Apple") do
		task.spawn(function()
			while true do
				task.wait()
				
				for i = 1, 10, 1 do
					v.PrimaryPart.Position += Vector3.new(0, 0.1, 0)
					task.wait(0.1)
				end

				for i = 1, 10, 1 do
					v.PrimaryPart.Position += Vector3.new(0, -0.1, 0)
					task.wait(0.1)
				end
				
			end
			
		end)
		
	end
	
end

So, I want to make a part that goes up and down. I don’t want to use TweenService, because the parts will get moved occasionally, I tried using TweenService and it gave me an unexpected result.

So, this is currently how it is. It just keep moving upwards.


2 Likes

You can use sine waves to make an object go up and Down smoothly and reliably.

1 Like

How exactly can I do that? (charlimit)

1 Like
for i = 1, 180, 1 do
	--StartPosition is a vector. Distance is a number. i 
	v.PrimaryPart.Position += StartPosition + Vector3.new(0, math.sin(i) * Distance, 0)
	task.wait(0.01)
end
3 Likes

What is the Distance variable for? And why do you multiply it with math.sin(i)?

and what will math.sin(i) return? Why would we wanna use it?

And I assume that the loop won’t run forever.

Math.Sin() is a Trigonometric function. It just makes it so that when the value is 0 then it returns 1, when it is 90 then returns 0, when it is 180 then returns -1, when it is 270 then returns 0 but does this smoothly.
The distance variable is a variable that you need to define which will basically make the object move higher or lower.
So if you want the loop to be endless you need to do something like this:

while true do
	for i = 1, 360, 1 do
		--StartPosition is a vector. Distance is a number.
		v.PrimaryPart.Position += StartPosition + Vector3.new(0, math.sin(i) * Distance, 0)
		task.wait(0.01)
	end
end

Also i am not sure about it but i think that math.sin() should take a value in radian rather than degree so you should use: math.sin(math.rad(i)) * Distance. So the code would look like this:

while true do
	for i = 1, 360, 1 do
		--StartPosition is a vector. Distance is a number.
		v.PrimaryPart.Position += StartPosition + Vector3.new(0, math.sin(math.rad(i)) * Distance, 0)
		task.wait(0.01)
	end
end
2 Likes

Ok, but what is the for loop for? Oh wait, isn’t it for the angles (0, 90, 180, 270). Like sine returns the values based on those special angles.

It is only used to have the i variable change every frame but in case you don’t want that, you can do something like this:

while true do
	--StartPosition is a vector. Distance is a number. Speed is how fast the object moves
	v.PrimaryPart.Position += StartPosition + Vector3.new(0, math.sin(workspace.DistributedGameTime * Speed) * Distance, 0)
	task.wait(0.01)
end

It uses workspace.DistributedGameTime instead of i variable. It also had a Speed variable which you should set to a low number or it will go super fast.

Also, the player might be using a Fps unlocker but the code will run at 60 Fps so it will look janky to the player. We can counter this using the RenderStepped event on RunService.
It would look something like this:

game:GetService("RunService").RenderStepped:Connect(function()
	--StartPosition is a vector. Distance is a number. Speed is how fast the object moves
	v.PrimaryPart.Position += StartPosition + Vector3.new(0, math.sin(workspace.DistributedGameTime * Speed) * Distance, 0)
	task.wait(0.01)
end)
1 Like

Isn’t sin(0) = 0? and what about sin(360)?

How would this work inside the code as a replacement?

Oh i think i have mistaken it with cos() which is same as sin() but rotated by 90

So, this value represents the time the player is in the game. So we can use it instead of using i variable as even if the value is bigger than 360 it will still work.
Also the tick() function can be used instead of workspace.DistributedGameTime as it counts the time but instead from counting it from the game start, it counts it from a other time

1 Like

I don’t get it how tick() can be used instead of using i like this. Like doing math.sin(tick()) won’t give you values from like math.sin(0), math.sin(90), math.sin(180) as when using i right?

game:GetService("RunService").RenderStepped:Connect(function()
	--StartPosition is a vector. Distance is a number. Speed is how fast the object moves
	v.PrimaryPart.Position += StartPosition + Vector3.new(0, math.sin(tick() * Speed) * Distance, 0)
	task.wait(0.01)
end)

And is the smoothness of sine waves guaranteed?

And what are the usages of cosines and even tangents.

The smoothness is guaranteed.
So the Sin() when it gets a value larger than 360 for example 450 then it will return the value the same as it would return for 90 and if it would be 500 then it would return the same value as it would return for 140.

1 Like

So, the tick() in here is always going to reset and set to a new value. I don’t really know how it’s gonna go. But, the value returned by tick() is a very big number. Like 17293483293.32323 since the Epoch.

But, let’s say I want to make the movement slower, I increased the wait time and it is pretty janky.

Oh wait. Actually there shouldn’t be the task.wait(0.01) in the RenderStepped event. I forgot to delete that. You need to change the Speed variable to make it faster or slower.
If you will need to change the speed during the game then there is another way of doing it.

Not the wait time? Because I believe that will change how far up or down it will go. (characterlimit)

while true do
	for i = 1, 360, 1 do
		--StartPosition is a vector. Distance is a number.
		script.Parent.Position += Vector3.new(0, math.sin(i) * 0.4, 0)
		task.wait(0.15)
	end
	
	for i = 1, 360, 1 do
		--StartPosition is a vector. Distance is a number.
		script.Parent.Position += Vector3.new(0, math.sin(i) * -0.4, 0)
		task.wait(0.15)
	end
	
	
end
1 Like

You don’t need the second loop because in the first one the sin will also return a negative value.

1 Like