Making floating parts that goes up and down

local collectionService = game:GetService("CollectionService")
local runService = game:GetService("RunService")

local height = 2
local speed = 1

local storedYValues = {}

local function trig(x,height,speed,f)
	return height*f(speed*x)
end

runService.RenderStepped:Connect(function(dt)
	local sin = trig(tick(),height,speed,math.sin)
	local cos = trig(tick(),height,speed,math.cos)
	
	local apples = collectionService:GetTagged("Apple")
	
	for i,v in apples do
		if not v then continue end
		local Position,Orientation = v.Position,v.Orientation
		local ogY = storedYValues[v] or Position.Y; storedYValues[v] = ogY
		
		v.Position = Vector3.new(Position.X,ogY+sin,Position.Z)
		v.Orientation = Vector3.new(Orientation.X,Orientation.Y+math.abs(cos),Orientation.Z)
	end
end)

try this it should fix that error, also the script activity is high because its a loop that constantly changes the position

local collectionService = game:GetService("CollectionService")
local runService = game:GetService("RunService")

local height = 2
local speed = 1

local storedYValues = {}

local function trig(x,height,speed,f)
	return height*f(speed*x)
end

runService.RenderStepped:Connect(function(dt)
	local sin = trig(tick(),height,speed,math.sin)
	local cos = trig(tick(),height,speed,math.cos)

	local apples = collectionService:GetTagged("Apple")

	for i,v in apples do
		if not v then continue end
		local Position, Orientation = v.PrimaryPart.Position, v.PrimaryPart.Orientation
		local ogY = storedYValues[v] or Position.Y; storedYValues[v] = ogY

		Position = Vector3.new(Position.X,ogY+sin,Position.Z)
		Orientation = Vector3.new(Orientation.X,Orientation.Y+math.abs(cos),Orientation.Z)
	end
end)

Didn’t work, I tweaked the code a bit.

I don’t think this is necessary though.

This is happening because the primary part does not exist. Instead try this code (will only work on models):

local collectionService = game:GetService("CollectionService")
local runService = game:GetService("RunService")

local height = 2
local speed = 1

local storedYValues = {}

local function trig(x,height,speed,f)
	return height*f(speed*x)
end

runService.RenderStepped:Connect(function(dt)
	local sin = trig(tick(),height,speed,math.sin)
	local cos = trig(tick(),height,speed,math.cos)

	local apples = collectionService:GetTagged("Apple")

	for i,v in apples do
        if not v:IsA("Model") then continue end
		local Position, Orientation = v:GetPivot().Position,v:GetPivot():ToOrientation()
		local ogY = storedYValues[v] or Position.Y; storedYValues[v] = ogY

		Position = Vector3.new(Position.X,ogY+sin,Position.Z)
		Orientation = Vector3.new(Orientation.X,Orientation.Y+math.abs(cos),Orientation.Z)

        v:PivotTo(CFrame.new(Position)*CFrame.Angles(math.rad(Orientation.X),math.rad(Orientation.Y),math.rad(Orientation.Z))
	end
end)

I wonder why, when literally…

Screenshot 2024-02-05 182915

Another error.

tweening works perfectly for this

charlimitttttttttttttttttttt

1 Like
local collectionService = game:GetService("CollectionService")
local runService = game:GetService("RunService")

local height = 2
local speed = 1

local storedYValues = {}

local function trig(x,height,speed,f)
	return height*f(speed*x)
end

runService.RenderStepped:Connect(function(dt)
	local sin = trig(tick(),height,speed,math.sin)
	local cos = trig(tick(),height,speed,math.cos)

	local apples = collectionService:GetTagged("Apple")

	for i,v in apples do
		if not v:IsA("Model") then continue end
		local Position, x,y,z = v:GetPivot().Position,v:GetPivot():ToOrientation()
		local ogY = storedYValues[v] or Position.Y; storedYValues[v] = ogY

		Position = Vector3.new(Position.X,ogY+sin,Position.Z)

		v:PivotTo(CFrame.new(Position)*CFrame.Angles(x,y+math.abs(cos)/100,z))
	end
end)

tested this one so it should work

Oh no.

robloxapp-20240205-1957218.wmv (669.4 KB)

change the height and try adding +90 after x or z:

It didn’t work.

local collectionService = game:GetService("CollectionService")
local runService = game:GetService("RunService")

local height = 1
local speed = 1

local storedYValues = {}

local function trig(x,height,speed,f)
	return height*f(speed*x)
end

runService.RenderStepped:Connect(function(dt)
	local sin = trig(tick(),height,speed,math.sin)
	local cos = trig(tick(),height,speed,math.cos)

	local apples = collectionService:GetTagged("Apple")

	for i,v in apples do
		if not v:IsA("Model") then continue end
		local Position, x,y,z = v:GetPivot().Position,v:GetPivot():ToOrientation()
		local ogY = storedYValues[v] or Position.Y; storedYValues[v] = ogY

		Position = Vector3.new(Position.X,ogY+sin,Position.Z)

		v:PivotTo(CFrame.new(Position)*CFrame.Angles(x, y+math.abs(cos)/100, z))
	end
end)

Honestly I’d just use my first script and add the apple tag to each part but NOT the model. Idk what the problem could be here it might have something to do with the rounding and stuff in cframe it can get innacurate sometimes. This is the code you should use:

local collectionService = game:GetService("CollectionService")
local runService = game:GetService("RunService")

local height = 2
local speed = 1

local storedYValues = {}

local function trig(x,height,speed,f)
	return height*f(speed*x)
end

runService.RenderStepped:Connect(function(dt)
	local apples = collectionService:GetTagged("Apple")
	
	local sin = trig(tick(),height,speed,math.sin)
	local cos = trig(tick(),height,speed,math.cos)
	
	for i,v in apples do
		local Position,Orientation = v.Position,v.Orientation
		local ogY = storedYValues[v] or Position.Y; storedYValues[v] = ogY
		
		v.Position = Vector3.new(Position.X,ogY+sin,Position.Z)
		v.Orientation = Vector3.new(Orientation.X,Orientation.Y+math.abs(cos),Orientation.Z)
	end
end)

replace your createFood() with:

local function createFood()
	local food = game:GetService("ServerStorage").Apple:Clone()
	food.PrimaryPart.CFrame = CFrame.new(math.random(-100, 100), 2, math.random(-100, 100))
	food.Parent = folder
	for _,child in pairs(food:GetChildren()) do
       CS:AddTag(child, "Apple")
    end
end
1 Like

This is what I did instead. The cylinder is unanchored and welded to the apple.

Screenshot 2024-02-05 203753

While still keeping the same function.

local function createFood()
	local food = game:GetService("ServerStorage").Apple:Clone()
	food.CFrame = CFrame.new(math.random(-100, 100), 2, math.random(-100, 100))
	food.Parent = folder
	CS:AddTag(food, "Apple")
end

I used the first script of yours.

local collectionService = game:GetService("CollectionService")
local runService = game:GetService("RunService")

local height = 2
local speed = 1

local storedYValues = {}

local function trig(x,height,speed,f)
	return height*f(speed*x)
end

runService.RenderStepped:Connect(function(dt)
	local apples = collectionService:GetTagged("Apple")
	
	local sin = trig(tick(),height,speed,math.sin)
	local cos = trig(tick(),height,speed,math.cos)
	
	for i,v in apples do
		local Position,Orientation = v.Position,v.Orientation
		local ogY = storedYValues[v] or Position.Y; storedYValues[v] = ogY
		
		v.Position = Vector3.new(Position.X,ogY+sin,Position.Z)
		v.Orientation = Vector3.new(Orientation.X,Orientation.Y+math.abs(cos),Orientation.Z)
	end
end)

But, it didn’t work out well.

I don’t know why this happens, but this is my last option.

did you try what I suggested? char limit

2 Likes

It works pretty well. I do notice that some apples move slightly higher than the others. I don’t think that bothers too much though. And I also notice that the apple stop spinning once it gets to the top position or the bottom position, then continues spinning again. However, I think it is meant to be like that.

robloxapp-20240206-1852540.wmv (481.9 KB)

The current code:

local collectionService = game:GetService("CollectionService")
local runService = game:GetService("RunService")

local height = 0.5
local speed = 3.5

local storedYValues = {}

local function trig(x,height,speed,f)
	return height*f(speed*x)
end

runService.RenderStepped:Connect(function(dt)
	local apples = collectionService:GetTagged("Apple")

	local sin = trig(tick(),height,speed,math.sin)
	local cos = trig(tick(),height,speed,math.cos)

	for i,v in apples do
		local Position,Orientation = v.Position,v.Orientation
		local ogY = storedYValues[v] or Position.Y; storedYValues[v] = ogY

		v.Position = Vector3.new(Position.X,ogY+sin,Position.Z)
		v.Orientation = Vector3.new(Orientation.X,Orientation.Y+math.abs(cos),Orientation.Z)
	end
end)

Screenshot 2024-02-06 203800

The script activity is so high though, it is not fine.

Now the issue is that this part of the code that moves the apple detects the stem of the apple too. So, the hit connection function runs thrice or twice. It moves the apple thrice or twice. I’m still figuring it out. It printed "yes" thrice or twice.

character.PrimaryPart.Touched:Connect(function(hitPart)
			if hitPart.Parent.Parent ~= folder then return end -- we want it to only touch apple
			print("yes")
			hitPart.Parent.PrimaryPart.CFrame = CFrame.new(math.random(-100, 100), 2, math.random(-100, 100))
			
			createPart(character)
			
			character:WaitForChild("Humanoid").WalkSpeed += 5
		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.

There is a trick when you can totally use tweens, that will not break when apple is moved. What you need to do is to use invisible, anchored “Root” part, and weld the apple to that part with “Motor6D” weld. Then instead of tweening the apple itself, you can tween “C0” property of that weld.

All you need to remember is that when moving apple, you NEED to use Root CFrame and not position, as adjusting position breaks welds.

apple.PrimaryPart.CFrame = CFrame.new(x,y,z) --where x, y, z is the new position

Here is an example code. This works best in the LocalScript:

local CS = game:GetService("CollectionService")
local TS = game:GetService("TweenService")

 for i, v in CS:GetTagged("Apple") do
	
	while not v.PrimaryPart do
		task.wait()
	end
	--only main root gets to be anchored
	v.PrimaryPart.Anchored = false

	--first root is stationary
	local root = Instance.new("Part")
	root.Anchored = true
	root.Position = v.PrimaryPart.Position
	root.Transparency = 1
	root.CanCollide = false
	root.Name = "Root"
	root.Parent = v

	--intermittent root that only hovers, but does not spin
	local hoveringRoot = root:Clone()
	hoveringRoot.Name = "HoveringRoot"
	hoveringRoot.Anchored = false
	hoveringRoot.Parent = v

	--hovering weld
	local hweld = Instance.new('Motor6D')
	hweld.Part0 = root
	hweld.Part1 = hoveringRoot
	hweld.Parent = root

	--spinning weld
	local sweld = Instance.new('Motor6D')
	sweld.Part0 = hoveringRoot
	sweld.Part1 = v.PrimaryPart
	sweld.Parent = hoveringRoot
	
	--stationary root will become the new primary part
	v.PrimaryPart = root
	
	-- hovering tween is easy
	-- set and forget
	-- i added a random delay, so all apples do not hover in sync
	task.delay(math.random(40)/10,function()
		
		TS:Create(hweld,
			TweenInfo.new(
				2, --total 4 second for both ways
				Enum.EasingStyle.Sine,
				Enum.EasingDirection.InOut,
				-1, --forever
				true), --reverses
			{C0 = CFrame.new() + Vector3.new(0,2,0)}):Play()

	end)
	
	
	
	
	task.delay(math.random(40)/10,function()

		-- spin is a bit more tricky, since tweens can go maximum 180 degrees
		-- you need at least 2 tweens for the part to make 360 turn
		-- but I always suggest 3, so you can control the direction of the tween
		
		--swap ANY of these tweens to switch direction, each tween is 1/3 turn
		local tweens = {
			TS:Create(sweld,TweenInfo.new(1,Enum.EasingStyle.Linear),{C0 = CFrame.Angles(0,math.pi*2/3,0)}),
			TS:Create(sweld,TweenInfo.new(1,Enum.EasingStyle.Linear),{C0 = CFrame.Angles(0,math.pi*4/3,0)}),
			TS:Create(sweld,TweenInfo.new(1,Enum.EasingStyle.Linear),{C0 = CFrame.Angles(0,0,0)}),
		}
		
		for i, tween in pairs(tweens) do
			tween.Completed:Connect(function()
				tweens[i%3 + 1]:Play() -- play next tween
			end)
		end
		
		-- start the first tween
		tweens[1]:Play()

	end)


end

Hope that helps.

P.S. If you want to animate apples on client, and move them around on server (recommended), you will need to create all roots and welds on server and not on client as in this example.

1 Like

Will it have a high script activity if I do this?

1 Like

Much less than RenderStepped or task.wait(), which runs every frame all the time.

For the hovering, you will have 0% script activity. The CFrames will be recalculated automatically from tweens. That does not mean it will have no effect on the performance, just that if you add lots of apples, the penalty will not come from scripts, but from the rendering engine.

The spinning is a bit more complicated. Each apple will run very short function 3 times each spin. I would not be concerned with script activity, but the amount of connections can get out of hand for huge amount of apples (3 connections per apple). I assumed you are making a snake game, so as long as it is not ridiculous amount, you should be fine.

Unless you run into problems, I would not worry about this.

But if you do, there are 2 solutions:

  1. You might want to consider grouping apples into groups and play the rotation tweens for example 10 apples per connection. This will have a downside of syncing each group, but it will not be noticeable by players.

  2. Make the apples symmetric in one axis. This way you can set the 180 degree infinite tween without reversing. It will not require connections at all, but you might be stuck with whatever direction Roblox decides to spin it. This will have 0% script activity.

EDIT:
Pro solution: You can opt for a script that will automatically disable tweens for objects that are not in the proximity of a player (out of view) and dynamically re-enable animations as needed. Lots of work, but doable.

EDIT 2:
Finally, you can obviously get rid of spinning altogether or set up the 180 degree sine back and forward half-spin, much like the hovering. IMHO though, constant spin simply looks better.

2 Likes

What if I use physics? fwefwqweefrgfwq

You shouldn’t use physics unless you have to. Those are much less efficient, since they interact with other parts around them.

You may get away with physics working together with up and down tweens. So you can put something on apple, and while it won’t spin, it will move up and down nicely.

But… tweens are rigid, so do not expect them to stop just because there is a part in the way. This won’t work.

Only use physics when you need:

  • parts that have been put on an apple to travel with it horizontally,
  • parts that have been put on an apple to spin with it,
  • the apple to stop movement if it encounters an obstacle,
  • push things horizontally,
  • push things vertically with limited force.
1 Like