☰
Godot 2D 物理关节 PinJoint2D 完全指南:铰链、摇杆与马达驱动实现
2026/10/13 6:45:45 网站建设 项目流程
  • 文档
  • 教程
  • 游戏开发

【免费下载链接】godot-docs

Godot Engine official documentation

项目地址:https://gitcode.com/GitHub_Trending/go/godot-docs
点击查看免费下载

PinJoint2D 是 Godot 2D 物理引擎中最基础的关节节点,它把两个 2D 物理体(如 RigidBody2D、StaticBody2D)钉在一个单点上,让它们可以自由旋转,是制作钟摆、跷跷板、绳索、连杆机构与 2D 布偶动画的核心工具。本文将基于官方文档类参考,结合 Godot 源码文档中的底层物理服务器 API,系统讲解 PinJoint2D 的节点搭建、六个核心属性、角度限位与马达的实战配置,以及低阶 RID 编程用法。

PinJoint2D 是什么

PinJoint2D(销钉关节)是一种 2D 物理关节:它将两个物理体在一个点位上连接起来,允许二者围绕该点自由旋转。官方类参考原文(classes/class_pinjoint2d.rst)给出的定义是:

A physics joint that attaches two 2D physics bodies at a single point, allowing them to freely rotate.

例如,把一个 RigidBody2D 附加到 StaticBody2D 上,就可以轻松做出钟摆(pendulum)或跷跷板(seesaw)。关节本身不传递位移约束以外的信息——销钉点两侧的物体只被限制在一点上保持重合,而旋转角度不受限制(除非你开启角度限位)。

继承关系与节点类型

PinJoint2D 的完整继承链为:

PinJoint2D < Joint2D < Node2D < CanvasItem < Node < Object

它直接继承自Joint2D(所有 2D 物理关节的抽象基类)。在 Godot 编辑器中,与它同属 Joint2D 子类的还有DampedSpringJoint2D(阻尼弹簧)和GrooveJoint2D(沟槽关节),三者共用一个基类约束接口。详细继承关系见 classes/class_joint2d.rst。

由于 PinJoint2D 继承自 Node2D,它自带 2D 变换(位置、旋转、缩放)。关节的锚点位置由该节点自身的位置决定,因此创建时把 PinJoint2D 节点放在两个物理体连接处的坐标上即可。

快速上手:搭建一个钟摆

最经典的应用是把一个 RigidBody2D 钉到 StaticBody2D 上,形成单摆。步骤如下:

  1. 在场景中创建一个StaticBody2D(作为固定支点,如天花板)。
  2. 在支点下方创建一个RigidBody2D(作为摆锤),并为其添加CollisionShape2D与合适的碰撞形状(如CapsuleShape2D或RectangleShape2D)。
  3. 新建一个PinJoint2D节点,将它的位置放在支点与摆锤连接处(即摆杆的悬挂点)。
  4. 在 PinJoint2D 的检查器中,把Node A(node_a)设为 StaticBody2D 的路径,Node B(node_b)设为 RigidBody2D 的路径。
  5. 运行场景,摆锤即围绕销钉点往复摆动。

使用 GDScript 动态创建同样直观:

extends Node2D func _ready() -> void: # 假设场景中已有两个物理体节点 var pin := PinJoint2D.new() pin.position = Vector2(320, 120) # 销钉锚点 pin.node_a = pivot_body.get_path() # 支点(StaticBody2D) pin.node_b = pendulum_body.get_path() # 摆锤(RigidBody2D) add_child(pin)

注意:node_a/node_b指向的节点必须继承自 PhysicsBody2D(RigidBody2D、StaticBody2D、CharacterBody2D、AnimatableBody2D 等皆可)。如果两者未设置或类型不符,关节不会生效。此约束来自基类 Joint2D 的官方属性说明(classes/class_joint2d.rst)。

基类 Joint2D 的通用属性

所有 2D 关节共享四个通用属性,PinJoint2D 同样继承它们,理解这些属性是正确使用销钉关节的前提:

属性类型默认值说明
node_aNodePathNodePath("")被连接的第一个物理体 A,必须继承 PhysicsBody2D
node_bNodePathNodePath("")被连接的第二个物理体 B,必须继承 PhysicsBody2D
biasfloat0.0关节回正速度;设为 0 时使用项目级默认值
disable_collisionbooltrue为 true 时,被连接的两个物理体彼此不碰撞

bias(回正系数)是最容易忽略的参数:当 node_a 与 node_b 朝不同方向运动时,bias 控制关节把它们拉回原始相对位置的快慢。bias 越低,两个物体"拉扯"关节的空间越大(关节显得越松弛);bias 越高,关节约束越刚性。当 bias 为0时,将回退到项目设置physics/2d/solver/default_constraint_bias的默认值0.2(见 classes/class_projectsettings.rst)。

disable_collision默认开启,意味着被同一关节绑定的两个物理体不会互相碰撞——这通常正是我们想要的(例如摆锤不会与支点本身发生碰撞响应)。若需要它们碰撞,可将其关闭。

此外 Joint2D 还提供get_rid()方法,返回该关节在PhysicsServer2D内部的 RID 句柄,供低阶物理服务器 API 调用(详见下文"底层原理"一节)。

六大专属属性详解

PinJoint2D 自己的六个属性(官方类参考 Properties 表,classes/class_pinjoint2d.rst)如下:

属性类型默认值含义
angular_limit_enabledboolfalse是否启用角度限位
angular_limit_lowerfloat0.0最小旋转角(弧度)
angular_limit_upperfloat0.0最大旋转角(弧度)
motor_enabledboolfalse是否启用马达驱动
motor_target_velocityfloat0.0马达目标角速度(弧度/秒)
softnessfloat0.0销钉连接的柔性程度

角度限位:angular_limit_enabled / lower / upper

销钉关节默认允许 360° 自由旋转。若希望限制旋转范围(如门铰链只允许开合 90°),需要:

  1. 将angular_limit_enabled设为true;
  2. 用angular_limit_lower定义最小旋转角,angular_limit_upper定义最大旋转角。

两个限位值均以弧度为单位。当限位被启用后,销钉连接的物体只能在[lower, upper]区间内旋转,超出即被约束力阻挡。官方描述明确指出这两个限位值"仅在angular_limit_enabled为 true 时生效"。

GDScript 中对应的 setter/getter 为set_angular_limit_enabled/is_angular_limit_enabled、set_angular_limit_lower/get_angular_limit_lower、set_angular_limit_upper/get_angular_limit_upper。

一个实用的"摆动门"示例——让门在 −60° 到 +60° 之间开合:

var pin := PinJoint2D.new() pin.node_a = wall.get_path() # 门框(StaticBody2D) pin.node_b = door_body.get_path() # 门板(RigidBody2D) pin.angular_limit_enabled = true pin.angular_limit_lower = deg_to_rad(-60.0) pin.angular_limit_upper = deg_to_rad(60.0) add_child(pin)

提示:deg_to_rad()是 GDScript 内置函数,用于把角度换算成弧度;限位参数要求弧度值。

马达:motor_enabled / motor_target_velocity

motor_enabled为true时,关节内置的马达会驱动销钉旋转——官方表述是 "a motor turns the pin"(马达转动销钉)。旋转的目标速度由motor_target_velocity决定,单位是弧度每秒(rad/s)。

典型用途:制作持续转动的轮轴、绞盘、传送带转轮。例如让轮子以每秒 2 弧度(约 114.6°/s)匀速旋转:

pin.motor_enabled = true pin.motor_target_velocity = 2.0 # rad/s

马达是一个"目标速度追踪器":它会持续施加力矩,试图让连接体达到目标角速度,而不是直接设定绝对角度。因此结合角度限位使用,可以实现"转动到限位处自动停住"的效果。

柔性:softness

softness控制销钉连接的"柔韧度":数值越高,销钉与配对物体之间的连接可以弯曲/弹性变形的程度越大。官方原文为:

The higher this value, the more the bond to the pinned partner can flex.

默认值0.0表示刚性连接(两点严格重合)。在需要模拟绳索、软连接或链条类效果时,可以适度提高 softness 获得弹性松弛感;但过高的值会让连接明显"发飘"、产生抖动,需要配合调参。

底层原理:PhysicsServer2D 中的销钉关节

PinJoint2D 节点本质上是PhysicsServer2D低阶 API 的封装。理解底层调用链有助于排查问题与做高阶定制。

关节的创建与 RID

所有 Joint2D 派生节点在内部都会通过PhysicsServer2D创建一个关节 RID。基类的get_rid()方法即返回这个 RID。低阶创建流程(见 classes/class_physicsserver2d.rst):

  • joint_create():在物理服务器中创建关节,返回 RID;
  • joint_make_pin(joint, anchor, body_a, body_b = RID()):把关节设为销钉类型。若body_b为空 RID,则body_a被钉在世界坐标anchor点上;否则body_a与body_b在anchor(全局坐标)处互相钉住。

PinJointParam 与 PinJointFlag 枚举

销钉关节特有的参数与开关在 PhysicsServer2D 中分别以枚举表示:

PinJointParam(参数,用于pin_joint_set_param/pin_joint_get_param):

常量值对应节点属性
PIN_JOINT_SOFTNESS0softness
PIN_JOINT_LIMIT_UPPER1angular_limit_upper
PIN_JOINT_LIMIT_LOWER2angular_limit_lower
PIN_JOINT_MOTOR_TARGET_VELOCITY3motor_target_velocity

PinJointFlag(开关,用于pin_joint_set_flag/pin_joint_get_flag):

常量值对应节点属性
PIN_JOINT_FLAG_ANGULAR_LIMIT_ENABLED0angular_limit_enabled
PIN_JOINT_FLAG_MOTOR_ENABLED1motor_enabled

可以看到,节点层六个属性与底层枚举一一对应:softness、上下限位、马达目标速度是"参数",限位开关与马达开关是"标志位"。这些枚举及方法签名均记录在 classes/class_physicsserver2d.rst。

运行时动态调整示例

借助 RID 可以在运行时直接读写底层参数,避免反复切换节点属性:

var pin: PinJoint2D = get_node("PinJoint2D") var rid: RID = pin.get_rid() var server := PhysicsServer2D # 读取当前 softness var soft: float = server.pin_joint_get_param(rid, server.PIN_JOINT_SOFTNESS) # 运行时开启马达并提速 server.pin_joint_set_flag(rid, server.PIN_JOINT_FLAG_MOTOR_ENABLED, true) server.pin_joint_set_param(rid, server.PIN_JOINT_MOTOR_TARGET_VELOCITY, 3.0)

这种写法适合需要高频微调关节行为(如物理模拟中的动态机构)的场景。

实战应用:跷跷板与铰链机构

跷跷板

把一块 RigidBody2D 面板的中央钉在一个 StaticBody2D 支点上,即构成跷跷板。与钟摆的唯一区别是销钉锚点位于面板中部而非端点,两端会因重量差异上下摆动。开启角度限位可以让跷跷板摆动幅度受限(如 ±20°),避免翻转。

连杆 / 四杆机构

串联多个 PinJoint2D 即可组成连杆机构:每个销钉连接一对物理体,整体形成链条状结构。制作时注意:

  • 每个 PinJoint2D 的锚点必须精确落在相邻两体的连接处;
  • disable_collision保持默认 true,避免相邻环节互相穿透产生抖动;
  • 若需要整体结构"松弛",可适当调大 softness。

2D 布偶(ragdoll)

在 2D 骨骼物理中,PinJoint2D 是连接各物理骨骼的默认关节选择。classes/class_physicalbone2d.rst 明确指出:

PhysicalBone2D 节点不会自动创建 Joint2D 节点来连接骨骼,必须手动创建。大多数情况下应使用 PinJoint2D 节点;一旦 Joint2D 被添加为其子节点,PhysicalBone2D 会自动配置该关节。

即把PinJoint2D添加为PhysicalBone2D的子节点,前者会自动填入 node_a/node_b 并完成连接,然后可通过PhysicalBone2D.get_joint()获取该关节进行后续调节(classes/class_physicalbone2d.rst)。

作为对照,3D 场景的 ragdoll 教程中也提到 PinJoint 是"保持两体连接"的默认关节,但容易导致骨骼"皱缩"(crumpling),通常建议角色改用 HingeJoint 或 ConeJoint——2D 中则没有这种取舍压力,PinJoint2D 即为标准选择。详见 tutorials/physics/ragdoll_system.rst。

调参与常见问题

1. 关节没有生效 / 物体直接掉落

  • 检查 node_a、node_b 是否指向正确的 PhysicsBody2D 派生节点;
  • 检查 PinJoint2D 的锚点位置是否与被连接体的连接点重合——节点位置即销钉点;
  • 确认连接的两个物理体至少有一个是动态体(如 RigidBody2D);两个 StaticBody2D 之间没有可模拟的关节运动。

2. 摆动物体剧烈抖动

  • 降低bias(0 时使用项目默认physics/2d/solver/default_constraint_bias= 0.2);
  • 检查softness是否设得过大;
  • 确认两个物理体的碰撞形状没有互相穿插且disable_collision为 true;
  • 检查物理帧步长与刚体质量比是否悬殊。

3. 限位不生效

  • 确认angular_limit_enabled = true;
  • 确认 lower < upper,且数值以弧度为单位(可先用deg_to_rad()换算验证);
  • 记住限位描述的是销钉两侧的相对旋转。

4. 马达不转

  • 确认motor_enabled = true且motor_target_velocity非 0;
  • 若同时启用了限位,注意旋转到限位边界时马达力矩会被限位约束抵消。

结语

PinJoint2D 虽小,却是 Godot 2D 物理游戏机构设计的基石:从钟摆、跷跷板到连杆机构与 2D 布偶,几乎一切"绕点旋转"的机械结构都建立在它之上。掌握其六个核心属性(角度限位、马达、柔性)与基类 Joint2D 的 bias/disable_collision 语义,再结合 PhysicsServer2D 的低阶 RID API,即可在运行时对关节做精细控制。官方类参考是最终权威,建议直接阅读 classes/class_pinjoint2d.rst、classes/class_joint2d.rst 与 classes/class_physicsserver2d.rst 获取完整方法签名与枚举定义;更系统的 2D 物理入门可参考 tutorials/physics/physics_introduction.rst。

  • 文档
  • 教程
  • 游戏开发

【免费下载链接】godot-docs

Godot Engine official documentation

项目地址:https://gitcode.com/GitHub_Trending/go/godot-docs
点击查看免费下载

相关推荐

上一篇:Gravitee API 网关 Docker Compose 一键部署指南:APIM 门户、AM 认证与 Prometheus 监控实战
下一篇:pacsomatic Agent 技能:基于 BAM 输入可复现运行 nf-core/pacsomatic 的完整操作手册

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询