How to implement screenshake near camera limit?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Diet Estus

To do screenshake, you can walk through smooth noise over some duration, multiply by a max screen offset, and then set the camera’s offset equal to this.

The problem is that when the camera is near its limits, adjusting the offset in the direction of the limit won’t do anything. This creates a very ugly asymmetrical shake.

Is there a way to adapt the technique so it works when a camera is near the perimeter of its limiting rectangle?

After some experimentation, it should be possible to get around this problem by accessing the default CanvasLayer of the root Viewport (and any other CanvasLayers used in the scene) and manually adjusting their Transform2D. That said, I’m not sure exactly how to do that, or how to achieve a single pixel shift using the Transform2D of the CanvasLayer. Any help is appreciated.

Can obviously do something like:

	get_tree().get_root().canvas_transform.x.x += .001
	get_tree().get_root().canvas_transform.x.y += .001
	get_tree().get_root().canvas_transform.y.x += .001
	get_tree().get_root().canvas_transform.y.y += .001

But the shifts look distorted in windowed mode (though look fine in full screen). Also, how to determine what value corresponds to a pixel?

You could widen the limts of the camera temporarly - like in this answer to a similar question: Screen shake across camera limits - Archive - Godot Forum

Kaligule | 2019-07-05 06:10

Should be possible by directly shifting the CanvasLayer. This will bypass the problem with the Camera2D limits.

Diet Estus | 2019-07-05 06:50

:bust_in_silhouette: Reply From: Zylann

You could maybe tweak the offset property, I believe it was added for this kind of purpose (I think it’s neither affected by limits nor smoothing).

Unfortunately, in my experience it appears that the offset is indeed affected by the camera limits. Would love to be proven wrong though.

AUD_FOR_IUV | 2019-07-05 16:06

Then that looks like a problem to raise on Github as a feature request, because I can’t imagine a use case for that limitation Oo

Zylann | 2019-07-05 18:11

I reported the issue here: Camera2D offset is blocked by limit · Issue #30358 · godotengine/godot · GitHub

Diet Estus | 2019-07-06 00:24

Looks like they’ve already got a pull request slated for inclusion in the 3.2 release: Camera2D's offset now ignores the limit property by LikeLakers2 · Pull Request #30361 · godotengine/godot · GitHub

AUD_FOR_IUV | 2019-07-06 16:53

:bust_in_silhouette: Reply From: groug

I had the same problem (and my question was unanswered)
Changing the limit was not an option for me, because of drag margins and smoothing, it doesn’t run well.

I used a variant of what you proposed:

get_tree().get_root().global_canvas_transform.origin = offset_vector

You have to use global canvas transform, not just canvas transform.
It’s working great, the only thing is that by moving the canvas, you can see the default background color, but that’s OK.