Topic was automatically imported from the old Question2Answer platform.
Asked By
Diet Estus
I have a Camera2D with a screen_shake() method which alters the camera’s rotation_degrees as well as its offset.
I notice that this causes my ParallaxLayersto rotate different amounts. I imagine this is because they all have different motion_scales. Ideally, I’d like them all to rotate the same amount.
The short answer is no. The engine’s built-in parallax layers do not respect camera rotation, and there is no magic checkbox that I know of to fix the issue.
However, you can write your own parallax functionality that does respect rotation. See below for one I put together for a project last spring (and haven’t touched since - fair warning!).
Rotating parallax layers or backgrounds is not sufficient: they have to be rotated around the camera, which is extra weird because the motion scales muck with the camera’s “position” anyways. I don’t know how parallax backgrounds work internally: it’s a bit odd to me since they’re separate canvas layers by definition, and afaik canvas layers usually ignore cameras that aren’t their own descendants.
extends Node2D
# scene tree:
# parallax_layer (Node2D)
# camera_follower(Node2D)
# mirroring should be at least as big as screen dimensions.
# if cameras are allowed to rotate, each mirroring dimension
# has to be at least as big as the biggest resolution dimension.
# i.e. when the camera is turned 90 degrees, the wrapping needs
# to happen beyond the width of the viewport that (in this situation)
# wraps with *y* motion.
export(NodePath) var camera_path
var camera setget set_camera
export(float) var parallax_scale = 1.0
export(Vector2) var mirroring = Vector2()
export(int) var mirror_margin = 64
var original_position
var motion = Vector2()
func _ready():
if camera_path:
camera = get_node(camera_path)
original_position = get_position()
func _process(delta):
if camera != null:
update_motion()
wrap_children()
else:
# grab the first thing in the 'camera' group
var camera_group = get_tree().get_nodes_in_group("camera")
if camera_group.size() > 0:
set_camera(camera_group[0])
func update_motion():
var to_camera = camera.get_global_position() - $camera_follower.get_global_position()
motion += to_camera
position = original_position + (motion * (1.0 - parallax_scale))
$camera_follower.set_global_position(camera.get_global_position())
func wrap_children():
if mirroring.x == 0 and mirroring.y == 0:
return
var mirror_bounds = Rect2()
mirror_bounds.size = Vector2(mirroring)
mirror_bounds.position = camera.get_global_position()
# position is camera top left, not center
# not actually camera top left, but bounds top left :\
# avoids viewport dimension non-squareness causing wrap problems when rotated
mirror_bounds.position -= mirror_bounds.size / 2.0
for child in get_children():
if mirror_bounds.size.x != 0:
if child.get_global_position().x < (mirror_bounds.position.x - mirror_margin):
child.position.x += mirror_bounds.size.x + (2 * mirror_margin)
elif child.get_global_position().x > (mirror_bounds.position.x + mirror_bounds.size.x + mirror_margin):
child.position.x -= mirror_bounds.size.x + (2 * mirror_margin)
if mirror_bounds.size.y != 0:
if child.get_global_position().y < (mirror_bounds.position.y - mirror_margin):
child.position.y += mirror_bounds.size.y + (2 * mirror_margin)
elif child.get_global_position().y > (mirror_bounds.position.y + mirror_bounds.size.y + mirror_margin):
child.position.y -= mirror_bounds.size.y + (2 * mirror_margin)
func set_camera(new_cam):
camera = new_cam
# initial offset so things are where they are
motion += get_global_position() - camera.get_global_position()