• Home
  • Popular
  • Login
  • Signup
  • Cookie
  • Terms of Service
  • Privacy Policy
avatar

Posted by User Bot


08 Jan, 2025

Updated at 26 Jan, 2025

Can I move a BasePart or Model on the server without replicating the movement to the client?

Im working on enemy movement for a tower defense game. I had an issue where because I was handling all the movement on the server with tween service on the client the enemy movement looked choppy so i added this event that will tell the clients to tween the enemies model to make it look smooth for them without actually relying on the client to change its position. I also added some logic on the server for moving the enemies that doesnt use the tween service but instead uses runservice.heartbeat signals to make the results more accurate (because using task.wait() isnt always the same wait time) but for some reason it still looks choppy on the client, i believe the issue is that the server movements are overriding the clients tween. Is there some way for me to make it so the server’s movements dont get replicated to the client, at least until i want them to be? (preferably every waypoint it will be replicated/synced with client)

Server Script (the part that handles movement)

local height : number = model:GetAttribute("Height") or 0

local primaryPart = model.PrimaryPart
if primaryPart == nil then warn("Enemy model didnt have a PrimaryPart"); return end

task.spawn(function()
	
	local function moveToWaypoint(i : number, startingDistance : number?)
		local lastPoint = waypointsFolder:FindFirstChild(`{i}`)
		local nextPoint = waypointsFolder:FindFirstChild(`{i+1}`)
		if lastPoint == nil or not lastPoint:IsA("BasePart") then warn(`Waypoint {i} missing or wrong type`); return end
		
		if nextPoint == nil then -- it reached the end
			model:Destroy()
			return 
		end
		if not nextPoint:IsA("BasePart") then warn(`Waypoint {i+1} is wrong type`); return end

		primaryPart.CFrame = CFrame.new(lastPoint.Position.X, lastPoint.Position.Y + height, lastPoint.Position.Z)
		
		local distanceBetweenPoints = (nextPoint.Position - lastPoint.Position).Magnitude
		local targetPos = Vector3.new(nextPoint.CFrame.Position.X, nextPoint.CFrame.Position.Y + height, nextPoint.CFrame.Position.Z)
		local directionVector = (targetPos - primaryPart.Position).Unit
		
		local totalDistanceTraveled = 0

		local heartbeatConnection = nil
		heartbeatConnection = RunService.Heartbeat:Connect(function(deltaTime)
			local distanceToTravel = self.WalkSpeed*deltaTime + (startingDistance or 0)
			startingDistance = 0
			
			local newPosition = primaryPart.Position + directionVector * distanceToTravel 
			primaryPart.CFrame = CFrame.new(newPosition)
			totalDistanceTraveled += distanceToTravel
			
			if totalDistanceTraveled >= distanceBetweenPoints then
				assert(heartbeatConnection, "there wasnt a heartbeat connection")
				heartbeatConnection:Disconnect()
				moveToWaypoint(i+1, totalDistanceTraveled - distanceBetweenPoints)
			end
		end)
		
		rev_TweenEnemyModel:FireAllClients(primaryPart, targetPos, distanceBetweenPoints, self.WalkSpeed)
	end
	
	moveToWaypoint(1)
	
end)

Client Script (the function that is called when the event is fired)

local function TweenEnemyModel(primaryPart : BasePart?, targetPos : Vector3, distance : number, walkSpeed : number)
	if primaryPart == nil then return end
	
	local estimatedTravelTime = distance/walkSpeed
	
	primaryPart.CFrame = CFrame.lookAt(primaryPart.Position, targetPos)
	TweenService:Create(primaryPart, TweenInfo.new(estimatedTravelTime, Enum.EasingStyle.Linear), {
		CFrame = CFrame.lookAt(targetPos, targetPos + (targetPos - primaryPart.Position).Unit)
	}):Play()
end

And it is essential that the movements do happen on the server as I’m going to use the positions of enemies to calculate tower attacks/targeting on the server. and I want there to be some sort of a voice of reason that keeps track of all the enemy positions or else everybody will be seeing different stuff.

2 posts - 2 participants

Read full topic