You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.26 20:45:08