反射激光对撞机

时间:2017-06-05 21:50:10

标签: c# unity3d

我试图准确地将激光束反射到墙壁/对撞机上。激光束是从LaserGun发射的,很小,约为2。

所以我目前将我的LaserBeam设置为3D Capsule并将其着色为红色。它非常丑陋,但我现在不太关心。

每当LaserBeam与物体/墙碰撞时,它都不会像我想的那样反弹。我想它必须被墙/对撞机完全吸收,这样才能指向正确的方向。

以下网站中的图片应该说明我想要实现的目标。 http://answers.unity3d.com/questions/631311/making-an-object-bounce-off-a-wall-the-same-way-li.html (如果LaserBeam是一个箭头。箭头是InDirection,一旦箭头与墙壁相撞,它将在结果的方向上。)

我已将Drag和AngularDrag都设置为0。 在我的胶囊材料中。动态和静态摩擦设置为0. Bounciness为1.FrictionCombine为Min,BounceCombine为Max。

我想知道是否必须将3D Capsule更改为LineRenderer?

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:1)

此脚本仅使用Raycast检测冲突。它首先在它的(激光器)尖端做一个Raycast,测试它是否与任何东西发生碰撞。如果是这样,它会产生自身的反射版本。此外,它在最后测试q Raycast,以测试它是否完全穿透了对撞机。如果是这样,它会摧毁自己。结果是一个非常逼真的激光束,在保持其总长度的同时甚至会在碰撞中“弯曲”。

脚本假设

  • 激光束有一个指向Y方向并且以(0,0,0)为中心的CapsuleCollider
  • 没有 Rigidbody附加
  • 您指定了希望激光在wallLayers
  • 中反弹的图层
  • 激光束本身位于wallLayers
  • 中未包含的层中
  • 你的墙壁足够大,可以完全包含激光束(这只是相关的,因为否则会看起来很奇怪,但仍然可以工作)

脚本将

  • 沿着物体的正Y轴以每秒speedOfLight个单位行驶
  • 即使在非常(!)的高行驶速度下也能可靠地检测到碰撞
  • 在3D空间自由旅行,所以如果你想要它坚持一个平原,你将不得不为此添加逻辑

测试一下,很有趣:

using UnityEngine;

[RequireComponent(typeof(CapsuleCollider))]
public class LaserBeam : MonoBehaviour
{
    public LayerMask wallLayers;
    public float speedOfLight = 1f;

    private Vector3 reflectionTestPointLocal, completeIntrusionTestPointLocal;
    private float beamLengthLocal;
    private bool didSpawnReflection;

    void Awake()
    {
        CapsuleCollider capsuleCollider = GetComponent<CapsuleCollider>();
        beamLengthLocal = capsuleCollider.height;
        reflectionTestPointLocal = Vector3.up * beamLengthLocal * .5f;
        completeIntrusionTestPointLocal = -Vector3.up * beamLengthLocal * .5f;
    }

    void Update()
    {
        float stepLength = speedOfLight * Time.deltaTime;

        Travel(stepLength);
    }

    private void Travel(float stepLength)
    {
        Vector3 step = transform.up * stepLength;

        if (!didSpawnReflection)
        {
            RaycastHit hit;
            if (Physics.Raycast(transform.TransformPoint(reflectionTestPointLocal), step, out hit, stepLength, wallLayers))
            {
                SpawnReflection(hit.point, hit.normal, stepLength - hit.distance);
                didSpawnReflection = true;
            }
        }
        if (didSpawnReflection)
        {
            RaycastHit hit;
            if (Physics.Raycast(transform.TransformPoint(completeIntrusionTestPointLocal), step, out hit, stepLength, wallLayers))
            {
                Destroy(gameObject);
            }
        }

        transform.position += step;
    }

    private void SpawnReflection(Vector3 pointOfReflection, Vector3 reflectionNormal, float intrusion)
    {
        float impactAngle = Vector3.Angle(-transform.up, reflectionNormal);
        Vector3 impactTangent = Vector3.Cross(-transform.up, reflectionNormal);

        Quaternion reflectedRotation = Quaternion.AngleAxis(180 + impactAngle * 2, impactTangent) * transform.rotation;

        LaserBeam reflectedBeam = Instantiate(this);
        reflectedBeam.gameObject.name = gameObject.name;
        reflectedBeam.transform.parent = transform.parent;
        reflectedBeam.transform.localScale = transform.localScale;
        reflectedBeam.transform.rotation = reflectedRotation;
        reflectedBeam.transform.position = pointOfReflection - reflectedBeam.transform.TransformVector(Vector3.up * beamLengthLocal * .5f);

        reflectedBeam.Travel(intrusion);
    }
}

答案 1 :(得分:0)

您是否尝试过使用 TrailRenderer 组件?

通过这种方式,您可以将“激光”设置为一个小球体(大小将是您的激光宽度):在此对象上,您将拥有以下组件:

  • 转换(有点明显)
  • SphereCollider (您可以设置其大小并为其提供有弹性的物理材料)
  • RigidBody (将两个拖动设置为零,使用重力为假并冻结所有旋转)
  • TrailRenderer (在这里您可以调整激光的视觉效果:宽度,材质,长度(使用时间属性),...)

要“激发”激光,您只需将此对象设置为预制并在给定位置实例化,然后根据所需的速度/方向设置 RigidBody 速度:)< / p>

此方法的一个好处是您可以轻松注册OnCollision[...]个事件,并根据您的需要使用它们。

希望这有帮助,