有趣交互的场景:
interestinginteractable.png
手雷爆炸实现:
1、由于手雷的不规则,我们需要添加多个Collider 来实现包裹 该模型
2、该手雷的抓取,有两种:Grip : 捏取(即用食指按动的扳机按钮),Pinch :握取(即手柄两边的侧边键)
不同的方式,有不同的抓取 Offset 偏移位置点
- 手雷结构图:
Grenade.png
脚本组件等基本与上一案例一致,可抛脚本组件继承自 Throwable ,变为 Modal Throwable 脚本组件
Modal Throwable.png
using UnityEngine;
using UnityEngine.Events;
using System.Collections;
namespace Valve.VR.InteractionSystem
{
public class ModalThrowable : Throwable
{
//局部点作为位置和转动偏移量,在用抓地式抓取时使用
public Transform gripOffset;
//作为位置和旋转偏移量的局部点,在夹紧式抓取时使用
public Transform pinchOffset;
//重写了HandHoverUpdate() 方法
protected override void HandHoverUpdate(Hand hand)
{
GrabTypes startingGrabType = hand.GetGrabStarting();
if (startingGrabType != GrabTypes.None)
{
if (startingGrabType == GrabTypes.Pinch)
{
hand.AttachObject(gameObject, startingGrabType, attachmentFlags, pinchOffset);
}
else if (startingGrabType == GrabTypes.Grip)
{
hand.AttachObject(gameObject, startingGrabType, attachmentFlags, gripOffset);
}
else
{
hand.AttachObject(gameObject, startingGrabType, attachmentFlags, attachmentOffset);
}
hand.HideGrabHint();
}
}
}
}
自定义脚本组件 GrenadeInteractable :
该脚本用来执行落地检测,产生爆炸效果
GrenadeInteractable.png
可设置属性:
- Explode Part Prefab : 单个爆炸生成物 预制体
- Explode Count : 爆炸物的数量
- Min Magnitude To Explode : 最小的爆炸冲量强度
- Text Mesh : 3D Canvas 上显示手雷当前状态的 3D Text
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Valve.VR.InteractionSystem;
public class GrenadeInteractable : MonoBehaviour
{
public GameObject explodePartPrefab; //爆炸生成物 预制体
public int explodeCount = 10; //爆炸物的数量
public float minMagnitudeToExplode = 1f; //最小的爆炸冲量强度
private Interactable interactable; //用来判断是否还在手上
public TextMesh textMesh; //用于显示状态的 3D 文本
private float attachTime; //抓取的时长
private void Start()
{
interactable = this.GetComponent<Interactable>();
textMesh.text = "无手悬停!";
}
private void OnCollisionEnter(Collision collision)
{
if (interactable != null && interactable.attachedToHand != null) //防止在手上发生爆炸
return;
if (collision.impulse.magnitude > minMagnitudeToExplode) // 碰撞冲量强度 大于 最小爆炸强度才产生爆炸物
{
for (int explodeIndex = 0; explodeIndex < explodeCount; explodeIndex++)
{
GameObject explodePart = (GameObject)GameObject.Instantiate(explodePartPrefab, this.transform.position, this.transform.rotation);
explodePart.GetComponentInChildren<MeshRenderer>().material.SetColor("_TintColor", Random.ColorHSV(0f, 1f, 1f, 1f, 0.5f, 1f));
}
Destroy(this.gameObject); //销毁手雷
}
}
private void OnHandHoverBegin(Hand hand)
{
textMesh.text = "手雷正被: " + hand.name + " 悬停!";
}
private void OnHandHoverEnd(Hand hand)
{
textMesh.text = "无手悬停!";
}
//-------------------------------------------------
// 当可交互物体刚被手抓取附着时,被调用一次
//-------------------------------------------------
private void OnAttachedToHand(Hand hand)
{
textMesh.text = "手雷附着在:" + hand.name;
attachTime = Time.time;
}
//-------------------------------------------------
// 当可交互物体刚被手释放分离时,被调用一次
//-------------------------------------------------
private void OnDetachedFromHand(Hand hand)
{
textMesh.text = "手雷从 " + hand.name + " 分离!";
}
//-------------------------------------------------
//当可交互物体刚被手一直抓取附着时,被每帧调用
//-------------------------------------------------
private void HandAttachedUpdate(Hand hand)
{
textMesh.text = "手雷附着在:" + hand.name + "\n附着时间: " + (Time.time - attachTime).ToString("F2");
}
}