
附件系统API
一种简单、自动化且优化的将部件附加到对象上的方法
查看大图附件系统 API
一个独立的框架,可将零件附件到任何物体上,汽车、家具,任何东西。
■ 关于
用于在 My Summer Car / My Winter Car 中将零件吸附到物体上的独立框架
基于 OASIS,但完全重写,更加直观、更加自动化、更加优化,而且附带了指南。
- 玩家:将
AttachmentSystem.dll放入 Mods 文件夹的References文件夹中。完成。 - **模组开发者:继续阅读。 **
■ UNITY 设置
1. Plugins 文件夹:Assets/Plugins/
- AttachmentSystem.dll
- PlayMaker.dll
- UnityEngine.dll
- (两者均来自游戏的 Managed 文件夹)
2. Editor 文件夹:Assets/Editor/
- AttachmentPartsEditor.cs — 在检视面板中添加拖放框
- SnapTriggerIdAutomator.cs — 添加
工具 ▸ 附件系统菜单
3. Visual Studio:添加对 AttachmentSystem.dll 的引用,然后:
using AttachmentSystem;
■ 三个核心脚本
AttachmentParts:挂在零件本身(你要附着的物体)上bolts:挂在固定零件的每个独立螺栓上SnapTriggerId:挂在不可见的触发器碰撞体(“安装点”)上
■ 设置零件(分步指南)
1. 将 AttachmentParts 添加到你的零件 GameObject 上。
2. 设置 Trigger Ids 数组:该零件可以吸附到的安装点的字符串 ID。
3. 设置 Bolts 数组:将属于该零件的每个螺栓 GameObject 拖入。
4. (可选)填写 Required Parts 和 Blocker Parts:
- Required Parts:在此零件可以吸附之前必须已经附着的其他零件(例如气缸盖需要先有缸体)。
- Blocker:不能附着的零件,否则此零件被阻止(例如气门室盖阻止凸轮轴拆卸)。
5. (可选)Joint Physics:
useJoint = true→ 零件使用真实的 FixedJoint,可在碰撞中脱落。maxBreakForce→ 完全拧紧时断裂所需的力。unbreakableAtTightness→ 设置一个紧固度值,使零件在该值下变得不可破坏(使用 -1 表示始终可破坏)。
■ 设置吸附触发器
吸附触发器是目标物体(汽车、家具……)上的一个不可见碰撞体,表示“此零件安装在这里”。
方法 A — 手动(推荐):
- 在零件应吸附的位置创建一个空 GameObject。
- 添加一个 Collider(通常是 BoxCollider),标记为 Is Trigger。
- 添加
SnapTriggerId脚本。 - 将 Id 字段设置为唯一字符串(例如
MyCustomPart_Trigger)。 - 在你的零件的
AttachmentParts中,将相同的字符串添加到Trigger Ids中。
方法 B — 自动(批量):
在层级视图中选中所有触发器 GameObject → 菜单 工具 ▸ 附件系统 ▸ 自动为选中对象添加 SnapTriggerId。每个触发器都会获得一个 SnapTriggerId,其 Id 设置为 GameObject 名称。
额外功能:在 AttachmentParts 检视面板上有一个“将触发器拖到此处以自动填充 ID”的框,将触发器 GameObject 拖入其中,Trigger Ids 数组会自动填充。
■ 预制体布局示例
Car (prefab)
└── Triggers
└── MyCustomPart_Trigger [BoxCollider (isTrigger)] + [SnapTriggerId id="MyCustomPart_Trigger"]
MyCustomPart (prefab)
├── AttachmentParts
│ ├── Trigger Ids: [ "MyCustomPart_Trigger" ]
│ └── Bolts: [ Bolt_1, Bolt_2, Bolt_3, Bolt_4 ]
├── Bolt_1 [bolts, size=0.5, maxTightness=8]
├── Bolt_2 [bolts, size=0.5, maxTightness=8]
├── Bolt_3 [bolts, size=0.5, maxTightness=8]
└── Bolt_4 [bolts, size=0.5, maxTightness=8]
■ 设置螺栓
- 将 Bolt GameObject 添加为零件的子物体。
- 添加
bolts脚本。 - 设置
Wrench Size和Max Tightness(原版游戏使用 8)。 - 将其拖入零件的
Bolts数组中。
扳手尺寸对照表(与原版 MSC 数值一致):
0.5 = 5 mm 1.0 = 10 mm 1.4 = 14 mm
0.6 = 6 mm 1.1 = 11 mm 1.5 = 15 mm
0.7 = 7 mm 1.2 = 12 mm
0.8 = 8 mm 1.3 = 13 mm
只有当数组中的每个螺栓都完全拧紧时,零件才被视为完全安装(并达到完整的 breakForce)。
■ 保存与加载
框架不会为你保存状态,它暴露了所有内容,以便你可以使用 MSCLoader 的 SaveLoad 进行保存。
每个零件需要保存的内容:
attachedTo(int)— 零件吸附到的触发器索引,如果松散则为 -1。- 对每个螺栓:
bolts[i].tightness(int)。 - 如果零件在世界中处于松散状态,则保存 Transform 位置/旋转。
示例:
using System;
using System.Linq;
using UnityEngine;
using MSCLoader;
[Serializable]
public class PartSave
{
public int attachedTo = -1;
public int[] boltTightness;
public Vector3 pos;
public Vector3 rot; // Eulers
}
// --- 如何保存状态 ---
void SavePartState(Mod mod, AttachmentParts myPart)
{
PartSave data = new PartSave
{
attachedTo = myPart.attachedTo,
boltTightness = myPart.bolts != null
? myPart.bolts.Select(b => b != null ? b.tightness : 0).ToArray()
: new int[0],
pos = myPart.transform.position,
rot = myPart.transform.eulerAngles
};
SaveLoad.WriteValue<PartSave>(mod, "MyCustomPartSave", data);
}
// --- 如何加载/恢复状态(OnLoad / Start) ---
void LoadPartState(Mod mod, AttachmentParts myPart)
{
if (SaveLoad.ValueExists(mod, "MyCustomPartSave"))
{
PartSave loadedData = SaveLoad.ReadValue<PartSave>(mod, "MyCustomPartSave");
if (loadedData == null) return;
if (loadedData.attachedTo >= 0)
{
// 使用 ForceAttach 恢复附着槽位(启动时绕过声音/事件)
myPart.ForceAttach(loadedData.attachedTo);
if (myPart.bolts != null && loadedData.boltTightness != null)
{
for (int i = 0; i < myPart.bolts.Length; i++)
{
if (i < loadedData.boltTightness.Length && myPart.bolts[i] != null)
{
myPart.bolts[i].tightness = loadedData.boltTightness[i];
}
}
}
}
else
{
// 恢复世界中的松散位置和旋转
myPart.transform.position = loadedData.pos;
myPart.transform.rotation = Quaternion.Euler(loadedData.rot);
}
}
}
■ 事件与回调
在检视面板中(UnityEvents,无需代码):
onAttachedEvent/onDetachedEventonFullyTightenedEvent/onFullyLoosenedEventonBreakEvent— 在碰撞中关节断裂时触发
在 C# 中(代码回调):
myPart.onAttach += (index) => Debug.Log("Attached to " + index);
myPart.onDetach += (index) => Debug.Log("Detached from " + index);
myPart.onBreak += (force) => Debug.Log("Broke at " + force);
// 门控 — 返回 false 以阻止操作
myPart.canAttach = () => Game.EngineIsOff;
myPart.canDetach = () => Game.HandbrakeOn;
■ 故障排除
- 零件无法吸附 → 检查触发器是否启用了 Is Trigger,并且 Id 完全匹配(区分大小写)。
- 控制台显示“SnapTrigger not found” →
triggerIds中有拼写错误,或者触发器 GameObject 在加载时处于非活动状态。 - 螺栓不显示 → 正常。螺栓在零件附着到触发器之前是隐藏的。
- 零件穿过汽车掉落 →
useJoint = true且breakForce非常低。提高maxBreakForce或设置unbreakableAtTightness。 - 关于 Editor 脚本的构建错误 → Editor 脚本必须放在名为
Editor的文件夹内。它们绝不能包含在最终 DLL 中。
就这些,这是我能做到的最“傻瓜式”的教程了,爱你们。
- 框架:Toko
- 灵感来源:OASIS
正在加载版本记录…
正在加载评论…
评论在新手盒子客户端中发表,这里同步展示。