Skip to content

Instantly share code, notes, and snippets.

@Decapitated
Last active February 15, 2025 03:47
Show Gist options
  • Select an option

  • Save Decapitated/735dfc30e9c7139919e2b5c792e1a71b to your computer and use it in GitHub Desktop.

Select an option

Save Decapitated/735dfc30e9c7139919e2b5c792e1a71b to your computer and use it in GitHub Desktop.
A simple 2D curtain class.
@tool
class_name Curtains extends Node2D
@export_range(0.0, 100.0, 0.1,) var curtain_lerp: float = 50.0
@export_group("Rail", "rail_")
@export var rail_texture: Texture2D = null
@export_range(0.0, 500.0, 0.1, "or_greater") var rail_width: float = 500.0
@export_range(-1.0, 100.0, 0.1, "or_greater") var rail_thickness: float = 25.0
@export_range(0.0, 100.0, 0.1) var rail_max_width: float = 100.0
@export_range(0.0, 100.0, 0.1, "or_greater") var rail_end_padding: float = 0.0
@export_group("Curtains", "curtain_")
@export_tool_button("Perfect Width") var curtain_tb_perfect_width: Callable = func(): curtain_width = get_perfect_width()
@export var curtain_texture: Texture2D = null
@export var curtain_use_texture_size: bool = true
@export_range(2, 5, 1, "or_greater") var curtain_count: int = 5
@export_range(0.0, 500.0, 0.1, "or_greater") var curtain_width: float = 100.0
@export_range(0.0, 500.0, 0.1, "or_greater") var curtain_length: float = 500.0
@export_group("Debug", "debug_")
@export var debug_draw_rail: bool = false
@export var debug_draw_curtain_position: bool = false
@export var debug_draw_curtains: bool = false
func _process(_delta: float) -> void:
queue_redraw()
func _draw() -> void:
var rail_rect := Rect2(
Vector2(-rail_width / 2.0, -rail_thickness / 2.0),
Vector2(rail_width, rail_thickness))
if rail_texture:
draw_texture_rect(rail_texture, rail_rect, false)
if debug_draw_rail:
draw_rect(rail_rect, Color.BLACK)
draw_rect(rail_rect, Color.GREEN, false, 2.0)
var current_lerp_position := get_lerp_position(curtain_lerp / 100.0)
var real_lerp_positions := get_real_lerps(current_lerp_position)
for i in curtain_count:
var lerp_i: float = i / float(curtain_count - 1)
var curtain_position = real_lerp_positions[0].lerp(real_lerp_positions[1], lerp_i)
var curtain_rect := Rect2(
Vector2(-curtain_width / 2.0, 0.0) + curtain_position,
Vector2(curtain_width, curtain_length))
if curtain_texture:
if curtain_use_texture_size:
var texture_size := curtain_texture.get_size()
curtain_rect = Rect2(
Vector2(-texture_size.x / 2.0, 0.0) + curtain_position,
texture_size
)
draw_texture_rect(curtain_texture, curtain_rect, false)
if debug_draw_curtains:
draw_rect(curtain_rect, Color.BROWN)
draw_rect(curtain_rect, Color.WHITE, false, 2.0)
if debug_draw_curtain_position:
draw_circle(real_lerp_positions[0], rail_thickness / 2.0, Color.BLUE)
draw_circle(real_lerp_positions[0], rail_thickness / 2.0, Color.SKY_BLUE, false, 2.0)
draw_circle(real_lerp_positions[1], rail_thickness / 2.0, Color.BLUE)
draw_circle(real_lerp_positions[1], rail_thickness / 2.0, Color.SKY_BLUE, false, 2.0)
draw_circle(current_lerp_position, rail_thickness / 2.0, Color.RED)
draw_circle(current_lerp_position, rail_thickness / 2.0, Color.WHITE, false, 2.0)
func get_lerp_position(p_lerp: float) -> Vector2:
var right := get_right()
return (-right).lerp(right, p_lerp)
func get_real_lerps(current_lerp_position: Vector2) -> Array[Vector2]:
var right := get_right()
var right_vec := right - current_lerp_position
var max_length := right_vec.length()
if max_length > right.x:
max_length = (rail_width - rail_end_padding * 2.0) - max_length
max_length = min(get_usable_width() / 2.0, max_length)
return [
current_lerp_position + (-right).normalized() * max_length,
current_lerp_position + right.normalized() * max_length
]
func get_right() -> Vector2:
return Vector2(rail_width / 2.0 - rail_end_padding, 0.0)
func get_usable_width() -> float:
return rail_width * (rail_max_width / 100.0)
func get_perfect_width() -> float:
return rail_width / curtain_count * (1.0 + 1.0 / maxi(1, curtain_count - 1))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment