前言
在编程的奇妙世界里,代码不仅仅是冰冷的指令集合,它还可以成为表达情感、传递温暖的独特方式。今天,我们将一同探索用 Python 语言绘制爱心的神奇之旅。
爱心,这个象征着爱与温暖的符号,一直以来都在人类的情感世界中占据着特殊的地位。而通过 Python 的强大功能,我们可以将这一美好的象征以数字化的形式呈现出来。
无论是向心爱的人表达爱意,还是为了给自己的编程之旅增添一抹浪漫的色彩,这段 Python 爱心代码都将成为你手中的魔法棒。它不仅仅是一段代码,更是一份情感的寄托,一个创意的表达。
在接下来的代码中,我们将运用 Python 的绘图库和数学知识,精心构建一个充满爱意的爱心图案。每一行代码都像是一个小小的画笔,共同勾勒出这份独特的情感画卷。让我们一起沉浸在编程的乐趣中,感受代码与爱心的完美融合。
爱心代码
通过使用turtle
库实现画爱心
pip安装步骤
同时按Win+R键,调出“运行”对话框;
然后在对话框中输入cmd,敲回车键运行;
进入【cmd.exe】界面;
在【cmd.exe】中输入安装命令:pip install turtle
安装成功后如下图所示:
使用turtle
库可以绘制很多不同的图形
多边形
绘制三角形:
import turtle
t = turtle.Turtle()
for _ in range(3):
t.forward(100)
t.left(120)
turtle.done()
正方形:
import turtle
t = turtle.Turtle()
for _ in range(4):
t.forward(100)
t.left(90)
turtle.done()
正五边形:
import turtle
t = turtle.Turtle()
for _ in range(5):
t.forward(100)
t.left(72)
turtle.done()
圆形和弧形
圆形:
import turtle
t = turtle.Turtle()
t.circle(50)
turtle.done()
半圆:
import turtle
t = turtle.Turtle()
t.circle(50, 180)
turtle.done()
螺旋图形
螺旋线:
import turtle
t = turtle.Turtle()
for i in range(100):
t.forward(i * 5)
t.right(144)
turtle.done()
花朵形状
简单花朵:
import turtle
t = turtle.Turtle()
for _ in range(12):
t.circle(50)
t.right(30)
turtle.done()
星星形状
五角星:
import turtle
t = turtle.Turtle()
for _ in range(5):
t.forward(100)
t.right(144)
turtle.done()
Python代码实现
代码展示
这段代码使用turtle
库的函数来控制画笔绘制一个红色的爱心图形。你可以根据需要调整画笔速度和颜色等参数。
import turtle
# 设置画笔速度和颜色
t = turtle.Turtle()
t.speed(3)
t.color("red")
# 绘制爱心
def draw_heart():
t.begin_fill()
t.left(140)
t.forward(111.65)
t.circle(-45, 195)
t.left(120)
t.circle(-45, 195)
t.forward(111.65)
t.end_fill()
draw_heart()
turtle.done()
代码逐行注释
import turtle
# 设置画笔速度和颜色
t = turtle.Turtle() # 创建一个 turtle 对象,命名为 t
t.speed(3) # 设置画笔移动速度为 3,值越大速度越快
t.color("red") # 设置画笔颜色为红色
# 绘制爱心
def draw_heart():
t.begin_fill() # 开始填充图形
t.left(140) # 向左旋转 140 度
t.forward(111.65) # 向前移动 111.65 个单位长度
t.circle(-45, 195) # 以半径为 -45 画 195 度的弧
t.left(120) # 再次向左旋转 120 度
t.circle(-45, 195) # 以半径为 -45 画另一段 195 度的弧
t.forward(111.65) # 向前移动 111.65 个单位长度,回到起始位置
t.end_fill() # 结束填充图形
draw_heart() # 调用函数绘制爱心
turtle.done() # 使窗口保持打开状态,等待用户关闭
运行思路
以下是这段代码的运行思路:
- 首先导入
turtle
模块,这个模块提供了绘制图形的功能。 - 创建一个
turtle
对象t
,它将用于执行各种绘图操作。 - 设置画笔的移动速度为
3
,这样在绘制图形时可以看到画笔的移动过程,速度适中既不会太快让人看不清,也不会太慢影响体验。 - 设置画笔的颜色为 “红色”,确定绘制爱心的颜色。
- 定义一个函数
draw_heart
来专门绘制爱心。- 在这个函数中,首先调用
t.begin_fill()
表示开始填充图形,后续封闭的图形内部将被填充颜色。 - 然后通过
t.left(140)
将画笔向左旋转140
度,为绘制爱心的起始角度做准备。 t.forward(111.65)
让画笔向前移动特定长度,这是爱心的一部分线条。t.circle(-45, 195)
以半径为-45
画一个195
度的圆弧,这是爱心的一个弯曲部分。t.left(120)
再次向左旋转120
度,调整画笔方向以绘制爱心的另一部分。- 再次调用
t.circle(-45, 195)
画另一段圆弧。 - 最后通过
t.forward(111.65)
回到起始位置,完成爱心的轮廓。 - 调用
t.end_fill()
结束填充,此时爱心内部将被填充为之前设置的颜色。
- 在这个函数中,首先调用
- 调用
draw_heart()
函数开始绘制爱心。 - 最后,
turtle.done()
确保程序运行结束后绘图窗口不会立即关闭,而是保持打开状态,以便用户查看绘制好的爱心图形。
Python实现效果图
代码效果图:
代码实现效果图:
修改代码
下面是一个更复杂的 Python 爱心代码,其中加入了一些动态效果和颜色变化:
import turtle
import time
import random
# 设置窗口
window = turtle.Screen()
window.bgcolor("black")
window.title("Complex Heart")
# 创建画笔
pen = turtle.Turtle()
pen.speed(0)
pen.pensize(2)
# 定义颜色列表
colors = ["red", "pink", "purple", "orange"]
# 绘制爱心函数
def draw_heart(size):
pen.begin_fill()
pen.left(140)
pen.forward(size)
pen.circle(-size/2, 195)
pen.left(120)
pen.circle(-size/2, 195)
pen.forward(size)
pen.end_fill()
# 绘制多个爱心并动态变化
for _ in range(50):
x = random.randint(-300, 300)
y = random.randint(-300, 300)
color = random.choice(colors)
pen.penup()
pen.goto(x, y)
pen.pendown()
pen.color(color)
size = random.randint(20, 100)
draw_heart(size)
# 显示文字
pen.penup()
pen.goto(0, -200)
pen.color("white")
pen.write("Love is in the air!", align="center", font=("Arial", 20, "bold"))
# 结束绘制
turtle.done()
代码逐行注释
import turtle
import time
import random
# 设置窗口
window = turtle.Screen() # 创建一个 turtle 绘图窗口对象
window.bgcolor("black") # 将窗口背景颜色设置为黑色
window.title("Complex Heart") # 设置窗口标题为"Complex Heart"
# 创建画笔
pen = turtle.Turtle() # 创建一个 turtle 画笔对象,命名为 pen
pen.speed(0) # 设置画笔移动速度为最快(0)
pen.pensize(2) # 设置画笔的粗细为 2
# 定义颜色列表
colors = ["red", "pink", "purple", "orange"] # 创建一个包含多种颜色的列表
# 绘制爱心函数
def draw_heart(size):
pen.begin_fill() # 开始填充图形
pen.left(140) # 向左旋转 140 度
pen.forward(size) # 向前移动指定大小的距离
pen.circle(-size/2, 195) # 以负半径画 195 度的圆弧
pen.left(120) # 再次向左旋转 120 度
pen.circle(-size/2, 195) # 再次以负半径画 195 度的圆弧
pen.forward(size) # 向前移动指定大小的距离,回到起始位置
pen.end_fill() # 结束填充图形
# 绘制多个爱心并动态变化
for _ in range(50): # 循环 50 次
x = random.randint(-300, 300) # 生成一个 -300 到 300 之间的随机整数作为 x 坐标
y = random.randint(-300, 300) # 生成一个 -300 到 300 之间的随机整数作为 y 坐标
color = random.choice(colors) # 从颜色列表中随机选择一种颜色
pen.penup() # 抬起画笔,移动时不绘制线条
pen.goto(x, y) # 将画笔移动到指定的坐标位置
pen.pendown() # 放下画笔,准备绘制
pen.color(color) # 设置画笔颜色为随机选择的颜色
size = random.randint(20, 100) # 生成一个 20 到 100 之间的随机整数作为爱心大小
draw_heart(size) # 调用函数绘制爱心
# 显示文字
pen.penup() # 抬起画笔
pen.goto(0, -200) # 将画笔移动到坐标 (0, -200)
pen.color("white") # 设置画笔颜色为白色
pen.write("Love is in the air!", align="center", font=("Arial", 20, "bold")) # 在当前位置书写文字
# 结束绘制
turtle.done() # 使窗口保持打开状态,等待用户关闭
运行思路
-
导入必要的模块:
turtle
模块用于绘图。time
模块虽然在这段代码中未被显式使用,但可能在后续扩展中用于控制动画的时间间隔等。random
模块用于生成随机数。
-
设置窗口:
- 创建一个
turtle
绘图窗口对象window
。 - 将窗口背景颜色设置为黑色,通过
window.bgcolor("black")
。 - 设置窗口标题为 “Complex Heart”,使用
window.title("Complex Heart")
。
- 创建一个
-
创建画笔:
- 创建一个
turtle
画笔对象pen
。 - 设置画笔移动速度为最快(速度参数为 0),
pen.speed(0)
,这样在绘制时可以快速完成,减少等待时间。 - 设置画笔的粗细为 2,
pen.pensize(2)
。
- 创建一个
-
定义颜色列表:
- 创建一个包含多种颜色的列表
colors
,其中包含 “red”(红色)、“pink”(粉色)、“purple”(紫色)和 “orange”(橙色)等颜色,用于给爱心随机上色。
- 创建一个包含多种颜色的列表
-
绘制多个爱心并动态变化:
- 使用一个循环,循环次数为 50 次。
- 在每次循环中:
- 生成随机的坐标值
x
和y
,范围在 -300 到 300 之间,x = random.randint(-300, 300)
和y = random.randint(-300, 300)
。这将决定每个爱心在窗口中的位置。 - 从颜色列表中随机选择一种颜色赋给
color
,color = random.choice(colors)
。 - 抬起画笔,
pen.penup()
,移动到随机生成的坐标位置,pen.goto(x, y)
,然后放下画笔,pen.pendown()
。 - 生成一个随机的爱心大小
size
,范围在 20 到 100 之间,size = random.randint(20, 100)
。 - 使用随机选择的颜色设置画笔颜色,
pen.color(color)
。 - 调用
draw_heart(size)
函数绘制爱心,传入随机生成的大小参数。
- 生成随机的坐标值
-
显示文字:
- 抬起画笔,
pen.penup()
。 - 将画笔移动到坐标 (0, -200),
pen.goto(0, -200)
。 - 设置画笔颜色为白色,
pen.color("white")
。 - 使用指定的字体、大小和对齐方式在当前位置书写文字 “Love is in the air!”,
pen.write("Love is in the air!", align="center", font=("Arial", 20, "bold"))
。
- 抬起画笔,
-
结束绘制:
- 调用
turtle.done()
使窗口保持打开状态,等待用户关闭窗口。这样用户可以查看绘制好的图形。
- 调用
Python实现效果图
代码效果图
代码实现效果图
呼吸效果修改
更加复杂绚丽且带有呼吸效果的 Python 爱心代码:
import turtle
import time
import random
# 设置窗口
window = turtle.Screen()
window.bgcolor("black")
window.title("Complex Heart with Breathing Effect")
# 创建画笔
pen = turtle.Turtle()
pen.speed(0)
pen.pensize(2)
# 定义颜色列表
colors = ["red", "pink", "purple", "orange", "magenta", "cyan"]
# 绘制爱心函数
def draw_heart(size):
pen.begin_fill()
pen.left(140)
pen.forward(size)
pen.circle(-size/2, 195)
pen.left(120)
pen.circle(-size/2, 195)
pen.forward(size)
pen.end_fill()
# 呼吸效果函数
def breathing_effect(size):
while True:
for i in range(10):
pen.clear()
new_size = size + i
draw_heart(new_size)
time.sleep(0.05)
for i in range(10):
pen.clear()
new_size = size + 9 - i
draw_heart(new_size)
time.sleep(0.05)
# 绘制多个爱心并动态变化
for _ in range(50):
x = random.randint(-300, 300)
y = random.randint(-300, 300)
color = random.choice(colors)
pen.penup()
pen.goto(x, y)
pen.pendown()
pen.color(color)
size = random.randint(20, 100)
draw_heart(size)
breathing_effect(size)
# 显示文字
pen.penup()
pen.goto(0, -200)
pen.color("white")
pen.write("Love is in the air!", align="center", font=("Arial", 20, "bold"))
# 结束绘制
turtle.done()
逐行注释
import turtle
import time
import random
# 设置窗口
window = turtle.Screen() # 创建一个 turtle 绘图窗口对象
window.bgcolor("black") # 将窗口背景颜色设置为黑色
window.title("Complex Heart with Breathing Effect") # 设置窗口标题
# 创建画笔
pen = turtle.Turtle() # 创建一个 turtle 画笔对象
pen.speed(0) # 设置画笔移动速度为最快
pen.pensize(2) # 设置画笔粗细为 2
# 定义颜色列表
colors = ["red", "pink", "purple", "orange", "magenta", "cyan"] # 可用于爱心的颜色列表
# 绘制爱心函数
def draw_heart(size):
pen.begin_fill() # 开始填充图形
pen.left(140) # 向左旋转 140 度
pen.forward(size) # 向前移动指定大小的距离
pen.circle(-size/2, 195) # 以负半径画 195 度的圆弧
pen.left(120) # 再次向左旋转 120 度
pen.circle(-size/2, 195) # 再次以负半径画 195 度的圆弧
pen.forward(size) # 向前移动指定大小的距离,回到起始位置
pen.end_fill() # 结束填充图形
# 呼吸效果函数
def breathing_effect(size):
while True: # 无限循环以实现持续的呼吸效果
for i in range(10): # 逐渐增大爱心尺寸
pen.clear() # 清除之前的图形
new_size = size + i # 计算新的爱心尺寸
draw_heart(new_size) # 绘制新尺寸的爱心
time.sleep(0.05) # 暂停一小段时间,控制动画速度
for i in range(10): # 逐渐减小爱心尺寸
pen.clear() # 清除之前的图形
new_size = size + 9 - i # 计算新的爱心尺寸
draw_heart(new_size) # 绘制新尺寸的爱心
time.sleep(0.05) # 暂停一小段时间,控制动画速度
# 绘制多个爱心并动态变化
for _ in range(50): # 循环 50 次,绘制多个爱心
x = random.randint(-300, 300) # 随机生成 x 坐标
y = random.randint(-300, 300) # 随机生成 y 坐标
color = random.choice(colors) # 从颜色列表中随机选择一种颜色
pen.penup() # 抬起画笔
pen.goto(x, y) # 移动到随机坐标位置
pen.pendown() # 放下画笔
pen.color(color) # 设置画笔颜色为随机选择的颜色
size = random.randint(20, 100) # 随机生成爱心尺寸
draw_heart(size) # 绘制爱心
breathing_effect(size) # 为每个爱心添加呼吸效果
# 显示文字
pen.penup() # 抬起画笔
pen.goto(0, -200) # 移动到指定坐标位置
pen.color("white") # 设置画笔颜色为白色
pen.write("Love is in the air!", align="center", font=("Arial", 20, "bold")) # 书写文字
# 结束绘制
turtle.done() # 使窗口保持打开状态,等待用户关闭
运行思路
-
导入模块:
turtle
模块用于图形绘制。time
模块用于控制时间间隔,实现动画效果。random
模块用于生成随机数。
-
设置窗口:
- 创建一个
turtle
绘图窗口对象window
。 - 将窗口背景颜色设置为黑色,
window.bgcolor("black")
,营造出特定的氛围。 - 设置窗口标题为 “Complex Heart with Breathing Effect”,
window.title("Complex Heart with Breathing Effect")
。
- 创建一个
-
创建画笔:
- 创建一个
turtle
画笔对象pen
。 - 设置画笔移动速度为最快,
pen.speed(0)
,这样在绘制时可以快速呈现效果。 - 设置画笔粗细为 2,
pen.pensize(2)
。
- 创建一个
-
定义颜色列表:
- 创建一个包含多种颜色的列表
colors
,这些颜色将用于绘制不同的爱心。
- 创建一个包含多种颜色的列表
-
定义绘制爱心的函数:
draw_heart(size)
函数用于绘制一个特定大小的爱心。- 首先,开始填充图形,
pen.begin_fill()
。 - 然后,通过一系列的移动和画弧操作,使用给定的大小参数
size
,绘制出爱心的形状。 - 最后,结束填充图形,
pen.end_fill()
。
-
定义呼吸效果函数:
breathing_effect(size)
函数实现爱心的呼吸效果。- 使用一个无限循环
while True
,确保呼吸效果持续进行。 - 在循环中,通过两个嵌套的
for
循环来逐渐增大和减小爱心的尺寸。 - 每次循环中,先清除之前的图形,
pen.clear()
。 - 然后计算新的爱心尺寸,
new_size = size + i
或new_size = size + 9 - i
。 - 调用
draw_heart(new_size)
绘制新尺寸的爱心。 - 使用
time.sleep(0.05)
暂停一小段时间,控制动画的速度,使呼吸效果看起来更加自然。
-
绘制多个爱心并动态变化:
- 使用一个循环,循环次数为 50 次。
- 在每次循环中:
- 生成随机的坐标值
x
和y
,范围在 -300 到 300 之间,x = random.randint(-300, 300)
和y = random.randint(-300, 300)
,确定每个爱心在窗口中的位置。 - 从颜色列表中随机选择一种颜色赋给
color
,color = random.choice(colors)
。 - 抬起画笔,
pen.penup()
,移动到随机生成的坐标位置,pen.goto(x, y)
,然后放下画笔,pen.pendown()
。 - 生成一个随机的爱心大小
size
,范围在 20 到 100 之间,size = random.randint(20, 100)
。 - 使用随机选择的颜色设置画笔颜色,
pen.color(color)
。 - 调用
draw_heart(size)
绘制爱心。 - 接着调用
breathing_effect(size)
为每个爱心添加呼吸效果。
- 生成随机的坐标值
-
显示文字:
- 抬起画笔,
pen.penup()
。 - 将画笔移动到坐标 (0, -200),
pen.goto(0, -200)
。 - 设置画笔颜色为白色,
pen.color("white")
。 - 使用指定的字体、大小和对齐方式在当前位置书写文字 “Love is in the air!”,
pen.write("Love is in the air!", align="center", font=("Arial", 20, "bold"))
。
- 抬起画笔,
-
结束绘制:
- 调用
turtle.done()
使窗口保持打开状态,等待用户关闭窗口。这样用户可以查看绘制好的图形和动画效果。
- 调用
Python实现效果图
代码效果图
代码实现效果图
不同编程语言实现
一、Python 使用 turtle
库
import turtle
import math
# 设置画笔速度和填充颜色模式
t = turtle.Turtle()
t.speed(5)
turtle.colormode(255)
# 绘制爱心并实现颜色渐变
def draw_heart_and_gradient():
for angle in range(0, 360):
r = 150 - 150 * math.sin(math.radians(angle))
x = r * math.cos(math.radians(angle))
y = r * math.sin(math.radians(angle))
t.penup()
t.goto(x, y)
t.pendown()
# 设置颜色渐变,这里根据角度调整 RGB 值
t.color(int(255 * (angle / 360)), int(150 * (angle / 360)), int(200 * (angle / 360)))
t.begin_fill()
t.circle(5)
t.end_fill()
draw_heart_and_gradient()
turtle.done()
代码逐行注释
import turtle
import math
# 设置画笔速度和填充颜色模式
t = turtle.Turtle()
t.speed(5)
turtle.colormode(255)
# 绘制爱心并实现颜色渐变
def draw_heart_and_gradient():
for angle in range(0, 360):
r = 150 - 150 * math.sin(math.radians(angle))
x = r * math.cos(math.radians(angle))
y = r * math.sin(math.radians(angle))
t.penup()
t.goto(x, y)
t.pendown()
# 设置颜色渐变,这里根据角度调整 RGB 值
t.color(int(255 * (angle / 360)), int(150 * (angle / 360)), int(200 * (angle / 360)))
t.begin_fill()
t.circle(5)
t.end_fill()
draw_heart_and_gradient()
turtle.done()
运行思路
-
导入必要的模块:
turtle
模块用于图形绘制。math
模块用于数学计算,这里主要用于角度和弧度的转换以及三角函数的计算。
-
设置画笔和颜色模式:
- 创建一个
turtle
画笔对象t
。 - 设置画笔速度为
5
,这个速度值可以控制画笔移动的快慢,数值越大速度越快。 - 使用
turtle.colormode(255)
设置颜色模式为255
模式,这意味着可以使用 0 到 255 的整数值来表示 RGB 颜色通道的值。
- 创建一个
-
定义绘制爱心并实现颜色渐变的函数:
draw_heart_and_gradient
函数用于绘制带有颜色渐变效果的爱心。- 使用一个循环遍历从 0 到 360 度的角度范围:
- 对于每个角度,首先根据心形曲线的数学公式
r = 150 - 150 * math.sin(math.radians(angle))
计算出当前角度对应的半径r
。这里使用了math.sin
函数来计算正弦值,并且通过math.radians(angle)
将角度从度转换为弧度,因为三角函数在 Python 的math
模块中通常接受弧度作为参数。 - 接着,通过
x = r * math.cos(math.radians(angle))
和y = r * math.sin(math.radians(angle))
计算出当前角度对应的坐标(x, y)
。这里使用了三角函数math.cos
和math.sin
来计算横坐标和纵坐标。 - 然后,抬起画笔
t.penup()
,移动到计算出的坐标位置t.goto(x, y)
,再放下画笔t.pendown()
。 - 根据当前角度调整 RGB 值来设置画笔颜色。具体来说,使用
t.color(int(255 * (angle / 360)), int(150 * (angle / 360)), int(200 * (angle / 360)))
。这里通过将角度与特定的数值进行计算,得到不同角度下的 RGB 值,从而实现颜色渐变效果。 - 开始填充图形
t.begin_fill()
,画一个半径为 5 的圆t.circle(5)
,这个圆将作为爱心的一部分,最后结束填充t.end_fill()
。
- 对于每个角度,首先根据心形曲线的数学公式
-
调用绘制函数:
- 调用
draw_heart_and_gradient()
函数开始绘制带有颜色渐变的爱心。
- 调用
-
保持窗口打开:
- 使用
turtle.done()
使turtle
绘图窗口保持打开状态,等待用户手动关闭窗口。这样用户可以查看绘制好的图形。
- 使用
二、JavaScript 使用 canvas
API
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<canvas id="myCanvas" width="500" height="500"></canvas>
<script>
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
// 绘制爱心并实现颜色渐变
function drawHeartAndGradient() {
// 遍历 0 到 360 度
for (let angle = 0; angle < 360; angle++) {
// 根据心形曲线公式计算半径
const r = 150 - 150 * Math.sin(angle * (Math.PI / 180));
// 计算横坐标
const x = r * Math.cos(angle * (Math.PI / 180));
// 计算纵坐标
const y = r * Math.sin(angle * (Math.PI / 180));
// 设置颜色渐变,这里根据角度调整 RGB 值
ctx.fillStyle = `rgb(${255 * (angle / 360)}, ${150 * (angle / 360)}, ${200 * (angle / 360)})`;
ctx.beginPath();
// 在指定位置画一个小圆点作为爱心的一部分
ctx.arc(x + canvas.width / 2, y + canvas.height / 2, 5, 0, 2 * Math.PI);
ctx.fill();
}
}
drawHeartAndGradient();
</script>
</body>
</html>
运行思路
- 在 HTML 文件中创建一个
<canvas>
元素,并通过document.getElementById
获取到这个元素的引用,同时获取其 2D 绘图上下文ctx
。 - 定义一个函数
drawHeartAndGradient
。- 在这个函数中,使用一个循环遍历从 0 到 360 的角度。
- 对于每个角度,根据心形曲线公式
const r = 150 - 150 * Math.sin(angle * (Math.PI / 180))
计算出半径r
。 - 然后通过
const x = r * Math.cos(angle * (Math.PI / 180))
和const y = r * Math.sin(angle * (Math.PI / 180))
计算出该角度对应的坐标(x, y)
。 - 根据当前角度计算颜色的 RGB 值,设置为填充样式
ctx.fillStyle =
rgb(${255 * (angle / 360)}, ${150 * (angle / 360)}, ${200 * (angle / 360)})`。 - 开始路径,在指定位置画一个半径为 5 的圆
ctx.arc(x + canvas.width / 2, y + canvas.height / 2, 5, 0, 2 * Math.PI)
,然后填充这个圆。
- 调用
drawHeartAndGradient
函数开始绘制爱心和颜色渐变效果。
三、Java 使用 Graphics2D
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
class HeartWithGradient extends JPanel {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
// 遍历 0 到 360 度
for (int angle = 0; angle < 360; angle++) {
// 根据心形曲线公式计算半径
double r = 150 - 150 * Math.sin(Math.toRadians(angle));
// 计算横坐标
int x = (int) (r * Math.cos(Math.toRadians(angle)));
// 计算纵坐标
int y = (int) (r * Math.sin(Math.toRadians(angle)));
// 设置颜色渐变,这里根据角度调整 RGB 值
g2d.setColor(new Color((int) (255 * (angle / 360)), (int) (150 * (angle / 360)), (int) (200 * (angle / 360))));
// 在指定位置画一个小圆点作为爱心的一部分
g2d.fill(new Ellipse2D.Double(x + getWidth() / 2 - 5, y + getHeight() / 2 - 5, 10, 10));
}
}
}
public class HeartGradientApp {
public static void main(String[] args) {
JFrame frame = new JFrame("Heart with Gradient");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new HeartWithGradient());
frame.setSize(500, 500);
frame.setVisible(true);
}
}
运行思路
- 定义一个自定义面板类
HeartWithGradient
,继承自JPanel
。 - 在
HeartWithGradient
类的paintComponent
方法中,获取Graphics2D
对象g2d
。- 使用一个循环遍历从 0 到 360 的角度。
- 对于每个角度,根据心形曲线公式
double r = 150 - 150 * Math.sin(Math.toRadians(angle))
计算出半径r
。 - 然后通过
int x = (int) (r * Math.cos(Math.toRadians(angle)));
和int y = (int) (r * Math.sin(Math.toRadians(angle)));
计算出该角度对应的坐标(x, y)
。 - 根据当前角度计算颜色的 RGB 值,创建一个新的
Color
对象g2d.setColor(new Color((int) (255 * (angle / 360)), (int) (150 * (angle / 360)), (int) (200 * (angle / 360))));
。 - 在指定位置画一个半径为 5 的椭圆
g2d.fill(new Ellipse2D.Double(x + getWidth() / 2 - 5, y + getHeight() / 2 - 5, 10, 10))
。
- 在
main
方法中,创建一个JFrame
对象,设置标题、关闭行为、大小等属性。 - 将
HeartWithGradient
实例添加到JFrame
中,并使JFrame
可见。
Python其它绘画方式
第一种
import random
from math import sin, cos, pi, log
from tkinter import *
CANVAS_WIDTH = 640 # 画布的宽
CANVAS_HEIGHT = 640 # 画布的高
CANVAS_CENTER_X = CANVAS_WIDTH / 2 # 画布中心的X轴坐标
CANVAS_CENTER_Y = CANVAS_HEIGHT / 2 # 画布中心的Y轴坐标
IMAGE_ENLARGE = 11 # 放大比例
HEART_COLOR = "#e77c8e" # 心的颜色#ff7171
def heart_function(t, shrink_ratio: float = IMAGE_ENLARGE):
"""
“爱心函数生成器”
:param shrink_ratio: 放大比例
:param t: 参数
:return: 坐标
"""
# 基础函数
x = 16 * (sin(t) ** 3)
y = -(13 * cos(t) - 5 * cos(2 * t) - 2 * cos(3 * t) - cos(4 * t))
# 放大
x *= shrink_ratio
y *= shrink_ratio
# 移到画布中央
x += CANVAS_CENTER_X
y += CANVAS_CENTER_Y
return int(x), int(y)
def scatter_inside(x, y, beta=0.15):
"""
随机内部扩散
:param x: 原x
:param y: 原y
:param beta: 强度
:return: 新坐标
"""
ratio_x = - beta * log(random.random())
ratio_y = - beta * log(random.random())
dx = ratio_x * (x - CANVAS_CENTER_X)
dy = ratio_y * (y - CANVAS_CENTER_Y)
return x - dx, y - dy
def shrink(x, y, ratio):
"""
抖动
:param x: 原x
:param y: 原y
:param ratio: 比例
:return: 新坐标
"""
force = -1 / (((x - CANVAS_CENTER_X) ** 2 + (y - CANVAS_CENTER_Y) ** 2) ** 0.6) # 这个参数...
dx = ratio * force * (x - CANVAS_CENTER_X)
dy = ratio * force * (y - CANVAS_CENTER_Y)
return x - dx, y - dy
def curve(p):
"""
自定义曲线函数,调整跳动周期
:param p: 参数
:return: 正弦
"""
# 可以尝试换其他的动态函数,达到更有力量的效果(贝塞尔?)
return 2 * (3 * sin(4 * p)) / (2 * pi)
class Heart:
"""
爱心类
"""
def __init__(self, generate_frame=20):
self._points = set() # 原始爱心坐标集合
self._edge_diffusion_points = set() # 边缘扩散效果点坐标集合
self._center_diffusion_points = set() # 中心扩散效果点坐标集合
self.all_points = {} # 每帧动态点坐标
self.build(2000)
self.random_halo = 1000
self.generate_frame = generate_frame
for frame in range(generate_frame):
self.calc(frame)
def build(self, number):
# 爱心
for _ in range(number):
t = random.uniform(0, 2 * pi) # 随机不到的地方造成爱心有缺口
x, y = heart_function(t)
self._points.add((x, y))
# 爱心内扩散
for _x, _y in list(self._points):
for _ in range(3):
x, y = scatter_inside(_x, _y, 0.05)
self._edge_diffusion_points.add((x, y))
# 爱心内再次扩散
point_list = list(self._points)
for _ in range(4000):
x, y = random.choice(point_list)
x, y = scatter_inside(x, y, 0.17)
self._center_diffusion_points.add((x, y))
@staticmethod
def calc_position(x, y, ratio):
# 调整缩放比例
force = 1 / (((x - CANVAS_CENTER_X) ** 2 + (y - CANVAS_CENTER_Y) ** 2) ** 0.520) # 魔法参数
dx = ratio * force * (x - CANVAS_CENTER_X) + random.randint(-1, 1)
dy = ratio * force * (y - CANVAS_CENTER_Y) + random.randint(-1, 1)
return x - dx, y - dy
def calc(self, generate_frame):
ratio = 10 * curve(generate_frame / 10 * pi) # 圆滑的周期的缩放比例
halo_radius = int(4 + 6 * (1 + curve(generate_frame / 10 * pi)))
halo_number = int(3000 + 4000 * abs(curve(generate_frame / 10 * pi) ** 2))
all_points = []
# 光环
heart_halo_point = set() # 光环的点坐标集合
for _ in range(halo_number):
t = random.uniform(0, 2 * pi) # 随机不到的地方造成爱心有缺口
x, y = heart_function(t, shrink_ratio=11.6) # 魔法参数
x, y = shrink(x, y, halo_radius)
if (x, y) not in heart_halo_point:
# 处理新的点
heart_halo_point.add((x, y))
x += random.randint(-14, 14)
y += random.randint(-14, 14)
size = random.choice((1, 2, 2))
all_points.append((x, y, size))
# 轮廓
for x, y in self._points:
x, y = self.calc_position(x, y, ratio)
size = random.randint(1, 3)
all_points.append((x, y, size))
# 内容
for x, y in self._edge_diffusion_points:
x, y = self.calc_position(x, y, ratio)
size = random.randint(1, 2)
all_points.append((x, y, size))
for x, y in self._center_diffusion_points:
x, y = self.calc_position(x, y, ratio)
size = random.randint(1, 2)
all_points.append((x, y, size))
self.all_points[generate_frame] = all_points
def render(self, render_canvas, render_frame):
for x, y, size in self.all_points[render_frame % self.generate_frame]:
render_canvas.create_rectangle(x, y, x + size, y + size, width=0, fill=HEART_COLOR)
def draw(main: Tk, render_canvas: Canvas, render_heart: Heart, render_frame=0):
render_canvas.delete('all')
render_heart.render(render_canvas, render_frame)
main.after(160, draw, main, render_canvas, render_heart, render_frame + 1)
if __name__ == '__main__':
root = Tk() # 一个Tk
root.title('宝贝爱你哟') # 将标题设置为'tkinter'
canvas = Canvas(root, bg='black', height=CANVAS_HEIGHT, width=CANVAS_WIDTH)
canvas.pack()
heart = Heart() # 心
draw(root, canvas, heart) # 开始画
root.mainloop()
代码逐行注释
import random
from math import sin, cos, pi, log
from tkinter import *
CANVAS_WIDTH = 640 # 画布的宽
CANVAS_HEIGHT = 640 # 画布的高
CANVAS_CENTER_X = CANVAS_WIDTH / 2 # 画布中心的 X 轴坐标
CANVAS_CENTER_Y = CANVAS_HEIGHT / 2 # 画布中心的 Y 轴坐标
IMAGE_ENLARGE = 11 # 放大比例
HEART_COLOR = "#e77c8e" # 心的颜色#ff7171
def heart_function(t, shrink_ratio: float = IMAGE_ENLARGE):
"""
“爱心函数生成器”
:param shrink_ratio: 放大比例
:param t: 参数
:return: 坐标
"""
# 基础函数
x = 16 * (sin(t) ** 3)
y = -(13 * cos(t) - 5 * cos(2 * t) - 2 * cos(3 * t) - cos(4 * t))
# 放大
x *= shrink_ratio
y *= shrink_ratio
# 移到画布中央
x += CANVAS_CENTER_X
y += CANVAS_CENTER_Y
return int(x), int(y)
def scatter_inside(x, y, beta=0.15):
"""
随机内部扩散
:param x: 原 x
:param y: 原 y
:param beta: 强度
:return: 新坐标
"""
ratio_x = - beta * log(random.random())
ratio_y = - beta * log(random.random())
dx = ratio_x * (x - CANVAS_CENTER_X)
dy = ratio_y * (y - CANVAS_CENTER_Y)
return x - dx, y - dy
def shrink(x, y, ratio):
"""
抖动
:param x: 原 x
:param y: 原 y
:param ratio: 比例
:return: 新坐标
"""
force = -1 / (((x - CANVAS_CENTER_X) ** 2 + (y - CANVAS_CENTER_Y) ** 2) ** 0.6) # 这个参数影响抖动效果
dx = ratio * force * (x - CANVAS_CENTER_X)
dy = ratio * force * (y - CANVAS_CENTER_Y)
return x - dx, y - dy
def curve(p):
"""
自定义曲线函数,调整跳动周期
:param p: 参数
:return: 正弦
"""
# 可以尝试换其他的动态函数,达到更有力量的效果(贝塞尔?)
return 2 * (3 * sin(4 * p)) / (2 * pi)
class Heart:
"""
爱心类
"""
def __init__(self, generate_frame=20):
self._points = set() # 原始爱心坐标集合
self._edge_diffusion_points = set() # 边缘扩散效果点坐标集合
self._center_diffusion_points = set() # 中心扩散效果点坐标集合
self.all_points = {} # 每帧动态点坐标
self.build(2000)
self.random_halo = 1000
self.generate_frame = generate_frame
for frame in range(generate_frame):
self.calc(frame)
def build(self, number):
# 爱心
for _ in range(number):
t = random.uniform(0, 2 * pi) # 随机不到的地方造成爱心有缺口
x, y = heart_function(t)
self._points.add((x, y))
# 爱心内扩散
for _x, _y in list(self._points):
for _ in range(3):
x, y = scatter_inside(_x, _y, 0.05)
self._edge_diffusion_points.add((x, y))
# 爱心内再次扩散
point_list = list(self._points)
for _ in range(4000):
x, y = random.choice(point_list)
x, y = scatter_inside(x, y, 0.17)
self._center_diffusion_points.add((x, y))
@staticmethod
def calc_position(x, y, ratio):
# 调整缩放比例
force = 1 / (((x - CANVAS_CENTER_X) ** 2 + (y - CANVAS_CENTER_Y) ** 2) ** 0.520) # 魔法参数,影响点的位置调整
dx = ratio * force * (x - CANVAS_CENTER_X) + random.randint(-1, 1)
dy = ratio * force * (y - CANVAS_CENTER_Y) + random.randint(-1, 1)
return x - dx, y - dy
def calc(self, generate_frame):
ratio = 10 * curve(generate_frame / 10 * pi) # 圆滑的周期的缩放比例
halo_radius = int(4 + 6 * (1 + curve(generate_frame / 10 * pi)))
halo_number = int(3000 + 4000 * abs(curve(generate_frame / 10 * pi) ** 2))
all_points = []
# 光环
heart_halo_point = set() # 光环的点坐标集合
for _ in range(halo_number):
t = random.uniform(0, 2 * pi) # 随机不到的地方造成爱心有缺口
x, y = heart_function(t, shrink_ratio=11.6) # 魔法参数
x, y = shrink(x, y, halo_radius)
if (x, y) not in heart_halo_point:
# 处理新的点
heart_halo_point.add((x, y))
x += random.randint(-14, 14)
y += random.randint(-14, 14)
size = random.choice((1, 2, 2))
all_points.append((x, y, size))
# 轮廓
for x, y in self._points:
x, y = self.calc_position(x,