Godot Version
v4.6.1.stable.mono.official [14d19694e]
Question
I’m trying to implement a Camera3D that can empirically determine when it has moved too far in one direction and stop moving.
Right now I have a rectangular room which the Camera3D overlooks, and on top of each wall is a VisibleOnScreenNotifier3D. Whenever the Camera3D tries to update its position in response to player input (WASD), it checks whether any of these Notifiers are on-screen, and for each one that is, it adds an oppositional Vector3D to the Camera3D’s movement.
Here is the full code of the VisibleOnScreenNotifier3D:
public partial class OwCamBound : VisibleOnScreenNotifier3D
{
public static List<OwCamBound> visibleBounds = new();
public Vector3 relativeForward;
public override void _Ready()
{
relativeForward = new Vector3(GlobalTransform.Basis.Z.X, 0, GlobalTransform.Basis.Z.Z).Normalized();
ScreenEntered += VisibleEnable;
ScreenExited += VisibleDisable;
}
private void VisibleEnable()
{
visibleBounds.Add(this);
}
private void VisibleDisable()
{
visibleBounds.Remove(this);
}
}
and here is the relevant code for the Camera3D’s movement:
foreach (OwCamBound visBound in OwCamBound.visibleBounds)
{
camVelocity -= visBound.relativeForward;
}
camVelocity *= camMoveSpeed * delta;
if (camVelocity != Vector3.Zero)
{
Position = new Vector3(Position.X + camVelocity.X, Position.Y, Position.Z + camVelocity.Z);
}
This works about perfectly for movement in cardinal directions (i.e. the Camera3D is either parallel or perpendicular to each wall), but I’m not happy with how it behaves when the Camera3D is rotated on the other 45° increments such as Northwest; right now it can only face in these eight directions. I’d like it to instead begin disabling movement when the Notifier has passed the center of the screen.
I’ve thought of a few potential solutions for this:
- Use
UnprojectPosition(visBound.GlobalPosition)and trigonometry to calculate the area of the screen occupied by the Notifier, and check that against the center of the screen. - Parent a more zoomed-in Camera3D to the main one, so that it is always only looking at the center portion of the screen, and tie the Notifiers to that Camera3D when the view is diagonal.
Both of these seem pretty convoluted, so I wanted to make sure there isn’t a simpler solution to my problem that I didn’t turn up before going ahead with it.
