Using UserInputService while in a vehicle seat (ship)

I am currently in development of a pirate ship-related game. The player can use WASD to drive the ship but also I’m looking to add a way to use Q&E to fire the left and right cannons on the ship. I created a local script attempting user input service to fire a Bindable Event towards the cannons. My script currently doesn’t even pick up the buttons being pressed in the first place. I tried local and regular scripts. Similar to how a police car drives and you are able to toggle certain things like sirens, horn or headlights, I attempted to copy some code and modify it to this but it never worked either. This is my current Progress:

local CannonQ = script.Parent.Parent.CanQ
local CannonE = script.Parent.Parent.CanE
local UserInputService = game:GetService(“UserInputService”)

UserInputService.InputBegan:Connect(function(key)
if key.KeyCode == Enum.KeyCode.Q then
print(“fireQ2”)
CannonQ:Fire()
end
end)

UserInputService.InputBegan:Connect(function(key)
print(“fireE1”)
if key.KeyCode == Enum.KeyCode.E then
print(“fireE2”)
CannonE:Fire()
end
end)

Also here is my ship layout
Capture

Any help is appreciated.

1 Like

Is this a problem with the replication or a problem with the mechanic overall?

Thanks to FilteringEnabled, if you want anything to replicate from the client (user input) to the server (other players seeing it), you’ll have to use remote events rather than bindable events so the information is sent over to the server for all other clients to receive.

The above problem may be separate from your current problem, though; according to your post, you can’t even get the button presses to register, and that’s definitely a local script error. The main potential problem I see is addressing the first two variables. When in a local script, sometimes instances won’t load in before scripts are ran, so it may help to use :WaitForChild() on those instances rather than directly referring to them.

LocalScripts won’t run code unless it is a descendant of

A Player’s Backpack, such as a child of a Tool
A Player’s character model
A Player’s PlayerGui
A Player’s PlayerScripts.
The ReplicatedFirst service

you can find more information on LocalScripts here

What I personally would do is, in a local script under StarterPlayerScripts detect if the Player is sitting in the pirate ship and then begin getting input if they are. If they arent, disconnect the functions.

3 Likes

The Button detection is stored on the ship itself and nothing happens locally scripting wise. There is nothing in the output either after the change done(adding wait for child on variables, and changing it to a regular script). If there is no way for the server to track the buttons being pressed by the player, is the only way a local script on the player firing to the ship if the player is on the ship?

Or would a [Server->Client-> Server] model work, where if a player sits in the ship, the server fires and creates a local script in the players scripts, and thus begins tracking the player key presses until the player jumps out of the seat destroying the script.

Both of those ideas would work, but it’d be easier to go with the first method. Also, as @SkoobiDoobiDoo mentioned, your local script cannot run unless it’s parented correctly, which is something I initially overlooked.

You could parent the local script to StarterPlayerScripts, then connect it to a remote event created in a fitting place such as ReplicatedStorage for the button detection. When the button is pressed, use :FireServer() to send the signal to a server script inside of the ship which will operate the vehicle functions. You also want to check to make sure the player who pressed the button is the same as the player on the seat. Remote events automatically pass the player as an argument to the server, so you can do something like this on the server script:

local remote = game.ReplicatedStorage.ShipRemote 
local seat = script.Parent 
local CannonQ = seat.Parent.CanQ 
local CannonE = seat.Parent.CanE 

remote.OnServerEvent:Connect(function(player,button) 
	
	local chara = player.Character 
	
	if chara then 
	
		local human = chara:FindFirstChildWhichIsA("Humanoid") 
		
		if human and human == seat.Occupant then --check mentioned above 
			
			if button == "Q" then 
				
				--code to shoot CannonQ 
				
			elseif button == "E" then 
				
				--code to shoot CannonE 
				
			end 
			
		end 
		
	end 
	
end) 

You can then handle the user input on the client in a local script, likely in StarterPlayerScripts:

local remote = game.ReplicatedStorage:WaitForChild("ShipRemote") 
local UserInputService = game:GetService("UserInputService") 

UserInputService.InputBegan:Connect(function(key) 
	
	if key.KeyCode == Enum.KeyCode.Q then 
		
		remote:FireServer("Q") 
		
	elseif key.KeyCode == Enum.KeyCode.E then 
		
		remote:FireServer("E") 
		
	end 
	
end) 

I don’t know how familiar you are with remote events/functions, but whenever firing from client to server, don’t let the arguments confuse you. The only argument passed in the local script is a string value, either “Q” or “E”, to indicate which key was pressed. However, in the server script, you can see that the function has two arguments, the first being the player. This personally confused me a lot when I first learned about remotes, so just remember that the ‘player’ is always automatically there as the first argument when the client uses :FireServer(), even though it isn’t passed as an argument.

9 Likes

Thank You so much.
This put me back on track