Godot MultiMeshInstance工具脚本编写:如何自动配置碰撞形状
错误根因
触发Invalid set index 'Shape' (on base: 'Nil')报错的原因是两个问题叠加:
- tool脚本下的
onready变量赋值时机不对:onready只会在节点走完_ready()流程时才赋值,但你用setget改参数触发update()的时机,要么早于节点加载完成,要么发生在编辑器还没把子节点实例化的阶段,这时候coll变量就是空的Nil,给空值赋属性必然报错。 - 属性名写错:Godot里CollisionShape的碰撞形状属性是全小写的
shape,不是大写开头的Shape,就算拿到了节点,大小写不对照样会报属性错误。
修正实现步骤
- 删掉原来的
onready var coll = get_node("static/collision"),不要靠onready拿子节点,改成每次要更新碰撞的时候再动态拿节点引用,必须加判空,不然编辑器加载阶段必崩。 - 给
update()加前置校验:确认节点已经挂到场景树里了再执行逻辑,没挂的话直接跳过,适配tool脚本在编辑器里的运行时机。 - 把原来的
coll.Shape = shape改成coll.shape = shape,修正大小写问题。 - 调整碰撞范围的计算:原代码算的包围盒没对齐阵列的实际位置,要把碰撞形状的中心移到阵列中点,不然碰撞范围会飘到可视物体外面。
- 在
_ready()里主动跑一次update,保证节点刚加载完的时候,碰撞形状和阵列参数是对齐的,不用手动刷。
修正后的核心代码参考:
tool extends MultiMeshInstance export (float) var distance:float = 1.0 setget set_distance export (int) var count:int = 1 setget set_count export (Mesh) var mesh:Mesh setget set_mesh export (Vector3) var rotMesh:Vector3 setget set_rotMesh export (Vector3) var sclMesh:Vector3 setget set_sclMesh export (Vector3) var colMesh:Vector3 func set_distance(new_distance): distance = new_distance update() func set_count(new_count): count = new_count update() func set_mesh(new_mesh): mesh = new_mesh update() func set_rotMesh(new_rot): rotMesh = new_rot update() func set_sclMesh(new_scl): sclMesh = new_scl update() func _ready(): # 节点加载完成后主动刷新一次 update() func update(): # 未挂载到场景树时直接跳过,避免空引用 if not is_inside_tree(): return # 动态获取碰撞形状节点,空值时跳过 var coll = get_node_or_null("static/collision") if not coll: return # 初始化MultiMesh实例阵列 self.multimesh = MultiMesh.new() self.multimesh.transform_format = MultiMesh.TRANSFORM_3D self.multimesh.instance_count = count self.multimesh.visible_instance_count = count self.multimesh.mesh = mesh var offset = Vector3(0,0,0) var trfMesh:Basis = Basis(rotMesh) trfMesh = trfMesh.scaled(sclMesh) for i in range(count): self.multimesh.set_instance_transform(i, Transform(trfMesh, offset)) offset.x += distance # 计算匹配阵列的碰撞包围盒 var total_arr_length = distance * (count - 1) var shape = BoxShape.new() shape.extents = Vector3(total_arr_length/2 + colMesh.x, colMesh.y, colMesh.z) # 小写属性名赋值 coll.shape = shape # 碰撞形状位置对齐到阵列中点 coll.position = Vector3(total_arr_length/2, 0, 0)
性能优化说明
针对栅栏这类长条形静态阵列,用整体包围盒做碰撞的性能最高,不会因为逐实例的物理碰撞计算拖慢系统。如果后续需要单个实例的独立碰撞响应,再替换为多碰撞形状组合的结构即可。
内容的提问来源于stack exchange,提问作者Kirill Moskalew
相关产品推荐
相关产品推荐

