【Godot4.2】数组扩展类型Array2D及使用手册
Godot本身的Array太过于宽松,并且只提供了通用的方法。而在很多场景下,我们都会用到二维数组,而Array自身提供的通用方法在一些二维数组操作上并不便利,所以编写一个自定义类是非常有必要的。Array2D就是专门针对二维数组的创建和操作而编写的,通过其自定义方法可以更便捷、多样和灵活的创建二维数组,并对其进行操纵。本文贴出Array2D类的源码,以及具体的使用方法。这个类目前只是一个初级版本
概述
Godot本身的Array
太过于宽松,并且只提供了通用的方法。
而在很多场景下,我们都会用到二维数组,而Array
自身提供的通用方法在一些二维数组操作上并不便利,所以编写一个自定义类是非常有必要的。
Array2D就是专门针对二维数组的创建和操作而编写的,通过其自定义方法可以更便捷、多样和灵活的创建二维数组,并对其进行操纵。
本文贴出Array2D类的源码,以及具体的使用方法。
这个类目前只是一个初级版本,后续可能会继续改进和扩充。
Array2D类源码
# ========================================================
# 名称:Array2D
# 类型:自定义类
# 简介:二维数组类,专用于处理二维数组
# 作者:巽星石
# Godot版本:4.1.1-stable (official)
# 创建时间:2023-09-24 23:30:57
# 最后修改时间:2023年9月25日21:38:07
# ========================================================
class_name Array2D
var data:Array
func _init(p_data:Array = []):
data = p_data
# 返回指定行数和列数以及填充内容的二维数组
static func fill_rect(rows:int,cols:int,fill_content) -> Array2D:
# 构造行
var row = Array()
row.resize(cols)
row.fill(fill_content)
# 构造二维数组
var arr2 = Array()
arr2.resize(rows)
arr2.fill(row)
return Array2D.new(arr2)
# 返回一个使用介于min到max之间的随机数整数填的二维数组
static func fill_rect_random(rows:int,cols:int,min:int,max:int) -> Array2D:
# 构造一维数组
var arr = []
arr.resize(rows * cols)
# 填充随机数
arr = arr.map(func(num):
return randi_range(min,max)
)
return Array2D.array_to_array2d(arr,cols)
# 控制台显示
func show() -> void:
if data.is_empty():
print(data)
else:
for row in data:
print(row)
# 用内容填充整个二维数组
func fill(fill_content) -> void:
for row in data:
row.fill(fill_content)
# 用min到max之间的随机数填充当前二维数组
func random_fill_int(min:int,max:int):
data = fill_rect_random(data.size(),data[0].size(),min,max).data
# 用内容填充整个二维数组边界
func fill_border(fill_content) -> void:
for i in range(data.size()):
if i == 0 or i == data.size() - 1:
data[i] = data[i].map(func(num):
return fill_content;
)
pass
else:
data[i][0] = fill_content
data[i][data[i].size()-1] = fill_content
# 获取指定位置 - 上方 - 单元格值或无
func get_up(row:int,col:int):
return get_cell(row-1,col)
# 获取指定位置 - 下方 - 单元格值或无
func get_down(row:int,col:int):
return get_cell(row+1,col)
# 获取指定位置 - 左侧 - 单元格值或无
func get_left(row:int,col:int):
return get_cell(row,col - 1)
# 获取指定位置 - 右侧 - 单元格值或无
func get_right(row:int,col:int):
return get_cell(row,col + 1)
# 获取指定位置 - 上方 - 单元格值或无
func get_upv(pos:Vector2):
return get_up(pos.x,pos.y)
# 获取指定位置 - 下方 - 单元格值或无
func get_downv(pos:Vector2):
return get_cell(pos.x,pos.y)
# 获取指定位置 - 左侧 - 单元格值或无
func get_leftv(pos:Vector2):
return get_cell(pos.x,pos.y)
# 获取指定位置 - 右侧 - 单元格值或无
func get_rightv(pos:Vector2):
return get_cell(pos.x,pos.y)
# =================================== 获取/设定值 ===================================
# ----------------------------------- 行 -----------------------------------
# 获取行
func get_row(index:int):
return data[index]
# 设定行 - 用新的数组取代原来的行
func set_row(index:int,new_row:Array) -> void:
data[index] = new_row
# 将行元素全部填充为fill_content
func fill_row(index:int,fill_content) -> void:
var new_row = Array()
new_row.fill(fill_content)
data[index] = new_row
# 在指定位置插入新行
func insert_row(pos:int,new_row:Array) -> void:
data.insert(pos,new_row)
# 在开头插入新行
func insert_row_start(new_row:Array) -> void:
data.insert(0,new_row)
# 在末尾插入新行
func insert_row_end(new_row:Array) -> void:
data.append(new_row)
# 在末尾添加行
func append_row(new_row:Array) -> void:
data.append(new_row)
# 移除指定位置行
func remove_row(pos:int) -> void:
data.remove_at(pos)
# 移除第一行
func remove_row_start() -> void:
data.remove_at(0)
# 移除末尾行
func remove_row_end() -> void:
data.remove_at(data.size()-1)
# 重置 - 不修改行列大小,所有元素重置为int_val(默认为null)
func reset(int_val = null) -> void:
fill(int_val)
# 清除所有行 -- data.resize(0)
func clear() -> void:
data.clear()
# 按行进行洗牌
func shuffle_with_rows() -> void:
# 所有行自己进行洗牌
for row in data:
row.shuffle()
# 对行顺序进行洗牌
data.shuffle()
# 整体洗牌
func shuffle() -> void:
# 转为一维数组
var arr1d = to_array()
# 对所有元素进行洗牌
arr1d.shuffle()
# 再次转化为数组
data = array_to_array2d(arr1d,data[0].size()).data
# Array --> Array2D
static func array_to_array2d(array:Array,num:int) -> Array2D:
var arr = array.duplicate(true)
var arr_back:Array[Array] = []
while !arr.is_empty():
var sub_arr:Array
for i in range(num if num < arr.size() else arr.size()):
sub_arr.append(arr[0])
arr.remove_at(0)
arr_back.append(sub_arr)
return Array2D.new(arr_back)
# Array2D --> Array
func to_array() -> Array:
var arr = data.duplicate(true)
var arr1:Array = []
if arr.size() >0:
arr1 = arr[0] if typeof(arr[0]) == TYPE_ARRAY else [arr[0]]
for i in range(1,arr.size()):
arr1.append_array(arr[i] if typeof(arr[i]) == TYPE_ARRAY else [arr[i]])
return arr1
# ----------------------------------- 列 -----------------------------------
# 获取列
func get_col(index:int):
var col = []
for row in data:
col.append(row[index])
return col
# 设定列
func set_col(index:int,new_col:Array) -> void:
for i in range(data.size()):
data[i][index] = new_col[i]
# 将行元素全部填充为fill_content
func fill_col(index:int,fill_content) -> void:
var new_col = Array()
new_col.resize(data.size())
new_col.fill(fill_content)
set_col(index,new_col)
# ----------------------------------- 单元格 -----------------------------------
# 获取单元格的值
func get_cell(row_idx:int,col_idx:int):
# 超出范围
if row_idx not in range(data.size()) or col_idx not in range(data[0].size()-1):
return null
return data[row_idx][col_idx]
# 获取单元格的值 -- Vector2参数形式
func get_cellv(cellv:Vector2):
return data[cellv.x][cellv.y]
# 设定单元格的值
func set_cell(row_idx:int,col_idx:int,new_val):
data[row_idx][col_idx] = new_val
# 设定单元格的值 -- Vector2参数形式
func set_cellv(cellv:Vector2,new_val):
data[cellv.x][cellv.y] = new_val
创建Array2D
使用普通二维数组字面量(嵌套的Array)创建
最简单的方式就是直接在new()中传入一个二维数组。
var arr2d = Array2D.new([
[1,2,3,4,5],
[6,7,8,9,10],
[11,12,13,14,15],
[16,17,18,19,20],
])
new()会调用Array2D类的构造函数,也就是_init并将二维数组传递给Array2D实例的data属性。
实例化后后续的操作全在data上进行操作。
使用填充创建
静态方法fill_rect,可以创建一个几行×几列形式的二维数组,并对其填充指定的内容。
var arr2d = Array2D.fill_rect(10,10,1) # 10行×10列,填充元素1
arr2d.show()
输出:
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
var arr2d = Array2D.fill_rect(2,2,0) # 2行×2列,填充元素0
arr2d.show()
输出:
[0, 0]
[0, 0]
使用随机填充创建
var arr2d = Array2D.fill_rect_random(5,5,0,3) # 5行×5列,填充0-3之间的随机数
arr2d.show()
输出:
[3, 1, 3, 3, 0]
[0, 2, 0, 2, 2]
[0, 3, 1, 2, 0]
[2, 0, 2, 2, 2]
[3, 2, 0, 3, 3]
在通过new()、fill_rect()或fill_rect_random()创建Array2D的实例后,随时可以使用
fill()、random_fill_int()方法来重新进行整体填充。
填充边缘
fill_border可以只对二维数组的“矩形边缘”进行填充。
var arr2d = Array2D.fill_rect(5,5,"□")
arr2d.fill_border("■") # 填充边缘
arr2d.show()
输出:
["■", "■", "■", "■", "■"]
["■", "□", "□", "□", "■"]
["■", "□", "□", "□", "■"]
["■", "□", "□", "□", "■"]
["■", "■", "■", "■", "■"]
获取单元格四向临近单元格的值
get_up、get_down、get_left、get_right以及他们末尾带v的形式get_upv、get_downv、get_leftv、get_rightv分别用于获取指定位置单元格的临近上下左右四个单元格的值。
var arr2d = Array2D.fill_rect(5,5,"□")
arr2d.fill_border("■")
print(arr2d.get_up(1,1)) # ■
print(arr2d.get_up(0,0)) # <null>
print(arr2d.get_upv(Vector2(1,1))) # ■
print(arr2d.get_upv(Vector2(0,0))) # <null>
行、列、单元格操作
添加行
var arr2d = Array2D.fill_rect(2,2,0) # 创建2行2列,初始值为0的矩形二维数组
arr2d.insert_row(0,[1,1]) # 添加行
arr2d.show() # 控制台输出显示
等价写法insert_row_start([1,1]):
[1, 1]
[0, 0]
[0, 0]
insert_row_end([1,1])或append([1,1])将在末尾添加行。
删除行
var arr2d = Array2D.fill_rect(2,2,0) # 创建2行2列,初始值为0的矩形二维数组
arr2d.remove_row(0) # 删除行,remove_row(0)等价于remove_row_start()
arr2d.show() # 控制台输出显示
输出:
[0, 0]
remove_row_end()删除末尾行。
获取列
var arr2d = Array2D.fill_rect(2,2,0)
print(arr2d.get_col(0)) # 获取第一列
输出:
[0, 0]
设置列
var arr2d = Array2D.fill_rect(5,5,0)
arr2d.set_col(2,[1,1,1,1,1])
arr2d.show()
输出:
[0, 0, 1, 0, 0]
[0, 0, 1, 0, 0]
[0, 0, 1, 0, 0]
[0, 0, 1, 0, 0]
[0, 0, 1, 0, 0]
填充列
var arr2d = Array2D.fill_rect(5,5,0)
arr2d.fill_col(2,2)
arr2d.show()
输出:
[0, 0, 2, 0, 0]
[0, 0, 2, 0, 0]
[0, 0, 2, 0, 0]
[0, 0, 2, 0, 0]
[0, 0, 2, 0, 0]
获取单元格
var arr2d = Array2D.new([
[1,2,3,4,5],
[6,7,8,9,10],
[11,12,13,14,15],
[16,17,18,19,20],
])
print(arr2d.get_cell(2,2)) # 13
get_cell(2,2)等价于get_cellv(Vector2(2,2))
设定单元格值
var arr2d = Array2D.new([
[1,2,3,4,5],
[6,7,8,9,10],
[11,12,13,14,15],
[16,17,18,19,20],
])
arr2d.set_cell(2,2,0)
arr2d.show()
set_cell(2,2,0)等价于set_cellv(Vector2(2,2),0)
[1, 2, 3, 4, 5]
[6, 7, 8, 9, 10]
[11, 12, 0, 14, 15]
[16, 17, 18, 19, 20]
重置
var arr2d = Array2D.fill_rect(2,2,0) # 创建2行2列,初始值为0的矩形二维数组
arr2d.reset() # 重置二维数组
arr2d.show() # 控制台输出显示
输出:
[<null>, <null>]
[<null>, <null>]
arr2d.reset(0) # 重置二维数组
arr2d.show() # 控制台输出显示
输出:
[0, 0]
[0, 0]
● reset()将保留二维数组的结构,把每一个元素变成null;
● reset()接受一个参数,可以将数组元素设定为非null;
清除
清除会删除所有行,让二维数组变成一维空数组。
var arr2d = Array2D.fill_rect(2,2,0) # 创建2行2列,初始值为0的矩形二维数组
arr2d.clear() # 清除
arr2d.show() # 控制台输出显示
输出:
[]
洗牌
二维数组的洗牌有两种思路:
● 每行各自洗牌,然后对行的顺序进行洗牌
● 将二维数组转为一维数组,洗牌后再转为二维数组
按行洗牌
先对每一行的元素进行顺序的打乱,再对所有行进行顺序的打乱。
var arr2d = Array2D.new([
[1,2,3,4,5],
[6,7,8,9,10],
[11,12,13,14,15],
[16,17,18,19,20],
])
arr2d.shuffle_with_rows() # 按行进行洗牌
arr2d.show()
输出:
[15, 13, 11, 14, 12]
[4, 3, 2, 1, 5]
[6, 10, 7, 9, 8]
[19, 20, 16, 17, 18]
虽然也是对行和列都进行了打乱,但是每行内的元素都还是原来的那几个。
全部元素一起洗牌
首先将二维数组转为一维数组,调用Array原生的shuffle()方法,进行所有元素的打乱,然后再转化为二维数组。
var arr2d = Array2D.new([
[1,2,3,4,5],
[6,7,8,9,10],
[11,12,13,14,15],
[16,17,18,19,20],
])
arr2d.shuffle() # 对所有元素洗牌
arr2d.show()
输出:
[2, 3, 10, 9, 4]
[8, 6, 5, 7, 13]
[20, 1, 12, 11, 16]
[14, 17, 19, 15, 18]
二维数组与一维数组互转
从一维数组构造二维数组
# 一维数组range(20),按每4个元素划分为二维数组
var arr2d = Array2D.array_to_array2d(range(20),4)
arr2d.show()
输出:
[0, 1, 2, 3]
[4, 5, 6, 7]
[8, 9, 10, 11]
[12, 13, 14, 15]
[16, 17, 18, 19]
二维数组转一维数组
var arr2d = Array2D.new([
[1,2,3,4,5],
[6,7,8,9,10],
[11,12,13,14,15],
[16,17,18,19,20],
])
print(arr2d.to_array()) # 将二维数组转化为一维数组
输出:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
更多推荐
所有评论(0)