OpenXR开发实战项目之VR 节奏光剑

2022-09-30  本文已影响0人  TonyWan_AR

一、框架视图

二、关键代码

ViewMusic

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ViewMusic : MonoBehaviour
{
    public Transform[] boxTransforms = new Transform[64];

    public int isRight = 1;

    public AudioSource audioSource;

    public float[] sepctrumData = new float[64];

    public MeshRenderer[] meshRenderers = new MeshRenderer[64];

    public int UpLerp = 12;

    void Start()
    {
        SetCunbeInfo();
    }

    // Update is called once per frame
    void Update()
    {
        audioSource.GetSpectrumData(sepctrumData, 0, FFTWindow.BlackmanHarris);
        SetScale();
        SetColor();
    }


    public void SetCunbeInfo()
    {
        Array.Clear(boxTransforms, 0, 64);
        Array.Clear(meshRenderers, 0, 64);

        for(int i=0;i<64;i++)
        {
            transform.GetChild(i).position = new Vector3(5 * isRight, 2.5f, 6.5f + 0.25f * i);
            transform.GetChild(i).localScale = new Vector3(0.2f, 3f, 0.01f);
            boxTransforms[i] = transform.GetChild(i);
            meshRenderers[i] = transform.GetChild(i).GetComponent<MeshRenderer>();
        }
    }

   public void SetScale()
    {
        for(int i=0;i<64;i++)
        {
            Vector3 _v3 = boxTransforms[i].transform.localScale;

            float a = sepctrumData[i] * 100000;

            Vector3 _v4 = new Vector3(0.2f, Mathf.Clamp(a, 0.1f, 3), 0.01f);

            boxTransforms[i].localScale = Vector3.Lerp(boxTransforms[i].localScale, _v4, Time.deltaTime * UpLerp);
        }
    }


    public void SetColor()
    {


        for (int i = 0; i < 64; i++)
        {
           
            
            if (boxTransforms[i].localScale.y <= 0.4f)
            {
                meshRenderers[i].material.SetColor("_EmissionColor", new Color(0.2f, 0.5f, 0.5f));
            }
            else if (boxTransforms[i].localScale.y <= 0.8f)
            {
                meshRenderers[i].material.SetColor("_EmissionColor", new Color(0.12f, 0.84f, 0.38f));
            }
            else if (boxTransforms[i].localScale.y <= 1.2f)
            {
                meshRenderers[i].material.SetColor("_EmissionColor", new Color(0.12f, 0.84f, 0.38f));
            }
            else if (boxTransforms[i].localScale.y <= 1.6f)
            {
                meshRenderers[i].material.SetColor("_EmissionColor", new Color(0.23f, 0.89f, 0.05f));
            }


            else if (boxTransforms[i].localScale.y <= 2f)
            {
                meshRenderers[i].material.SetColor("_EmissionColor", new Color(0.63f, 0.56f, 0.04f));
            }

            else if (boxTransforms[i].localScale.y <= 2.4f)
            {
                meshRenderers[i].material.SetColor("_EmissionColor", new Color(0.92f, 0.27f, 0.02f));
            }

            else if (boxTransforms[i].localScale.y <= 2.8f)
            {
                meshRenderers[i].material.SetColor("_EmissionColor", new Color(0.92f, 0.27f, 0.02f));
            }
            else
            {
                meshRenderers[i].material.SetColor("_EmissionColor", new Color(0.90f, 0.01f, 0.1f));
            }
            
        }
    }
}



Spawn

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Spawn : MonoBehaviour
{
    public List<Box> boxList;
    public List<Transform> transfromList;

    public float boxSpeed;

    public GameObject boomPrefab;
    public void Init()
    {
        boxSpeed = 5;
    }


    private void Start()
    {
        Init();
    }


    public void CreateBox()
    {
        GameObject temp = GameObject.Instantiate(boxList[Random.Range(0, boxList.Count)]).gameObject;
        temp.transform.position = transfromList[Random.Range(0, transfromList.Count)].position;

        Box box = temp.GetComponent<Box>();
        BoxType type = BoxType.Up;

        int num = Random.Range(0, 4);

        switch (num)
        {

            case 0:
                type = BoxType.Up; break;
            case 1:
                type = BoxType.Left; break;
            case 2:
                type = BoxType.Down; break;
            case 3:
                type = BoxType.Right; break;

        }

        box.Init(boxSpeed, type);
        box.SetRotationBaseType();
    }

    public void CreateBoom()
    {

        GameObject temp = GameObject.Instantiate(boomPrefab);
        temp.transform.position= transfromList[Random.Range(0, transfromList.Count)].position;

        Boom boom=temp.GetComponent<Boom>();
        boom.Init(boxSpeed);
    }
    
}

SortPannel

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class SortPannel : MonoBehaviour
{
    public Text sortText;


    private void Start()
    {
        sortText = GetComponentInChildren<Text>();
        ShowInfo();
    }

    public void ShowInfo()
    {
        DataMgr.Instance.ReadDate();

        if(DataMgr.Instance.saveScore.Count==0)
        {
            sortText.text = "_";
        }
        else
        {
            DataMgr.Instance.saveScore.Sort((x, y) => -x.CompareTo(y));
            sortText.text = "BestScore:" + DataMgr.Instance.saveScore[0];
        }
    }
}

Slice

using EzySlice;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.Tracing;
using System.IO;
using UnityEngine;
using Valve.VR;

public class Slice : MonoBehaviour
{
    public GameObject source;

    public Material material;

    public AudioSource audioSource;

    public AudioClip clip;

    public Saber saber;
    public int saberID;


    public GameObject hitEffect;

    
    private void Start()
    {
        audioSource=GetComponent<AudioSource>();
        saberID = saber.saberColor;
    }
    public void OnTriggerEnter(Collider other)
    {
        if(other.tag!="Box")
        {
            return;
        }

        source = other.gameObject;

        SlicedHull slicedHull = source.Slice(transform.position, transform.right,material);

        if(source==null)
        {
            return;
        }

        if(slicedHull==null)
        {
            return;
        }

        audioSource.PlayOneShot(clip);
        Shake();

        GameObject temp = GameObject.Instantiate(hitEffect, transform.position, Quaternion.identity);
        GameObject.Destroy(temp, 0.5f);
        if(saber.saberColor==other.gameObject.transform.root.GetComponent<Box>().boxColor)
        {
            //
            GameMgr.Instance.UpdateScore(1);
            GameMgr.Instance.UpdateCombom();

           
            GameMgr.Instance.lv.AddLV();
        }


        GameObject upGo = slicedHull.CreateUpperHull(source,material);
        GameObject lowerGo = slicedHull.CreateLowerHull(source, material);


        Vector3 location = this.transform.position;
        Vector3 closetPosition = other.ClosestPoint(location);
        upGo.transform.position = closetPosition;
        lowerGo.transform.position = closetPosition;
        GameObject.Destroy(other.transform.parent.gameObject);


        upGo.AddComponent<Rigidbody>();
        lowerGo.AddComponent<Rigidbody>();

       
        upGo.GetComponent<Rigidbody>().AddExplosionForce(500, upGo.transform.position - transform.right, 3);
        lowerGo.GetComponent<Rigidbody>().AddExplosionForce(500, lowerGo.transform.position + transform.right, 3);

        GameObject.Destroy(upGo.gameObject, 0.5f);
        GameObject.Destroy(lowerGo.gameObject, 0.5f);
    }


    public void Shake()
    {
        SteamVR_Actions.default_Haptic.Execute(0, 0.5f, 100, 200,saber.pose.inputSource);
       

    }
}

Player

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Valve.VR.Extras;

public class Player : MonoBehaviour
{
    public GameObject swordRed;
    public GameObject swordBlue;


    public GameObject ControllerLeft;
    public GameObject ControllerRight;

    public InteractUI interactLeft;
    public InteractUI interactRight;


    public void Awake()
    {

        interactLeft = ControllerLeft.GetComponent<InteractUI>();
        interactRight = ControllerLeft.GetComponent<InteractUI>();
    }
    public void ShowOrHideSaber(bool isShow)
    {
        swordRed.gameObject.SetActive(isShow);
        swordBlue.gameObject.SetActive(isShow);

    }
}

MusicEvent

using SonicBloom.Koreo;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;

public class MusicEvent : MonoBehaviour
{
    public string eventCreate;

    public Spawn spawn;


    public string eventGameOver;

    
    private void Start()
    {
        eventCreate = "Create";
        Koreographer.Instance.RegisterForEvents(eventCreate, Create);

        spawn = GameObject.Find("Spawn").GetComponent<Spawn>();

        eventGameOver = "SongOver";

        Koreographer.Instance.RegisterForEvents(eventGameOver, SongOver);
    }

    private void SongOver(KoreographyEvent koreoEvent)
    {
        GameMgr.Instance.gameState = GameState.gameEnd;
    }

    private void Create(KoreographyEvent koreoEvent)
    {
        int num =Random.Range(0, 10);
        if(num<=8)
        {
            spawn.CreateBox();
        }
        else
        {
            spawn.CreateBoom();
        }
    }
}

GameMgr

using System.Collections;
using System.Collections.Generic;
using UnityEngine;


public enum GameState
{
    gamePrepare,
    gameStart,
    gameEnd,


}

public class GameMgr : MonoBehaviour
{
    private static GameMgr instance;

    public static GameMgr Instance
    {
        get
        {
            if (instance != null)
            {
                return instance;
            }
            else
            {
                //为了防止脚本还未挂到物体上,找不到的异常情况,可以自行创建空物体挂上去
                instance = Object.FindFirstObjectByType<GameMgr>();
                if (instance == null)
                {
                    //如果创建对象,则会在创建时调用其身上脚本的Awake
                    //所以此时无需为instance赋值,其会在Awake中赋值,自然也会初始化所以无需init()
                    GameObject go = new GameObject("GameMgr");
                    go.AddComponent<GameMgr>();
                }
                instance.Init();
            }
            return instance;
        }
    }


    public int currentCombo;
    public int currentScore;

    public ScorePannel scorePannel;
    public bool isInterrupt=false;

    public int currentLV;
    public LV lv;
    public LVPannel lVPannel;

    public Dictionary<int, AudioClip> songDic = new Dictionary<int, AudioClip>();
    public AudioClip clip1;
    public AudioClip clip2;
    public AudioSource audioSource;

    public GameState gameState;

    public GameObject musicPlayer;
    public DataMgr datamgr;
    public MainPannel mainPannel;
    public Player player;

    private void Awake()
    {
        instance = this;
        scorePannel=GameObject.Find("ScoreBg").GetComponent<ScorePannel>();
        lVPannel= GameObject.Find("LVBg").GetComponent<LVPannel>();
        mainPannel= GameObject.Find("MainBg").GetComponent<MainPannel>();
        musicPlayer = GameObject.Find("MusicPlayer");
        player = GameObject.Find("XR Origin").GetComponent<Player>();
        Init();
    }

    public void Init()
    {
        gameState = GameState.gamePrepare;
        songDic.Clear();
        songDic.Add(1, clip1);
        songDic.Add(2,clip2);

        currentCombo = 0;
        currentLV = 0;
        currentScore = 0;

        isInterrupt = false;
    }

    private void Start()
    {
        Prepare();
    }
    public void UpdateScore(int score)
    {
        currentScore += score;
        if(currentScore<=0)
        {
            currentScore = 0;
        }

        scorePannel.UpdateScore(currentScore);
    }

    public void UpdateCombom()
    {
        if(isInterrupt)
        {
            currentCombo = 0;
            scorePannel.UpdateCombo(0);
            isInterrupt = false;
        }
        else
        {
            currentCombo++;
            scorePannel.UpdateCombo(currentCombo);
        }
    }

    public AudioClip SetSong(int index)
    {
        AudioClip clip;
        songDic.TryGetValue(index, out clip);

        if(clip==null)
        {
            clip = clip1;
        }

        return clip;
    }
    
    public void Prepare()
    {

      
        AudioClip clip = SetSong(DataMgr.Instance.currentIndex);
        audioSource.clip = clip;

        audioSource.Play();


       

        player.ShowOrHideSaber(true);

        mainPannel.gameObject.SetActive(false);

        scorePannel.Init();
        lVPannel.Init();

        gameState = GameState.gameStart;

    }


    private void Update()
    {
        if (gameState==GameState.gameEnd)
        {
            GameOver();
        }
    }

    public void GameOver()
    {
        mainPannel.gameObject.SetActive(true);
        mainPannel.ShowScore(currentScore);

        audioSource.Stop();
        player.ShowOrHideSaber(false);
    }
}

MainPannel

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class MainPannel : MonoBehaviour
{
    public Text totalText;
    public Button btn_Restart;
    public Button btn_Back;


    private void Awake()
    {
        totalText=transform.Find("Text_Total").GetComponentInChildren<Text>();
        btn_Back=transform.Find("Btn_Back").GetComponentInChildren<Button>();
        btn_Restart=transform.Find("Btn_Restart").GetComponentInChildren<Button>();

        btn_Back.onClick.AddListener(() => { Back(); });
        btn_Restart.onClick.AddListener(() => { Restart(); });
    }


    public void Back()
    {
       
        //
        DataMgr.Instance.currentScore = GameMgr.Instance.currentScore;
        //
        DataMgr.Instance.WriteData(DataMgr.Instance.currentScore);
        SceneManager.LoadScene(0);
    }

    public void Restart()
    {
        GameMgr.Instance.Init();
        GameMgr.Instance.Prepare();
    }

    public void ShowScore(int score)
    {
        totalText.text = "Score:" + score;
    }
}

LVPannel

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class LVPannel : MonoBehaviour
{
    public Text textLV;
    public Text healthText;

    public int maxHealth;
    public int currentHealth;
    private void Awake()
    {
        textLV= transform.Find("Text_LV").GetComponent<Text>();
        healthText = transform.Find("Text_Health").GetComponent<Text>();
        maxHealth = currentHealth = 100;
    }


    public void Init()
    {
        textLV.text = "LV:1";
        healthText.text = "Health:100";
    }


    private void Start()
    {
        Init();
    }

    public void CalculateDamage(int lv)
    {
        int baseCount = 10;
        float damage = maxHealth / (baseCount * 1.5f + lv - 1);
        int damage1 = Convert.ToInt32(damage);

        currentHealth -= damage1;
        if(currentHealth<=0)
        {
            currentHealth = 0;
        }

        healthText.text = "Health:" + currentHealth;
    }

   

    public void UpdateLV(int lv)
    {
        textLV.text = "LV:" + lv;
    }
}

LV

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LV : MonoBehaviour
{
    public int nextLevelScore;
    public Dictionary<int, int> lvScoreDic = new Dictionary<int, int>();
    void Awake()
    {
        Init();
    }

    private void Init()
    {
        lvScoreDic.Clear();
        lvScoreDic.Add(1, 3);
        lvScoreDic.Add(2, 5);
        lvScoreDic.Add(3, 7);
        lvScoreDic.Add(4, 10);
        lvScoreDic.Add(5, 14);
        lvScoreDic.Add(6, 18);
        lvScoreDic.Add(7, 25);
    }

    public void LimitLV()
    {
        if (GameMgr.Instance.currentLV <= 1)
        {
            GameMgr.Instance.currentLV = 1;
        }
        if (GameMgr.Instance.currentLV >= 8)
        {
            GameMgr.Instance.currentLV = 8;
        }
    }

    public void CalculateLV()
    {
        if (GameMgr.Instance.currentLV >= 1 && GameMgr.Instance.currentLV <= 7)
        {
            nextLevelScore = lvScoreDic[GameMgr.Instance.currentLV];

        }
    }

    public void AddLV()
    {
        CalculateLV();
        if (GameMgr.Instance.currentScore >= nextLevelScore)
        {
            GameMgr.Instance.currentLV += 1;
            LimitLV();
            GameMgr.Instance.lVPannel.UpdateLV(GameMgr.Instance.currentLV);
        }
    }

    public void ReduceLV()
    {
        GameMgr.Instance.currentLV -= 1;
        LimitLV();
        GameMgr.Instance.lVPannel.UpdateLV(GameMgr.Instance.currentLV);
    }

}

CheckMiss

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CheckMiss : MonoBehaviour
{
    public void OnTriggerEnter(Collider other)
    {
        
        if(other.tag=="Box")
        {
            GameMgr.Instance.isInterrupt = true;
            GameMgr.Instance.UpdateCombom();
           
        }

        GameObject.Destroy(other.gameObject);
    }
}

Box

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public enum BoxType
{ 
    Up,
    Down,
    Left,
    Right,

}

public class Box : MonoBehaviour
{
    public float boxSpeed;
    public BoxType boxType;
    public int boxColor;

    private void Start()
    {
        GameObject.Destroy(this.gameObject, 8f);
    }
    public void Init(float speed,BoxType type)
    {
        boxSpeed = speed;
        boxType = type;
    }

    public void SetRotationBaseType()
    {
        switch(boxType)
        {

            case BoxType.Up:
                transform.rotation = Quaternion.Euler(0, 0, 0);
                break;
                case BoxType.Left:
                transform.rotation = Quaternion.Euler(0, 0, 90);
                break;
                     case BoxType.Down:
                transform.rotation = Quaternion.Euler(0, 0, 180);
                break;
                      case BoxType.Right:
                transform.rotation = Quaternion.Euler(0, 0, 270); ;
                break;

        }
    }


    public void Update()
    {
        transform.Translate(-transform.forward * Time.deltaTime * boxSpeed);
        if(GameMgr.Instance.gameState==GameState.gameEnd)
        {
            GameObject.Destroy(this.gameObject);
        }
    }

}

Boom

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Boom : MonoBehaviour
{
    public float Speed;
    public GameObject hitEffect;
    private void Start()
    {
        GameObject.Destroy(this.gameObject, 8f);
    }
    public void Init(float speed=5)
    {
        Speed = speed;
    }

    public void Update()
    {
        transform.Translate(-transform.forward * Time.deltaTime *Speed);
        if (GameMgr.Instance.gameState == GameState.gameEnd)
        {
            GameObject.Destroy(this.gameObject);
        }
    }

    public void OnTriggerEnter(Collider other)
    {
        if(other.tag=="Slice")
        {
            GameMgr.Instance.lv.ReduceLV();
            GameMgr.Instance.lVPannel.CalculateDamage(GameMgr.Instance.currentLV);
            GameMgr.Instance.UpdateScore(-2);
            GameObject go=  GameObject.Instantiate(hitEffect, transform.position, Quaternion.identity);
            GameObject.Destroy(go, 0.5f);
            GameObject.Destroy(gameObject);

        }
    }

    
}

StartUI

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//给按钮点击注册事件 选中哪个歌,就记录该首歌 ,跳转目标场景 
public class StartUI : MonoBehaviour
{
    public List<SongSlot> btnSongList;

    private void Start()
    {
        SetSlotUI();
    }
    public void SetSlotUI()
    {
        for (int i = 0; i < btnSongList.Count; i++)
        {
            //注数组越界 完整的应写无限滚动列表
            //注意i 可能在字典里越界
            btnSongList[i].slotIndex = i;
            btnSongList[i].SetUI(DataMgr.Instance.songNameDic[i]);
        }
    }
}

SongSlot

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class SongSlot : MonoBehaviour
{
    public Text song;
    public string songName;

    //格子索引
    public int slotIndex;



    private void Awake()
    {
        song = GetComponentInChildren<Text>();
        GetComponent<Button>().onClick.AddListener(() => { LoadGame(); });
    }

    //设置UI信息 安全校验
    public void SetUI(string name)
    {
        if (string.IsNullOrEmpty(name))
        {
           
          
            return;
        }
        songName = name;
        song.text = songName;
    }

    //如果当前格子没有显示歌曲名 不跳转场景
    public void LoadGame()
    {
        if (string.IsNullOrEmpty(song.text))
        {
            return;
        }

        SceneManager.LoadScene(1);
    }
}

InteractUI

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Valve.VR.Extras;

[RequireComponent(typeof(SteamVR_LaserPointer))]
public class InteractUI : MonoBehaviour
{

    private SteamVR_LaserPointer laser;
    void Start()
    {
        laser = GetComponent<SteamVR_LaserPointer>();
        laser.PointerClick += Laser_PointerClick;
        laser.PointerIn += Laser_PointerIn;
        laser.PointerOut += Laser_PointerOut;
    }

    private void Laser_PointerOut(object sender, PointerEventArgs e)
    {
        
    }

    private void Laser_PointerIn(object sender, PointerEventArgs e)
    {
       
    }

    private void Laser_PointerClick(object sender, PointerEventArgs e)
    {
        Button btn = e.target.GetComponent<Button>();
        if(btn!=null)
        {
          SongSlot slot=  btn.GetComponentInChildren<SongSlot>();
            if(slot!=null)
            {
                DataMgr.Instance.currentIndex = slot.slotIndex;
            }

            btn.onClick.Invoke();
        }
    }

    void Update()
    {
        
    }
}

DataMgr

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;

//数据管理类 单例
public class DataMgr : MonoBehaviour
{
    private static DataMgr instance;
    //歌曲名字典 
    public Dictionary<int, string> songNameDic = new Dictionary<int, string>();

    public static DataMgr Instance
    {
        get
        {
            if (instance != null)
            {
                return instance;
            }
            else
            {
                //为了防止脚本还未挂到物体上,找不到的异常情况,可以自行创建空物体挂上去
                instance = Object.FindFirstObjectByType<DataMgr>();
                if (instance == null)
                {
                    //如果创建对象,则会在创建时调用其身上脚本的Awake
                    //所以此时无需为instance赋值,其会在Awake中赋值,自然也会初始化所以无需init()
                    GameObject go = new GameObject("DataMgr");
                    go.AddComponent<DataMgr>();
                }
                instance.Init();
            }
            return instance;
        }
    }

    public int currentIndex;
    public int currentScore;

    public string dataPath;
    public List<int> saveScore=new List<int>();
    private void Awake()
    {
        
        if(instance!=null)
        {
            GameObject.Destroy(this.gameObject);
            return;
        }
        else
        {
            instance = this;
        }
        Init();
        DontDestroyOnLoad(gameObject);
        dataPath = Application.persistentDataPath + "/SaveScore.txt";
        CreateDataFile();

    }


    private void Start()
    {
       
        
    }
    public void Init()
    {
        //假数据
        songNameDic.Clear();
        songNameDic.Add(0, "Night");
        songNameDic.Add(1, "");
        songNameDic.Add(2, "");
        songNameDic.Add(3, "");
    }

    public void CreateDataFile()
    {
        Debug.Log(dataPath);
        if(!File.Exists(dataPath))
        {
            Debug.Log("不存在该文件");
            File.Create(dataPath);
            Debug.Log("该文件已创建");
            return;
        }
    }
    
    public void WriteData(int currentScore)
    {
        CreateDataFile();
        using(StreamWriter sw = new StreamWriter(dataPath, true)) { sw.WriteLine(currentScore); }
    }

    public void ReadDate()
    {
        saveScore.Clear();
        string str = string.Empty;
        using(StreamReader sr = new StreamReader(dataPath))
        {

            while((str= sr.ReadLine()) != null)
            {
                if(string.IsNullOrWhiteSpace(str))
                {
                    continue;
                }
                int score = int.Parse(str);
                saveScore.Add(score);
            }


        }
    }
}

三、效果图

上一篇下一篇

猜你喜欢

热点阅读