PlayerCamera2 WIP

This commit is contained in:
Rakarake 2025-09-05 11:50:01 +02:00
parent 7641aa5d3e
commit d343c458a2
9 changed files with 147 additions and 30 deletions

View file

@ -190,4 +190,3 @@ func _on_filter_text_changed() -> void:
var sf = get_node(stat_filter) var sf = get_node(stat_filter)
for child in categories.get_children(): for child in categories.get_children():
child.visible = child.name.contains(sf.text) || sf.text == "" child.visible = child.name.contains(sf.text) || sf.text == ""

View file

@ -1,22 +1,10 @@
extends Node2D extends Node2D
class_name CameraProperties class_name CameraProperties
## In the camera stack, all these values have to be set at some point.
## x: transition time, y: completeness of transition (0.0 to 1.0) ## x: transition time, y: completeness of transition (0.0 to 1.0)
@export var transform_curve: Curve = null @export var transform_curve: Curve = null
## x: transition time, y: completeness of transition (0.0 to 1.0) @export var limits: Limits = null
@export var limits_curve: Curve = null @export var smoothing : Float = null
## x: transition time, y: completeness of transition (0.0 to 1.0)
@export var smoothing_curve: Curve = null
## The leftomost point of the screen will not pass this coordinate
@export var limit_left := -10000000
## -||-
@export var limit_right := 10000000
## -||-
@export var limit_top := -10000000
## -||-
@export var limit_bottom := 10000000
## The smoothing of the camera.
@export var smoothing := 8.0

View file

@ -0,0 +1,19 @@
extends Resource
class_name Limits
@export var left: float
@export var right: float
@export var top: float
@export var bottom: float
func _init(
p_left = -10000000,
p_right = 10000000,
p_top = - 10000000,
p_bottom = 10000000
):
left = p_left
right = p_right
top = p_top
bottom = p_bottom

View file

@ -0,0 +1 @@
uid://dbhp6ek2kwibq

View file

@ -1,7 +1,6 @@
extends Node2D extends Node2D
# TODO make "original properties" into "previous targets" for more natural @export var original_properties: NodePath
# transitions.
## If enabled, takes control of viewport transform. ## If enabled, takes control of viewport transform.
@export var enabled := false @export var enabled := false
@ -49,7 +48,6 @@ var example_properties := {
@onready var camera_stack : Array[CameraProperties] = [ get_node(fallback_properties) ] @onready var camera_stack : Array[CameraProperties] = [ get_node(fallback_properties) ]
## Schema: { <property_name>: <property_progress> (seconds) } ## Schema: { <property_name>: <property_progress> (seconds) }
var property_progress := {} var property_progress := {}
var original_properties := {}
## Used for smoothing ## Used for smoothing
## Schema: { <property_name>: <reference to node> } ## Schema: { <property_name>: <reference to node> }
var current_properties := {} var current_properties := {}
@ -99,7 +97,7 @@ func _reset(op):
if p_to_c[key] != new_p_to_c[key]: if p_to_c[key] != new_p_to_c[key]:
# reset timer # reset timer
property_progress[key] = 0.0 property_progress[key] = 0.0
original_properties[key] = p_to_c[key] get_node(original_properties)[key] = p_to_c[key]
func remove_camera(c): func remove_camera(c):
var op = func(): camera_stack.erase(c) var op = func(): camera_stack.erase(c)
@ -134,6 +132,9 @@ func reset_smoothing():
for p in properties: for p in properties:
original_properties[p] = _get_camera(p) original_properties[p] = _get_camera(p)
func _clamp_with_limits(value: Vector2, limits_node) -> Vector2:
pass
func _process(delta: float): func _process(delta: float):
# Lookaside (x-pan) # Lookaside (x-pan)
var target_pos = look_aside if looking_right else - look_aside var target_pos = look_aside if looking_right else - look_aside
@ -155,18 +156,16 @@ func _process(delta: float):
) )
var smoothing = current_properties["smoothing"] var smoothing = current_properties["smoothing"]
_property_step("limits", func(fraction, old, target_node): _property_step("limits", func(fraction, old, target_node):
var intermediate_left = lerpf(old.limit_left, target_node.limit_left, fraction) current_properties["limits"]["left"] = target_node.limit_left
current_properties["limits"]["left"] = lerpf(current_properties["limits"]["left"], intermediate_left, smoothing * delta) current_properties["limits"]["right"] = target_node.limit_right
var intermediate_right = lerpf(old.limit_right, target_node.limit_right, fraction) current_properties["limits"]["top"] = target_node.limit_top
current_properties["limits"]["right"] = lerpf(current_properties["limits"]["right"], intermediate_right, smoothing * delta) current_properties["limits"]["bottom"] = target_node.limit_bottom
var intermediate_top = lerpf(old.limit_top, target_node.limit_top, fraction)
current_properties["limits"]["top"] = lerpf(current_properties["limits"]["top"], intermediate_top, smoothing * delta)
var intermediate_bottom = lerpf(old.limit_bottom, target_node.limit_bottom, fraction)
current_properties["limits"]["bottom"] = lerpf(current_properties["limits"]["bottom"], intermediate_bottom, smoothing * delta)
) )
_property_step("transform", func(fraction, old, target_node): _property_step("transform", func(fraction, old, target_node):
# We are not interested in inherited transform properties except for position # We are not interested in inherited transform properties except for position
var end_target = target_node.transform.translated(target_node.global_transform.origin) var end_target_pos = _clamp_with_limits(target_node.transform.global_transform, _get_camera("limits"))
var end_target = target_node.transform.translated(end_target_pos)
var old_target = old.transform.translated(old.global_transform.origin) var old_target = old.transform.translated(old.global_transform.origin)
var intermediate_target: Transform2D = old_target.interpolate_with(end_target, fraction) var intermediate_target: Transform2D = old_target.interpolate_with(end_target, fraction)

View file

@ -0,0 +1,101 @@
extends Node
## If enabled, takes control of viewport transform.
@export var enabled := false
## Enables outputting debug info for this camera. Shows center of camera gizmo if gizmos are turned on.
## Outputs properties to debug screen.
@export var debug_show := false
var properties := ["transform", "smoothing", "limits"]
## The default camera properties.
@export var fallback_properties: NodePath
## Used to store nodes of properties of A during transition A -> B.
var _original_properties := {}
## Stack of references to CamerProperties
@onready var _camera_stack : Array[CameraProperties] = [ get_node(fallback_properties) ]
var _transition_progress := 1.0
var _current_transform: Transform2D = Transform2D.IDENTITY
func reset_smoothing():
_transition_progress = 1.0
## Finds the active CameraProperties for a given property.
## depth can be specified to get the camera of second/third/... priority.
func _get_camera(property: String, depth: int = 0):
var current_depth := depth
for i in _camera_stack.size():
var index = _camera_stack.size() -1 -i
var c = _camera_stack[index]
# Clean up destroyed cameras
if c == null:
_camera_stack.remove_at(index)
else:
var null_check_name = "transform_curve" if property == "transform" else property
if c[null_check_name] != null:
if current_depth <= 0:
return c
else:
current_depth -= 1
# there wasn't a camera with this depth? try getting one with higher priority
return _get_camera(property, depth - 1)
## Set timers and original properties on properites that changed after operation "op".
func _reset(op):
var p_to_c := {}
# get list of destination cameras for every property
for p in properties:
p_to_c[p] = _get_camera(p)
# remove/add camera
op.call()
# get list of destination cameras for every property
var new_p_to_c := {}
for p in properties:
new_p_to_c[p] = _get_camera(p)
# reset transition timer
if p_to_c["transform"] != new_p_to_c["transform"]:
_transition_progress = 1.0
# set original properties
for key in p_to_c:
if p_to_c[key] != new_p_to_c[key]:
_original_properties[key] = p_to_c[key]
func _clamp_with_limits(value: Vector2, limits: Limits, middle_offset: Vector2) -> Vector2:
return Vector2(
clampf(value.x, limits.left + middle_offset.x, limits.right - middle_offset.x),
clampf(value.y, limits.top + middle_offset.y, limits.bottom - middle_offset.y)
)
func _process(delta: float):
if enabled:
# the offset of the viewport to account for the screen size
var middle_offset: Vector2 = get_viewport().content_scale_size / 2
# update position
var target_node = _get_camera("transform")
var target_pos = _clamp_with_limits(target_node.transform.global_transform, _get_camera("limits").limits, middle_offset)
var target_transform = target_node.transform.translated(target_pos)
var original_node = _original_properties["transform"]
var original_pos = _clamp_with_limits(target_node.transform.global_transform, _original_properties["limits"].limits, middle_offset)
var original_transform = original_node.transform.translated(original_pos)
var intermediate_fraction = _get_camera("transform").transform_curve.sample(_transition_progress)
var intermediate_transform: Transform2D = original_transform.interpolate_with(target_transform, intermediate_fraction)
var smoothing = _get_camera("smoothing").smoothing.value
# interpolate between _current_transform and intermediate_transform
_current_transform.interpolate_with(intermediate_transform, smoothing * delta)
# apply to viewport
get_viewport().canvas_transform = _current_transform.inverse().translated(middle_offset)

View file

@ -0,0 +1 @@
uid://60wby2r3n4tx

View file

@ -0,0 +1,8 @@
extends Resource
class_name Float
@export var val: float = 0.0
func _init(p_val = 0.0):
val = p_val

View file

@ -0,0 +1 @@
uid://bmuu0n34auwaq