概述
在一个平面上基于一个定点,可以创建一个平面直角坐标系,同时也可以创建一个极坐标系。通过极坐标系,可以将平面上的点用极坐标形式描述出来。
本文就记录一下如何在Godot中创建和表示极坐标点,并将其运用于绘图。
极坐标系
极坐标系(polar coordinates)是指在平面内由极点、极轴和极径组成的坐标系。
- 在平面上取定一点
O
,称为极点。从O
出发引一条射线Ox
,称为极轴。 - 再取定一个单位长度,通常规定角度取逆时针方向为正。这样,平面上任一点
P
的位置就可以用线段OP
的长度ρ
以及从Ox
到OP
的角度θ
来确定,有序数对(ρ,θ)
就称为P
点的极坐标,记为P(ρ,θ)
; ρ
称为P
点的极径,θ
称为P
点的极角。
极坐标点函数
在Godot中,我们可以编写函数来表示极坐标点,对应的极坐标系与Godot的坐标系原点重合,单位长度一致,而且X轴正方向就是极坐标系的极轴。而且因为Y轴正方向向下,所以采用逆时针角度为正。
有了上面的设定之后,我们就可以用极坐标形式表示屏幕上任意位置。
编写极坐标点函数如下:
# 极坐标点函数 - 通过角度和长度定义一个点
func pVector2(angle:float = 0.0,length:float =0.0) -> Vector2:
var dir = Vector2.RIGHT.rotated(deg_to_rad(angle))
return dir * length
可以看到:
- 代码相当简洁,就是获取X轴正方向
Vector2.RIGHT
旋转angle
度之后再乘以length
指定的距离。 - 其中
angle
参数采用度而不是弧度的好处是,更直观,也更容易写 - 因为设定了
angle
和length
的默认值,所以pVector2()
返回的就是Vector2(0,0)
测试代码:
extends Node2D
func _draw() -> void:
# 绘制与X轴正方向夹角30°,距坐标系原点100像素的点
myCanvas.draw_point(self,pVector2(30,100))
上面的代码:
- 绘制一个与X轴正方向夹角
30°
,距坐标系原点100
像素的点
绘制效果:
用极坐标点绘制图形
绘制正多边形
extends Node2D
var points:PackedVector2Array = [] # 图形顶点
var steps := 4.0 # 边数
var start_angle := 0.0 # 起始角度
func _draw() -> void:
var step_ang := 360.0/steps # 间隔角度
# 求取顶点
for i in range(steps):
points.append(pVector2(step_ang * i + start_angle,100.0))
# 将绘图原点设定到(200,200)
draw_set_transform(Vector2(200,200))
# 绘制
draw_colored_polygon(points,Color.AQUAMARINE)
绘制任意多边形
extends Node2D
var points:PackedVector2Array = [] # 图形顶点
func _ready() -> void:
# 添加极坐标点
points.append(pVector2(-45.0,100.0))
points.append(pVector2(45.0,120.0))
points.append(pVector2(120.0,50.0))
points.append(pVector2(160.0,50.0))
func _draw() -> void:
# 将绘图原点设定到(200,200)
draw_set_transform(Vector2(200,200))
# 绘制多边形
draw_colored_polygon(points,Color.ORANGE_RED)
# 绘制中心点(绘图原点)
myCanvas.draw_point(self,Vector2())
# 绘制从绘图原点到各个顶点的向量
myCanvas.draw_point_to_points_vectors(self,Vector2(),points)
# 绘制各个顶点的坐标
myCanvas.draw_points_pos(self,points)
可以看到,在构造任意点来绘制多边形时,极坐标点更易于理解和使用,而直角坐标点则更难想象和编写。
极坐标与Vector2的关联
因为pVector2()
返回的是Vector2
类型,所以实际上我们可以直接对其使用Vector2
类型的运算及方法。
一些Vector2
类型的常量我们也可以找到对应的pVector2()
表示形式:
Vector2常量 | Vector2实际值 | pVector2值或表示形式 |
---|---|---|
Vector2.ZERO | Vector2(0,0) | pVector2()或pVector2(0,0) |
Vector2.ONE | Vector2(1,1) | pVector2(45,sqrt(2)) |
Vector2.RIGHT | Vector2(1,0) | pVector2(0,1) |
Vector2.LEFT | Vector2(-1,0) | pVector2(180,1)或pVector2(-180,1) |
Vector2.TOP | Vector2(0,-1) | pVector2(-90,1) |
Vector2.BOTTOM | Vector2(0,1) | pVector2(90,1) |
而任意角度单位向量(方向向量):
Vector2.RIGHT.rotated(deg_to_rad(45))
=pVector2(45,1)
Vector2.RIGHT.rotated(deg_to_rad(60))
=pVector2(60,1)
任意角度方向向量乘以长度:
Vector2.RIGHT.rotated(deg_to_rad(45)) * 100
=pVector2(45,100)
Vector2.RIGHT.rotated(deg_to_rad(60)) * 100
=pVector2(60,100)
可以看到用极坐标形式,可以大大简化向量旋转和伸缩的表示。
用极坐标加法获取图形顶点
extends Node2D
var points:PackedVector2Array = [] # 图形顶点
func _ready() -> void:
# 添加极坐标点
var p1 = pVector2(0,100.0)
var p2 = p1 + pVector2(-120,100)
var p3 = p2 + pVector2(180,100)
var p4 = p3 + pVector2(120,100)
var p5 = p4 + pVector2(60,100)
var p6 = p5 + pVector2(0,100)
points.append_array([p1,p2,p3,p4,p5,p6])
func _draw() -> void:
# 将绘图原点设定到(200,200)
draw_set_transform(Vector2(200,200))
# 绘制多边形
draw_colored_polygon(points,Color.ORANGE_RED)
# 绘制中心点(绘图原点)
myCanvas.draw_point(self,Vector2())
# 绘制从绘图原点到各个顶点的向量
myCanvas.draw_point_to_points_vectors(self,Vector2(),points)
# 绘制各个顶点的坐标
#myCanvas.draw_points_pos(self,points)
myCanvas.draw_points_idx(self,points)
# 极坐标点函数 - 通过角度和长度定义一个点
func pVector2(angle:float = 0.0,length:float =0.0) -> Vector2:
var dir = Vector2.RIGHT.rotated(deg_to_rad(angle))
return dir * length
绘制效果:
上面的正六边形绘制原理示意图如下:
这种方式与之前提到的基于旋转和移动的点求取方式有些相似,但是那种方式是基于当前位置和方向。而这里极坐标加减法,其旋转角度始终是与X轴正方向的夹角。
总结
- 本文描述了如何创建一个与Godot的屏幕坐标系保持一致的假想的极坐标系,并通过
pVector2()
函数来表示极坐标点 pVector2()
返回的实际是等价的直角坐标系中的Vector2
,因此我们可以直接将它用于图形顶点的表示和绘制pVector2()
本质上还是Vector2
,所以可以使用Vector2
拥有的属性、方法和运算。- 极坐标的加减法等同于等价的
Vector2
进行加减法,所以可以用来获取集合图形顶点。