概述
在构造多点路径时我们会用到PackedVector2Array
,并使用Vector2()
来构造点。在手动创建多点数据时,这种写法其实很难看,有大量重复的Vector2()
,比如下面这样:
var points = [Vector2(100,100),Vector2(200,200),Vector2(300,300)]
如果有办法省去重复的Vector2()
就好了。代码会显得简洁不少。
这也就是本篇文章探讨和实现的内容,用更简单的方式去表示点集(PackedVector2Array
)。
点数据简易表示法
多点坐标字符串
我们可以用字符串形式,表示多个点的数据。比如:
var points = "100,100 200,200 300,300"
每对坐标用空格间隔。转化函数如下:
# 字符串形式的点数据转化为PackedVector2Array
func PotsStr2Vec2Arr(pots_str:String) -> PackedVector2Array:
var arr:PackedVector2Array
for cord_str in pots_str.split(" "):
var cord = cord_str.split(",")
arr.append(Vector2(float(cord[0]),float(cord[1])))
return arr
转化结果:
[(100, 100), (200, 200), (300, 300)]
坐标对顺序数组
也可以用坐标元素组成的数组表示多个点。
var points = [[100,100],[200,200],[300,300]]
转化函数:
# Array[Array]形式的点数据转化为PackedVector2Array
func PotsArr2Vec2Arr(pots:Array) -> PackedVector2Array:
var arr:PackedVector2Array
for cord in pots:
arr.append(Vector2(cord[0],cord[1]))
return arr
坐标紧凑排列数组
更极端的表示方法是,将顺序的点坐标按顺序紧密的排列。
var points = [100,100,200,200,300,300]
转化函数:
# Array形式的点数据转化为PackedVector2Array
func Pots2Vec2Arr(pots:Array) -> PackedVector2Array:
var arr:PackedVector2Array = []
if pots.size() % 2 == 0:
for i in range(pots.size()):
if i % 2 == 0:
arr.append(Vector2(pots[i],pots[i+1]))
return arr
三合一解析
# 点数据转化为PackedVector2Array
func Vec2Arr(pots) -> PackedVector2Array:
var arr:PackedVector2Array = []
if pots is String: # 字符串形式
for cord_str in pots.split(" "):
var cord = cord_str.split(",")
arr.append(Vector2(float(cord[0]),float(cord[1])))
else: # 数组形式
if pots[0] is Array: # Array[Array] 形式
for cord in pots:
arr.append(Vector2(cord[0],cord[1]))
else:
if pots.size() % 2 == 0:
for i in range(pots.size()):
if i % 2 == 0:
arr.append(Vector2(pots[i],pots[i+1]))
return arr
则以下三种形式都可以被正确解析:
var points = Vec2Arr("100,100 200,200 300,300")
var points = Vec2Arr([[100,100],[200,200],[300,300]])
var points = Vec2Arr([100,100,200,200,300,300])
Points2D
紧缩二维向量数组PackedVector2Array
,通常被用来表示2D折线或多边形的顺序点集,通常用于CanvasItem
绘图等。
在求解复杂图形时,对于2D点集,通常我们会进行大量的变换、逆序等操作,而且会对其点、线进行遍历等操作。PackedVector2Array
虽然也可以实现这些操作,但是每次都需要重新编写,二且作为数据类型,是无法拓展子类的。所以单独写一个类就很有必要了。
- 通过将PackedVector2Array封装为Point2D类型,便可以将变换和翻转操作直接写成方法,并直接返回操作后的顶点数据。
- 简易点数据转化函数可以写成该类的静态方法,既方便类实例使用,也方便其他地方使用。
class_name Points2D
var points:PackedVector2Array
# ==================== 实例化 ====================
func _init(pots) -> void:
if pots is PackedVector2Array:
self.points = pots
else:
self.points = Vec2Arr(pots)
# ==================== 变换 ====================
# 水平翻转
func flip_x() -> PackedVector2Array:
return Transform2D.FLIP_X * points
# 垂直翻转
func flip_y() -> PackedVector2Array:
return Transform2D.FLIP_Y * points
# 旋转
func rotated(degree:float) -> PackedVector2Array:
return Transform2D().rotated(deg_to_rad(degree)) * points
# 平移
func translated(offset:Vector2) -> PackedVector2Array:
return Transform2D().translated(offset) * points
# ==================== 逆序 ====================
func reverse() -> PackedVector2Array:
var pots = points.duplicate()
pots.reverse()
return pots
# ==================== 简易点数据转化函数 ====================
# 点简易数据转化为 PackedVector2Array
static func Vec2Arr(pots) -> PackedVector2Array:
var arr:PackedVector2Array = []
if pots is String: # 字符串形式
for cord_str in pots.split(" "):
var cord = cord_str.split(",")
arr.append(Vector2(float(cord[0]),float(cord[1])))
else: # 数组形式
if pots[0] is Array: # Array[Array] 形式
for cord in pots:
arr.append(Vector2(cord[0],cord[1]))
else:
if pots.size() % 2 == 0:
for i in range(pots.size()):
if i % 2 == 0:
arr.append(Vector2(pots[i],pots[i+1]))
return arr
使用测试
extends Node2D
var points = Points2D.Vec2Arr("100,100 200,200 300,200")
func _draw() -> void:
draw_polyline(points,Color.AQUAMARINE,1)
可以看到:
- 通过将
Vec2Arr
作为Points2D
的静态方法,我们可以很方便的使用简易点表示表示法。
extends Node2D
var points = Points2D.new("100,100 200,200 300,200")
func _draw() -> void:
draw_polyline(points.points,Color.AQUAMARINE,1)
同样的,我们可在用new()
实例化一个Points2D
对象时,传入简易点数据表示形式。
使用镜像变换
extends Node2D
var points = Points2D.new("100,100 200,200 300,200")
func _draw() -> void:
draw_polyline(points.points,Color.AQUAMARINE,1)
draw_polyline(points.flip_x(),Color.ORANGE,1)
draw_polyline(points.flip_y(),Color.YELLOW_GREEN,1)
使用旋转变换
extends Node2D
var points = Points2D.new("100,100 200,200 300,200")
func _draw() -> void:
draw_polyline(points.points,Color.AQUAMARINE,1)
for i in range(1,10):
draw_polyline(points.rotated(15 * i),Color.ORANGE,1)
使用逆序+平移变换
extends Node2D
var points = Points2D.new("100,100 200,200 300,200")
func _ready() -> void:
var ps2 = Points2D.new(points.reverse()) # 逆序点
points.points.append_array(ps2.translated(Vector2(100,-100)))
func _draw() -> void:
draw_polyline(points.points,Color.AQUAMARINE,1)
可以看到:
- 通过添加平移了一段距离的折线的逆序点,可以构造一个多边形。上面的点集用
draw_polygon()
可以直接绘制出多边形。