Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
0

How can I stop the camera from turning upside down?

Asked by
Lamar 45
8 years ago

So I asked a question a while back asking how to get the type of side view camera I need. Luckily I figured it out after a lot of troubleshooting, but now I have a new issue. Every half circle around the other player, the camera turns upside down. I believe this is due to the method I used to make sure the camera doesn't tilt when the y axes of the Torsos don't align.

I know the cause, which is the subtraction of rz from the camera's angle. I just don't have the first clue how to fix it.

Here's the script. Everything works except for the camera turning upside down.

local cam = workspace.CurrentCamera
cam.CameraType = Enum.CameraType.Scriptable
local player = game.Players.LocalPlayer
local playerOne = workspace:WaitForChild("playerOne")
local playerTwo = workspace:WaitForChild("playerTwo")

function getDistance(p1, p2)
    return p1.Torso.Position - p2.Torso.Position
end

    local centerPart = Instance.new("Part",workspace)
    centerPart.Transparency = 1
    centerPart.Anchored = true

function updateCamera(camera)
    local otherPlayer
    if playerTwo.Value == player.Name and playerOne.Value ~= "" then
        otherPlayer = workspace:WaitForChild(playerOne.Value)
    elseif playerOne.Value == player.Name and playerTwo.Value ~= "" then
        otherPlayer = workspace:WaitForChild(playerTwo.Value)
    end
    if otherPlayer ~= nil then
        local distance = getDistance(player.Character, otherPlayer)
        local center = player.Character.Torso.CFrame:lerp(otherPlayer.Torso.CFrame, 1/2)
        camera.CoordinateFrame = CFrame.new(center.p, otherPlayer.Torso.Position)
                                *CFrame.Angles(0,math.rad(90),0)
                                *CFrame.new(0,0,distance.magnitude/2)
        local rx, ry, rz = camera.CoordinateFrame:toEulerAnglesXYZ()
        print(rx.." "..ry.." "..rz)
        camera.CoordinateFrame = camera.CoordinateFrame * CFrame.Angles(0,0,-rz)
    else
        camera.CameraType = Enum.CameraType.Track
    end
end

game:GetService("RunService").RenderStepped:connect(function()
    updateCamera(cam)
end)

1 answer

Log in to vote
3
Answered by 8 years ago

Your CFrame and vector math is overly messy. Simplifying that bit would eliminate weird issues like the one you have.

Calculating the CFrame from components would be simpler, even though it might sound way more complex.

if otherPlayer ~= nil then

-- CFrame is nothing more than a set of 4 vectors: position, up direction, right direction and back direction
-- If we calculate all these vectors, you can simply put them together into CFrame

-- Keeping up vector constantly pointing up, since we don't want any rolling or tilting
local up = Vector3.new( 0, 1, 0 )

-- From reading your code, I assumed you wished the camera to always have player on left side and otherPlayer on right side, so let's make right vector point to the otherPlayer direction
-- First get the direction from player to otherPlayer
local right = (otherPlayer.Torso.Position - player.Character.Torso.Position).unit
-- Then get rid of y component, and normalize it again. Now we know direction to other player without affecting roll
right = Vector3.new( right.x, 0, right.z ).unit

-- Back vector can now be acquired by getting cross vector from up and right
-- Cross product takes two vectors and returns third vector, which will be perpendicular to both provided vectors
-- If your camera acts weird, you might need to inverse this vector(just make it negative)
local back = up:Cross( right ).unit

-- Not sure why you need that function call
local distance = (player.Character.Torso.Position - otherPlayer.Torso.Position).magnitude
local center = player.Character.Torso.Position:lerp(otherPlayer.Torso.Position,  1/2)

-- Now to offset the camera by the distance, just apply some simple vector math
center = center + back*distance/2

-- Now, if I position the components in this sort of fashion, you might start to see the pattern that the components make. Just like I mentioned before, CFrame consists only from 4 vectors which can be nicely laid out in this array fashion.
camera.CoordinateFrame = CFrame.new(    
    center.x, center.y, center.z
    right.x, up.x, back.x,
    right.y, up.y, back.y,
    right.z, up.z, back.z 
)

else
    camera.CameraType = Enum.CameraType.Track
end

Note that I couldn't get to test any of this, so if it does error or do unexpected things, please let me know.

0
I'll try this out when I get a chance. I knew I wasn't doing it the most efficient way. I have a lot of trouble understanding math relating to vectors and 3D space, so I appreciate the extra-detailed explanation. Thank you! Lamar 45 — 8y
Ad

Answer this question