我在运行时生成了一个预制对象(实际上是在另一个对象的Start()
方法中),并且需要对对象进行缩放。我制作了一个小组件来处理此问题:
public class Spawner : MonoBehaviour {
public Transform SpawnPrefab;
public Vector3 Scale;
void Start () {
var spawn = Instantiate(SpawnPrefab, Vector3.zero, Quaternion.identity);
spawn.localScale = Vector3.Scale(spawn.localScale, Scale);
// spawn.GetComponent<Rigidbody>().ResetCenterOfMass(); // Has no effect
}
}
我生成的预制件的枢轴点与对象的质心不一致。因此,重新缩放意味着相对于枢轴的重心位置将发生变化。但是,不是会自动更新,因此生成的对象具有意外的物理特性。
我尝试在调用GetComponent<Rigidbody>().ResetCenterOfMass()
之后立即添加对Scale()
的调用(上面的注释行),但这没有效果。
但是,如果我在添加到衍生对象的单独小组件的ResetCenterOfMass()
方法的Start()
方法中调用public class COMReset : MonoBehaviour {
void Start() {
GetComponent<Rigidbody>().ResetCenterOfMass();
}
}
,例如
ResetCenterOfMass()
这样做 会导致重新正确计算质心。但是,此时生成的对象似乎已经通过至少一次错误的COM进行了物理更新,因此已经获得了一些意外的动力。
为什么在不必显式调用Instantiate()
的情况下不能自动重新计算COM?而且,如果我必须手动触发它,是否可以在调用Scale()
和Cypress.Commands.add(
'expectLdapUsersListToBe',
(listUserNames, listUserIds) => {
const ldapUserNames = cy.get(ADD_LDAP_USER_DOM.texts.ldapUserNames);
ldapUserNames.should('have.length', listUserNames.length);
ldapUserNames.each(($item, index) => {
cy.wrap($item).contains(listUserNames[index]);
});
const ldapUserIds = cy.get(ADD_LDAP_USER_DOM.texts.ldapUserIds);
ldapUserIds.should('have.length', listUserIds.length);
ldapUserIds.each(($item, index) => {
cy.wrap($item).contains(listUserIds[index]);
});
}
);
之后立即执行此操作,而不是像这样推迟执行?
答案 0 :(得分:1)
感谢GameDev上的@DMGregory的建议,在调用Rigidbody.ResetCenterOfMass
之前调用Physics.SyncTransforms
可以解决此问题:
public class Spawner : MonoBehaviour {
public Transform SpawnPrefab;
public Vector3 Scale;
void Start () {
var spawn = Instantiate(SpawnPrefab, Vector3.zero, Quaternion.identity);
spawn.localScale = Vector3.Scale(spawn.localScale, Scale);
Physics.SyncTransforms();
spawn.GetComponent<Rigidbody>().ResetCenterOfMass();
}
}
显然,转换比例的这种直接修改不会自动传递到物理引擎,但是Physics.SyncTransforms
让我们手动将这些更改向下冲刷到PhysX,这样ResetCenterOfMass
计算就可以了基于正确缩放的变换。