Lights, Camera, Action || 2D Fighter Dev Blog 1

Acknowledgements

After taking some inspiration from @daftcube 's Hex Planet development blog format, I decided to make use of that by doing a development blog to keep myself invested in my project.

Intro

In case you didn’t know: I’ve started a project codenamed “Project Fireball” which you can see the project announcement here

With that out of the way, I wanted to talk about how fighting games keep players in view of the camera. Because there are a few ways of doing this -

Camera Manipulation

Idea number 1 would be to just make maps really small and keep the camera in the same place, but this is boring.

So I used a handy little feature called Linear interpolation which is in everything from Color3’s to Vector3’s to CFrames!

By using a delta of 0.5, you can find the spot in between both players!

But VNLA, How do you find out how to get the distance!

that part comes easy, since we can find the distance between two players by tracking their HumanoidRootParts (or equivalent part for custom humanoid rigs), we can use trigonometry to find the
length it would take to keep two points in a field of view.

As a handy dandy formula

local distance = (hrp1.Position - hrp2.Position).Magnitude
local fov = workspace.CurrentCamera.FieldOfView

local length = (distance/2)/math.tan(fov/2) --we can clamp this to keep it reasonable

And presto!

Next Steps:

The next steps I would have would be to implement attacking each other. Since I’m using a custom ControlScript to keep them on a 2D Axis, this shouldn’t be difficult to make.

8 Likes

Let there be great formatting! Thanks for the shout-out.

Nice first post. I think the mixed use of trigonometry and linear interpolation is fairly good way to solve this problem.

Something I would like to see in future posts is a longer explanation for how the method works. As someone with a large amount of experience, I was able to take a look at your sample code and get a good sense for what was happening conceptually under-the-hood. However, it might be a bit hard to follow for newer programmers unfamiliar with using trigonometric functions in this context.

Taking the time to make images showing each step of the derivation of your formula would make this post that much better™.

2 Likes

Thanks!

Yeah, I definitely will do that next time. My bad habit with these kinds of posts is that I write as though everyone reads like I do. And that everyone who would read them knows what I know.

Cheers!

Nice post I understood everything really well and I’ve been trying to do something similar the a 2D fighter, but I’m curious on how a 2D Axis would be made.

Hi I’m sorry for being a year late to all this, but if you could, can you explain how to use all the numbers found for the camera lerping? I’m fairly new to scripting and don’t really understand what I’m supposed to do with the lengths and stuff found.

So the lerp formulas work as such:

hrp1 is the player on the client,

hrp2 is whoever the opponent target is.

local plr1 = game.Players.LocalPlayer
local plr2 = nil --Find who this is

local hrp1 = plr1.Character.HumanoidRootPart
local hrp2 = plr2.Character.HumanoidRootPart.Position

When conducting the distance between to positions, you can use Vector3:Magnitude(), which gives you the size of any one vector

--The distance between two points is the Size of their difference (Position1 - Position2)
local distance = (hrp1.Position - hrp2.Position).Magnitude

And then the distance back to keep them in frame uses trigonometry. Your viewport camera basically works like a triangle
image
We use the tangent which is the size of the opposite side of the triangle divided by the size of the adjacent side.

local fov = workspace.CurrentCamera.FieldOfView

local length = (distance/2)/math.tan(fov/2) 
--[[
If we cut the viewport triangle into two right triangles, 
then the angle at the camera would be half of the FieldOfView. 
Likewise we would have to cut the distance in half to make the 
calculation correct ]]--

The numbers are a bit complicated if you aren’t great with trigonometry

What would the final code for lerping the camera cframe look like?

local center =  hrp1.Position:Lerp(hrp2.Position, 0.5)
local offset = Vector3.new(0, 0, length)

local goalCF = CFrame.new(center + offset, center)

workspace.CurrentCamera.CFrame = workspace.CurrentCamera.CFrame:Lerp(goalCF, dt)

--[[
All of these calculations should be done inside RunService.RenderStepped 
to get the delta time
]]--