【问题标题】:UNITY - Shoot Projectile on the direction of where the gun is facingUNITY - 向枪口方向发射弹丸
【发布时间】:2019-09-16 23:17:21
【问题描述】:

我有一把枪,它会产生一个弹丸,弹射对撞机(弹跳弹)。它应该朝枪口的方向射击,但我得到的是弹丸总是向右上方 45 度射击,我知道这是因为我的常量声明向量 2。

我尝试使用 Vector2.up,但它会阻止弹丸产生弹跳效果,因为它总是想向上移动。

我应该如何实现这些东西?我只想让弹丸射向我的枪所面对的方向并在对撞机上反弹。顺便说一句,这是一个 2D 游戏。我在下面附上了我的代码,所以你可以看到。谢谢!

射弹脚本:

private Rigidbody2D rb;
public static bool canMove = true;

void Start()
{
 rb = GetComponent<Rigidbody2D>();
 rb.velocity = new Vector2(10f, 10f);
}
void Update()
{
 //transform.Translate(Vector2.up * speed * Time.deltaTime);
 if (canMove)
 {
     rb.isKinematic = false;

 }
 else if (!canMove)
 {
     rb.isKinematic = true;
 }
} 

枪法:

float offset = -90f;

public GameObject projectile;
public Transform shotPoint;
public GameObject child;

void Start()
{

}

void Update()
{
    Vector3 diff = Camera.main.ScreenToWorldPoint(Input.mousePosition) - transform.position;
    float rotZ = Mathf.Atan2(diff.y, diff.x) * Mathf.Rad2Deg;
    transform.rotation = Quaternion.Euler(0f, 0f, rotZ + offset);

    if (Input.GetMouseButtonDown(0))
    {
        Instantiate(projectile, shotPoint.position, transform.rotation);
        Projectile.canMove = true;
    }
}

【问题讨论】:

    标签: c# unity3d game-physics


    【解决方案1】:

    Rigodbody.velocity 位于 世界空间 坐标中。

    当你进来时

    rb.velocity = new Vector2(10f, 10f);
    

    它将在 X 方向进入世界空间 10,在 Y 方向进入 10。


    为了将其作为局部坐标传递,通常你不能总是依赖Tramsform.InverseTransformDirection 作为suggested here,因为Transform 组件。在这种特定情况下,它可能会起作用,但通常您在 FixedUpdate 中设置速度,此时 Transform 组件可能尚未更新!


    Rigidbody2D 组件通常如此,您可以使用Rigidbody2D.GetRelativeVector 将相对于刚体的局部向量转换为世界坐标:

    // Might also be Vector.up depending on your setup
    rb.velocity = rb.GetRelativeVector(Vector2.right * speed);
    

    注意:最好自己做

    [SerializeField] private Rigidbody2D rb;
    

    并且已经通过 Inspector 引用它。然后你就可以摆脱昂贵的GetComponent 电话。

    【讨论】:

    • 枪是Rigidbody吗?因为如果不是,那么Rigidbody2D.GetRelativeVector 的唯一方法将是相对于射弹,而不是枪。这与枪的transform.rotation 相结合,这使我们回到“在那一刻,(枪)变换组件可能还没有更新!”问题。这就是为什么我一开始没有走那条路的原因。
    • 另外,GetComponent 对于像 Update 这样的性能关键型上下文来说代价高昂,但对于初始化来说通常很好。通过在检查器中进行设置,您无缘无故地引入了潜在故障点(未设置、设置错误等)。那是过早的优化。
    • 因为 GetComponent 调用发生在每个实例化的子弹上,它实际上很重要。而且由于项目符号是预制件,因此您可能在此处错误地引用的内容数量非常有限。不,刚体是弹丸而不是枪..这就是为什么我将这段代码留在projectlie中而不是在枪被实例化的地方..因为弹丸是用正确的旋转实例化的,它自己的右/上矢量点在它想要移动的方向。正如在这种特定情况下所说InverseTransformDirection 可能没问题,但一般来说你应该通过 Rb
    • 取决于项目符号的数量以及它们被实例化的频率。据我们所知,游戏可能介于屏幕上一次只有很少的子弹/球的“砖块破坏者”和有很多的 2D 自上而下的射击游戏之间。我说我们带着最少的假设去。 --- 此外,在实例化的数量和频率变得相关时,适当的解决方案变得完全不同。您首先避免实例化,使用池化。 --- 最后,不,射弹是在枪脚本中实例化的,带有枪变换旋转,正如您所说,这可能已经过时了。
    • @XenoRo 到你的第一点......是的,这正是我的观点:在 Inspector 中设置它一次比调用GetComponent 便宜得多,即使它只是一次用于实例化,但用于每个弹丸......是的,它是通过枪脚本实例化的......但是设置初始速度是在弹丸脚本的Start 中完成的,该脚本以正确的方向实例化。刚开始时,刚体和变换仍然是同步的,所以这两种方法都可以工作......但正如我所说,我更喜欢一般工作的那个
    【解决方案2】:

    因为你告诉它这样做。

    rb.velocity = new Vector2(10f, 10f);

    向右 10,向上 10。


    除非您的射弹具有恒定的力,例如导弹,否则请摆脱射弹脚本中与力或速度相关的所有内容。这对你没有好处。

    然后,在 gun 脚本上:

    //...
    if (Input.GetMouseButtonDown(0)) {
        var projectileInstance = Instantiate(projectile, shotPoint.position, transform.rotation);
        var rigidbody = projectileInstance.GetComponent<Rigidbody2D>();
        rigidbody.velocity = transform.TransformDirection(yourDirectionVector);
        Projectile.canMove = true;
    }
    

    其中Transform.TransformDirection 是使yourDirectionVector(相对于枪的方向)转换为相对于世界空间的方向的原因。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-30
      • 2018-11-04
      • 1970-01-01
      相关资源
      最近更新 更多