using UnityEditor;
using UnityEngine;
using UnityEngine.XR.Interaction.Toolkit;
using System.IO;
using System.Collections.Generic;
public class PicoGestureGameCreator : EditorWindow
{
private GameObject spawnArea;
private Material defaultMaterial;
private Material highlightMaterial;
private ParticleSystem disappearEffect;
[MenuItem("Pico Tools/创建手势交互游戏")]
public static void ShowWindow()
{
GetWindow<PicoGestureGameCreator>("Pico手势游戏配置");
}
private void OnGUI()
{
GUILayout.Label("Pico手势交互游戏一键配置", EditorStyles.boldLabel);
EditorGUILayout.Space(10);
if (GUILayout.Button("创建完整游戏环境", GUILayout.Height(40)))
{
CreateFullEnvironment();
}
EditorGUILayout.Space(20);
GUILayout.Label("高级选项", EditorStyles.boldLabel);
if (GUILayout.Button("仅创建XR基础"))
{
CreateBaseXRSetup();
}
if (GUILayout.Button("仅创建交互物体"))
{
CreateInteractableObjects();
}
if (GUILayout.Button("仅创建手势管理器"))
{
CreateGestureManager();
}
}
private void CreateFullEnvironment()
{
CreateBaseXRSetup();
CreateGestureManager();
CreateInteractableObjects();
CreateDisappearEffect();
EditorUtility.DisplayDialog("配置完成", "Pico手势交互游戏环境已成功创建!\n\n请连接Pico设备进行测试。", "确定");
}
private static void CreateBaseXRSetup()
{
// 确保存在XR Interaction Manager
if (!FindObjectOfType<XRInteractionManager>())
{
GameObject managerObj = new GameObject("XR Interaction Manager");
managerObj.AddComponent<XRInteractionManager>();
}
// 创建XR Origin
GameObject xrOrigin = null;
if (GameObject.Find("XR Origin") == null)
{
xrOrigin = new GameObject("XR Origin");
xrOrigin.AddComponent<Camera>();
// 添加XR组件
xrOrigin.AddComponent<UnityEngine.XR.Interaction.Toolkit.XROrigin>();
var loco = xrOrigin.AddComponent<LocomotionSystem>();
var teleport = xrOrigin.AddComponent<TeleportationProvider>();
// 创建左右手控制器
CreateController("LeftHand Controller", xrOrigin.transform);
CreateController("RightHand Controller", xrOrigin.transform);
}
// 创建地面
if (GameObject.Find("Ground") == null)
{
GameObject ground = GameObject.CreatePrimitive(PrimitiveType.Plane);
ground.name = "Ground";
ground.transform.position = new Vector3(0, -0.5f, 0);
ground.transform.localScale = new Vector3(10, 1, 10);
ground.GetComponent<Renderer>().material.color = Color.gray;
}
}
private static void CreateController(string name, Transform parent)
{
GameObject controller = new GameObject(name);
controller.transform.SetParent(parent);
controller.transform.localPosition = Vector3.zero;
// 添加交互器
GameObject interactor = new GameObject("Direct Interactor");
interactor.transform.SetParent(controller.transform);
interactor.transform.localPosition = new Vector3(0, 0, 0.1f);
var interactorComp = interactor.AddComponent<XRDirectInteractor>();
var collider = interactor.AddComponent<SphereCollider>();
collider.isTrigger = true;
collider.radius = 0.1f;
// 添加手势检测器
var gestureDetector = interactor.AddComponent<PicoGestureDetector>();
gestureDetector.handType = name.Contains("Left") ?
PicoGestureDetector.HandType.Left :
PicoGestureDetector.HandType.Right;
}
private void CreateGestureManager()
{
if (FindObjectOfType<PicoGestureManager>()) return;
GameObject manager = new GameObject("Gesture Manager");
var gestureManager = manager.AddComponent<PicoGestureManager>();
// 创建生成区域
spawnArea = GameObject.CreatePrimitive(PrimitiveType.Cube);
spawnArea.name = "Spawn Area";
spawnArea.transform.position = new Vector3(0, 1, 3);
spawnArea.transform.localScale = new Vector3(8, 0.1f, 8);
spawnArea.GetComponent<Renderer>().material.color = new Color(0.2f, 0.8f, 0.3f, 0.3f);
spawnArea.GetComponent<Collider>().enabled = false;
gestureManager.spawnArea = spawnArea.transform;
gestureManager.maxObjects = 8;
gestureManager.spawnInterval = 4f;
}
private void CreateInteractableObjects()
{
// 确保存在手势管理器
if (!FindObjectOfType<PicoGestureManager>())
{
CreateGestureManager();
}
// 创建默认材质
CreateMaterials();
// 创建物体预制体
List<GameObject> objectPrefabs = new List<GameObject>();
objectPrefabs.Add(CreatePrefabObject("Sphere", PrimitiveType.Sphere, Color.red));
objectPrefabs.Add(CreatePrefabObject("Cube", PrimitiveType.Cube, Color.blue));
objectPrefabs.Add(CreatePrefabObject("Capsule", PrimitiveType.Capsule, Color.green));
// 添加到手势管理器
FindObjectOfType<PicoGestureManager>().objectPrefabs = objectPrefabs.ToArray();
}
private GameObject CreatePrefabObject(string name, PrimitiveType type, Color color)
{
GameObject obj = GameObject.CreatePrimitive(type);
obj.name = name;
obj.transform.position = new Vector3(0, 1, 0);
// 添加材质
Renderer renderer = obj.GetComponent<Renderer>();
renderer.material = defaultMaterial;
// 添加物理组件
Rigidbody rb = obj.AddComponent<Rigidbody>();
rb.mass = 1.5f;
rb.drag = 0.5f;
// 添加交互组件
var grabInteractable = obj.AddComponent<XRGrabInteractable>();
grabInteractable.movementType = XRBaseInteractable.MovementType.VelocityTracking;
// 添加消失行为
var disappear = obj.AddComponent<DisappearOnAction>();
disappear.disappearDelay = 2f;
disappear.destroyDelay = 0.7f;
// 保存为预制体
if (!Directory.Exists("Assets/Prefabs"))
{
Directory.CreateDirectory("Assets/Prefabs");
}
string prefabPath = $"Assets/Prefabs/{name}.prefab";
PrefabUtility.SaveAsPrefabAsset(obj, prefabPath);
DestroyImmediate(obj);
return AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
}
private void CreateMaterials()
{
// 默认材质
defaultMaterial = new Material(Shader.Find("Standard"));
defaultMaterial.color = new Color(0.8f, 0.2f, 0.4f);
defaultMaterial.name = "DefaultObjectMat";
// 高亮材质
highlightMaterial = new Material(Shader.Find("Standard"));
highlightMaterial.color = new Color(0.9f, 0.9f, 0.2f);
highlightMaterial.name = "HighlightMat";
// 保存材质
AssetDatabase.CreateAsset(defaultMaterial, "Assets/Materials/DefaultObjectMat.mat");
AssetDatabase.CreateAsset(highlightMaterial, "Assets/Materials/HighlightMat.mat");
AssetDatabase.SaveAssets();
}
private void CreateDisappearEffect()
{
GameObject effectObj = new GameObject("DisappearEffect");
disappearEffect = effectObj.AddComponent<ParticleSystem>();
// 配置粒子系统
var main = disappearEffect.main;
main.startSize = 0.3f;
main.startSpeed = 2f;
main.startLifetime = 1f;
main.maxParticles = 20;
var emission = disappearEffect.emission;
emission.rateOverTime = 0;
emission.SetBursts(new[] { new ParticleSystem.Burst(0f, 15) });
var shape = disappearEffect.shape;
shape.shapeType = ParticleSystemShapeType.Sphere;
shape.radius = 0.5f;
var renderer = effectObj.GetComponent<ParticleSystemRenderer>();
renderer.material = new Material(Shader.Find("Standard"));
renderer.material.color = new Color(1, 0.5f, 0, 0.8f);
// 保存为预制体
PrefabUtility.SaveAsPrefabAsset(effectObj, "Assets/Prefabs/DisappearEffect.prefab");
DestroyImmediate(effectObj);
}
}
// ============= 运行时脚本 =============
// 手势管理器
public class PicoGestureManager : MonoBehaviour
{
[Header("生成设置")]
public GameObject[] objectPrefabs;
public Transform spawnArea;
public int maxObjects = 10;
public float spawnInterval = 5f;
private float lastSpawnTime;
private int currentObjectCount;
void Start()
{
SpawnInitialObjects();
}
void Update()
{
if (Time.time - lastSpawnTime > spawnInterval && currentObjectCount < maxObjects)
{
SpawnObject();
lastSpawnTime = Time.time;
}
}
private void SpawnInitialObjects()
{
for (int i = 0; i < maxObjects / 2; i++)
{
SpawnObject();
}
}
private void SpawnObject()
{
if (objectPrefabs == null || objectPrefabs.Length == 0) return;
Vector3 spawnPos = new Vector3(
Random.Range(spawnArea.position.x - spawnArea.localScale.x/2,
spawnArea.position.x + spawnArea.localScale.x/2),
spawnArea.position.y + 1f,
Random.Range(spawnArea.position.z - spawnArea.localScale.z/2,
spawnArea.position.z + spawnArea.localScale.z/2)
);
GameObject obj = Instantiate(
objectPrefabs[Random.Range(0, objectPrefabs.Length)],
spawnPos,
Quaternion.identity
);
currentObjectCount++;
}
public void ObjectDestroyed()
{
currentObjectCount--;
}
}
// 物体消失行为
public class DisappearOnAction : MonoBehaviour
{
[Header("消失设置")]
public float disappearDelay = 2f;
public float destroyDelay = 0.5f;
private Rigidbody rb;
private bool isDisappearing;
void Start()
{
rb = GetComponent<Rigidbody>();
}
private void OnCollisionEnter(Collision collision)
{
if (!isDisappearing && collision.relativeVelocity.magnitude > 2f)
{
StartDisappearing();
}
}
public void StartDisappearing()
{
if (isDisappearing) return;
isDisappearing = true;
StartCoroutine(DisappearSequence());
}
private IEnumerator DisappearSequence()
{
yield return new WaitForSeconds(disappearDelay);
// 播放消失特效(如果有)
// if (disappearEffect != null) Instantiate(disappearEffect, transform.position, Quaternion.identity);
// 物体消失动画
float timer = 0;
Vector3 startScale = transform.localScale;
while (timer < destroyDelay)
{
timer += Time.deltaTime;
transform.localScale = Vector3.Lerp(startScale, Vector3.zero, timer / destroyDelay);
yield return null;
}
// 通知管理器
if (FindObjectOfType<PicoGestureManager>())
FindObjectOfType<PicoGestureManager>().ObjectDestroyed();
Destroy(gameObject);
}
}
// 手势检测器(模拟版)
public class PicoGestureDetector : MonoBehaviour
{
public enum HandType { Left, Right }
public HandType handType;
private XRDirectInteractor interactor;
void Start()
{
interactor = GetComponent<XRDirectInteractor>();
}
void Update()
{
// 模拟手势检测
bool isGrabbing = SimulateGestureInput();
// 抓取逻辑
if (isGrabbing)
{
if (!interactor.isSelectActive)
{
interactor.StartManualInteraction();
}
}
else
{
if (interactor.isSelectActive)
{
interactor.EndManualInteraction();
}
}
}
// 模拟手势输入(实际项目中使用Pico SDK)
private bool SimulateGestureInput()
{
// 按键模拟:
// 左手:左Ctrl键
// 右手:鼠标右键
return handType == HandType.Left ?
Input.GetKey(KeyCode.LeftControl) :
Input.GetMouseButton(1);
}
}
最新发布