maxgame/addons/popochiu/engine/cursor/cursor.gd
2025-07-17 01:49:18 -04:00

168 lines
3.8 KiB
GDScript

class_name PopochiuCursor
extends CanvasLayer
# TODO: Deprecate this? I'll leave it here while we merge the refactor for the
# creation popups because in those the Cursor.Type enum is used.
enum Type {
NONE,
ACTIVE,
DOWN,
IDLE,
LEFT,
LOOK,
RIGHT,
SEARCH,
TALK,
UP,
USE,
WAIT,
}
@export var is_pixel_perfect := false
var is_blocked := false
@onready var main_cursor: AnimatedSprite2D = $MainCursor
@onready var secondary_cursor: Sprite2D = $SecondaryCursor
#region Godot ######################################################################################
func _init() -> void:
Engine.register_singleton(&"Cursor", self)
func _ready():
Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN)
# Connect to autoload signals
PopochiuUtils.e.ready.connect(show_cursor)
func _process(delta):
var texture_size := (main_cursor.sprite_frames.get_frame_texture(
main_cursor.animation,
main_cursor.frame
) as Texture2D).get_size()
var mouse_position: Vector2 = main_cursor.get_global_mouse_position()
if is_pixel_perfect:
# Thanks to @whyshchuck
main_cursor.position = Vector2i(mouse_position)
secondary_cursor.position = Vector2i(mouse_position)
else:
main_cursor.position = mouse_position
secondary_cursor.position = mouse_position
if main_cursor.position.x < 1.0:
main_cursor.position.x = 1.0
elif main_cursor.position.x > PopochiuUtils.e.width - 2.0:
main_cursor.position.x = PopochiuUtils.e.width - 2.0
if main_cursor.position.y < 1.0:
main_cursor.position.y = 1.0
elif main_cursor.position.y > PopochiuUtils.e.height - 2.0:
main_cursor.position.y = PopochiuUtils.e.height - 2.0
#endregion
#region Public #####################################################################################
func show_cursor(anim_name := "normal", ignore_block := false) -> void:
if not ignore_block and is_blocked: return
if (
not anim_name.is_empty()
and not main_cursor.sprite_frames.has_animation(anim_name)
):
PopochiuUtils.print_error("Cursor has no animation: %s" % anim_name)
return
main_cursor.play(anim_name)
main_cursor.show()
secondary_cursor.hide()
func set_secondary_cursor_texture(texture: Texture2D, ignore_block := false) -> void:
if not ignore_block and is_blocked: return
secondary_cursor.texture = texture
if PopochiuUtils.e.settings.scale_gui:
# Scale the cursor based the relation of the texture size compared to the main cursor
# texture size
secondary_cursor.scale = Vector2.ONE * ceil(
float(texture.get_height()) / float(get_cursor_height())
)
secondary_cursor.show()
func remove_secondary_cursor_texture() -> void:
secondary_cursor.texture = null
if PopochiuUtils.e.settings.scale_gui:
secondary_cursor.scale = PopochiuUtils.e.scale
secondary_cursor.hide()
func toggle_visibility(is_visible: bool) -> void:
main_cursor.visible = is_visible
secondary_cursor.visible = is_visible
func block() -> void:
is_blocked = true
func unblock() -> void:
is_blocked = false
func scale_cursor(factor: Vector2) -> void:
secondary_cursor.scale = factor
main_cursor.scale = factor
func get_position() -> Vector2:
return secondary_cursor.position
func replace_frames(new_node: AnimatedSprite2D) -> void:
main_cursor.sprite_frames = new_node.sprite_frames
main_cursor.offset = new_node.offset
func hide_main_cursor() -> void:
main_cursor.hide()
func show_main_cursor() -> void:
main_cursor.show()
func hide_secondary_cursor() -> void:
secondary_cursor.hide()
func show_secondary_cursor() -> void:
secondary_cursor.show()
func get_type_name(idx: int) -> String:
return Type.keys()[idx].to_snake_case()
func get_cursor_height() -> int:
var height := 0
if main_cursor.visible:
height = main_cursor.sprite_frames.get_frame_texture(main_cursor.animation, 0).get_height()
elif secondary_cursor.visible:
height = secondary_cursor.texture.get_height()
return height
#endregion