【问题标题】:how to limit collision with multiple objects如何限制与多个对象的碰撞
【发布时间】:2023-02-25 04:42:22
【问题描述】:

我有一个机械师。有一个玩家和一个敌人。他们每个人都可以在触摸时吸引立方体。所以当双方都碰到立方体时,立方体会同时飞向敌人和玩家,我需要它飞向第一个碰到它的人。 这就是我现在所拥有的


[SerializeField] private Transform _cube;
[SerializeField] private Transform _playerParent;
[SerializeField] private Transform _enemyParent;
private Transform _carPlayer, _carEnemy;

public void OnTriggerEnter(Collider collider)
{
    if (collider.gameObject.tag == "Player")
    {
        _carPlayer = collider.transform;
    }

    if (collider.gameObject.tag == "Enemy")
    {
        _carEnemy = collider.transform;
    }
}

private void FixedUpdate()
{
    if (_carPlayer)
    {
        PlayerTakeCube();
    }

    if (_carEnemyFirst)
    {
        EnemyFirstTakeCube();
    }
}

private void PlayerTakeCube()
{
    _cube.transform.position = Vector3.MoveTowards(transform.position, 
    _playerParent.position, 0.02f);
    _cube.transform.rotation = _playerParent.transform.rotation;
    _rigidbody.isKinematic = true;
    _cube.transform.SetParent(_playerParent);
}

private void EnemyFirstTakeCube()
{
    _cube.transform.position = Vector3.MoveTowards(transform.position, 
    _enemyParent.position, 0.02f);
    _cube.transform.rotation = _enemyParent.transform.rotation;
    _rigidbody.isKinematic = true;
    _cube.transform.SetParent(_enemyParent);
}

【问题讨论】:

  • 有点不清楚 _playerParent_enemyParent 来自哪里以及究竟应该发生什么..但是你的代码非常多余,你可以有一个方法并在两种情况下重用它..你也存储 _carPlayer_carEnemy 引用但从未真正使用过它们...另外_cube 与此对象相同吗?
  • _playerParent 和 _enemyParent 是立方体 (_cube) 应该移动到的 Transforms,它们是汽车的子对象。我在 FixedUpdate() 中使用 _carPlayer 和 _carEnemy 来运行 PlayerTakeCube() 和 EnemyFirstTakeCube() 方法。我需要如果有人是第一个接触立方体的人,他就会飞起来,并且他不应该再对第二个玩家做出反应。
  • _cube 是这个脚本附加到的同一个对象吗? _rigidbody 也在 _cube / 这个脚本附加的对象上吗?
  • 是的 _cube,这是脚本附加到的对象,是的 _rigidbody 在这个对象上

标签: c# unity3d


【解决方案1】:

在 OnTriggerEnter 中检查 carPlayer 或 carEnemy 是否已经分配,​​如果是则不执行其余的:

我还建议将以下行:'rigidbody.isKinematic = true' 和 'cube.transform.SetParent(...)' 放入 OnTriggerEnter 方法中,因为您不需要在每个 FixedUpdate() 中调用它;

public void OnTriggerEnter(Collider collider)
{
    if(_carPlayer || _carEnemy) return; //Check if someone already took control
    if (collider.gameObject.tag == "Player")
    {
        _carPlayer = collider.transform;
        _rigidbody.isKinematic = true;
        _cube.transform.SetParent(_playerParent);
    }
    
    if (collider.gameObject.tag == "Enemy")
    {
        _carEnemy = collider.transform;
        _rigidbody.isKinematic = true;
        _cube.transform.SetParent(_enemyParent);
    }
}

仅当您不希望多维数据集可以相互窃取时,以上示例才有效。
如果可以的话,我会说创建一个 1 秒的短计时器,在有人触摸立方体后无法控制立方体:

public void OnTriggerEnter(Collider collider)
{
    if(timer < 1) return;
    if (collider.gameObject.tag == "Player")
    {
        _carPlayer = collider.transform;
        _rigidbody.isKinematic = true;
        _cube.transform.SetParent(_playerParent);
        timer = 0;
    }

    if (collider.gameObject.tag == "Enemy")
    {
        _carEnemy = collider.transform;
        _rigidbody.isKinematic = true;
        _cube.transform.SetParent(_enemyParent);
        timer = 0;
    }
}

private void FixedUpdate()
{
    if(timer < 1)
        timer += Time.fixedDeltaTime
    ...
}

【讨论】:

  • 这个想法是,两辆汽车各由立方体组成,当它们发生碰撞时,立方体会飞走(汽车倒塌),你需要把它们捡起来,每个立方体都有自己的变换,它飞向汽车并站在它的变换上,我插入了这一行 if (_carPlayer || _carEnemy) return ;现在他们只是飞到汽车后面。
【解决方案2】:

我会统一这一点,并简单地拥有一个组件,例如

public class Car : MonoBehaviour
{
    public Transform CubeParent;
}

在你的两辆/所有汽车上。

然后你可以简单地做

private Car currentTarget;

public void OnTriggerEnter(Collider collider)
{
    // Someone else was here before already 
    if(currentTarget) return;

    // Otherwise is this even a car at all?
    if(collider.TryGetComponent<Car>(out var car))
    {
        // If so get the parent object we should move to
        currentTarget = car.CubeParent;
        // make this kinematic
        _rigidbody.isKinematic = true;         
    }
}

private void FixedUpdate()
{
    // Only if _cube and currentTarget are both set
    if(_cube && currentTarget)
    {
        // Move the cube towards the target
        _cube.transform.position = Vector3.MoveTowards(_cube.transform.position, currentTarget.position, 0.02f);
        _cube.transform.rotation = currentTarget.rotation;

        // If it reaches the position
        if(_cube.transform.position == currentTarget.position)
        {
            // parent it and forget the cube and target as no longer needed
            _cube.transform.SetParent(currentTarget);
            _cube = null;
            currentTarget = null;
        }
    }
}

【讨论】:

    猜你喜欢
    • 2014-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-07
    • 1970-01-01
    • 2015-12-04
    • 2015-07-26
    • 2017-09-25
    相关资源
    最近更新 更多