How to make a 2D follow dynamic camera?

I want to make a 2D dynamic camera like in smash bros where it focuses on two players or more players depending on how far they are. But I don’t know where to start, How can I achieve this? (I’m here for someone to help me, not for a free script, unless you actually are helpful enough to give me a script.)

12 Likes

I’m not really sure how the camera works in smash bros.

If this is what you’re looking for, you could find the average of their positions (point in the middle of two or more characters), and position the camera there. Then zoom in and out until all characters are in view, and probably then some to add distance from the edge of the screen.

How can I position the camera to be zoom in and out? That’s what I can’t do.

you can find the average magnitude between all of the characters and use that as the z offset

local cam = workspace.CurrentCamera

local xoffset = 0
local yoffset = 2
local zoffset = 10

local camPart = Instance.new("Part")
camPart.Anchored = true
camPart.Name = "CamPart"
camPart.Parent = workspace

function calculateAveragePosition()
	local total = Vector3.new()
	for _, humrootpart in pairs(ARRAY_OF_HUMANOID_ROOTPARTS:GetChildren()) do    
		total += humrootpart.Position
	end
	return total / #ARRAY_OF_HUMANOID_ROOTPARTS:GetChildren()
end

function calculateAverageMagnitude()
	local total = 0
	for _, humrootpart in pairs(ARRAY_OF_HUMANOID_ROOTPARTS:GetChildren()) do    
		total += (humrootpart.Position - camPart.Position).Magnitude
	end

	return total / #ARRAY_OF_HUMANOID_ROOTPARTS:GetChildren()
end

wait()
cam.CameraType = Enum.CameraType.Scriptable

game:GetService("RunService").RenderStepped:Connect(function()
	local averagePos = calculateAveragePosition()
	local averageMagnitude = calculateAverageMagnitude() + zoffset

	camPart.Position = averagePos
	cam.CFrame = camPart.CFrame * CFrame.new(Vector3.new(xoffset, yoffset, averageMagnitude))
end)


here’s the placefile for good measure
smash bros camera.rbxl (21.9 KB)

29 Likes

Do you know how I could make it to where if a player is out of a specific range, the camera will ignore them?

I don’t know much about it, but maybe put in a block that’s connected to HumanoidRootPart, and make it not move in a certain axis? Just suggesting.

Also, this camera script can also be used as a camera like in 2D Fighters (ex. Street Fighter, Mortal Kombat) if you remove magnitude calculation, and set it to a specific axis, so that’s actually pretty useful for a potential future project that is in fact, a 2D Fighting game.

1 Like

You will need to get the distance of the player and if they are further then the distance you choose do not add them in the table.

2 Likes

How could I add to this so that it would rotate camera based on the players movement if they were moving vertically like Tekken 7 or something?

3 Likes

i know it’s been a while but do you mean like this?:

local cam = workspace.CurrentCamera
local Players = game:GetService("Players")
local xoffset = 0
local yoffset = 2
local zoffset = 10

local hrpArray = {}

for _, player in Players:GetPlayers() do
    task.spawn(function()
        local character = player.Character or player.CharacterAdded:Wait()
        hrpArray[player] = character:WaitForChild("HumanoidRootPart")
    end)
    end
    Players.PlayerAdded:Connect(function(player)
    local character = player.Character or player.CharacterAdded:Wait()
    hrpArray[player] = character:WaitForChild("HumanoidRootPart")
end)
Players.PlayerRemoving:Connect(function(player)
    hrpArray[player] = nil
end)

print(hrpArray)

local camPart = Instance.new("Part")
camPart.Anchored = true
camPart.Name = "CamPart"
camPart.Parent = workspace

function calculateAveragePosition()
    local total = Vector3.new()
    for _, humrootpart in pairs(hrpArray) do    
        total += humrootpart.Position
    end
    return total / #hrpArray
end

function calculateAverageMagnitude()
    local total = 0
    for _, humrootpart in pairs(hrpArray) do    
        total += (humrootpart.Position - camPart.Position).Magnitude
    end

    return total / #hrpArray
end

wait()
cam.CameraType = Enum.CameraType.Scriptable

game:GetService("RunService").RenderStepped:Connect(function()
    local averagePos = calculateAveragePosition()
    local averageMagnitude = calculateAverageMagnitude() + zoffset

    camPart.Position = averagePos
    cam.CFrame = camPart.CFrame * CFrame.new(Vector3.new(xoffset, yoffset, averageMagnitude))
end)

(this is in a local script)

1 Like