ajhahn.de
← Theria
GDScript 226 lines
@tool
extends Node2D

class Eyeball:
	extends Node2D

	var _should_draw_laser = false
	var _laser_end_pos = Vector2.ZERO
	var _laser_timer : Timer = null
	var _color_tween : Tween
	var _size_tween : Tween

	var sprite : Sprite2D = null
	var default_position = Vector2(0, 0)
	var move_radius = 25
	var move_center = Vector2(0, 0)
	var default_color = Color(0.31, 0.31, 0.31)
	var _color = default_color :
		set(val):
			_color = val
			queue_redraw()
	var color = _color :
		set(val):
			_start_color_tween(_color, val)
		get(): return _color
	var default_size = 70
	var _size = default_size :
		set(val):
			_size = val
			queue_redraw()
	var size = _size :
		set(val):
			_start_size_tween(_size, val)
		get(): return _size


	func _init(node):
		sprite = node
		default_position = sprite.position
		move_center = sprite.position
		# hijack the original sprite, because I want to draw it here but keep
		# the original in the scene for layout.
		position = sprite.position
		sprite.get_parent().add_child(self)
		sprite.visible = false


	func _ready():
		_laser_timer = Timer.new()
		_laser_timer.wait_time = .1
		_laser_timer.one_shot = true
		add_child(_laser_timer)
		_laser_timer.timeout.connect(func():  _should_draw_laser = false)


	func _process(_delta):
		if(_should_draw_laser):
			queue_redraw()


	func _start_color_tween(old_color, new_color):
		if(_color_tween != null and _color_tween.is_running()):
			_color_tween.kill()
		_color_tween = create_tween()
		_color_tween.tween_property(self, '_color', new_color, .3).from(old_color)
		_color_tween.play()


	func _start_size_tween(old_size, new_size):
		if(_size_tween != null and _size_tween.is_running()):
			_size_tween.kill()
		_size_tween = create_tween()
		_size_tween.tween_property(self, '_size', new_size, .3).from(old_size)
		_size_tween.play()


	var _laser_size = 20.0
	func _draw() -> void:
		draw_circle(Vector2.ZERO, size, color, true, -1, true)
		if(_should_draw_laser):
			var end_pos = (_laser_end_pos - global_position) * 2
			var laser_size = _laser_size * (float(size)/float(default_size))
			draw_line(Vector2.ZERO, end_pos, color, laser_size)
			draw_line(Vector2.ZERO, end_pos, Color(1, 1, 1, .5), laser_size * .8)


	# There's a bug in here where the eye shakes like crazy.  It's a feature
	# now.  Don't fix it.
	func look_at_local_position(local_pos):
		var dir = position.direction_to(local_pos)
		var dist = position.distance_to(local_pos)
		position = move_center + (dir * min(dist, move_radius))
		position.x = clamp(position.x, move_center.x - move_radius, move_center.x + move_radius)
		position.y = clamp(position.y, move_center.y - move_radius, move_center.y + move_radius)


	func reset():
		color = default_color
		size = default_size


	func eye_laser(global_pos):
		_should_draw_laser = true
		_laser_end_pos = global_pos
		_laser_timer.start()


	func _stop_laser():
		_should_draw_laser = false



# ------------------------------------------------------------------------------
# ------------------------------------------------------------------------------
var GutEditorGlobals = load('res://addons/gut/gui/editor_globals.gd')
# Active means it's actively doing stuff.  When this is not active the eyes
# won't follow, but you can still make the sizes change by calling methods on
# this.
@export var active = false :
	set(val):
		active = val
		if(!active and is_inside_tree()):
			left_eye.position = left_eye.default_position
			right_eye.position = right_eye.default_position
# When disabled, this will reset to default and you can't make it do anything.
@export var disabled = false :
	set(val):
		disabled = val
		if(disabled and is_inside_tree()):
			left_eye.position = left_eye.default_position
			right_eye.position = right_eye.default_position
			left_eye.reset()
			right_eye.reset()
			modulate = Color.GRAY
			$BaseLogo.texture = _no_shine
		else:
			$BaseLogo.texture = _normal
			modulate = Color.WHITE

@onready var _reset_timer = $ResetTimer
@onready var _face_button = $FaceButton
@onready var left_eye : Eyeball = Eyeball.new($BaseLogo/LeftEye)
@onready var right_eye : Eyeball = Eyeball.new($BaseLogo/RightEye)

var _no_shine = load("res://addons/gut/images/GutIconV2_no_shine.png")
var _normal = load("res://addons/gut/images/GutIconV2_base.png")
var _is_in_edited_scene = false

signal pressed

func _debug_ready():
	position = Vector2(500, 500)
	active = true


func _ready():
	_is_in_edited_scene = GutEditorGlobals.is_being_edited_in_editor(self)

	if(get_parent() == get_tree().root):
		_debug_ready()

	disabled = disabled
	active = active
	left_eye.move_center.x -= 20
	right_eye.move_center.x += 10
	_face_button.modulate.a = 0.0


func _process(_delta):
	if(active and !disabled and !_is_in_edited_scene):
		left_eye.look_at_local_position(get_local_mouse_position())
		right_eye.look_at_local_position(get_local_mouse_position())


# ----------------
# Events
# ----------------
func _on_reset_timer_timeout() -> void:
	left_eye.reset()
	right_eye.reset()


func _on_face_button_pressed() -> void:
	pressed.emit()


# ----------------
# Public
# ----------------
func set_eye_scale(left, right=left):
	if(disabled or _is_in_edited_scene):
		return
	left_eye.size = left_eye.default_size * left
	right_eye.size = right_eye.default_size * right
	_reset_timer.start()


func reset_eye_size():
	if(disabled or _is_in_edited_scene):
		return
	left_eye.size = left_eye.default_size
	right_eye.size = right_eye.default_size


func set_eye_color(left, right=left):
	if(disabled or _is_in_edited_scene):
		return
	left_eye.color = left
	right_eye.color = right
	_reset_timer.start()


func reset_eye_color():
	if(disabled or _is_in_edited_scene):
		return
	left_eye.color = left_eye.default_color
	right_eye.color = right_eye.default_color


# I removed the eye lasers because they aren't ready yet.  I've already spent
# too much time on this logo.  It's great, I love it...but it's been long
# enough.  This gives me, or someone else, something to do later.
#func eye_lasers(global_pos):
	#left_eye.eye_laser(global_pos)
	#right_eye.eye_laser(global_pos)