Animated Flower Tree with Python Turtle – Growing & Falling Flowers
Create Stunning Animated Nature Scenes with Python’s Built-in Turtle Module
Python’s Turtle graphics module isn’t just for simple shapes – it can create beautiful, complex animations with physics simulations! This tutorial shows you how to build an animated flowering tree where blossoms gradually grow on branches and then gently fall with realistic physics. You’ll learn recursive tree generation, color blending, growth animation, and basic physics simulation – all with pure Python.
Table of Contents
- Overview
- What You’ll Learn
- Step 1: Setting Up the Environment
- Step 2: Generating the Tree Structure
- Step 3: Color Blending for Natural Look
- Step 4: Drawing Flowers with Growth Animation
- Step 5: Physics for Falling Flowers
- Complete Code
- How It Works
- Customization Ideas
- Key Learnings
Overview
This project creates a procedurally generated tree with these animated features:
- Recursive tree generation with random branching angles
- Color blending from brown trunk to green branches
- Gradual flower growth animation
- Realistic flower falling with gravity and wind physics
- Natural swaying motion for attached flowers
What You’ll Learn
- Recursive algorithms for tree generation
- Turtle graphics advanced techniques
- Color theory and RGB blending
- Animation principles with growth stages
- Basic physics simulation (gravity, wind, rotation)
- Object-oriented thinking with flower data structures
Step 1: Setting Up the Environment
We start by importing necessary modules and setting up configuration constants.
import turtle
from random import random, uniform, seed
import math
import time
# Settings
W, H = 420, 420 # Window dimensions
DEPTH = 7 # Recursion depth for tree
LENGTH = 80 # Initial branch length
BA = 25 # Base branching angle
GRAVITY = 1.5 # Physics constants
WIND = 2.0 # Wind strength
FPS = 0.02 # Animation frame delay
seed(192) # Seed for reproducible randomness
branch_params = []
Key Settings Explained:
DEPTHControls how detailed the tree is (higher = more branches)LENGTHStarting branch length in pixelsGRAVITY/WINDPhysics parameters for falling animationseed(192)Ensures the same tree generates every time
Step 2: Generating the Tree Structure
We use recursion to generate tree parameters before drawing.
def record_my_params(length, depth, level=0):
"""Recursively generate tree branch parameters"""
if depth == 0:
return
# Randomize angles and lengths for natural look
a1 = uniform(BA - 10, BA + 10)
a2 = uniform(BA - 10, BA + 10)
l1 = length * uniform(0.6, 0.8) # Child branches are shorter
l2 = length * uniform(0.6, 0.8)
branch_params.append((a1, a2, l1, l2, level))
# Recursive calls for sub-branches
record_my_params(l1, depth - 1, level + 1)
record_my_params(l2, depth - 1, level + 1)
record_my_params(LENGTH, DEPTH)
def param_gen():
"""Generator for branch parameters"""
for p in branch_params:
yield p
How Recursion Works:
- Each branch splits into two sub-branches
- Sub-branches have randomized angles and lengths
- Process continues until depth reaches 0
- Parameters are stored for consistent drawing
Step 3: Color Blending for Natural Look
We blend colors from brown (trunk) to green (branches) based on branch level.
def blend(c1, c2, t):
"""Linear color interpolation between two RGB colors"""
return (
c1[0] + (c2[0] - c1[0]) * t,
c1[1] + (c2[1] - c1[1]) * t,
c1[2] + (c2[2] - c1[2]) * t,
)
# Usage in drawing:
t = (DEPTH - depth) / DEPTH # Normalized position (0=trunk, 1=tip)
brown = (139/255, 69/255, 19/255)
green = (34/255, 139/255, 34/255)
r, g, b = blend(brown, green, t)
Color Theory:
- Brown trunk: (139/255, 69/255, 19/255) - earthy, strong
- Green tips: (34/255, 139/255, 34/255) - vibrant, leafy
- Linear interpolation: Creates smooth color transitions
Step 4: Drawing Flowers with Growth Animation
Flowers are drawn as pentagram shapes with gradual growth animation.
def draw_flower_at_position(pen, x, y, color, size, rotation=0, growth_factor=1.0):
"""Draw a flower at specific position with growth animation"""
pen.penup()
pen.goto(x, y)
pen.setheading(rotation)
pen.pendown()
# Apply growth factor to size
current_size = size * growth_factor
if current_size < 0.5: # Don't draw if too small
return
pen.fillcolor(color)
pen.pencolor(color)
pen.begin_fill()
for _ in range(5):
pen.circle(current_size, 72) # Draw petal
pen.left(144) # Turn for next petal
pen.end_fill()
# Draw flower center
pen.penup()
pen.goto(x, y)
pen.dot(current_size * 0.6, (0.9, 0.4, 0.6))
def animate_flower_growth(screen, tree_pen, flower_positions):
"""Animate flowers growing on the tree"""
flower_pen = turtle.Turtle()
flower_pen.hideturtle()
flower_pen.speed(0)
flower_pen.penup()
growth_stages = 20 # Number of growth stages
for stage in range(growth_stages + 1):
flower_pen.clear()
growth_factor = stage / growth_stages # 0 to 1
for flower in flower_positions:
draw_flower_at_position(
flower_pen,
flower['x'],
flower['y'],
flower['color'],
flower['size'],
growth_factor=growth_factor
)
screen.update()
time.sleep(FPS)
Growth Animation Features:
- 20 growth stages for smooth appearance
- Size scaling from 0% to 100%
- Separate turtle for flowers vs tree
- Controlled frame rate for smooth animation
Step 5: Physics for Falling Flowers
Realistic falling animation with gravity, wind, and rotation physics.
def make_flowers_fall(screen, tree_pen, flower_pen, flower_positions):
"""Animate flowers falling with physics simulation"""
velocities = {} # Store velocity for each flower
rotations = {} # Store rotation for each flower
while True:
flower_pen.clear()
# Randomly detach flowers over time
for flower in flower_positions:
if flower['attached'] and random() < 0.03:
flower['attached'] = False
flower_id = flower['id']
# Initialize physics properties
velocities[flower_id] = [
uniform(-WIND, WIND), # Horizontal velocity (wind)
-GRAVITY * uniform(0.8, 1.2) # Vertical velocity
]
rotations[flower_id] = uniform(0, 360) # Initial rotation
# Update falling flowers
for flower in flower_positions:
if not flower['attached']:
flower_id = flower['id']
vx, vy = velocities[flower_id]
# Apply physics
flower['x'] += vx
flower['y'] += vy
vy -= GRAVITY * 0.08 # Gravity acceleration
# Air resistance and random movement
vx *= 0.998
vy *= 0.998
vx += uniform(-0.008, 0.008)
# Update rotation based on horizontal movement
rotations[flower_id] += vx * 3
# Ground collision
if flower['y'] <= -H//2 + 20:
flower['y'] = -H//2 + 20 # Stop at ground
if abs(vy) > 0.3:
vy = -vy * 0.2 # Bounce
else:
vy = 0 # Stop moving
velocities[flower_id] = [vx, vy]
# Draw with current rotation
draw_flower_at_position(
flower_pen,
flower['x'],
flower['y'],
flower['color'],
flower['size'],
rotations[flower_id]
)
screen.update()
time.sleep(FPS)
Physics Simulation Elements:
- Gravity: Constant downward acceleration
- Wind: Random horizontal movement
- Rotation: Flowers spin as they fall
- Air resistance: Velocity gradually decreases
- Ground collision: Realistic bouncing and stopping
- Random variations: Natural, non-uniform movement
Complete Code
# source code at www.pyshine.com
import turtle
from random import random, uniform, seed
import math
import time
# Settings
W, H = 420, 420
DEPTH = 7
LENGTH = 80
BA = 25
GRAVITY = 1.5
WIND = 2.0
FPS = 0.02
seed(192)
branch_params = []
def record_my_params(length, depth, level=0):
if depth == 0:
return
a1 = uniform(BA - 10, BA + 10)
a2 = uniform(BA - 10, BA + 10)
l1 = length * uniform(0.6, 0.8)
l2 = length * uniform(0.6, 0.8)
branch_params.append((a1, a2, l1, l2, level))
record_my_params(l1, depth - 1, level + 1)
record_my_params(l2, depth - 1, level + 1)
record_my_params(LENGTH, DEPTH)
def param_gen():
for p in branch_params:
yield p
def blend(c1, c2, t):
return (
c1[0] + (c2[0] - c1[0]) * t,
c1[1] + (c2[1] - c1[1]) * t,
c1[2] + (c2[2] - c1[2]) * t,
)
def draw_flower_at_position(pen, x, y, color, size, rotation=0, growth_factor=1.0):
"""Draw a flower at a specific position with growth animation"""
pen.penup()
pen.goto(x, y)
pen.setheading(rotation)
pen.pendown()
# Apply growth factor to size
current_size = size * growth_factor
if current_size < 0.5: # Don't draw if too small
return
pen.fillcolor(color)
pen.pencolor(color)
pen.begin_fill()
for _ in range(5):
pen.circle(current_size, 72)
pen.left(144)
pen.end_fill()
pen.penup()
pen.goto(x, y)
pen.dot(current_size * 0.6, (0.9, 0.4, 0.6))
def draw_tree_with_flowers():
screen = turtle.Screen()
screen.setup(W, H)
screen.title("Turtle Tree with Growing and Falling Flowers")
screen.bgcolor("black")
screen.tracer(0, 0) # Turn off animation for initial drawing
# Create main tree pen
tree_pen = turtle.Turtle()
tree_pen.hideturtle()
tree_pen.speed(0)
tree_pen.left(90)
tree_pen.penup()
tree_pen.goto(0, -H//2 + 30)
tree_pen.pendown()
# Store flower positions during tree drawing
flower_positions = []
def draw_branch(length, depth):
"""Recursively draw tree branches and record flower positions."""
if depth == 0:
# Record leaf/flower position but don't draw yet
size = uniform(2, 5)
color = (1.0, uniform(0.6, 0.8), uniform(0.7, 0.9))
flower_positions.append({
'x': tree_pen.xcor(),
'y': tree_pen.ycor(),
'color': color,
'size': size,
'attached': True,
'grown': False, # Flower hasn't grown yet
'id': len(flower_positions) # Unique ID for each flower
})
return
t = (DEPTH - depth) / DEPTH
brown = (139/255, 69/255, 19/255)
green = (34/255, 139/255, 34/255)
r, g, b = blend(brown, green, t)
tree_pen.pencolor(r, g, b)
tree_pen.pensize(max(1, depth / 2))
tree_pen.forward(length)
if random() < 0.12 and depth < DEPTH - 2:
# Record branch flower position but don't draw yet
size = uniform(2, 5)
color = (1.0, uniform(0.6, 0.8), uniform(0.7, 0.9))
flower_positions.append({
'x': tree_pen.xcor(),
'y': tree_pen.ycor(),
'color': color,
'size': size,
'attached': True,
'grown': False, # Flower hasn't grown yet
'id': len(flower_positions) # Unique ID for each flower
})
try:
a1, a2, l1, l2, level = next(params)
except StopIteration:
return
tree_pen.left(a1)
draw_branch(l1, depth - 1)
tree_pen.right(a1 + a2)
draw_branch(l2, depth - 1)
tree_pen.left(a2)
tree_pen.backward(length)
# Draw the initial tree structure (without flowers)
params = param_gen()
draw_branch(LENGTH, DEPTH)
screen.update() # Show the initial tree
print(f"Tree structure complete. {len(flower_positions)} flower positions recorded.")
# Now animate flowers growing
animate_flower_growth(screen, tree_pen, flower_positions)
def animate_flower_growth(screen, tree_pen, flower_positions):
"""Animate flowers growing on the tree"""
# Create a separate pen for flowers
flower_pen = turtle.Turtle()
flower_pen.hideturtle()
flower_pen.speed(0)
flower_pen.penup()
print("Flowers growing...")
# Grow flowers gradually
growth_stages = 20 # Number of growth stages
breeze_phase = 0
breeze_strength = 0.8
breeze_frequency = 0.08
for stage in range(growth_stages + 1):
flower_pen.clear()
# Calculate breeze effect for subtle movement
breeze_phase += breeze_frequency
current_breeze = math.sin(breeze_phase) * breeze_strength
# Calculate growth factor (0 to 1)
growth_factor = stage / growth_stages
# Draw each flower with current growth factor
for flower in flower_positions:
if not flower['grown']:
# Slight sway with breeze
sway_x = current_breeze * 0.1 * math.sin(stage * 0.5 + flower['x'] * 0.01)
draw_flower_at_position(
flower_pen,
flower['x'] + sway_x,
flower['y'],
flower['color'],
flower['size'],
current_breeze * 2,
growth_factor
)
screen.update()
time.sleep(FPS)
# Mark all flowers as fully grown
for flower in flower_positions:
flower['grown'] = True
print("All flowers have grown!")
time.sleep(1) # Pause to show fully grown flowers
# Now start the falling animation
make_flowers_fall(screen, tree_pen, flower_pen, flower_positions)
def make_flowers_fall(screen, tree_pen, flower_pen, initial_flowers):
"""Animate flowers falling from the tree"""
# Create a separate pen for falling flowers
fall_pen = turtle.Turtle()
fall_pen.hideturtle()
fall_pen.speed(0)
fall_pen.penup()
# Copy initial flowers for animation
flowers = []
for flower in initial_flowers:
flowers.append({
'x': flower['x'],
'y': flower['y'],
'color': flower['color'],
'size': flower['size'],
'attached': True,
'grown': True,
'id': flower['id']
})
# Initialize velocities and rotations
velocities = {}
rotations = {}
fallen_count = 0
frame_count = 0
breeze_phase = 0
breeze_strength = 0.8
breeze_frequency = 0.08
print(f"Flowers starting to fall...")
# Store which flowers are currently attached to the tree
attached_flowers = {flower['id']: flower for flower in flowers if flower['attached']}
while True:
frame_count += 1
fall_pen.clear()
flower_pen.clear() # Clear the flower pen to remove flowers from tree
# Calculate breeze effect
breeze_phase += breeze_frequency
current_breeze = math.sin(breeze_phase) * breeze_strength
# Check for flowers starting to fall
flowers_to_detach = []
for flower in flowers:
if (flower['attached'] and frame_count > 10 and
random() < 0.03 and frame_count % 4 == 0):
flowers_to_detach.append(flower['id'])
# Detach the flowers
for flower_id in flowers_to_detach:
for flower in flowers:
if flower['id'] == flower_id and flower['attached']:
flower['attached'] = False
velocities[flower_id] = [
uniform(-WIND * 0.7, WIND * 0.7) + current_breeze * 0.4,
-GRAVITY * uniform(0.8, 1.2)
]
rotations[flower_id] = uniform(0, 360)
fallen_count += 1
# Remove from attached flowers
if flower_id in attached_flowers:
del attached_flowers[flower_id]
print(f"🌸 Flower {flower_id} dropped! {fallen_count}/{len(flowers)}")
# Draw only the flowers that are still attached to the tree
for flower in attached_flowers.values():
if flower['attached']:
# Draw attached flower with slight sway
sway_x = current_breeze * 0.1 * math.sin(frame_count * 0.2 + flower['x'] * 0.01)
draw_flower_at_position(
flower_pen,
flower['x'] + sway_x,
flower['y'],
flower['color'],
flower['size'],
current_breeze * 2
)
# Update and draw falling flowers
all_fallen = len(attached_flowers) == 0
active_falling_flowers = False
for flower in flowers:
if not flower['attached']:
# Update falling flower physics
flower_id = flower['id']
vx, vy = velocities.get(flower_id, (0, 0))
# Apply physics
flower['x'] += vx + current_breeze * 0.05
flower['y'] += vy
vy -= GRAVITY * 0.08
vx += current_breeze * 0.015 + uniform(-0.008, 0.008)
vx *= 0.998
vy *= 0.998
# Update rotation
if flower_id in rotations:
rotations[flower_id] += vx * 3
# Ground collision
ground_level = -H//2 + flower['size'] * 1.4 + 20
if flower['y'] <= ground_level:
flower['y'] = ground_level
if abs(vy) > 0.3:
vy = -vy * 0.2
else:
vy = 0
vx *= 0.8
velocities[flower_id] = [vx, vy]
rotation = rotations.get(flower_id, 0)
# Draw falling flower
draw_flower_at_position(
fall_pen,
flower['x'],
flower['y'],
flower['color'],
flower['size'],
rotation
)
if vy != 0 or vx != 0:
active_falling_flowers = True
screen.update()
time.sleep(FPS)
# End condition: all flowers have fallen and stopped moving
if all_fallen and not active_falling_flowers and frame_count > 60:
break
print(f"All {fallen_count} flowers have fallen!")
# Keep the window open
screen.exitonclick()
if __name__ == "__main__":
draw_tree_with_flowers()
How It Works
- Tree Generation: Recursive algorithm builds tree structure with random variations
- Flower Placement: Flowers are positioned at branch endpoints during tree drawing
- Growth Animation: Flowers appear gradually over 20 animation frames
- Physics Simulation: Each flower gets velocity and rotation properties
- Natural Falling: Random detachment with gravity, wind, and collision detection
Customization Ideas
- Seasonal Colors: Change flower colors for different seasons
- Different Tree Types: Modify branching patterns for various tree species
- Weather Effects: Add rain, snow, or stronger wind
- Interactive Elements: Click to make flowers fall or grow new ones
- Background: Add sky, ground, or other landscape elements
Key Learnings
- Recursive Algorithms: Perfect for tree-like structures and branching patterns
- Turtle Graphics: Advanced techniques beyond basic shapes
- Animation Principles: Gradual growth, smooth transitions, frame control
- Physics Simulation: Gravity, wind, rotation, and collision detection
- Color Theory: Natural color blending and RGB manipulation
- Data Structures: Using dictionaries to track multiple animated objects
This project demonstrates that Python’s Turtle graphics can create much more than simple drawings. By combining recursive algorithms, color theory, and physics simulation, you can build beautiful, complex animations that bring digital nature to life. The techniques learned here can be applied to game development, data visualization, or interactive art projects.
Try modifying the parameters to create your own unique animated scenes!