Preventing player transparency in first person

Essentially I want to have my weapon script put the player in a “Shift-Lock” type state, where they have an above shoulder camera and they can turn simply by moving their mouse.

I have accomplished this by simply setting the CameraMaxZoomDistance property to 0.5 to force first person, giving the mouse movement to turn effect, and then using CameraOffset to move the Camera.

Code (runs each RenderStepped):

game.Players.LocalPlayer.CameraMinZoomDistance = 0.5
local y = workspace.CurrentCamera.CoordinateFrame.lookVector.Y
game.Players.LocalPlayer.Character:FindFirstChild("Humanoid").CameraOffset = Vector3.new(math.max(1.5,1.5-y),math.abs(y/2)-y*3.8642337322235,4-math.abs(y))

The issue is that now the player becomes transparent (as a result of going in first person - see GIF below). I’ve tried using the following code on every RenderStepped to prevent this but it does not work.

game:GetService("RunService").RenderStepped:Connect(function()
	if equiped then
		for i,v in pairs(game.Players.LocalPlayer.Character:GetDescendants()) do
			if v:IsA("BasePart") then
				v.TransparencyModifier = 0
				v.Changed:connect(function(propertyChanged)
					if propertyChanged == "TransparencyModifier" then
						v.TransparencyModifier = 0
					end
				end)
			end
		end
	end
end)

Example:
https://gyazo.com/0a397453ec111f9d71638abc28a33c3a

Any ideas?

1 Like

The Roblox camera CoreScript uses this code to do update the player transparency, maybe try that?

RunService:BindToRenderStep("cameraRenderUpdate", Enum.RenderPriority.Camera.Value, Update) -- where Update is your function to reset the transparency modifier.
I checked and BindToRenderStep is not not RobloxScriptSecurity. Unfortunately it’s not possible to disable the transparency script entirely, and every time the Update function is called the player’s local transparency modifier is set.

1 Like

Where do you find this script?

Transparency CoreScript: Core-Scripts/PlayerScripts/StarterPlayerScripts/CameraScript/TransparencyController.lua at master · Roblox/Core-Scripts · GitHub

Camera CoreScript: Core-Scripts/PlayerScripts/StarterPlayerScripts/CameraScript.lua at master · Roblox/Core-Scripts · GitHub

Until I find a better solution, commenting out the code that sets the player’s character transparent will work.

That particular CoreScript cannot be modified (unlike the Chat script for example); you’ll have to work around it.

I just modified it and it works.

This kind of a third person camera sounds very hacky. It’s abusing first person, that much is for sure.

Your code has a few flaws in it that need to be addressed:

  • Consider attaching the Character to a variable. If your code is in StarterPlayerScripts, write a handler that updates the character variable or a function that returns the character.

  • Don’t use RenderStepped, use BindToRenderStep to control the priority. The default CameraModule does this, so you will need to run a process over it.

    • BindToRenderStep gives you more control anyway and an easier API to work with. I’m referring to how you can use UnbindFromRenderStep over having a process attached to RenderStepped that runs at all times with no indication of disconnecting it in the code.

    • Code in RenderStepped prevents frames from being rendered until all functions have run. On the other hand, BindToRenderStep (hence its name) does not defer frame rendering. Regardless of each case, note that attaching code to a render step should only be done in absolute necessity. Camera and character transparency updates are acceptable use cases.

  • TransparencyModifier is not a valid member of BaseParts, it’s LocalTransparencyModifier. Did you check your console? It would’ve thrown an error.

  • Your code assumes that LocalPlayer.Character is non-nil, which is a bad assumption to make. This should be self explanatory - code can run before a character exists or a character can be changed to nil under the LocalPlayer.

  • GetPropertyChangedSignal allows granular control of changed properties. Instead of checking if all properties change, you can check only if a specific property you specify changes.

    • Your code is in RunService, so you have no reason to be using Changed or GetPropertyChangedSignal here at all. Brute force a zero value for LocalTransparencyModifier every frame.

Here’s some code that incorporates your current style. I’m assuming that your code is in StarterPlayerScripts for this example.

local RunService = game:GetService("RunService")
local LocalPlayer = game:GetService("Players").LocalPlayer

-- Lower render priority value means higher priority.
local RENDER_PRIORITY = Enum.RenderPriority.Character.Value - 5

local function updateCharacterTransparency()
    -- Don't use LocalPlayer.CharacterAdded:Wait(), unnecessary
    local character = LocalPlayer.Character

    if character then
        for _, part in ipairs(character:GetDescendants()) do
            if part:IsA("BasePart") then
                -- Remember that LTM is a multiplier; 0-values will not force different transparency
                part.LocalTransparencyModifier = 0
            end
        end
    end
end

-- Use on equip or changing to third person camera mode
RunService:BindToRenderStep("CharacterTransparency", RENDER_PRIORITY, updateCharacterTransparency)

-- Use on unequip or changing to non-third person camera mode
RunService:UnbindFromRenderStep("CharacterTransparency")

This code has several benefits which you can observe:

  • We don’t attach a process that runs at all times. We only add it when we need it and remove it when we don’t care to keep it anymore.

  • We don’t do anything unnecessary in code. A character is checked for and if one exists, then we proceed to set the LocalTransparencyModifier of descendant BaseParts as needed.

  • We have our transparency updater in a function, so we can always bind or unbind it from RenderStep at any given time. No managing an RBXScriptConnection and an easy-use API to work with (BindToRenderStep and UnbindFromRenderStep, beautiful).

  • Clean code. Good code.

If you want to go on the offensive, you can fork the PlayerModule and make changes that exposes certain API or methods that allow your code to control when the TransparencyController sets the LocalTransparencyModifier and when it doesn’t. For example, you can do this through a flag or a tag in CollectionService such as “PreventTransparencyUpdate”. Whatever you like.


@catamorphism1 That repository is out of date, the last commit was back in 2018. If you want to reference an updated copy, refer to either CloneTrooper1019’s Client Tracker repository or your local file system. The path is the scripts folder under the latest RobloxPlayer version folder.

14 Likes

I was hoping you’d end up replying. Your solution works.

I tried swapping TransparencyModifier to LocalTransparencyModifier in my solution and it worked. For whatever reason using TransparencyModifier didn’t throw any errors so I didn’t notice.

I’ll defiantly make use of BindToRenderStep. I’ve never done anything with RenderService before so I wasn’t sure if it was needed.

Also, the actual script does have Character and LocalPlayer variables as well as checks to ensure the character isn’t nil. They just weren’t included in the post.

Thanks.

edit: Happy “cake day” if that’s even a thing on DevForum

1 Like

Since TransparencyModifier isn’t a valid child or member of BaseParts, it should be throwing. Considering the original code didn’t work, I want to chalk it up to a silent error but I’m quite sure that code in RenderStepped does not silently error.

Thanks, but it’s actually anniversary cake, not birthday cake.

1 Like

Yeah, that’s what I meant. They call your Reddit anniversary “Cake Day”.

After investigating further, it looks like it is throwing an error with TransparencyModifier. It was just buried in the output logs, thanks to the ‘CharacterSoundEvent’ log spam bug.