[SOLVED] Tween works incorrectly but there's no errors

I want my tower in my TD game to look at the enemy when attacking.

Targeting is correct, there is no animation.

My Tower script is a module script. Face target, attack functions are also placed here.
image

A function that makes the tower look at the enemy:

function tower.FaceTarget(newTower, target, duration) -- Aim tower's function

	local targetVector = Vector3.new(target.PrimaryPart.Position.X, newTower.PrimaryPart.Position.Y, target.PrimaryPart.Position.Z)
	local targetCFrame = CFrame.new(newTower.PrimaryPart.Position, targetVector)

	local tweenInfo = TweenInfo.new(duration, Enum.EasingStyle.Linear, Enum.EasingDirection.Out, 0, false, 0)
	local faceTargetTween = TweenService:Create(newTower.PrimaryPart, tweenInfo, {CFrame = targetCFrame})

	faceTargetTween:Play()

	faceTargetTween.Completed:Connect(function(playbackState)
		print(tostring(playbackState))
	end)
	print(newTower, target, duration)
end

My facing function fires in the attack function:

tower.FaceTarget(newTower, target, 0.06) --last number - duration during tower aiming

I tried to do this using Tween, nothing happens and there are no errors.
If I set duration to near 0 and I place tower and enemy is in its range, placed tower will look at enemy but then it won’t move anymore. Tower attacks, dealing damage, etc. work properly.

I used to use BodyGyro, but I ran into a problem: when I set up a tower and it needed to turn quickly to face the enemy, the tower would spin up and start moving uncontrollably around the map until it stopped. So I decided that I needed a smoother aiming system where I could control the duration of the turn.

BodyGyro is off. All data transferred correctly to FaceTarget, I used prints to check. Also, as I found out, Tween probably works too, to check it I used:

faceTargetTween.Completed:Connect(function(playbackState)
		print(tostring(playbackState))
	end)

image

I tried to put FaceTarget function into a local script into a part and it worked:

I would appreciate any help because I’ve already spent 2 months and still haven’t found the solution.

I think you might have more success with lerping, which is tweening for CFrame in very simple terms.

workspace:WaitForChild("StraightScared")
local PartMoving = script.Parent
local TheTarget = workspace:WaitForChild("StraightScared")

local speed = 0.5

function UpdatePart(Target)

	local direction = (Target.PrimaryPart.Position - PartMoving.Position).unit
	local newCFrame = CFrame.new(PartMoving.Position, PartMoving.Position + direction)

	PartMoving.CFrame = PartMoving.CFrame:lerp(newCFrame, speed)
end

game:GetService("RunService").Heartbeat:Connect(function()
	UpdatePart(TheTarget)
end)

By the way I tested it and it works wonderfully. Oh and if you want to keep your original formula, it should still work.

function UpdatePart(Target)

	local targetVector = Vector3.new(target.PrimaryPart.Position.X, newTower.PrimaryPart.Position.Y, target.PrimaryPart.Position.Z)
	local targetCFrame = CFrame.new(newTower.PrimaryPart.Position, targetVector)

	PartMoving.CFrame = PartMoving.CFrame:lerp(targetCFrame, speed)
end

Tweens are basically linear interpolation (which is what lerp is) but lerp is easier when working with moving the target value since lerp is an interpolation between two values and the first value being the parts cframe and the second value being the target. The problem with tweens is when you loop them the tween before had not finished and now you have overlapping tweens but what lerp does is just changes that second value (the targets position) and smoothly follows it even when its changed. (This is a very oversimplification but I’m not too great at explaining the concept either, so I hope this helps.)

1 Like
function UpdatePart(newTower, target, duration)

	local targetVector = Vector3.new(target.PrimaryPart.Position.X, newTower.PrimaryPart.Position.Y, target.PrimaryPart.Position.Z)
	local targetCFrame = CFrame.new(newTower.PrimaryPart.Position, targetVector)

	newTower.PrimaryPart.CFrame = newTower.PrimaryPart.CFrame:lerp(targetCFrame, duration)
	print("Done")
end

I adapted the code for my script because I don’t have a “PartMoving” (I thought it’s a tower, right?) but if still not working. But “Done” is printing. Maybe because I use primary part in lerp?

And I also fire function like so, because I need to fire this function only when tower attack:
(It fired in the Attack function)

UpdatePart(newTower, target, 0.06)

If I place tower and enemy is in its range, placed tower will look at enemy but then it won’t move anymore.

It looks like something is blocking the movement, but I don’t know how to detect it when I have no errors.

At the same time, BodyGyro was working correctly and I added it to the spawn function when placing the tower.

Code in the Spawn function:

local bodyGyro = Instance.new("BodyGyro")
bodyGyro.MaxTorque = Vector3.new(math.huge, math.huge, math.huge)
bodyGyro.D = 0
bodyGyro.CFrame = newTower.HumanoidRootPart.CFrame
bodyGyro.Parent = newTower.HumanoidRootPart

And BodyGyro was fired into Attack function:

local targetVector = Vector3.new(target.PrimaryPart.Position.X, newTower.PrimaryPart.Position.Y, target.PrimaryPart.Position.Z)
		local targetCFrame = CFrame.new(newTower.PrimaryPart.Position, targetVector)
		
		newTower.HumanoidRootPart.BodyGyro.CFrame = targetCFrame

*P.S. for now this ALL BodyGyro code is off. So it’s not blocking movement

Try to anchor the primarypart of the tower and unanchor all the other parts.

workspace:WaitForChild("StraightScared")
local PartMoving = script.Parent
local TheTarget = workspace:WaitForChild("StraightScared")

local speed = 0.5

function UpdatePart(TargetPart, PartYourMoving)

	local direction = (Target.Position - PartYourMoving.Position).unit
	local newCFrame = CFrame.new(PartYourMoving.Position, PartYourMoving.Position + direction)

	PartYourMoving.CFrame = PartYourMoving.CFrame:lerp(newCFrame, speed)
end

game:GetService("RunService").Heartbeat:Connect(function()
	UpdatePart(TheTarget.PrimaryPart, PartMoving) -- PartMoving is the primary part of the tower and TheTarget.PriamryPart is the enemy's primarypart.
end)

also you said it worked in a localscript which I find weird, is there anything that you could be doing to the Enemies or the Tower on the client and not on the server that could cause that?

If this fix doesn’t work than its probably some other technical issue that the code either isn’t showing or is happening before you even turn the tower or maybe even spawning the enemy.

1 Like

Yees! I’ve already tried to anchor parts, but the problem was I was using this one in another function:

if towerToOptimize:FindFirstChild("HumanoidRootPart") then
		towerToOptimize.HumanoidRootPart:SetNetworkOwner(nil)
	elseif towerToOptimize.PrimaryPart ~= nil then
		towerToOptimize.PrimaryPart:SetNetworkOwner(nil)
	end

Now I read in the Dev Hub:

By default, the server retains ownership of any BasePart. Additionally, the server always owns anchored BaseParts and you cannot manually change their ownership.

I turned off this function, anchored PrimaryPart and everything worked wonderfully!
Your function works properly and my Tween function too.

Thanks a million for your time bro! :grinning:

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.