概述
用于生成常见二维几何图形顶点数据(PackedVector2Array
)的静态函数库。
生成的数据可用于_draw
和Line2D
、Polygon2D
等进行绘制和显示。
枚举
enum{AXIS_X = 1,AXIS_Y = 2,
}
enum{SIDE_UP = 1,SIDE_RIGHT = 2,SIDE_BOTTOM = 3,SIDE_LEFT = 4
}
测试场景
创建一个Control
为根节点的场景。我们将基于这个空的控件,来实现绘图函数的测试。
在你的Godot4.2测试工程中创建脚本文件ShapePoints.gd
,将ShapePoints
源码拷贝到这个脚本文件中。
为Control节点添加如下的基础脚本:
@tool
extends Controlfunc _draw():pass# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:var rect = get_rect()return Rect2(rect.position - position,rect.size/scale)
其中:
@tool
开启工具脚本模式,这样脚本会在编辑器中实时运行_draw()
是CanvasItem
类型的虚函数,用于执行draw_*
绘图函数的绘图任务- 隐含:
_draw()
会在控件进入场景树和改变大小等时机自动重绘。 get_draw_safety_rect()
函数可以获取在任意平移、旋转和缩放下都保持显示正确的控件矩形区域
基础图形点求取函数
rect(size:Vector2,offset:Vector2 = Vector2.ZERO) -> PackedVector2Array
返回长宽为size的矩形的四个顶点的数据。offset可以理解为整体的偏移。
使用CanvasItem内置draw_rect绘制矩形
CanvasItem
内置的draw_rect
函数本身就可以进行矩形的绘制。
@tool
extends Controlfunc _draw():var rect = get_draw_safety_rect()draw_rect(rect,Color.WHITE,false,2)# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:var rect = get_rect()return Rect2(rect.position - position,rect.size/scale)
绘制后的效果,无论是平移、旋转还是缩放,都可以看到矩形被正确绘制。
使用ShapePoints的Rect函数
ShapePoints
的Rect
函数返回的是一个包含矩形的5个顶点PackedVector2Array
,在Control
的_draw()
中,我们使用draw_polyline
绘制白色,宽度为2,和控件矩形一样大的空心矩形。
@tool
extends Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var points = ShapePoints.rect(ctl_rect.size,ctl_rect.position)draw_polyline(points,Color.WHITE,2)# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:var rect = get_rect()return Rect2(rect.position - position,rect.size/scale)
将draw_polyline(points,Color.WHITE,2)
改为draw_polyline(points,[Color.WHITE])
可以绘制实心矩形。
regular_polygon(start_angle:int,edges:int,r:float,offset:Vector2) -> PackedVector2Array
返回正多边形顶点。
@tool
extends Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var points = ShapePoints.regular_polygon(0,3,ctl_rect.size.y/2.0,ctl_rect.get_center())draw_polyline(points,Color.WHITE,2)# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:var rect = get_rect()return Rect2(rect.position - position,rect.size/scale)
把draw_polyline(points,Color.WHITE,2)
改为draw_polygon(points,[Color.WHITE])
,就可以绘制实心三角形。
通过改变edges
参数为4、5、6…可以创建正方形、正五边形、正六边形等等。
circle(r:float,offset:Vector2) -> PackedVector2Array
返回圆顶点。
@tool
extends Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var points = ShapePoints.circle(ctl_rect.size.y/2.0,ctl_rect.get_center())draw_polyline(points,Color.WHITE,1)# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:var rect = get_rect()return Rect2(rect.position - position,rect.size/scale)
sector(start_angle:int,end_angle:int,r:float) -> PackedVector2Array
返回扇形顶点。
@tool
extends Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var points = ShapePoints.sector(0,90,ctl_rect.get_center().y,ctl_rect.size.y/2.0)draw_polyline(points,Color.WHITE,1)# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:var rect = get_rect()return Rect2(rect.position - position,rect.size/scale)
起始角度0
,结束角度90
,半径为Control
高度一半的扇形:
sector(-120,45,ctl_rect.get_center().y,ctl_rect.get_center())
则表示起始角度-120
,结束角度45
,半径为Control
高度一半的扇形:
arc(start_angle:int,end_angle:int,r:float,offset:Vector2) -> void
返回圆弧顶点。
@tool
extends Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var points = ShapePoints.arc(-120,45,ctl_rect.get_center().y,ctl_rect.get_center())draw_polyline(points,Color.WHITE,1)# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:var rect = get_rect()return Rect2(rect.position - position,rect.size/scale)
起始角度-120
,结束角度45
,半径为Control
高度一半的弧形:
star(start_angle:int,edges:int,r:float,r2:float = 0,offset:Vector2 = Vector2.ZERO) -> void
返回星形顶点。
@tool
extends Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var r1 = ctl_rect.size.y/2.0var points = ShapePoints.star(0,5,r1,r1/2.0,ctl_rect.get_center())draw_polyline(points,Color.WHITE,1)# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:var rect = get_rect()return Rect2(rect.position - position,rect.size/scale)
起始角度0,5个角,外径为Control
高度一半,内径为外径一半的五角星:
其他edges
参数下生成的星形:
round_rect(size:Vector2,r1:float,r2:float,r3:float,r4:float) -> PackedVector2Array
这是是描述。
@tool
extends Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var r1 = ctl_rect.size.y/2.0var points = ShapePoints.round_rect(ctl_rect.size,10,10,10,10,ctl_rect.position)draw_polyline(points,Color.WHITE,1)# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:var rect = get_rect()return Rect2(rect.position - position,rect.size/scale)
和Control
大小始终一致,四个圆角半径都固定是10px
的空心圆角矩形(下图左),改为draw_polygon(points,[Color.WHITE])
后就是实心矩形:
或者通过先draw_polygon
再draw_polyline
,绘制实心带描边的圆角矩形:
@tool
extends Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var r1 = ctl_rect.size.y/2.0var points = ShapePoints.round_rect(ctl_rect.size,10,10,10,10,ctl_rect.position)draw_polygon(points,[Color.WHITE])draw_polyline(points,Color.ORANGE,2)# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:var rect = get_rect()return Rect2(rect.position - position,rect.size/scale)
可以设定四个圆角半径的数值不同:
round_rect(ctl_rect.size,10,20,40,100,ctl_rect.position)
也可以将圆角半径设为一个动态变化的比例值。
var r = ctl_rect.size.x/20.0
var points = ShapePoints.round_rect(ctl_rect.size,r,r,r,r,ctl_rect.position)
chamfer_rect(size:Vector2,a:float,b:float,c:float,d:float) -> PackedVector2Array
返回倒角矩形顶点。
@tool
extends Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var r1 = ctl_rect.size.y/2.0var points = ShapePoints.chamfer_rect(ctl_rect.size,10,20,30,40,ctl_rect.position)draw_polyline(points,Color.WHITE,2)# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:var rect = get_rect()return Rect2(rect.position - position,rect.size/scale)
capsule(size:Vector2) -> PackedVector2Array
返回胶囊形顶点。
@tool
extends Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var r1 = ctl_rect.size.y/2.0var points = ShapePoints.capsule(ctl_rect.size,ctl_rect.position)draw_polyline(points,Color.WHITE,2)# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:var rect = get_rect()return Rect2(rect.position - position,rect.size/scale)
spindle(size:Vector2) -> PackedVector2Array
返回梭形顶点。目前版本还有瑕疵。
@tool
extends Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var r1 = ctl_rect.size.y/2.0var points = ShapePoints.spindle(ctl_rect.size,ctl_rect.position)draw_polyline(points,Color.WHITE,2)# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:var rect = get_rect()return Rect2(rect.position - position,rect.size/scale)
特殊图形
taiji(r:float,offset:Vector2) -> Dictionary
返回太极图案各部分的字典。
taiji["pan"]
:底盘的圆形taiji["yin"]
:阴鱼taiji["yang"]
:阳鱼taiji["yin_eye"]
:阴鱼眼taiji["yang_eye"]
:阳鱼眼
@tool
extends Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var r1 = ctl_rect.size.y/2.0var taiji = ShapePoints.taiji(ctl_rect.size.y/2.0,ctl_rect.get_center())draw_polyline(taiji["pan"],Color.WHITE,2)draw_polyline(taiji["yin"],Color.WHITE,2)draw_polyline(taiji["yang"],Color.WHITE,2)draw_polyline(taiji["yin_eye"],Color.WHITE,2)draw_polyline(taiji["yang_eye"],Color.WHITE,2)# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:var rect = get_rect()return Rect2(rect.position - position,rect.size/scale)
注意:目前版本有瑕疵,用draw_polygon绘制阳鱼部分时随着Control缩放,部分情况下无法绘制实心多边形。期待后续改进。
helix(start_angle:int,start_r:float,end_r:float,step:int,offset:Vector2) -> PackedVector2Array
返回螺旋线顶点。注意:目前版本有瑕疵,后续改进
@tool
extends Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var r1 = ctl_rect.size.y/2.0var points = ShapePoints.helix(0,0,ctl_rect.size.x/2.0,10,ctl_rect.get_center())draw_polyline(points,Color.WHITE,2)# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:var rect = get_rect()return Rect2(rect.position - position,rect.size/scale)
边线重复半圆花纹
repeat_circle(length:float,r:float,space:float = 0,axis:int = AXIS_X,concave:bool = false,reverse:bool = false,offset:Vector2 = Vector2.ZERO) -> PackedVector2Array
返回重复半圆花纹的线。
@tool
extends Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var r1 = ctl_rect.size.y/2.0var points = ShapePoints.repeat_circle(ctl_rect.size.x,10)draw_polyline(points,Color.WHITE,2)# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:var rect = get_rect()return Rect2(rect.position - position,rect.size/scale)
可以设定半圆之间的间隔:
repeat_circle(ctl_rect.size.x,10,10)
可以设定半圆是凸出还是凹进去:
repeat_circle(ctl_rect.size.x,10,10,true)
最后一个参数将点的位置全部逆序,可以用于拼接矩形。
repeat_circle(ctl_rect.size.x,10,10,true,true)
可以设定纵向:
repeat_circle(ctl_rect.size.y,10,0,ShapePoints.AXIS_Y)
repeat_circle_edge(size:Vector2,r:float,space:float,side:int,concave:bool) -> PackedVector2Array
返回指定size
大小的矩形所能使用的重复半圆边线。其中side
可以使用以下枚举的值:
enum{SIDE_UP = 1,SIDE_RIGHT = 2,SIDE_BOTTOM = 3,SIDE_LEFT = 4
}
分别代表矩形的上、右、底、左四边。根据side
的不同,会返回适用于矩形不同边的半圆重复花纹。
@tool
extends Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var r1 = ctl_rect.size.y/2.0var points = ShapePoints.repeat_circle_edge(ctl_rect.size,10,10,ShapePoints.SIDE_LEFT)draw_polyline(points,Color.WHITE,2)# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:var rect = get_rect()return Rect2(rect.position - position,rect.size/scale)
repeat_circle_edge_rect(size:Vector2,r:float,space:float,concave:bool) -> PackedVector2Array
返回带重复半圆花边的矩形。
@tool
extends Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var r1 = ctl_rect.size.y/2.0var points = ShapePoints.repeat_circle_edge_rect(ctl_rect.size,10,10)draw_polyline(points,Color.WHITE,2)# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:var rect = get_rect()return Rect2(rect.position - position,rect.size/scale)
repeat_circle_edge_rect(ctl_rect.size,10,10,true)
网格点、网格十字和棋盘格
line_cross(position:Vector2,length:float,start_angle:int) -> Array
这是是描述。
@tool
extends Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var r1 = ctl_rect.size.y/2.0var points = ShapePoints.line_cross(ctl_rect.get_center(),10,0)draw_polyline(points[0],Color.WHITE,2) # 绘制水平线draw_polyline(points[1],Color.WHITE,2) # 绘制垂直线# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:var rect = get_rect()return Rect2(rect.position - position,rect.size/scale)
在控件中心绘制一个白色十字:
checker_board_rects(size:Vector2,cell_size:Vector2) -> Array
返回棋盘格矩形集合。返回一个包含2个Array[Rect2]
的数组。第1个数组存储所有空心矩形,第2个数组存储所有实心矩形。
@tool
extends Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var r1 = ctl_rect.size.y/2.0var rects = ShapePoints.checker_board_rects(Vector2(10,10),ctl_rect.size/10.0)for rect in rects[0]:draw_rect(rect,Color.WHITE,false,1)for rect in rects[1]:draw_rect(rect,Color.WHITE,true,1)# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:var rect = get_rect()return Rect2(rect.position - position,rect.size/scale)
创建了一个始终随控件大小自适应的棋盘格,划分为10行10列:
rect_grid_points(size:Vector2,cell_size:Vector2) -> PackedVector2Array
返回矩形网格的所有顶点的位置。至于绘制什么,你可以自己说了算。
@tool
extends Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var r1 = ctl_rect.size.y/2.0var points = ShapePoints.rect_grid_points(Vector2(10,10),ctl_rect.size/10.0)for point in points:draw_circle(point,5,Color.WHITE)# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:var rect = get_rect()return Rect2(rect.position - position,rect.size/scale)
依然是10
行10
列网格,所有顶点绘制为半径5
像素,填充白色的圆:
rect_grid_lines(size:Vector2,cell_size:Vector2) -> Dictionary
返回矩形网格的水平线和垂直线集合。
lines["h_lines"]
:包含多个[p1,p2]
,也就是水平线段起止点信息的数组lines["v_lines"]
:包含多个[p1,p2]
,也就是垂直线段起止点信息的数组
@tool
extends Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var r1 = ctl_rect.size.y/2.0var lines = ShapePoints.rect_grid_lines(Vector2(10,10),ctl_rect.size/10.0)for line in lines["h_lines"]:draw_line(line[0],line[1],Color.WHITE,1)# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:var rect = get_rect()return Rect2(rect.position - position,rect.size/scale)
只绘制横线:
绘制横线和竖线:
for line in lines["h_lines"]:draw_line(line[0],line[1],Color.WHITE,1)
for line in lines["v_lines"]:draw_line(line[0],line[1],Color.WHITE,1)
triangle_grid_points(size:Vector2,cell_size:Vector2) -> PackedVector2Array
这是是描述。2024年3月18日01:21:03,等待继续书写
hex_grid_points(size:Vector2,cell_size:Vector2) -> PackedVector2Array
这是是描述。
刻度线求取函数
arc_scale(start_angle:int,end_angle:int,steps:int,r:float,length:float) -> Array
这是是描述。
line_scale(ruler_width:float,steps:int,length:float) -> void
这是是描述。
连线和箭头求取函数
待扩展。
源代码
以下是完整源代码:
# ========================================================
# 名称:ShapePoints
# 类型:静态函数库
# 简介:用于生成常见几何图形的顶点数据(PackedVector2Array)
# 可用于_draw和Line2D、Polygon2D等进行绘制和显示
# 作者:巽星石
# Godot版本:4.1-stable (official) --> v4.2.1.stable.official [b09f793f5]
# 创建时间:2023-07-08 20:45:22
# 最后修改时间:2024年3月18日01:20:17
# ========================================================
class_name ShapePoints# 返回矩形的顶点
static func rect(size:Vector2,offset:Vector2 = Vector2.ZERO) -> PackedVector2Array:var points:PackedVector2Array = [offset,offset + Vector2.RIGHT * size.x,offset + size,offset + Vector2.DOWN * size.y,offset]return points# 返回正多边形顶点
static func regular_polygon(start_angle:int,edges:int,r:float,offset:Vector2 = Vector2.ZERO):var points:PackedVector2Arrayvar vec = Vector2.RIGHT.rotated(deg_to_rad(start_angle)) * rfor i in range(edges):points.append(vec.rotated(2* PI/edges * i) + offset)points.append(points[0]) # 返回第一个点return points# 返回圆顶点
static func circle(r:float,offset:Vector2 = Vector2.ZERO):var points = regular_polygon(0,2 * PI * r,r,offset)points.append(points[0])return points# 返回扇形顶点
# 注意start_angle和end_angle都是角度
static func sector(start_angle:int,end_angle:int,r:float,offset:Vector2 = Vector2.ZERO):var points:PackedVector2Arraypoints.append(Vector2.ZERO + offset)points.append_array(arc(start_angle,end_angle,r,offset))points.append(Vector2.ZERO + offset)return points# 弧形
# 注意start_angle和end_angle都是角度
static func arc(start_angle:int,end_angle:int,r:float,offset:Vector2 = Vector2.ZERO):var points:PackedVector2Arrayvar angle = deg_to_rad(end_angle - start_angle)var edges:float = ceilf(angle * r) # 要绘制的点的个数 = θ * rvar vec = Vector2.RIGHT.rotated(deg_to_rad(start_angle)) * rfor i in range(edges+1):points.append(vec.rotated(angle/edges * i) + offset)return points# 星形
static func star(start_angle:int,edges:int,r1:float,r2:float = r1/2.0,offset:Vector2 = Vector2.ZERO):var points:PackedVector2Array# 外部半径var vec = Vector2.RIGHT.rotated(deg_to_rad(start_angle)) * r1# 内部半径var vec2 = Vector2.RIGHT.rotated(deg_to_rad(start_angle + 180/edges)) * r2for i in range(edges):points.append(vec.rotated(2 * PI/edges * i) + offset)points.append(vec2.rotated(2 * PI/edges * i) + offset)points.append(points[0]) # 返回第一个点return points# 返回圆角矩形的顶点
# 注意:以(0,0)为几何中心
static func round_rect(size:Vector2,r1:float,r2:float,r3:float,r4:float,offset:Vector2 = Vector2.ZERO) -> PackedVector2Array:var points:PackedVector2Arraypoints.append_array(arc(180,270,r1,Vector2(r1,r1) + offset))points.append_array(arc(270,360,r2,Vector2(size.x - r2,r2) + offset))points.append_array(arc(0,90,r3,Vector2(size.x - r3,size.y -r3) + offset))points.append_array(arc(90,180,r4,Vector2(r4,size.y - r4) + offset))points.append(Vector2(0,r1)+offset)return points# 返回倒角矩形的顶点
# 注意:以(0,0)为几何中心
static func chamfer_rect(size:Vector2,a:float,b:float,c:float,d:float,offset:Vector2 = Vector2.ZERO) -> PackedVector2Array:var points:PackedVector2Array = [Vector2(0,a) + offset,Vector2(a,0) + offset,Vector2(size.x-b,0) + offset,Vector2(size.x,b) + offset,Vector2(size.x,size.y-c) + offset,Vector2(size.x-c,size.y) + offset,Vector2(d,size.y) + offset,Vector2(0,size.y-d) + offset]points.append(points[0]) # 闭合return points# 返回胶囊形的顶点
static func capsule(size:Vector2,offset:Vector2 = Vector2.ZERO) -> PackedVector2Array:var points:PackedVector2Array = []var r:float = min(size.x,size.y)/2.0if size.x>size.y: # 横向points.append_array(arc(90,270,r,Vector2(r,r) + offset))points.append_array(arc(-90,90,r,Vector2(size.x-r,r) + offset))else: # 纵向points.append_array(arc(180,360,r,Vector2(r,r) + offset))points.append_array(arc(0,180,r,Vector2(r,size.y-r) + offset))points.append(points[0]) # 闭合return points# 返回梭形的顶点
# 注意:以(0,0)为几何中心
static func spindle(size:Vector2,offset:Vector2 = Vector2.ZERO) -> PackedVector2Array:var points:PackedVector2Array = []var dx:float = size.x/2.0var dy:float = size.y/2.0var d_max = max(dx,dy)var d_min = min(dx,dy)var r = (pow(d_max,2.0) + pow(d_min,2.0))/(2.0 * d_min) # 圆弧半径var angle = rad_to_deg(asin(d_max/r))if dx<dy:points.append_array(arc(180-angle,180+angle,r,Vector2(r,dy)))points.append(Vector2(dx,0))points.append_array(arc(-angle,angle,r,Vector2(-r+2*dx+1,dy)))points.append(points[0]) # 闭合else:points.append_array(arc(270-angle,270+angle,r,Vector2(dx,r)))points.append(Vector2(size.x,dy))points.append_array(arc(90-angle,90+angle,r,Vector2(dx,-r+2*dy+1)))points.append(points[0]) # 闭合return points
# =================================== 特殊图形 ===================================
# 太极
static func taiji(r:float,offset:Vector2 = Vector2.ZERO) -> Dictionary:var dict = {pan = circle(r,offset), # 底部圆盘yin = [], # 阴鱼yang = [], # 阳鱼yin_eye = circle(r/10,Vector2(0,-r/2)+ offset), # 阴鱼眼yang_eye = circle(r/10,Vector2(0,r/2)+ offset), # 阳鱼眼}# 阴鱼dict["yin"].append_array(arc(90,270,r,offset))dict["yin"].append_array(arc(-90,90,r/2,Vector2(0,-r/2)+offset))var ac = arc(90,270,r/2,Vector2(0,r/2)+offset)ac.reverse()dict["yin"].append_array(ac)# 阳鱼dict["yang"].append_array(arc(-90,90,r,offset))dict["yang"].append_array(arc(90,270,r/2,Vector2(0,r/2)+offset))var ac2 = arc(-90,90,r/2,Vector2(0,-r/2)+offset)ac2.reverse()dict["yang"].append_array(ac2)return dict# 螺旋线
static func helix(start_angle:int,start_r:float,end_r:float,step:int =1,offset:Vector2 = Vector2.ZERO) -> PackedVector2Array:var points:PackedVector2Arrayvar steps = end_r - start_rfor i in range(steps):points.append(Vector2.RIGHT.rotated(deg_to_rad(start_angle + step * i)) * (start_r+i) + offset)return points# =================================== 花边图形 ===================================
enum{AXIS_X = 1,AXIS_Y = 2,
}# 返回与实际矩形不相关的重复半圆边数据
static func repeat_circle(length:float,r:float,space:float = 0,axis:int = AXIS_X,concave:bool = false,reverse:bool = false,offset:Vector2 = Vector2.ZERO) -> PackedVector2Array:var points:PackedVector2Arraymatch axis:AXIS_X: # 水平方向var yu = fmod(length,(2.0 * r + space)) # 余数if !concave: # 凸出points.append(Vector2.ZERO + offset)for i in floorf(length/(2.0 * r + space)):points.append_array(arc(180,360,r,Vector2(2 * r + space,0) * i + Vector2(r + yu/2.0,0) + offset))points.append(Vector2(length,0) + offset)else: # 凹进去points.append(Vector2.ZERO + offset)for i in floorf(length/(2.0 * r + space)):var ac = arc(0,180,r,Vector2(2 * r + space,0) * i + Vector2(r + yu/2.0,0) + offset)ac.reverse()points.append_array(ac)points.append(Vector2(length,0) + offset)AXIS_Y: # 垂直方向var yu = fmod(length,(2.0 * r + space)) # 余数if !concave: # 凸出points.append(Vector2.ZERO + offset)for i in floorf(length/(2.0 * r + space)):points.append_array(arc(-90,90,r,Vector2(0,2 * r + space) * i + Vector2(0,r + yu/2.0) + offset))points.append(Vector2(0,length) + offset)else: # 凹进去points.append(Vector2.ZERO + offset)for i in floorf(length/(2.0 * r + space)):var ac = arc(90,270,r,Vector2(0,2 * r + space) * i + Vector2(0,r + yu/2.0) + offset)ac.reverse()points.append_array(ac)points.append(Vector2(0,length) + offset)# 是否逆序所有点if reverse:points.reverse()return points enum{SIDE_UP = 1,SIDE_RIGHT = 2,SIDE_BOTTOM = 3,SIDE_LEFT = 4
}# 返回边线重复半圆的矩形的边
static func repeat_circle_edge(size:Vector2,r:float,space:float = 0,side:int = SIDE_UP,concave:bool = false,offset:Vector2 = Vector2.ZERO) -> PackedVector2Array:var points:PackedVector2Arraymatch side:SIDE_UP:points.append_array(repeat_circle(size.x,r,space,AXIS_X,concave))SIDE_RIGHT:points.append_array(repeat_circle(size.y,r,space,AXIS_Y,concave,false,Vector2(size.x,0)))SIDE_LEFT:points.append_array(repeat_circle(size.y,r,space,AXIS_Y,!concave,true))SIDE_BOTTOM:points.append_array(repeat_circle(size.x,r,space,AXIS_X,!concave,true,Vector2(0,size.y)))return points# 返回边线重复半圆的矩形的边
static func repeat_circle_edge_rect(size:Vector2,r:float,space:float = 0,concave:bool = false,offset:Vector2 = Vector2.ZERO) -> PackedVector2Array:var points:PackedVector2Arraypoints.append_array(repeat_circle_edge(size,r,space,SIDE_UP,concave,offset))points.append_array(repeat_circle_edge(size,r,space,SIDE_RIGHT,concave,offset))points.append_array(repeat_circle_edge(size,r,space,SIDE_BOTTOM,concave,offset))points.append_array(repeat_circle_edge(size,r,space,SIDE_LEFT,concave,offset))return points# 返回指定点为中心,给定长度的两条互相垂直线段,可以用于绘制十字坐标线
static func line_cross(position:Vector2,length:float,start_angle:int = 0) -> Array:var start_rad = deg_to_rad(start_angle)# 水平线段俩端点var h_line = [Vector2.LEFT.rotated(start_rad) * length/2.0 + position,Vector2.RIGHT.rotated(start_rad) * length/2.0 + position,]# 水平线段俩端点var v_line = [Vector2.UP.rotated(start_rad) * length/2.0 + position,Vector2.DOWN.rotated(start_rad) * length/2.0 + position,]return [h_line,v_line]# =================================== 网格矩形求取函数 ===================================
# 矩形网格 - 棋盘格矩形求取函数
static func checker_board_rects(size:Vector2,cell_size:Vector2) -> Array:var rects_yang:Array[Rect2]var rects_yin:Array[Rect2]for x in range(size.x):for y in range(size.y):var pos = Vector2(x,y) * cell_sizeif (x % 2 == 0 and y % 2 == 0) or (x % 2 == 1 and y % 2 == 1):rects_yang.append(Rect2(pos,cell_size))else:rects_yin.append(Rect2(pos,cell_size))return [rects_yang,rects_yin]# =================================== 网格线和点求取函数 ===================================
# 方形 - 网格点求取函数
static func rect_grid_points(size:Vector2,cell_size:Vector2) ->PackedVector2Array:var points:PackedVector2Arrayfor x in range(size.x + 1):for y in range(size.y + 1):points.append(Vector2(x,y) * cell_size)return points# 三角 - 网格点求取函数
static func triangle_grid_points(size:Vector2,cell_size:Vector2) ->PackedVector2Array:var points:PackedVector2Arrayfor y in range(size.y + 1):if y % 2 == 0: # 偶数行for x in range(size.x + 1):points.append(Vector2(x,y) * cell_size)else: # 奇数行for x in range(size.x):points.append(Vector2(x,y) * cell_size + Vector2(cell_size.x/2,0))return points# 六边形 - 网格点求取函数
static func hex_grid_points(size:Vector2,cell_size:Vector2) ->PackedVector2Array:var points:PackedVector2Arrayfor y in range(size.y + 1):if y % 2 == 0: # 偶数行for x in range(size.x):if (x+1)% 3 != 0:points.append(Vector2(x,y) * cell_size + Vector2(cell_size.x/2,0))else: # 奇数行for x in range(size.x + 1):if x % 3 != 1:points.append(Vector2(x,y) * cell_size)return points# 方形 - 网格线求取函数
static func rect_grid_lines(size:Vector2,cell_size:Vector2) -> Dictionary:var lines = {v_lines = [], # 垂直的网格线h_lines = [] # 水平的网格线}var v_line1 = [Vector2.ZERO,Vector2.DOWN * cell_size.y * size.y]var h_line1 = [Vector2.ZERO,Vector2.RIGHT * cell_size.x * size.x]lines["v_lines"].append(v_line1)lines["h_lines"].append(h_line1)for x in range(1,size.x+1):var offset_x = Vector2(cell_size.x,0) * xlines["v_lines"].append([v_line1[0] + offset_x,v_line1[1] + offset_x])for y in range(1,size.y+1):var offset_y = Vector2(0,cell_size.y) * ylines["h_lines"].append([h_line1[0] + offset_y,h_line1[1] + offset_y])return lines# =================================== 刻度线生成 ===================================# 返回指定范围的弧形刻度线起始点坐标集合
# start_angle:起始角度
# end_angle:结束角度
# steps:切分次数
# r:半径
# length:刻度线长
static func arc_scale(start_angle:int,end_angle:int,steps:int,r:float,length:float) -> Array:var scales:Array = []var vec1 = (Vector2.RIGHT * (r-length)).rotated(deg_to_rad(start_angle))var vec2 = (Vector2.RIGHT * r).rotated(deg_to_rad(start_angle))var angle = deg_to_rad(end_angle - start_angle) # 夹角for i in range(steps+1):var line = [vec1.rotated((angle/steps) * i),vec2.rotated((angle/steps) * i)]scales.append(line)return scales# 返回指定范围的直线刻度线起始点坐标集合
static func line_scale(ruler_width:float,steps:int,length:float):var scales:Array = []var vec1 = Vector2.ZEROvar vec2 = Vector2.DOWN * lengthvar space = ruler_width/steps # 单位间隔for i in range(steps+1):var line = [vec1 + Vector2(space,0) * i,vec2 + Vector2(space,0) * i]scales.append(line)return scales