extends Node const IMAGE_WIDTH := 1024 const IMAGE_HEIGHT := 1048 const PLACEHOLDER_SEED_TEXTURE: Texture = preload("res://entities/plants/assets/sprites/default/seed.png") const PLACEHOLDER_MATURE_TEXTURE: Texture = preload("res://entities/plants/assets/sprites/default/mature.png") const PLACEHOLDER_GROWING_TEXTURE: Texture = preload("res://entities/plants/assets/sprites/default/growing.png") # @export var parts_archetype_associations: Dictionary[PlantArchetype, PartArchetypeAssociation] TODO:: have the archetypes @export var bases: Array[PlantPart] @export var baby_bases: Array[PlantPart] @export var branches: Array[PlantPart] @export var n_branches: int = 2 @export var base_leaves: Array[PlantPart] @export var parts_mutation_associations: Dictionary[String, PartMutationAssociation] var rng := RandomNumberGenerator.new() var image: Image = Image.create_empty(IMAGE_WIDTH, IMAGE_HEIGHT, false, Image.FORMAT_RGBA8) var image_center: Vector2i = Vector2(0.5, 1) * Vector2(image.get_size()) func random_ind(array: Array) -> int: return rng.randi_range(0, array.size() - 1) func pick_random(array: Array) -> Variant: return array[random_ind(array)] func shuffle(array: Array): var available_ind := 0 for i in range(array.size()): var temp = array[available_ind] var picked_ind := rng.randi_range(available_ind, array.size() - 1) array[available_ind] = array[picked_ind] array[picked_ind] = temp func build_seed_texture(_random_seed: int) -> Texture: return PLACEHOLDER_SEED_TEXTURE func build_plant_texture(plant_data: PlantData) -> Texture: rng.seed = plant_data.random_seed var mature_texture: Texture = PLACEHOLDER_MATURE_TEXTURE var base_part: PlantPart var base_image_coord: Vector2i var available_attaches: Array[PlantAttach] var parent_image_coords: Array[Vector2] var parts_to_place: Array[PlantPart] match plant_data.get_state(): PlantData.State.MATURE: # print("Build mature texture") # var plant_archetype := plant_data.archetype if bases.size() == 0: printerr("No base in archetype") return mature_texture # var base_part: PlantPart = pick_random(parts_archetype_associations[plant_archetype].bases) base_part = pick_random(bases) var base_image := base_part.image var base_image_center: Vector2i = 0.5 * base_image.get_size() base_image_coord = image_center - Vector2i(base_part.root.position) image.blend_rect(base_image, Rect2i(Vector2i.ZERO, base_image.get_size()), base_image_coord - base_image_center) if branches.size() == 0: printerr("No branches in archetype") # var branch_parts: Array[PlantPart] = parts_archetype_associations[plant_archetype].branches for i in n_branches: parts_to_place.append(pick_random(branches)) for m in plant_data.mutations: # print("mutations: ", m.id) var association: PartMutationAssociation = parts_mutation_associations[m.id] var mutation_possible_parts := association.parts for p in association.part_amount: parts_to_place.append(pick_random(mutation_possible_parts)) PlantData.State.GROWING: # print("Build growing texture") # var plant_archetype := plant_data.archetype if baby_bases.size() == 0: printerr("No baby base in archetype") return mature_texture # var base_part: PlantPart = pick_random(parts_archetype_associations[plant_archetype].baby_bases) base_part = pick_random(baby_bases) var base_image := base_part.image var base_image_center: Vector2i = 0.5 * base_image.get_size() base_image_coord = image_center - Vector2i(base_part.root.position) image.blend_rect(base_image, Rect2i(Vector2i.ZERO, base_image.get_size()), base_image_coord - base_image_center) for m in plant_data.mutations: # print("mutations: ", m.id) var association: PartMutationAssociation = parts_mutation_associations[m.id] var mutation_possible_parts := association.parts for p in ceil(0.5 * association.part_amount): parts_to_place.append(pick_random(mutation_possible_parts)) _: print("Not handled state") return null available_attaches = base_part.attaches.duplicate() parent_image_coords.resize(available_attaches.size()) parent_image_coords.fill(base_image_coord) for part: PlantPart in parts_to_place: # print("Add part : ", part.resource_name) var ind := find_random_matching_attach_ind(part.root, available_attaches) if ind == -1: printerr("No attach found") continue var attach: PlantAttach = available_attaches.pop_at(ind) var parent_image_coord: Vector2i = parent_image_coords.pop_at(ind) var part_image: Image = part.image var part_image_center: Vector2i = 0.5 * part_image.get_size() var part_image_coord: Vector2i = parent_image_coord + Vector2i(attach.position - part.root.position) image.blend_rect(part_image, Rect2i(Vector2i.ZERO, part.image.get_size()), part_image_coord - part_image_center) for sub_attach in part.attaches: available_attaches.append(sub_attach) parent_image_coords.append(part_image_coord) mature_texture = ImageTexture.create_from_image(image) image.fill(Color.TRANSPARENT) return mature_texture ## returns -1 if not found func find_random_matching_attach_ind(attach_to_match: PlantAttach, array: Array[PlantAttach]) -> int: var indices: Array = range(array.size()) shuffle(indices) for i in indices: if array[i].attach_types.any(func(type): return attach_to_match.attach_types.has(type)): return i return -1