Initial camera handling #6

I lied! Kinda. I did some work on my first item and it has progressed nicely, but I got sidetracked by not really liking how my camera was being handled – it was way too choppy when dashing around. So in this short post, I will show how I improved it and share the code in case someone is also facing this.

As a side note, after making this I learnt about the existence of a camera handler plugin. I am in no rush to integrate it into my project, but it seems that it will be worth investigating the moment I need something more than lagging behind from my camera. Since I write my scripts in C# I hope that by the time I need that plugin the support for using it in non-GDScript will be added as it is pointed out here.

Initially, the camera was just following the player. Simple and easy to implement. This produces a view like this:

(A gid might not be the best way to illustrate it, but my WordPress plan doesn’t allow me videos:/)

So my two small goals were to stop the stiff camera movement and also put in the guards preventing the player from getting “escaping” the camera.

To achieve the first goal I first marked the camera node as a top-level node with this code snippet in the Ready function TopLevel = true;. This way I can keep the camera as the child of the player, which makes the management a bit easier, but also stops the camera node from using the parent node’s transforms. The interpolation between the camera’s current position and the player’s position was handled by this code:

public override void _Process(double delta)
	{
		if (Position != targetNode.Position)
		{
			// Interpolation bit
			Position = Position.Lerp(targetNode.Position, ((float)delta) * currentCameraLerpSpeed);
			if (Position.IsEqualApprox(targetNode.Position))
			{
				Position = targetNode.Position;
			}
			//...
		} 
	}

The safeguard was implemented by getting by tracking if the player hasn’t left the safe space (a percentage of the screen) and if they have – snap to the edge of the safe space or double up the lerp speed. The code looks like this:

{
				Vector2 cameraPositionInViewport = GetGlobalTransformWithCanvas().Origin;
				Vector2 targetNodePositionInViewPort = targetNode.GetGlobalTransformWithCanvas().Origin;
				Vector2 screenHalfExtent = GetViewportRect().Size * 0.5f;
				Vector2 safeZoneExtent = screenHalfExtent * screenSafeSpaceRatio;
				Vector2 direction = targetNodePositionInViewPort - cameraPositionInViewport;
				Vector2 directionComparable = direction.Abs();
				Vector2 viewportDiff = directionComparable - safeZoneExtent;

				// The faster speed approach
				// if (viewportDiff.X > 0 || viewportDiff.Y > 0)
				// {
				// 	currentCameraLerpSpeed = defaultCameraSpeed * 2.0f;
				// }
				// else if (currentCameraLerpSpeed != defaultCameraSpeed)
				// {
				// 	currentCameraLerpSpeed = defaultCameraSpeed;
				// }
				// The hard zone approach
				Position += new Vector2()
				{
					X = viewportDiff.X > 0 ? viewportDiff.X * Mathf.Sign(direction.X) : 0,
					Y = viewportDiff.Y > 0 ? viewportDiff.Y * Mathf.Sign(direction.Y) : 0,
				};	
}

And the results look like this:

Next time I will definitely make a post about the items, this time I just wanted to make a small post!

Leave a comment