195 lines
8.7 KiB
GDScript
195 lines
8.7 KiB
GDScript
extends Node
|
|
|
|
const IMAGE_WIDTH := 1000
|
|
const IMAGE_HEIGHT := 2000
|
|
|
|
const SEED_TEXTURE_SIZE = 150
|
|
|
|
const COLOR_PALETTE : Array[Color] = [
|
|
Color("#78AEBA"),
|
|
Color("#A7B35B"),
|
|
Color("#DB6B75"),
|
|
Color("#EC8E49"),
|
|
Color("#F9FFCE"),
|
|
]
|
|
|
|
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 parts_mutation_associations: Dictionary[String, PartMutationAssociation]
|
|
@export var seed_texture_sets: Array[SeedTextureSet]
|
|
|
|
var rng := RandomNumberGenerator.new()
|
|
|
|
func build_seed_texture(random_seed: int) -> Texture:
|
|
rng.seed = random_seed
|
|
|
|
var texture_set : SeedTextureSet = pick_random(seed_texture_sets)
|
|
var image := Image.create(SEED_TEXTURE_SIZE,SEED_TEXTURE_SIZE, false, Image.FORMAT_RGBA8)
|
|
|
|
for color_texture in texture_set.color_textures:
|
|
var color_image = color_texture.get_image().duplicate()
|
|
color_image.resize(SEED_TEXTURE_SIZE,SEED_TEXTURE_SIZE)
|
|
modulate_image(color_image, pick_random(COLOR_PALETTE))
|
|
image.blend_rect(
|
|
color_image,
|
|
Rect2i(0,0,SEED_TEXTURE_SIZE,SEED_TEXTURE_SIZE),
|
|
Vector2i.ZERO
|
|
)
|
|
if texture_set.outline_texture:
|
|
var outline_image = texture_set.outline_texture.get_image().duplicate()
|
|
outline_image.resize(SEED_TEXTURE_SIZE,SEED_TEXTURE_SIZE)
|
|
image.blend_rect(outline_image, Rect2i(0,0,SEED_TEXTURE_SIZE,SEED_TEXTURE_SIZE),Vector2i.ZERO)
|
|
|
|
if rng.randi()%2 == 0:
|
|
image.flip_x()
|
|
|
|
return ImageTexture.create_from_image(image)
|
|
|
|
func build_plant_texture(plant_data: PlantData) -> Texture:
|
|
rng.seed = plant_data.random_seed
|
|
|
|
var mature_texture: Texture = PLACEHOLDER_MATURE_TEXTURE
|
|
var mature_image: Image = Image.create_empty(IMAGE_WIDTH, IMAGE_HEIGHT, false, Image.FORMAT_RGBA8)
|
|
var mature_image_center: Vector2i = 0.5 * mature_image.get_size()
|
|
var branch_parts: Array[PlantPart]
|
|
var base_part: PlantPart
|
|
var available_base_attaches: Array[Vector2]
|
|
var available_base_bottom_attach: Array[Vector2]
|
|
var branch_attaches: Array[Vector2]
|
|
var branch_root: Array[Vector2]
|
|
var branch_parent_attach: 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.texture.get_image()
|
|
var base_image_center: Vector2i = 0.5 * base_image.get_size()
|
|
mature_image.blend_rect(base_image, Rect2i(Vector2i.ZERO, base_image.get_size()), mature_image_center - base_image_center - Vector2i(base_part.root))
|
|
|
|
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:
|
|
branch_parts.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.texture.get_image()
|
|
var base_image_center: Vector2i = 0.5 * base_image.get_size()
|
|
mature_image.blend_rect(base_image, Rect2i(Vector2i.ZERO, base_image.get_size()), mature_image_center - base_image_center - Vector2i(base_part.root))
|
|
|
|
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_base_attaches = base_part.attaches.duplicate()
|
|
available_base_bottom_attach = base_part.bottom_attaches.duplicate()
|
|
|
|
assert(branch_parts.size() <= base_part.attaches.size(),
|
|
str("More branches (", branch_parts.size(), ") than base attaches (", base_part.attaches.size(), ")"))
|
|
|
|
for branch in branch_parts:
|
|
if available_base_attaches.size() == 0:
|
|
break
|
|
|
|
var ind: int = rng.randi_range(0, available_base_attaches.size() - 1)
|
|
var attach: Vector2 = available_base_attaches.pop_at(ind)
|
|
|
|
var branch_image: Image = branch.texture.get_image()
|
|
var branch_image_center: Vector2i = 0.5 * branch_image.get_size()
|
|
mature_image.blend_rect(branch_image, Rect2i(Vector2i.ZERO, branch.texture.get_size()), mature_image_center - branch_image_center + Vector2i(attach - branch.root - base_part.root))
|
|
|
|
for branch_attach in branch.attaches:
|
|
branch_attaches.append(branch_attach)
|
|
branch_root.append(branch.root)
|
|
branch_parent_attach.append(attach)
|
|
|
|
if parts_to_place.size() > branch_attaches.size() + base_part.attaches.size() - branch_parts.size():
|
|
printerr("ERROR generating : Parts to place : ", parts_to_place.size(),
|
|
"; Branch Attaches : ", branch_attaches.size(),
|
|
"; Base attaches : ", base_part.attaches.size(),
|
|
"; Branch parts : ", branch_parts.size())
|
|
|
|
for part: PlantPart in parts_to_place:
|
|
print("create part")
|
|
var attach: Vector2
|
|
var parent_root: Vector2
|
|
var chosen_attach_type: int = 0
|
|
var attachables: Array[int]
|
|
if part.base_attachable && available_base_attaches.size() > 0:
|
|
attachables.append(1)
|
|
if part.bottom_attachable && available_base_bottom_attach.size() > 0:
|
|
attachables.append(2)
|
|
if part.branch_attachable && branch_attaches.size() > 0:
|
|
attachables.append(3)
|
|
# assert(attachables.size() > 0)
|
|
if attachables.size() == 0:
|
|
print("No attach available")
|
|
continue
|
|
chosen_attach_type = pick_random(attachables)
|
|
|
|
if chosen_attach_type == 1: # base attach
|
|
var ind := rng.randi_range(0, available_base_attaches.size() - 1)
|
|
attach = available_base_attaches.pop_at(ind)
|
|
parent_root = base_part.root
|
|
elif chosen_attach_type == 2: # bottom
|
|
var ind := rng.randi_range(0, available_base_bottom_attach.size() - 1)
|
|
attach = available_base_bottom_attach.pop_at(ind)
|
|
parent_root = base_part.root
|
|
elif chosen_attach_type == 3: # branch
|
|
var ind := rng.randi_range(0, branch_attaches.size() - 1)
|
|
attach = branch_attaches.pop_at(ind) - branch_root.pop_at(ind) + branch_parent_attach.pop_at(ind)
|
|
parent_root = base_part.root
|
|
|
|
var part_image: Image = part.texture.get_image()
|
|
var part_image_center: Vector2i = 0.5 * part_image.get_size()
|
|
var relative_root_centered_pos: Vector2 = Vector2(mature_image_center - part_image_center) - part.root
|
|
mature_image.blend_rect(part_image, Rect2i(Vector2i.ZERO, part.texture.get_size()), relative_root_centered_pos + attach - parent_root)
|
|
|
|
if rng.randi() % 2 == 0:
|
|
mature_image.flip_x()
|
|
mature_texture = ImageTexture.create_from_image(mature_image)
|
|
return mature_texture
|
|
|
|
func pick_random(array: Array):
|
|
return array[rng.randi_range(0, array.size() - 1)]
|
|
|
|
func modulate_image(i : Image, color : Color):
|
|
for x in i.get_size().x:
|
|
for y in i.get_size().y:
|
|
i.set_pixel(x,y, i.get_pixel(x,y)*color) |