[gd_scene load_steps=6 format=3 uid="uid://x4kv2y5f52cm"] [ext_resource type="Texture2D" uid="uid://b3kjaw1hajc6s" path="res://assets/grille_seeds.png" id="1_n5onq"] [sub_resource type="GDScript" id="GDScript_x3g5o"] script/source = "class_name Plant extends Node2D enum PlantState { SAPLING, GROWN, DEAD} signal grown signal died @onready var growing_timer: Timer = $Growing @onready var need_checker: Timer = $NeedChecker @onready var sapling_count_down: Timer = $SaplingCountDown @onready var reproduction: Timer = $Reproduction @onready var sprite_node: AnimatedSprite2D = $AnimatedSprite2D const NEED_CHECK_PERIOD := 0.5 const SAPLING_LIFETIME_MULT := 2.0 # this multiplies the time to grow to tell the time it can stay as a sapling const OFFSET_REPRODUCTION_PERCT_DIST := 0.5 var parameter: PlantType var state := PlantState.SAPLING var sapling_time_left: float var can_grow := true func init(plant_parameter: PlantType): parameter = plant_parameter sapling_count_down.start(SAPLING_LIFETIME_MULT * parameter.growing_time) sprite_node.sprite_frames = parameter.sprite_frames need_checker.start(NEED_CHECK_PERIOD) func _on_need_checker_timeout() -> void: can_grow = check_terrain_viability() growing_timer.paused = not can_grow and state == PlantState.SAPLING reproduction.paused = not can_grow func check_terrain_viability() -> bool: var water := GameTerrain.get_stat(position, GameTerrain.Stats.WATER) if water < parameter.water_need[0] or water > parameter.water_need[1]: return false var fertility := GameTerrain.get_stat(position, GameTerrain.Stats.FERTILITY) if fertility < parameter.fertility_need[0] or fertility > parameter.fertility_need[1]: return false var presence := GameTerrain.get_stat(position, GameTerrain.Stats.PRESENCE) presence += GameTerrain.LEVELS_NUMBER / 2 if presence < parameter.presence_need[0] or presence > parameter.presence_need[1]: return false return true func _on_growing_timeout() -> void: if state == PlantState.SAPLING: can_grow = check_terrain_viability() if not can_grow: growing_timer.start() return match state: PlantState.SAPLING: grow() PlantState.GROWN: die() PlantState.DEAD: remove() func plant(new_position: Vector2): position = new_position state = PlantState.SAPLING growing_timer.start(parameter.growing_time) sprite_node.play(\"SAPLING\") func grow(): if state != PlantState.SAPLING: push_error(\"Tried to grow \" + parameter.type + \", but was not at sapling state\") return state = PlantState.GROWN sapling_count_down.stop() growing_timer.start(parameter.dying_time) GameTerrain.modify_zone(position, parameter.distance_prod, GameTerrain.Stats.WATER, parameter.water_prod) GameTerrain.modify_zone(position, parameter.distance_prod, GameTerrain.Stats.FERTILITY, parameter.fertility_prod) GameTerrain.modify_zone(position, parameter.distance_prod, GameTerrain.Stats.PRESENCE, parameter.presence_prod) reproduction.start(parameter.dying_time / (parameter.offspring_per_lifetime + 1) + 0.1) grown.emit() sprite_node.play(\"GROWN\") func die(): state = PlantState.DEAD # remove alive prod and add dead prod GameTerrain.modify_zone(position, parameter.distance_prod, GameTerrain.Stats.WATER, -parameter.water_prod + parameter.dead_water_prod) GameTerrain.modify_zone(position, parameter.distance_prod, GameTerrain.Stats.FERTILITY, -parameter.fertility_prod + parameter.dead_fertility_prod) GameTerrain.modify_zone(position, parameter.distance_prod, GameTerrain.Stats.PRESENCE, -parameter.presence_prod) growing_timer.start(parameter.dead_time) died.emit() sprite_node.play(\"DEAD\") func remove(was_dead: bool = true): if was_dead: GameTerrain.modify_zone(position, parameter.distance_prod, GameTerrain.Stats.WATER, -parameter.dead_water_prod) GameTerrain.modify_zone(position, parameter.distance_prod, GameTerrain.Stats.FERTILITY, -parameter.dead_fertility_prod) queue_free() func _on_sapling_count_down_timeout() -> void: remove(false) func _on_reproduction_timeout() -> void: var min_dist := parameter.distance_prod - parameter.distance_prod * OFFSET_REPRODUCTION_PERCT_DIST var max_dist := parameter.distance_prod + parameter.distance_prod * OFFSET_REPRODUCTION_PERCT_DIST var plant_pos = position + (Vector2.RIGHT * randf_range(min_dist, max_dist)).rotated(randf_range(0, PI)) var space := get_world_2d().direct_space_state var parameters = PhysicsPointQueryParameters2D.new() parameters.position = plant_pos parameters.collide_with_areas = true parameters.collide_with_bodies = false var result := space.intersect_point(parameters, 1) if result.size() > 0: return var offspring = self.duplicate() self.get_parent().add_child(offspring) offspring.init(parameter) offspring.plant(plant_pos) " [sub_resource type="AtlasTexture" id="AtlasTexture_5did5"] atlas = ExtResource("1_n5onq") region = Rect2(810, 540, 270, 270) [sub_resource type="SpriteFrames" id="SpriteFrames_667un"] animations = [{ "frames": [{ "duration": 1.0, "texture": SubResource("AtlasTexture_5did5") }], "loop": true, "name": &"SEED", "speed": 5.0 }] [sub_resource type="CircleShape2D" id="CircleShape2D_jksuk"] radius = 36.0 [node name="Plant" type="Node2D"] script = SubResource("GDScript_x3g5o") [node name="Growing" type="Timer" parent="."] one_shot = true [node name="NeedChecker" type="Timer" parent="."] [node name="SaplingCountDown" type="Timer" parent="."] one_shot = true [node name="Reproduction" type="Timer" parent="."] [node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="."] scale = Vector2(0.2, 0.2) sprite_frames = SubResource("SpriteFrames_667un") animation = &"SEED" offset = Vector2(0, -250) [node name="Area2D" type="Area2D" parent="."] [node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D"] shape = SubResource("CircleShape2D_jksuk") [connection signal="timeout" from="Growing" to="." method="_on_growing_timeout"] [connection signal="timeout" from="NeedChecker" to="." method="_on_need_checker_timeout"] [connection signal="timeout" from="SaplingCountDown" to="." method="_on_sapling_count_down_timeout"] [connection signal="timeout" from="Reproduction" to="." method="_on_reproduction_timeout"]