- 文档
- 教程
- 游戏开发
【免费下载链接】godot-docs
Godot Engine official documentation
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 上,形成单摆。步骤如下:
- 在场景中创建一个
StaticBody2D(作为固定支点,如天花板)。 - 在支点下方创建一个
RigidBody2D(作为摆锤),并为其添加CollisionShape2D与合适的碰撞形状(如CapsuleShape2D或RectangleShape2D)。 - 新建一个
PinJoint2D节点,将它的位置放在支点与摆锤连接处(即摆杆的悬挂点)。 - 在 PinJoint2D 的检查器中,把
Node A(node_a)设为 StaticBody2D 的路径,Node B(node_b)设为 RigidBody2D 的路径。 - 运行场景,摆锤即围绕销钉点往复摆动。
使用 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_a | NodePath | NodePath("") | 被连接的第一个物理体 A,必须继承 PhysicsBody2D |
node_b | NodePath | NodePath("") | 被连接的第二个物理体 B,必须继承 PhysicsBody2D |
bias | float | 0.0 | 关节回正速度;设为 0 时使用项目级默认值 |
disable_collision | bool | true | 为 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_enabled | bool | false | 是否启用角度限位 |
angular_limit_lower | float | 0.0 | 最小旋转角(弧度) |
angular_limit_upper | float | 0.0 | 最大旋转角(弧度) |
motor_enabled | bool | false | 是否启用马达驱动 |
motor_target_velocity | float | 0.0 | 马达目标角速度(弧度/秒) |
softness | float | 0.0 | 销钉连接的柔性程度 |
角度限位:angular_limit_enabled / lower / upper
销钉关节默认允许 360° 自由旋转。若希望限制旋转范围(如门铰链只允许开合 90°),需要:
- 将
angular_limit_enabled设为true; - 用
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_SOFTNESS | 0 | softness |
PIN_JOINT_LIMIT_UPPER | 1 | angular_limit_upper |
PIN_JOINT_LIMIT_LOWER | 2 | angular_limit_lower |
PIN_JOINT_MOTOR_TARGET_VELOCITY | 3 | motor_target_velocity |
PinJointFlag(开关,用于pin_joint_set_flag/pin_joint_get_flag):
| 常量 | 值 | 对应节点属性 |
|---|---|---|
PIN_JOINT_FLAG_ANGULAR_LIMIT_ENABLED | 0 | angular_limit_enabled |
PIN_JOINT_FLAG_MOTOR_ENABLED | 1 | motor_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
相关推荐
3步解锁Cocos物理关节:从铰链到马达的动态交互
3步解锁Cocos物理关节:从铰链到马达的动态交互 你还在为游戏角色关节卡顿、物体连接不自然而烦恼吗?本文将通过Cocos引擎物理关节系统的三大核心组件——铰链
游戏开发图形学3D渲染Godot 3D 铰链关节 HingeJoint3D 完全指南:旋转约束、角度限制与电机驱动原理
Godot 3D 铰链关节 HingeJoint3D 完全指南:旋转约束、角度限制与电机驱动原理 本篇指南基于 Godot 官方文档仓库中的 HingeJoin
文档教程游戏开发如何掌握Cocos引擎物理关节驱动:从基础到高级力控制实现指南
如何掌握Cocos引擎物理关节驱动:从基础到高级力控制实现指南 Cocos引擎作为一款免费开源的跨平台游戏引擎,提供了强大的物理系统支持,其中物理关节是实现复杂
游戏开发图形学3D渲染
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考