class_name HardCards extends Node2D static var source_dicts: Array[Dictionary] = [ { "c_out_of_world": ["p_unique", "p_few_friends", []], "c_rejection": ["p_finding_friends", "p_laughed_at", []], "c_confusion": ["p_inner_conflict", "p_outer_conflict", []] }, { "c_homework": ["p_good_grades", "p_upset_peers", []], "c_teachers": ["p_volunteering", "p_becoming_teacher", []], "c_joy": ["p_worried_mother", "p_thomas_gifted", []] }, { "c_comic_heroes": ["p_effort", "p_agent_q", []], "c_boy_stuff": ["p_pretending", "p_girls", []], "c_teasing": ["p_stubborn", "p_good_intended", ["p_thomas_gifted"]] }, { "c_jui_jutsu": ["p_body", "p_girly", []], "c_void": ["p_wet", "p_stop", []], "c_hit": ["p_confidence", "p_vent", ["p_becoming_teacher"]] }, ] static var id_reference: Dictionary[StringName, StringName] = generate_id_reference(true, true) static var card_id_reference: Dictionary[StringName, StringName] = generate_id_reference(true, false) static var sticky_id_reference: Dictionary[StringName, StringName] = generate_id_reference(false, true) static func generate_id_reference(include_cards: bool, include_sticky: bool) -> Dictionary[StringName, StringName]: var out:Dictionary[StringName, StringName] = {} for id in range(source_dicts.size()): for card_name:String in source_dicts[id].keys(): if include_cards: out[card_name] = "%d.%s" % [id, card_name] if include_sticky: for sticky_name in source_dicts[id][card_name]: if sticky_name is String: out[sticky_name] = "%d.%s.%s" % [id, card_name, sticky_name] return out static func get_child_names_of(parent_id: StringName) -> Array[StringName]: var out: Array[StringName] for child_name: StringName in id_reference.keys(): if id_reference[child_name].contains(parent_id): if child_name != parent_id: out.append(child_name) return out #FIXME: enhance typing! static func get_children_of(parent_id: StringName) -> Array: return get_cards_by_name_array(get_child_names_of(parent_id))["sticky_notes"] func arrange(cards: Array[Card], rect: Rect2, obstacles: Array[Area2D]) -> Array[Card]: var total_cards = cards.size() var x:int = 0 var y:int = 0 var i:int = 0 var max:int = cards.size() var grid: int = ceil(sqrt(max)) var diameter:float = cards[0].diameter var r_cards: Array[Card] = cards.duplicate() r_cards.shuffle() while i < max: while x < grid and i < max: while y < ceil(sqrt(max)) and i < max: r_cards[i].position = rect.size / Vector2(y, x) * (1.0 / (rect.size.x * diameter) ) + rect.position + Vector2(randf_range(diameter/2+5, diameter-5), randf_range(diameter/2+5, diameter-5)) i += 1 y += 1 x += 1 for card: Card in r_cards: for _i in range(20): if is_out_of_bounds(card, rect): card.position = rect.get_center() - card.position * 0.8 continue var colliders: Array[Card] = [] for collision:Card in r_cards: if card != collision: if card.collider.collide(card.transform.rotated(PI/2), collision.collider, collision.transform.rotated(PI/2)): colliders.append(collision) if colliders != []: var nearest: Card = colliders[0] for colliding in colliders: if (colliding.position - card.position).length() > (nearest.position - card.position).length(): nearest = colliding card.position += min(nearest.position - card.position.normalized() * card.diameter + 1, nearest.position - card.position) continue break return r_cards func is_out_of_bounds(card: Card, rect: Rect2): var world_boundaries: Array[Transform2D] = [ Transform2D(PI, rect.position), Transform2D(PI/2, rect.position), Transform2D(-PI/2, rect.position+rect.size), Transform2D(0, rect.position+rect.size) ] var shape: = WorldBoundaryShape2D.new() for boundary:Transform2D in world_boundaries: if card.collider.collide(card.transform, shape, boundary): return true return false static func get_cards_by_scene_id(id: int) -> Array: var output:Array for card_name in source_dicts[id].keys(): output.append(Card.new(card_name, id_reference[card_name])) return output # used to put cards on the dev board static func get_cards_by_name_array(names: Array[StringName]) -> Dictionary: var output:Dictionary = { "cards": [], "sticky_notes": [] } for card_name:StringName in names: if card_id_reference.has(card_name): output["cards"].append(create_from_id(id_reference[card_name])) else: output["sticky_notes"].append(create_from_id(id_reference[card_name])) return output static func create_from_id(id:StringName) -> Area2D: var parsed: PackedStringArray = id.rsplit(".") var helper = card_id_reference var keys = card_id_reference.keys() if card_id_reference.values().has(id): return Card.new(parsed[1], id) elif sticky_id_reference.values().has(id): return StickyNote.new(parsed[2], id) else: push_error("Attempted to create Card or Sticky from non-existent ID!") return null static func create_dev_board(parent: Node2D, rect: Rect2) -> void: for x in range(source_dicts.size()): var sub_parent = Node2D.new() sub_parent.position = Vector2( rect.size.x/(source_dicts.size()+1) * (x+1) , 0) parent.add_child(sub_parent, false, Node.INTERNAL_MODE_BACK) var y = 1 for card_name in source_dicts[x].keys(): var card:Card = create_from_id(card_id_reference[card_name]) sub_parent.add_child(card, false, Node.INTERNAL_MODE_BACK) card.position = Vector2(0, card.diameter * y - card.diameter/2) var z = 0 for sticky_name in get_child_names_of(card_name): var sticky: StickyNote = create_from_id(sticky_id_reference[sticky_name]) card.add_child(sticky, false, Node.INTERNAL_MODE_BACK) sticky.position = card.sticky_note_position + Vector2(0, 80) * z z += 1 y += 1 func _ready() -> void: create_dev_board(self, get_viewport().get_visible_rect())