Python:繪製櫻花樹

這篇文章參考了別人的博客《三月桃花開,用python給你帶來你的桃花運,詳細解析畫一棵表白樹》[1],原文作者:沙漏在下雨,這裏簡單記錄一下學習過程。

這裏使用的是 python turtle 模塊,如果讀者使用的是 Pycharm ,在使用 turtle 時會存在一些問題,可以看我的另一篇博客《Ubuntu:解決PyCharm中turtle模塊無法使用的問題》[2]

目錄

一、代碼詳解

(一)繪製畫幕

(二)繪製落花

(三)繪製樹枝與花瓣

(四)繪製多棵樹

 二、完整代碼

(一)完整代碼

(二)效果


一、代碼詳解

(一)繪製畫幕

首先繪製畫幕,命令說明如下:

  1. screensize(width, height, bg=color):設置畫幕大小及顏色
  2. setup(p1, p2):設置畫幕大小,當 p1、p2 爲小數時表示屏幕佔比;當 p1、p2 爲整數時表示像素
  3. tracer(speed):設置繪製速度,speed越大表示繪製速度越快
def get_screen(width, height, color, speed):
    # 創建畫幕
    screen_obj = turtle.Screen()
    # 畫布大小:(width, height),顏色:color
    screen_obj.screensize(width, height, bg=color)
    screen_obj.setup(1.0, 1.0)
    # speed倍加速
    screen_obj.tracer(speed)

    return screen_obj

(二)繪製落花

在確定落花數量的情況下,我們首先要評估落花的範圍,這裏通過兩句語句來約束落花的範圍(落花數量越多,當然地落花範圍也就越大):

# 有正有負就可以讓畫筆往二個方向走
x = flower - 4 * flower * random()

# 花瓣整體寬度(-10, 10)
y = 10 - 20 * random()

然後我們來講講 turtle 常用的幾個命令吧:

首先,我們得明確,對於 turtle 畫布來說,其爲一個 xOy 的平面,畫布中心爲原點 O ;對於 turtle 畫筆來說,其有一個初始方向,指向 x 軸正方向

  1. penup():起筆(可以想象成畫畫的時候沾墨之後提筆)
  2. forward():向前移動
  3. backward():向後移動
  4. left(degree):逆時針旋轉 degree 度
  5. right(degree):順時針旋轉 degree 度
  6. pendown():落筆
  7. pencolor(color):筆墨顏色爲 color
  8. circle(r):畫一個半徑爲 r 的圓

代碼如下:

def draw_petal(turtle_obj, flower):
    # 繪製掉落的花瓣
    for i in range(int(flower / 2)):
        # 有正有負就可以讓畫筆往二個方向走
        x = flower - 2 * flower * random()

        # 花瓣整體寬度(-10, 10)
        y = 10 - 20 * random()

        # 提筆,向前y,左轉90,走x,落筆
        turtle_obj.penup()
        turtle_obj.forward(y)
        turtle_obj.left(90)
        turtle_obj.forward(x)
        turtle_obj.pendown()

        # 珊瑚色
        turtle_obj.pencolor("lightcoral")
        # 畫圓
        turtle_obj.circle(1)

        # 回到起點
        # 提筆,後退x,右轉90,後退y,落筆
        turtle_obj.penup()
        turtle_obj.backward(x)
        turtle_obj.right(90)
        turtle_obj.backward(y)
        turtle_obj.pendown()

(三)繪製樹枝與花瓣

 讀者會發現,在 drwa_tree 方法中,又出現了兩次 drwa_tree 方法,這是一個遞歸的方法,可以簡單理解爲一棵樹最下面的樹枝最少且最粗,越往上樹枝數量增加但是變細了。如果讀者看不懂如下代碼的話,可以查看《Turtle(python)畫分形樹理解遞歸》[3]文章。

def draw_tree(turtle_obj, branch, tree_color):
    # 設置一個最小分支長度
    min_branch = 4

    if branch > min_branch:
        if branch < 8:
            # 以0.5的概率,向左、右分支
            if randint(0, 1) == 0:
                # 左爲白色
                turtle_obj.pencolor("snow")
            else:
                # 右爲珊瑚色
                turtle_obj.pencolor("lightcoral")
            # 枝幹
            turtle_obj.pensize(branch / 2)
        elif 8 <= branch <= 16:
            # 以0.33的概率,分爲左、中、右分支
            if randint(0, 2) == 0:
                # 左爲白色
                turtle_obj.pencolor("snow")
            else:
                # 中、右爲珊瑚色
                turtle_obj.pencolor("lightcoral")
            # 樹枝
            turtle_obj.pensize(branch / 4)
        else:
            # 褐色
            turtle_obj.pencolor(tree_color)
            # 細枝
            turtle_obj.pensize(branch / 10)

        # 最開始的樹幹長度
        turtle_obj.forward(branch)

        # 隨機度數因子
        a = 1.5 * random()
        # 順時針旋轉隨機角度(0~30度)
        turtle_obj.right(20 * a)

        # 隨機長度因子
        b = 1.5 * random()
        # 往右畫,直到畫不動爲止
        draw_tree(turtle_obj, branch - 10 * b, tree_color)

        # 左轉隨機角度
        turtle_obj.left(40 * a)
        # 往左畫,直到畫不動位置
        draw_tree(turtle_obj, branch - 10 * b, tree_color)

        # 右轉一定角度
        turtle_obj.right(20 * a)
        # 提筆
        turtle_obj.penup()

        # 遞歸結束回到起點
        turtle_obj.backward(branch)
        turtle_obj.pendown()

(四)繪製多棵樹

這部分代碼的前半部分是用來約束樹根的位置的,爲了使樹可以在圖像中顯示地較爲完成,較大的樹根應該更靠近於畫幕底端,且不能太靠近兩邊,其餘部分代碼就很容易理解了。

def trees(tree_num):
    # 顏色
    color = ['brown', 'tan', 'black']

    for j in range(tree_num):
        # 樹幹顏色
        tree_color = color[randint(0, len(color) - 1)]

        # 畫筆大小
        pensize = randint(2, 5)
        # 前進像素
        forward = ((-1) ** pensize) * pensize * randint(20, 50)
        # 後退像素
        if pensize <= 3:
            backward = ((-1) ** pensize) * (5 - pensize) * randint(10, 15)
        else:
            backward = pensize * randint(45, 50)

        # 創建畫筆
        turtle_obj = turtle.Turtle()
        # 畫筆粗細
        turtle_obj.pensize(pensize)
        # 提筆,向前forward,左轉90,backward,落筆
        turtle_obj.penup()
        turtle_obj.forward(forward)
        turtle_obj.left(90)
        turtle_obj.backward(backward)
        turtle_obj.pendown()
        # 畫筆顏色:褐色
        turtle_obj.pencolor(tree_color)

        # 枝幹粗細
        branch = pensize * 15
        # 落花數
        flowers = branch
        # 第j棵樹
        draw_tree(turtle_obj, branch, tree_color)
        # 花瓣
        draw_petal(turtle_obj, flowers)

 二、完整代碼

(一)完整代碼

給出完整代碼:

import turtle

from random import random
from random import randint


def draw_petal(turtle_obj, flower):
    # 繪製掉落的花瓣
    for i in range(int(flower)):
        # 有正有負就可以讓畫筆往二個方向走
        x = flower - 4 * flower * random()

        # 花瓣整體寬度(-10, 10)
        y = 10 - 20 * random()

        # 提筆,向前y,左轉90,走x,落筆
        turtle_obj.penup()
        turtle_obj.forward(y)
        turtle_obj.left(90)
        turtle_obj.forward(x)
        turtle_obj.pendown()

        # 珊瑚色
        turtle_obj.pencolor("lightcoral")
        # 畫圓
        turtle_obj.circle(1)

        # 回到起點
        # 提筆,後退x,右轉90,後退y,落筆
        turtle_obj.penup()
        turtle_obj.backward(x)
        turtle_obj.right(90)
        turtle_obj.backward(y)
        turtle_obj.pendown()


# 畫樹枝部分
def draw_tree(turtle_obj, branch, tree_color):
    # 設置一個最小分支長度
    min_branch = 4

    if branch > min_branch:
        if branch < 8:
            # 以0.5的概率,向左、右分支
            if randint(0, 1) == 0:
                # 左爲白色
                turtle_obj.pencolor("snow")
            else:
                # 右爲珊瑚色
                turtle_obj.pencolor("lightcoral")
            # 枝幹
            turtle_obj.pensize(branch / 2)
        elif 8 <= branch <= 16:
            # 以0.33的概率,分爲左、中、右分支
            if randint(0, 2) == 0:
                # 左爲白色
                turtle_obj.pencolor("snow")
            else:
                # 中、右爲珊瑚色
                turtle_obj.pencolor("lightcoral")
            # 樹枝
            turtle_obj.pensize(branch / 4)
        else:
            # 褐色
            turtle_obj.pencolor(tree_color)
            # 細枝
            turtle_obj.pensize(branch / 10)

        # 最開始的樹幹長度
        turtle_obj.forward(branch)

        # 隨機度數因子
        a = 1.5 * random()
        # 順時針旋轉隨機角度(0~30度)
        turtle_obj.right(20 * a)

        # 隨機長度因子
        b = 1.5 * random()
        # 往右畫,直到畫不動爲止
        draw_tree(turtle_obj, branch - 10 * b, tree_color)

        # 左轉隨機角度
        turtle_obj.left(40 * a)
        # 往左畫,直到畫不動位置
        draw_tree(turtle_obj, branch - 10 * b, tree_color)

        # 右轉一定角度
        turtle_obj.right(20 * a)
        # 提筆
        turtle_obj.penup()

        # 遞歸結束回到起點
        turtle_obj.backward(branch)
        turtle_obj.pendown()


def get_screen(width, height, color, speed):
    # 創建畫幕
    screen_obj = turtle.Screen()
    # 畫布大小:(width, height),顏色:color
    screen_obj.screensize(width, height, bg=color)
    screen_obj.setup(1.0, 1.0)
    # speed倍加速
    screen_obj.tracer(speed)

    return screen_obj


def trees(tree_num):
    # 顏色
    color = ['brown', 'tan', 'black']

    for j in range(tree_num):
        # 樹幹顏色
        tree_color = color[randint(0, len(color) - 1)]

        # 畫筆大小
        pensize = randint(2, 5)
        # 前進像素
        forward = ((-1) ** pensize) * pensize * randint(20, 50)
        # 後退像素
        if pensize <= 3:
            backward = ((-1) ** pensize) * (5 - pensize) * randint(10, 15)
        else:
            backward = pensize * randint(45, 50)

        # 創建畫筆
        turtle_obj = turtle.Turtle()
        # 畫筆粗細
        turtle_obj.pensize(pensize)
        # 提筆,向前forward,左轉90,backward,落筆
        turtle_obj.penup()
        turtle_obj.forward(forward)
        turtle_obj.left(90)
        turtle_obj.backward(backward)
        turtle_obj.pendown()
        # 畫筆顏色:褐色
        turtle_obj.pencolor(tree_color)

        # 枝幹粗細
        branch = pensize * 15
        # 落花數
        flowers = branch
        # 第j棵樹
        draw_tree(turtle_obj, branch, tree_color)
        # 花瓣
        draw_petal(turtle_obj, flowers)


if __name__ == '__main__':

    # 創建畫幕
    my_screen_width = 800
    my_screen_height = 600
    my_screen_color = 'wheat'
    my_screen_speed = 5
    my_screen_obj = get_screen(my_screen_width, my_screen_height,
                               my_screen_color, my_screen_speed)

    # 櫻花樹
    # 棵數
    my_tree_num = 5
    trees(my_tree_num)

    # 點擊關閉畫布
    my_screen_obj.exitonclick()

(二)效果

整體效果還是挺美的。 

[1] https://blog.csdn.net/qq_45906219/article/details/104721978

[2] https://blog.csdn.net/qq_41297934/article/details/105331153

[3] https://blog.csdn.net/qq_36804363/article/details/88374263

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章