Files
przygody-pana-cegly/addons/rmsmartshape/normal_range.gd

100 lines
3.0 KiB
GDScript

@tool
extends Resource
class_name SS2D_NormalRange
## This class will determine if the normal of a vector falls within the specifed angle ranges.
##
## - if begin and end are equal, any angle is considered to be within range [br]
## - 360.0 and 0.0 degrees are considered equivilent [br]
@export_range (0, 360, 1) var begin: float = 0.0 : set = set_begin
@export_range (0, 360, 1) var distance: float = 0.0 : set = set_distance
# This is a hack to support the custom editor, needed a property
# to exist to lock the TextureProgressBar to. Makes it flow better
# in the Inspector.
@export var edgeRendering: Vector2
func set_distance(f: float) -> void:
distance = f
emit_changed()
func set_begin(f: float) -> void:
begin = f
emit_changed()
func _to_string() -> String:
return "NormalRange: %s - %s" % [begin, begin + distance]
static func get_angle_from_vector(vec: Vector2) -> float:
var normal: Vector2 = vec.normalized()
# With respect to the X-axis
# This is how Vector2.angle() is calculated, best to keep it consistent
var comparison_vector := Vector2(1, 0)
var ab: Vector2 = normal
var bc: Vector2 = comparison_vector
var dot_prod: float = ab.dot(bc)
var determinant: float = (ab.x * bc.y) - (ab.y * bc.x)
var angle: float = atan2(determinant, dot_prod)
# This angle has a range of 360 degrees
# Is between 180 and - 180
var deg: float = rad_to_deg(angle)
# Get range between 0.0 and 360.0
if deg < 0:
deg = 360.0 + deg
return deg
# Get in range between 0.0 and 360.0.
static func _get_positive_angle_deg(degrees: float) -> float:
while degrees < 0:
degrees += 360
return fmod(degrees, 360.0)
# Get in range between -360.0 and 360.0
static func _get_signed_angle_deg(degrees: float) -> float:
var new_degrees: float = degrees
while absf(new_degrees) > 360.0:
new_degrees += (360.0 * signf(degrees) * -1.0)
return new_degrees
# Saving a scene with this resource requires a parameter-less init method
func _init(_begin: float = 0.0, _distance: float = 0.0) -> void:
_begin = SS2D_NormalRange._get_signed_angle_deg(_begin)
_distance = SS2D_NormalRange._get_signed_angle_deg(_distance)
begin = _begin
distance = _distance
func is_in_range(vec: Vector2) -> bool:
# A Distance of 0 or 360 is the entire circle
if distance == 0 or SS2D_NormalRange._get_positive_angle_deg(distance) == 360.0:
return true
var begin_positive: float = SS2D_NormalRange._get_positive_angle_deg(begin)
var end_positive: float = SS2D_NormalRange._get_positive_angle_deg(begin + distance)
# If positive, counter clockwise direction
# If negative, clockwise direction
var direction: float = signf(distance)
var angle: float = SS2D_NormalRange.get_angle_from_vector(vec)
# Swap begin and end if direction is negative
if direction == -1:
var t: float = begin_positive
begin_positive = end_positive
end_positive = t
if begin_positive < end_positive:
return ((angle >= begin_positive) and (angle <= end_positive))
else:
return ((angle >= begin_positive) or (angle <= end_positive))