Pinball Machine Flipper - How to synchronise fast-changing boolean between client-and-server?

I’m trying to produce an experience in which the player can operate a simple pinball machine. My current focus is on the flippers at the bottom of the machine (I’m starting with the left one). I’d like it so the player can use A and D (or Left and Right) on their keyboard to operate the flippers.

Right now I have the flippers managed by the client entirely, since I figured it would be best not to have each keypress fired to the server to have it handle the motion instead.

At least that was the approach I was hoping to take. I’ve now reached the problem of communicating the position of the flipper to the server so that the ball knows how to act when it reaches the bottom of the machine. Since the motion of the ball is managed by the server, it treats the flippers as though they are always downwards. I don’t want to communicate every keypress as i’m concerned it would cause some lag. Nothing considerable of course, but enough to disrupt gameplay.

Excuse any spaghetti…

local userinputservice = game:GetService("UserInputService")
local ts = game:GetService("TweenService")

local leftFlipper = workspace.machineParts.leftFlipper
local leftOr = (CFrame.new(Vector3.new(-18.235, 56.257, 8.759)) * CFrame.Angles(math.rad(-8.649), math.rad(-120), math.rad(5.038)))  -- Position of the flipper when it's released
local leftFlipped = (CFrame.new(Vector3.new(-20.831, 56.72, 8.759)) * CFrame.Angles(math.rad(-8.649), math.rad(-60), math.rad(-5.038))) -- Position of the flipper when it's flipped
local fliptime = 0.1 -- Speed of the "flip" motion
local leftFlippedValue = leftFlipper.flipped -- "flipped" is a BoolValue instance

twinfo = TweenInfo.new(fliptime, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut)

local function flipLeftUp()
	local t = ts:Create(leftFlipper.flipperBody, twinfo, {CFrame = leftFlipped})
	leftFlippedValue.Value = true
	t:Play()
end
local function flipLeftDown()
	local t = ts:Create(leftFlipper.flipperBody, twinfo, {CFrame = leftOr})
	leftFlippedValue.Value = false
	t:Play()
end

local function onpress(input, _gameProcessed)
	if input.UserInputType == Enum.UserInputType.Keyboard then
		if input.UserInputState == Enum.UserInputState.Begin then
			if input.KeyCode == Enum.KeyCode.A or input.KeyCode == Enum.KeyCode.Left then
				flipLeftUp()
			end
		end
	end
end
local function onrelease(input, _gameProcessed)
	if input.UserInputType == Enum.UserInputType.Keyboard then
		if input.UserInputState == Enum.UserInputState.End then
			if input.KeyCode == Enum.KeyCode.A or input.KeyCode == Enum.KeyCode.Left then
				flipLeftDown()
			end
		end
	end
end

userinputservice.InputBegan:Connect(onpress)
userinputservice.InputEnded:Connect(onrelease)

I’m just really not certain on what the best approach would be here… Would it be feasible for me to fire every keypress to the server and just hope the player doesn’t decide to spam away at their keys? Could I have the ball managed by the client as well and have it communicate all interactions to the server? I apologise if it’s more of a brainfog situation on my end, but this is new territory for me :smile:.

You can try using BoolValues.

I would recommend this because I doubt it would create a lot of lag sending a couple of bytes worth of data and the game automatically limits the amount of remote events a client can fire.

1 Like

Also even if they spam, even with poor connection, it won’t cause any desynchronization/scrambling issues because the order in which requests are sent and received is always the same, it’ll just be delayed (order will be the same) when comparing the “sending” client and the “receiving” server/other clients because of network ping but that’s literally impossible to avoid.

1 Like

I’ve decided to take this approach. Thank you!

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