AR大屏互动自己整合基础框架
做了许多的AR互动游戏总结了一下期间的所需,根据其需求以及网上的资料查询整合了一些常用的属性编写了一套比较适合自己的小型框架。
首先我们知道AR所需要的功能
1.逻辑功能,大部分是一个一个的小型关卡和逻辑组成,所以这里我选择了有限状态机来实现一个关卡和一个关卡之间的逻辑。
2.其次是部分功能,大部分游戏由一个GameManger管理类,所以我们需要一个单例模板。
3.很多关卡是由时间控制,时间是由图片的切换来完成所以我们需要一个时间类,来时常调用。
4.无论砸球和体感都需要一个分数来实现,所以也需要一个分数类。
5.大部分物体,例如特效反复的实例化删除很耗性能一个不小心容易导致内存泄露所以使用一个内存池可以很好的控制这个发生的几率
6.数据载入,做一个沙池游戏中,一些教育类游戏会需要大量的文字显示,这样的话使用Xml会很方便,当然数据的载入也能使用,有时候也会用到txt载入看自己选择了。
7.音效管理类,之前都是哪里有音效直接挂哪里然后代码播放停止,现在学习之后用了一个类,使代码更加的简洁。
8.常用的一些方法,例如协程,和每隔一段时间需要重复一个逻辑。
下面就让我一个一个来实现
1。首先先实现有限状态机的框架这个之前也有分享过直接上代码
1.1状态机类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;namespace FSM
{/// <summary>/// 状态接口/// </summary>public interface Istate{/// <summary>/// 状态名/// </summary>string Name { get; }/// <summary>/// 状态标签/// </summary>string Tag { set; get; }/// <summary>/// 当前状态的状态机/// </summary>IstateMachine Parent { get; set; }/// <summary>/// 从进入状态开始计算的时长/// </summary>float Timer { get; }/// <summary>/// 状态过度当前状态的所有过度/// </summary>List<ITransition> Transition { get; }/// <summary>/// 进入状态时的回调/// </summary>/// <param name="prev">上一个状态</param>void EnterCallback(Istate prev);/// <summary>/// 退出状态时的回调/// </summary>/// <param name="next">下一个状态</param>void ExitCallback(Istate next);/// <summary>/// Update的回调/// </summary>/// <param name="deltaTime">Time.deltaTime</param>void UpdateCallback(float deltaTime);/// <summary>/// LateUpdate的回调/// </summary>/// <param name="deltaTime">Time.deltaTime</param>void LateUpdateCallback(float deltaTime);/// <summary>/// FixUppdate的回调/// </summary>void FixUppdateCallback();/// <summary>/// 添加过度/// </summary>/// <param name="t">状态过度</param>void AddTransition(ITransition t);}
}
1.2.状态机工厂
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace FSM
{/// <summary>
/// 状态机接口
/// </summary>public interface IstateMachine{/// <summary>/// 当前状态/// </summary>Istate CurrentState { get; }/// <summary>/// 默认状态/// </summary>Istate DefaultState { set; get; }/// <summary>/// 添加状态/// </summary>/// <param name="state">要添加的状态</param>void AddState(Istate state);/// <summary>/// 删除状态/// </summary>/// <param name="state">要删除的状态</param>void RemoveState(Istate state);/// <summary>/// 通过指定的tag值查找状态/// </summary>/// <param name="tag">状态 Tag值</param>/// <returns>查找到的状态</returns>Istate GetStateWithTage(string tag);}}
1.3状态机回掉
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace FSM
{public delegate void LexDelegate();public delegate void LexDelegateState(Istate State);public delegate void LexDelegateFloat(float f);public class LexState : Istate{/// <summary>/// 当进入状态时调用的事件/// </summary>public event LexDelegateState OnEnter;/// <summary>/// 当离开状态时调用的事件/// </summary>public event LexDelegateState OnExit;/// <summary>/// 当Update时调用的事件/// </summary>public event LexDelegateFloat OnUpdate;/// <summary>/// 当LateUpdate时调用的事件/// </summary>public event LexDelegateFloat OnLateUpdate;/// <summary>/// 当FixUpdate时调用的事件/// </summary>public event LexDelegate OnFixUpdate;private string _name;//状态名private string _tag;//状态标签private IstateMachine _parent;//当前状态的状态机private float _Timer;//计时器private List<ITransition> _transition;//状态过度/// <summary>/// 构造方法/// </summary>/// <param name="name">状态名</param>public LexState(string name){_name = name;_transition = new List<ITransition>();}/// <summary>/// 状态名/// </summary>public string Name{get{return _name;}}/// <summary>/// 状态标签/// </summary>public string Tag{get{return _tag;}set{_tag = value;}}/// <summary>/// 当前状态的状态机/// </summary>public IstateMachine Parent{get{return _parent;}set{_parent = value;}}/// <summary>/// 从进入状态开始计算的时长/// </summary>public float Timer{get{return _Timer;}}/// <summary>/// 状态过度当前状态的所有过度/// </summary>public List<ITransition> Transition{get{return _transition;}}/// <summary>/// 添加过度/// </summary>/// <param name="t">状态过度</param>public void AddTransition(ITransition t){if(t!=null&&!_transition.Contains(t)){_transition.Add(t);}}/// <summary>/// 进入状态时的回调/// </summary>/// <param name="prev">上一个状态</param>public virtual void EnterCallback(Istate prev){//重置计时器_Timer = 0;//进入状态时系统调用OnEnter事件if (OnEnter != null){OnEnter(prev);}}/// <summary>/// 退出状态时的回调/// </summary>/// <param name="next">下一个状态</param>public virtual void ExitCallback(Istate next){//离开状态时系统调用OnEnter事件if (OnExit != null){OnExit(next);}//重置计时器_Timer = 0;}/// <summary>/// Update的回调/// </summary>/// <param name="deltaTime">Time.deltaTime</param>public virtual void UpdateCallback(float deltaTime){//累加计时器_Timer += deltaTime;//Update时系统会调用OnUpdate事件if (OnUpdate!=null){OnUpdate(deltaTime);}}/// <summary>/// LateUpdate的回调/// </summary>/// <param name="deltaTime">Time.deltaTime</param>public virtual void LateUpdateCallback(float deltaTime){//LateUpdate时系统会调用OnLateUpdate事件if (OnLateUpdate!=null){OnLateUpdate(deltaTime);}}/// <summary>/// FixUppdate的回调/// </summary>public virtual void FixUppdateCallback(){//FixUpdate时系统会调用OnFixUpdate事件if (OnFixUpdate!=null){OnFixUpdate();}}}
}
1.4状态机回调工厂
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace FSM
{/// <summary>/// 状态机类需要继承与状态类并实现状态机接口/// </summary>public class LexStateMachine : LexState, IstateMachine{private Istate _CurrentState;//当前状态private Istate _DefaultState;//默认状态private List<Istate> _States;//所有状态private bool _isTransition = false;//是否正在过度private ITransition _t;//当前正在执行的过度/// <summary>/// 构造方法/// </summary>/// <param name="name"></param>public LexStateMachine(string name,Istate defaultState):base(name){_States = new List<Istate>();_DefaultState = defaultState;_DefaultState.EnterCallback(defaultState);}/// <summary>/// 当前状态/// </summary>public Istate CurrentState{get{return _CurrentState;}}/// <summary>/// 默认状态/// </summary>public Istate DefaultState{get{return _DefaultState;}set{AddState(value);_DefaultState = value;}}/// <summary>/// 添加状态/// </summary>/// <param name="state">要添加的状态</param>public void AddState(Istate state){if(state!=null &&!_States.Contains(state)){_States.Add(state);//将加入的新状态的的Parent设置为当前状态机state.Parent = this;if(_DefaultState==null){_DefaultState = state;}}}/// <summary>/// 删除状态/// </summary>/// <param name="state">要删除的状态</param>public void RemoveState(Istate state){//再状态机运行过程中不能够删除当前状态if (_CurrentState == state){return;}if (state != null && _States.Contains(state)){_States.Remove(state);//将已经移除的Parent设置为空state.Parent = null;if (_DefaultState == state){_DefaultState = (_States.Count >= 1) ? _States[0] : null;}}}/// <summary>/// 通过指定的tag值查找状态/// </summary>/// <param name="tag">状态 Tag值</param>/// <returns>查找到的状态</returns>public Istate GetStateWithTage(string tag){return null;}public override void UpdateCallback(float deltaTime){//检测当前是否再过度状态if(_isTransition){//检测当前执行的过度是否完成if(_t.TransitionCallback()){DoTransition(_t);_isTransition = false;}return;}base.UpdateCallback(deltaTime);if(_CurrentState==null){_CurrentState = _DefaultState;}List<ITransition> ts = _CurrentState.Transition;int Count = _CurrentState.Transition.Count;for (int i = 0; i < Count; i++){ITransition t = ts[i];if(t.ShouldBengin()){_isTransition = true;_t = t;return;}}_CurrentState.UpdateCallback(deltaTime);}public override void LateUpdateCallback(float deltaTime){base.LateUpdateCallback(deltaTime);_CurrentState.LateUpdateCallback(deltaTime);}public override void FixUppdateCallback(){base.FixUppdateCallback();_CurrentState.FixUppdateCallback();}//开始执行过度private void DoTransition(ITransition t){_CurrentState.ExitCallback(t.To);_CurrentState = t.To;_CurrentState.EnterCallback(t.From);}}
}
1.5状态机过度类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;namespace FSM
{/// <summary>
/// 状态过度的接口
/// </summary>public interface ITransition{/// <summary>/// 过度名/// </summary>string name { get; }/// <summary>/// 从哪个状态开始过度/// </summary>Istate From { get; set; }/// <summary>/// 要过度到哪个状态去/// </summary>Istate To { get; set; }/// <summary>/// 过度时的回调/// </summary>/// <returns>返回true过度结束返回false继续进行过度</returns>bool TransitionCallback();/// <summary>/// 能否开始过度/// </summary>/// <returns>如果是True就开始进行过度如果是False就不进行过度</returns>bool ShouldBengin();}
}
1.6过渡实现
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace FSM
{public delegate bool LexTransitionDelegate();public class LexTransition : ITransition{private Istate _From;//原状态private Istate _To;//目标状态private string _name;//过度名public event LexTransitionDelegate OnTransition;public event LexTransitionDelegate OnCheck;//检测条件是否满足/// <summary>/// 构造方法/// </summary>/// <param name="Name"></param>/// <param name="fromstate"></param>/// <param name="tostate"></param>public LexTransition(string Name, Istate fromstate, Istate tostate){_name = Name;_From = fromstate;_To = tostate;}/// <summary>/// 过度名/// </summary>public string name{get{return _name;}}/// <summary>/// 从哪个状态开始过度/// </summary>public Istate From{get{return _From;}set{_From = value;}}/// <summary>/// 要过度到哪个状态去/// </summary>public Istate To{get{return _To;}set{_To = value;}}/// <summary>/// 过度时的回调/// </summary>/// <returns>返回true过度结束返回false继续进行过度</returns>public bool TransitionCallback(){if (OnTransition != null){return OnTransition();}return true;}/// <summary>/// 能否开始过度/// </summary>/// <returns>如果是True就开始进行过度如果是False就不进行过度</returns>public bool ShouldBengin(){if (OnCheck != null){return OnCheck();}return false;}}}
1.7 状态机框架调用
1.7.1一个状态机一个类来实现
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using FSM;public class lightText : MonoBehaviour {private LexState OpenState;//灯光的打开状态private LexState CloseState;//灯光的关闭状态private Light _light;// Use this for initializationvoid Awake (){_light = GetComponent<Light>();OpenState = new LexState("_OpenState");//灯光再打开状态的时候实时打印OpenState.OnUpdate += (float f) =>{Debug.Log("Hello, World");};OpenState.OnEnter += new LexDelegateState(WillEnterState);CloseState = new LexState("CloseState");CloseState.OnExit += (Istate State) =>{Debug.Log("即将离开关闭状态");};}//即将进入打开状态时调用private void WillEnterState(Istate prev){Debug.Log("即将进入打开状态");_light.color = Color.blue;}}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using FSM;public class Test : MonoBehaviour {public float speed; //Cube每秒钟移动的距离private LexStateMachine _fsm;//状态机private LexState Idle;//闲置状态private LexState move;//移动状态private LexTransition _IdleToMove;//Idle到Move的状态过度private LexTransition _MoveToIdle;//Move到Idle的状态过度private bool IsMove=false;//能否开始移动// Use this for initializationvoid Start () {//初始化状态Idle = new LexState("Idle");//创建状态//Idle.EnterCallback(_fsm.CurrentState);Idle.OnEnter += (Istate state) =>{Debug.Log("进入Idle状态");};move = new LexState("Move");//移动状态的时候的逻辑move.OnUpdate += (float f) =>{transform.position += transform.forward * f * speed;};_IdleToMove = new LexTransition("idlemove", Idle, move);//创建过渡状态_IdleToMove.OnCheck += () =>{return IsMove;};Idle.AddTransition(_IdleToMove);//加入过渡状态链表//_IdleToMove.OnTransition += () =>// {// };_MoveToIdle = new LexTransition("moveIdle", move, Idle);_MoveToIdle.OnCheck += () =>{return !IsMove;};move.AddTransition(_MoveToIdle);_fsm = new LexStateMachine("Root", Idle);//创建状态机并加入状态_fsm.AddState(move);}// Update is called once per framevoid Update () {_fsm.UpdateCallback(Time.deltaTime);}void OnGUI(){if(GUILayout.Button("move")){IsMove = true;}if(GUILayout.Button("Stop")){IsMove = false;}}
}
1.7.2状态机整体调用并且可以实现层级状态机
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using FSM;public class LightControl : MonoBehaviour {public float maxIntensity;public float FadeSpeed;private LexStateMachine _fsm;private LexStateMachine _open;//open状态下的子状态声明private LexState _close;private LexTransition opentoclose;private LexTransition closetoopen;private LexState _changeIntensity;private LexState _changeColor;private LexTransition colortointensity;private LexTransition intensitytocolor;private bool isOpen=true;private bool isAnimation;private bool isResst;private float target;private Color targetColor;private Color StartColor;private float ColorTimer;public bool ischangecolor;private Light _light;// Use this for initializationvoid Start () {InitFSM();_light = GetComponent<Light>();}// Update is called once per framevoid Update () {_fsm.UpdateCallback(Time.deltaTime);}//初始化状态机private void InitFSM(){_changeIntensity = new LexState("changeIntensity");_changeIntensity.OnEnter += (Istate State) =>{isAnimation = true;isResst = true;};_changeIntensity.OnUpdate += (float f) =>{if (isAnimation){if (isResst){if (Fadeto(maxIntensity)){isResst = false;isAnimation = false;}}else{if (Fadeto(target)){isResst = true;}}}else{target = Random.Range(0.3f, 0.7f);isAnimation = true;}};_changeColor = new LexState("changeColor");_changeColor.OnEnter += (Istate State) =>{isAnimation = false;};_changeColor.OnUpdate += (float f) =>{if(isAnimation){if(ColorTimer>=1f){isAnimation = false;}else{ColorTimer += Time.deltaTime ;_light.color = Color.Lerp(StartColor, targetColor, ColorTimer);}}else{float r = Random.Range(0,0.5f);float g = Random.Range(0, 0.5f);float b = Random.Range(0, 0.5f);targetColor = new Color(r, g, b);StartColor = _light.color;ColorTimer = 0f;isAnimation = true;}};colortointensity = new LexTransition("colortointensity",_changeColor,_changeIntensity);colortointensity.OnCheck += () =>{return !ischangecolor;};_changeColor.AddTransition(colortointensity);intensitytocolor = new LexTransition("intensitytocolor", _changeIntensity, _changeColor);intensitytocolor.OnCheck += () =>{return ischangecolor;};_changeIntensity.AddTransition(intensitytocolor);_open = new LexStateMachine("open", _changeIntensity);//子状态的加入_open.AddState(_changeColor); _close = new LexState("close");_close.OnEnter += (Istate State) =>{_light.intensity = 0;};opentoclose = new LexTransition("OpenClose", _open, _close);opentoclose.OnCheck += () =>{return !isOpen;};//opentoclose.OnTransition += () =>//{// return Fadeto(0);//};_open.AddTransition(opentoclose);closetoopen = new LexTransition("CloseOpen", _close, _open);closetoopen.OnCheck += () =>{return isOpen;};closetoopen.OnTransition += () =>{return Fadeto(maxIntensity);};_close.AddTransition(closetoopen);_fsm = new LexStateMachine("Cube", _open);_fsm.AddState(_close);}void OnGUI(){if (GUI.Button(new Rect(150f,30f,55f,28f),"open")){isOpen = true;}if (GUI.Button(new Rect(150f, 65f, 55f, 28f), "Close")){isOpen = false;}}//将灯光光强渐变到指定的值private bool Fadeto(float f){if(Mathf.Abs(_light.intensity-f)<=0.05f){_light.intensity = f;return true;}else{int flag = _light.intensity > f ? -1 : 1;_light.intensity += Time.deltaTime * FadeSpeed*flag;return false;}}
}
2 单例模板
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using FSM;public class Test : MonoBehaviour {public float speed; //Cube每秒钟移动的距离private LexStateMachine _fsm;//状态机private LexState Idle;//闲置状态private LexState move;//移动状态private LexTransition _IdleToMove;//Idle到Move的状态过度private LexTransition _MoveToIdle;//Move到Idle的状态过度private bool IsMove=false;//能否开始移动// Use this for initializationvoid Start () {//初始化状态Idle = new LexState("Idle");//创建状态//Idle.EnterCallback(_fsm.CurrentState);Idle.OnEnter += (Istate state) =>{Debug.Log("进入Idle状态");};move = new LexState("Move");//移动状态的时候的逻辑move.OnUpdate += (float f) =>{transform.position += transform.forward * f * speed;};_IdleToMove = new LexTransition("idlemove", Idle, move);//创建过渡状态_IdleToMove.OnCheck += () =>{return IsMove;};Idle.AddTransition(_IdleToMove);//加入过渡状态链表//_IdleToMove.OnTransition += () =>// {// };_MoveToIdle = new LexTransition("moveIdle", move, Idle);_MoveToIdle.OnCheck += () =>{return !IsMove;};move.AddTransition(_MoveToIdle);_fsm = new LexStateMachine("Root", Idle);//创建状态机并加入状态_fsm.AddState(move);}// Update is called once per framevoid Update () {_fsm.UpdateCallback(Time.deltaTime);}void OnGUI(){if(GUILayout.Button("move")){IsMove = true;}if(GUILayout.Button("Stop")){IsMove = false;}}
}
2.1单例模板使用,很简单直接在所需单例类的后面继承,并在<>写上这个类调用单例类方法,类名.Instance.方法名。
3.时间管理类,这个是按分秒显示的如果只想用秒可以稍作改进
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using System;public class TimeManager : UnitySingleton<TimeManager>
{public int minite;//分public int second;//秒public float Timer;//时间public Sprite[] NumberSprite;//存放数字图片public GameObject[] TimeDisplay;//存放UIGameObject // Use this for initializationvoid Start () {}// Update is called once per framevoid Update () {Timer -= Time.deltaTime;minite = (int)Timer / 60;second = (int)Timer % 60;//秒第个位if(second>=0&&second<60){TimeDisplay[0].GetComponent<Image>().sprite = NumberSprite[FindNum(second, 1)];}//秒十位if (second >= 0 && second < 60){TimeDisplay[1].GetComponent<Image>().sprite = NumberSprite[FindNum(second, 2)];}//分个位if(minite>=0&& minite < 10){TimeDisplay[2].GetComponent<Image>().sprite = NumberSprite[FindNum(minite, 1)];}//分十位if (minite >= 10 && minite < 60){TimeDisplay[3].GetComponent<Image>().sprite = NumberSprite[FindNum(minite, 2)];}}/// <summary>/// 分数显示/// </summary>/// <param name="num">数字</param>/// <param name="n">位数</param>/// <returns></returns>public int FindNum(int num, int n){int power = (int)Math.Pow(10, n);return (num - num / power * power) * 10 / power;}}
4.分数类,实现一个简单的分数滚动机制
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using System;public class Score : MonoBehaviour
{public Sprite[] ScoreSprite;//数字贴图static public int CurrentScore;//当前分数static public int OriginalScore;//原始的分数 public GameObject[] ScoreDisplay;//分数显示float timeKeep = 0.1f;//多久滚动时间private float ChangeTime;//时间变量// Use this for initializationvoid Start(){CurrentScore = 0;OriginalScore = 0;ChangeTime = 0;}// Update is called once per framevoid Update(){if (CurrentScore < 0){CurrentScore = 0;}if (OriginalScore != CurrentScore){ChangeTime += Time.deltaTime;if (ChangeTime > timeKeep){if (OriginalScore < CurrentScore){OriginalScore++;}if (OriginalScore > CurrentScore){OriginalScore--;}ChangeScore(OriginalScore);ChangeTime = 0;int dis = Math.Abs(OriginalScore - CurrentScore);timeKeep = 0.01f / (float)(dis % 10 + 1); }}}/// <summary>/// 改变分数/// </summary>/// <param name="Number">分数</param>public void ChangeScore(int Number){char[] chars = Number.ToString().ToCharArray();for (int i = 0; i < chars.Length; i++){ int index = int.Parse(chars[chars.Length - i - 1].ToString());ScoreDisplay[i].GetComponent<Image>().sprite = ScoreSprite[index];}for (int i = 0; i < ScoreDisplay.Length- chars.Length; i++){ScoreDisplay[ScoreDisplay.Length-1-i].GetComponent<Image>().sprite = ScoreSprite[0];}}
}
5内存池,大部分重复使用的物体可以存放在里面,例如特效
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;public class Pool : UnitySingleton<Pool>
{//将要制作成对象池的Prefab拖到此数组中public GameObject[] prefabArray;Dictionary<string, SubPool> m_pools = new Dictionary<string, SubPool>();void Start(){DontDestroyOnLoad(this.gameObject);}void OnEnable(){}/// <summary>/// 物体被销毁时 OnDisable将被调用,并且可用于任意清理代码。脚本被卸载时,OnDisable将被调用,OnEnable在脚本被载入后调用/// </summary>void OnDisable(){foreach (var pool in m_pools){pool.Value.m_objects.Clear();}m_pools.Clear();}public GameObject Spwan(GameObject obj){if (!m_pools.ContainsKey(obj.name))CreatNewSubPool(obj);SubPool pool = m_pools[obj.name];return pool.Spawn();}public void UnSpwan(GameObject go){SubPool pool = null; foreach (SubPool p in m_pools.Values){if (p.Contains(go)){pool = p;break;} }pool.Unspawn(go);}public void UnspawnAll(){foreach (SubPool p in m_pools.Values)p.UnspawnAll();}public void CreatNewSubPool(GameObject obj){string name = obj.name;if (!m_pools.ContainsKey(name)){SubPool pool = new SubPool(transform,obj);m_pools.Add(name, pool);}}
}public class SubPool
{GameObject m_prefab;Transform m_parent;public List<GameObject> m_objects = new List<GameObject>();public SubPool(Transform parent, GameObject obj){this.m_parent = parent;this.m_prefab = obj;}public GameObject Spawn(){GameObject go = null;foreach (GameObject obj in m_objects){if (!obj.activeSelf){go = obj;break;}}if (go == null){go = GameObject.Instantiate<GameObject>(m_prefab);go.transform.parent = m_parent;m_objects.Add(go);}go.SetActive(true);return go;}//回收对象public void Unspawn(GameObject go){if (Contains(go)){go.SetActive(false);}}//回收该池子的所有对象public void UnspawnAll(){foreach (GameObject item in m_objects){if (item.activeSelf){Unspawn(item);}}}//是否包含对象public bool Contains(GameObject go){return m_objects.Contains(go);}
}
6.数据载入Xml
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Xml;
using System.IO;public class XmlLoad : UnitySingleton<XmlLoad>
{#region Public Variablespublic string LocalUrl = Application.streamingAssetsPath + "/Text.xml"; //Xml路径 public List<string> AllTitleName = new List<string>(); //所有标题名字public List<string> Content = new List<string>();//所有内容#endregion#region Methodspublic XmlDocument ReadAndLoadXml(){XmlDocument doc = new XmlDocument();doc.Load(LocalUrl);return doc;}/// <summary>/// 读取xml信息/// </summary>/// <param name="id">等级ID</param>/// <param name="attributeName">属性名称</param>/// <returns></returns>public string ParseXml(int id){string result = null;XmlReaderSettings set = new XmlReaderSettings();set.IgnoreComments = true;//这个设置是忽略xml注释文档的影响。有时候注释会影响到xml的读取//得到Levels节点下的所有子节点XmlNodeList xmlNodeList = ReadAndLoadXml().SelectSingleNode("Levels").ChildNodes;foreach (XmlElement item in xmlNodeList){if (item.GetAttribute("ID") == id.ToString()){AllTitleName = new List<string>();Content = new List<string>();foreach (XmlElement item1 in item.ChildNodes){//遍历id下的子节点加入链表AllTitleName.Add(item1.GetAttribute("Title"));Content.Add(item1.GetAttribute("Content"));}}}return result;}/// <summary>/// 修改Xml/// </summary>/// <param name="OriginalId"></param>/// <param name="NewId"></param>public void updateXML(int OriginalId,int NewId){ if (File.Exists(LocalUrl)){XmlDocument xml = new XmlDocument();//得到Levels节点下的所有子节点XmlNodeList xmlNodeList = ReadAndLoadXml().SelectSingleNode("Levels").ChildNodes;foreach (XmlElement item in xmlNodeList){if (item.GetAttribute("ID") == OriginalId.ToString()){//改变messages里iditem.SetAttribute("ID", NewId.ToString());}if (item.GetAttribute("ID") == OriginalId.ToString()){foreach (XmlElement item1 in item.ChildNodes){//改变子节点}} }xml.Save(LocalUrl);}}/// <summary>/// 创建Xml/// </summary>public void CreateXML(){//string path = Application.dataPath + "/data2.xml";if (!File.Exists(LocalUrl)){//创建最上一层的节点。XmlDocument xml = new XmlDocument();//创建最上一层的节点。XmlElement root = xml.CreateElement("objects");//创建子节点XmlElement element = xml.CreateElement("messages");//设置节点的属性element.SetAttribute("id", "1");XmlElement elementChild1 = xml.CreateElement("contents");elementChild1.SetAttribute("name", "a");//设置节点内面的内容elementChild1.InnerText = "这就是你,你就是天狼";XmlElement elementChild2 = xml.CreateElement("mission");elementChild2.SetAttribute("map", "abc");elementChild2.InnerText = "去吧,少年,去实现你的梦想";//把节点一层一层的添加至xml中,注意他们之间的先后顺序,这是生成XML文件的顺序element.AppendChild(elementChild1);element.AppendChild(elementChild2);root.AppendChild(element);xml.AppendChild(root);//最后保存文件xml.Save(LocalUrl);}}/// <summary>/// 添加Xml/// </summary>public void addXMLData(){///string path = Application.dataPath + "/data2.xml";if (File.Exists(LocalUrl)){XmlDocument xml = new XmlDocument();xml.Load(LocalUrl);XmlNode root = ReadAndLoadXml().SelectSingleNode("Levels");//下面的东西就跟上面创建xml元素是一样的。我们把他复制过来就行了XmlElement element = xml.CreateElement("messages");//设置节点的属性element.SetAttribute("id", "2");XmlElement elementChild1 = xml.CreateElement("contents");elementChild1.SetAttribute("name", "b");//设置节点内面的内容elementChild1.InnerText = "天狼,你的梦想就是。。。。。";XmlElement elementChild2 = xml.CreateElement("mission");elementChild2.SetAttribute("map", "def");elementChild2.InnerText = "我要妹子。。。。。。。。。。";//把节点一层一层的添加至xml中,注意他们之间的先后顺序,这是生成XML文件的顺序element.AppendChild(elementChild1);element.AppendChild(elementChild2);root.AppendChild(element);xml.AppendChild(root);//最后保存文件xml.Save(LocalUrl);}}#endregion#region Main #endregion
}
6.1Xml文档
<?xml version="1.0" encoding="UTF-8"?>-<Levels>-<Level ID="1"><contents Content="helloWord!" Title="helloWord!"/><contents Content="helloWord!" Title="helloWord!/><contents Content="翼龙又名翼手龙,是一种已经灭绝的爬行类,尽管与恐龙生存的时代相同,但翼龙并不是恐龙。希腊文意思为“有翼蜥蜴”,是飞行爬行动物演化支。 生存于晚三叠纪到白垩纪末,约2亿1000万年前到6500万年前。翼龙类是第一种飞行的脊椎动物,翼龙的翼是从位于身体侧面到四节翼指骨之间的皮肤膜衍生出来的。较早的物种有长而布满牙齿的颚部,以及长尾巴;较晚的物种有大幅缩短的尾巴,而且缺乏牙齿。翼龙类的体型有非常大的差距,从小如鸟类的森林翼龙,到地球上曾出现的最大型飞行生物。" Title="翼龙"/></Level>-<Level ID="2"><contents Content="" Title=""/><contents Content="" Title=""/><contents Content="" Title=""/></Level>-<Level ID="3"><contents Content="" Title=""/><contents Content="" Title=""/><contents Content="" Title=""/></Level></Levels>
6.2txt读取
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System;public class LoadTxt : MonoBehaviour
{string _url;public string[] LineStrings;void Start(){LoadTxtOnDatePath("my");}void Update(){}public void LoadTxtOnDatePath(string txtName){string _datePath = Application.dataPath;int _num = _datePath.LastIndexOf("/");_datePath = _datePath.Substring(0, _num);_url = _datePath + "/" + txtName + ".txt";try{string[] strs = File.ReadAllLines(_url);if (LineStrings != null){for (int i = 0; i < LineStrings.Length; i++){LineStrings[i] = ReadFile(strs, i);}}}catch (Exception e){Debug.Log(e);}}string ReadFile(string[] strs, int lineNum){if (lineNum == 0){return "";}else{if (lineNum < strs.Length + 1){return strs[lineNum - 1];}else{return "";}}}
}
7音效管理类,调用就可以直接用方法来调用Resources下Audio中的名字。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class AudioSourceControl : UnitySingleton<AudioSourceControl>
{
/// <summary>
/// *音乐管理器
/// </summary>
/// private Dictionary<string, int> AudioDictionary = new Dictionary<string, int>();private const int MaxAudioCount = 10;private const string ResourcePath = "Audio/";private const string StreamingAssetsPath = "";private AudioSource BGMAudioSource;private AudioSource LastAudioSource;#region Mono Function #endregion/// <summary> /// 播放 /// </summary> /// <param name="audioname"></param> public void SoundPlay(string audioname, float volume = 1){if (AudioDictionary.ContainsKey(audioname)){if (AudioDictionary[audioname] <= MaxAudioCount){AudioClip sound = this.GetAudioClip(audioname);if (sound != null){StartCoroutine(this.PlayClipEnd(sound, audioname));this.PlayClip(sound, volume);AudioDictionary[audioname]++;}}}else{AudioDictionary.Add(audioname, 1);AudioClip sound = this.GetAudioClip(audioname);if (sound != null){StartCoroutine(this.PlayClipEnd(sound, audioname));this.PlayClip(sound, volume);AudioDictionary[audioname]++;}}}/// <summary> /// 暂停 /// </summary> /// <param name="audioname"></param> public void SoundPause(string audioname){if (this.LastAudioSource != null){this.LastAudioSource.Pause();}}/// <summary> /// 暂停所有音效音乐 /// </summary> public void SoundAllPause(){AudioSource[] allsource = FindObjectsOfType<AudioSource>();if (allsource != null && allsource.Length > 0){for (int i = 0; i < allsource.Length; i++){allsource[i].Pause();}}}/// <summary> /// 停止特定的音效 /// </summary> /// <param name="audioname"></param> public void SoundStop(string audioname){GameObject obj = this.transform.Find("audioname").gameObject;if (obj != null){Destroy(obj);}}/// <summary> /// 设置音量 /// </summary> public void BGMSetVolume(float volume){if (this.BGMAudioSource != null){this.BGMAudioSource.volume = volume;}}/// <summary> /// 播放背景音乐 /// </summary> /// <param name="bgmname"></param> /// <param name="volume"></param> public void BGMPlay(string bgmname, float volume = 1f){BGMStop();if (bgmname != null){AudioClip bgmsound = this.GetAudioClip(bgmname);if (bgmsound != null){this.PlayLoopBGMAudioClip(bgmsound, volume);}}}/// <summary> /// 暂停背景音乐 /// </summary> public void BGMPause(){if (this.BGMAudioSource != null){this.BGMAudioSource.Pause();}}/// <summary> /// 停止背景音乐 /// </summary> public void BGMStop(){if (this.BGMAudioSource != null && this.BGMAudioSource.gameObject){Destroy(this.BGMAudioSource.gameObject);this.BGMAudioSource = null;}}/// <summary> /// 重新播放 /// </summary> public void BGMReplay(){if (this.BGMAudioSource != null){this.BGMAudioSource.Play();}}#region 音效资源路径 enum eResType{AB = 0,CLIP = 1}/// <summary> /// 下载音效 /// </summary> /// <param name="aduioname"></param> /// <param name="type"></param> /// <returns></returns> private AudioClip GetAudioClip(string aduioname, eResType type = eResType.CLIP){AudioClip audioclip = null;switch (type){case eResType.AB:break;case eResType.CLIP:audioclip = GetResAudioClip(aduioname);break;default:break;}return audioclip;}private IEnumerator GetAbAudioClip(string aduioname){yield return null;}private AudioClip GetResAudioClip(string aduioname){return Resources.Load(ResourcePath + aduioname) as AudioClip;}#endregion#region 背景音乐 /// <summary> /// 背景音乐控制器 /// </summary> /// <param name="audioClip"></param> /// <param name="volume"></param> /// <param name="isloop"></param> /// <param name="name"></param> private void PlayBGMAudioClip(AudioClip audioClip, float volume = 1f, bool isloop = false, string name = null){if (audioClip == null){return;}else{GameObject obj = new GameObject(name);obj.transform.parent = this.transform;AudioSource LoopClip = obj.AddComponent<AudioSource>();LoopClip.clip = audioClip;LoopClip.volume = volume;LoopClip.loop = true;LoopClip.pitch = 1f;LoopClip.Play();this.BGMAudioSource = LoopClip;}}/// <summary> /// 播放一次的背景音乐 /// </summary> /// <param name="audioClip"></param> /// <param name="volume"></param> /// <param name="name"></param> private void PlayOnceBGMAudioClip(AudioClip audioClip, float volume = 1f, string name = null){PlayBGMAudioClip(audioClip, volume, false, name == null ? "BGMSound" : name);}/// <summary> /// 循环播放的背景音乐 /// </summary> /// <param name="audioClip"></param> /// <param name="volume"></param> /// <param name="name"></param> private void PlayLoopBGMAudioClip(AudioClip audioClip, float volume = 1f, string name = null){PlayBGMAudioClip(audioClip, volume, true, name == null ? "LoopSound" : name);}#endregion#region 音效 /// <summary> /// 播放音效 /// </summary> /// <param name="audioClip"></param> /// <param name="volume"></param> /// <param name="name"></param> private void PlayClip(AudioClip audioClip, float volume = 1f, string name = null){if (audioClip == null){return;}else{GameObject obj = new GameObject(name == null ? "SoundClip" : name);obj.transform.parent = this.transform;AudioSource source = obj.AddComponent<AudioSource>();StartCoroutine(this.PlayClipEndDestroy(audioClip, obj));source.pitch = 1f;source.volume = volume;source.clip = audioClip;source.Play();this.LastAudioSource = source;}}/// <summary> /// 播放玩音效删除物体 /// </summary> /// <param name="audioclip"></param> /// <param name="soundobj"></param> /// <returns></returns> private IEnumerator PlayClipEndDestroy(AudioClip audioclip, GameObject soundobj){if (soundobj == null || audioclip == null){yield break;}else{yield return new WaitForSeconds(audioclip.length * Time.timeScale);Destroy(soundobj);}}/// <summary> /// /// </summary> /// <returns></returns> private IEnumerator PlayClipEnd(AudioClip audioclip, string audioname){if (audioclip != null){yield return new WaitForSeconds(audioclip.length * Time.timeScale);AudioDictionary[audioname]--;if (AudioDictionary[audioname] <= 0){AudioDictionary.Remove(audioname);}}yield break;}#endregion}
8常用方法
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;public class GeneralMethod : UnitySingleton<GeneralMethod>
{/// <summary>/// 协程/// </summary>/// <param name="action">事件</param>/// <param name="DelayTime">等待时间</param>/// <returns></returns>public IEnumerator Wait(Action action, float DelayTime){yield return new WaitForSeconds(DelayTime);action();}/// <summary>/// 每隔一段时间执行一次/// </summary>/// <param name="timer">时间变量一般0开始</param>/// <param name="timeKeep">时间间隔</param>/// <param name="action">事件</param>public void TimeInterval(ref float timer, float timeKeep, Action action){timer += Time.deltaTime;if (timer > timeKeep){action();timer = 0;}}}
9.互动砸求的主要类首先导入TouchScript插件在EventSystem这个组件中依次挂入TouchScriptInputModule,Tuio Input,StandardInput,并且在Tuio Input中设置摄像机和雷达端口3333.
取消Physics Raycaster组件。创建一个plane。
实现脚本
using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;
using System.Collections.Generic;
using System;
using UniRx;
using DG.Tweening;
public class OnHit : MonoBehaviour, IPointerDownHandler
{public GameObject hole;public List<GameObject> GetSorce;public int elephantHurtCount;public int CJLHurtCount;public changJL IP;public changJL IP1;Animator anim;public AudioClip Hit;public AudioClip SpaceHIt;public AudioClip Mhit;public AudioClip BigAnimal;public AnimalManager manager;public PaiHangBangCtrl over;public AudioSource BG;public AudioClip bg;void Start(){}// Update is called once per framevoid Update(){}public void OnPointerDown(PointerEventData eventData){CreatSpace(eventData.position);CreatAnimal(eventData.position);CreatDX(eventData.position);CreatCJL(eventData.position);CreatUI(eventData.position);}void CreatSpace(Vector3 pos){Ray ray = Camera.main.ScreenPointToRay(pos);RaycastHit hit;if (Physics.Raycast(ray, out hit, 10000, 1 << 8)){return;}if (Physics.Raycast(ray, out hit, 10000, 1 << 12)){return;}if (Physics.Raycast(ray, out hit, 10000, 1 << 9)){//拍击触碰事件GameObject clone = Pool.Instance.Spwan(Pool.Instance.prefabArray[0]);clone.transform.position = hit.point;clone.transform.parent = transform;hit.transform.GetComponent<AudioSource>().clip = SpaceHIt;hit.transform.GetComponent<AudioSource>().Play();}}void CreatAnimal(Vector3 pos){Ray ray = Camera.main.ScreenPointToRay(pos);RaycastHit hit;if (Physics.Raycast(ray, out hit, 10000, 1 << 8)){anim = hit.transform.parent.parent.GetComponent<Animator>();anim.SetTrigger("disappear");GameObject clone = Pool.Instance.Spwan(Pool.Instance.prefabArray[1]);clone.transform.position = hit.point;clone.transform.parent = transform;//hit.transform.GetComponent<BoxCollider>().enabled = false;StartCoroutine(BOX(hit));if (hit.transform.parent.parent.name == "bama(Clone)"){hit.transform.parent.parent.GetComponent<AudioSource>().clip = Hit;hit.transform.parent.parent.GetComponent<AudioSource>().Play();GameObject fenClone = (GameObject)Instantiate(GetSorce[0], new Vector3(hit.point.x, hit.point.y + 5, hit.point.z), Quaternion.Euler(new Vector3(0, 180, 0)));fenClone.transform.DOMoveY(fenClone.transform.position.y + 20, 0.6f).OnComplete(() => { Destroy(fenClone); });//fenClone.GetComponent<SpriteRenderer>().material.DOFade(0, 0.8f).OnComplete(() => { Destroy(fenClone); });Score.Score1 += 20;}if (hit.transform.parent.parent.name == "leopard@idle(Clone)"){hit.transform.parent.parent.GetComponent<AudioSource>().clip = Hit;hit.transform.parent.parent.GetComponent<AudioSource>().Play();GameObject fenClone = (GameObject)Instantiate(GetSorce[1], new Vector3(hit.point.x, hit.point.y + 5, hit.point.z), Quaternion.Euler(new Vector3(0, 180, 0)));fenClone.transform.DOMoveY(fenClone.transform.position.y + 20, 0.6f).OnComplete(() => { Destroy(fenClone); });//fenClone.GetComponent<SpriteRenderer>().material.DOFade(0, 0.8f).OnComplete(() => { Destroy(fenClone); });Score.Score1 += 30;}if (hit.transform.parent.parent.name == "lacoste@idle(Clone)"){hit.transform.parent.parent.GetComponent<AudioSource>().clip = Hit;hit.transform.parent.parent.GetComponent<AudioSource>().Play();GameObject fenClone = (GameObject)Instantiate(GetSorce[2], new Vector3(hit.point.x, hit.point.y + 5, hit.point.z), Quaternion.Euler(new Vector3(0, 180, 0)));fenClone.transform.DOMoveY(fenClone.transform.position.y + 20, 0.6f).OnComplete(() => { Destroy(fenClone); });//fenClone.GetComponent<SpriteRenderer>().material.DOFade(0, 0.8f).OnComplete(() => { Destroy(fenClone); });Score.Score1 += 40;}if (hit.transform.parent.parent.name == "Panda@idle(Clone)"){hit.transform.parent.parent.GetComponent<AudioSource>().clip = Hit;hit.transform.parent.parent.GetComponent<AudioSource>().Play();GameObject fenClone = (GameObject)Instantiate(GetSorce[3], new Vector3(hit.point.x, hit.point.y + 5, hit.point.z), Quaternion.Euler(new Vector3(0, 180, 0)));fenClone.transform.DOMoveY(fenClone.transform.position.y + 20, 0.6f).OnComplete(() => { Destroy(fenClone); });//fenClone.GetComponent<SpriteRenderer>().material.DOFade(0, 0.8f).OnComplete(() => { Destroy(fenClone); });Score.Score1 += 60;}if (hit.transform.parent.parent.name == "IP01@idle(Clone)" || hit.transform.parent.parent.name == "IP02@idle(Clone)"){hit.transform.parent.parent.GetComponent<AudioSource>().clip = Mhit;hit.transform.parent.parent.GetComponent<AudioSource>().Play();GameObject fenClone = (GameObject)Instantiate(GetSorce[7], new Vector3(hit.point.x, hit.point.y + 5, hit.point.z), Quaternion.Euler(new Vector3(0, 180, 0)));fenClone.transform.DOMoveY(fenClone.transform.position.y + 20, 0.6f).OnComplete(() => { Destroy(fenClone); });//fenClone.GetComponent<SpriteRenderer>().material.DOFade(0, 0.8f).OnComplete(() => { Destroy(fenClone); });Score.Score1 -= 30;}}}void CreatUI(Vector3 pos){//Debug.Log("12222222");Ray ray = Camera.main.ScreenPointToRay(pos);RaycastHit hit;if (Physics.Raycast(ray, out hit, 10000, 1 << 12)){//拍击触碰事件//Debug.Log(hit.point);GameObject clone = Pool.Instance.Spwan(Pool.Instance.prefabArray[1]);clone.transform.position = hit.point;clone.transform.parent = transform;if (hit.transform.name == "Start"){hit.transform.GetComponent<AudioSource>().clip = Mhit;hit.transform.GetComponent<AudioSource>().Play();manager.OpenGame();}if (hit.transform.name == "over"){hit.transform.GetComponent<AudioSource>().clip = Hit;hit.transform.GetComponent<AudioSource>().Play();BG.GetComponent<AudioSource>().clip = bg;BG.GetComponent<AudioSource>().Play();over.againGame();}}}void CreatDX(Vector3 pos){Ray ray = Camera.main.ScreenPointToRay(pos);RaycastHit hit;if (Physics.Raycast(ray, out hit, 10000, 1 << 8)){return;}if (Physics.Raycast(ray, out hit, 10000, 1 << 10)){elephantHurtCount += 1;anim = hit.transform.parent.parent.GetComponent<Animator>();GameObject Dx = hit.transform.parent.parent.gameObject;GameObject clone = Pool.Instance.Spwan(Pool.Instance.prefabArray[1]);clone.transform.position = hit.point;clone.transform.parent = transform;if (elephantHurtCount < 15){anim.SetTrigger("disappear");//anim.SetTrigger("hitback");}if (elephantHurtCount >= 15){anim.SetTrigger("disappear");anim.SetTrigger("die");IP1.IPd();Dx.transform.DOLocalMoveY(-250, 0.5f).SetEase(Ease.Linear).OnComplete(() =>{anim.SetTrigger("idle");elephantHurtCount = 0;});}if (hit.transform.parent.parent.name == "DaXiang@idle"){hit.transform.parent.parent.GetComponent<AudioSource>().clip = BigAnimal;hit.transform.parent.parent.GetComponent<AudioSource>().Play();GameObject fenClone = (GameObject)Instantiate(GetSorce[4], new Vector3(hit.point.x, hit.point.y + 5, hit.point.z), Quaternion.Euler(new Vector3(0, 180, 0)));fenClone.transform.DOMoveY(fenClone.transform.position.y + 20, 0.6f).OnComplete(() => { Destroy(fenClone); }); ;//fenClone.GetComponent<SpriteRenderer>().material.DOFade(0, 0.8f).OnComplete(() => { Destroy(fenClone); });Observable.Timer(System.TimeSpan.FromSeconds(0.2f)).Subscribe(_ =>{GameObject fenClone1 = (GameObject)Instantiate(GetSorce[4], new Vector3(hit.point.x, hit.point.y + 5, hit.point.z), Quaternion.Euler(new Vector3(0, 180, 0)));fenClone1.transform.DOMoveY(fenClone1.transform.position.y + 20, 0.6f).OnComplete(() => { Destroy(fenClone1); }); ;//fenClone1.GetComponent<SpriteRenderer>().material.DOFade(0, 0.8f).OnComplete(() => { Destroy(fenClone); });});Observable.Timer(System.TimeSpan.FromSeconds(0.4f)).Subscribe(_ =>{GameObject fenClone2 = (GameObject)Instantiate(GetSorce[4], new Vector3(hit.point.x, hit.point.y + 5, hit.point.z), Quaternion.Euler(new Vector3(0, 180, 0)));fenClone2.transform.DOMoveY(fenClone2.transform.position.y + 20, 0.6f).OnComplete(() => { Destroy(fenClone2); }); ;//fenClone2.GetComponent<SpriteRenderer>().material.DOFade(0, 0.8f).OnComplete(() => { Destroy(fenClone); });});Score.Score1 += 60;}}}void CreatCJL(Vector3 pos){Ray ray = Camera.main.ScreenPointToRay(pos);RaycastHit hit;if (Physics.Raycast(ray, out hit, 10000, 1 << 8)){return;}if (Physics.Raycast(ray, out hit, 10000, 1 << 11)){Debug.Log("次数" + CJLHurtCount);CJLHurtCount += 1;anim = hit.transform.parent.parent.GetComponent<Animator>();GameObject CJL = hit.transform.parent.parent.gameObject;GameObject clone = Pool.Instance.Spwan(Pool.Instance.prefabArray[1]);clone.transform.position = hit.point;clone.transform.parent = transform;if (CJLHurtCount < 30){anim.SetTrigger("disappear");//anim.SetTrigger("hitback");}if (CJLHurtCount >= 30){//Debug.Log("12312");anim.SetTrigger("disappear");anim.SetTrigger("die");IP.IPd();CJL.transform.DOLocalMoveY(-252, 0.5f).SetEase(Ease.Linear).OnComplete(() =>{anim.SetTrigger("idle");CJLHurtCount = 0;});}if (hit.transform.parent.parent.name == "ChangJingLu@idle"){hit.transform.parent.parent.GetComponent<AudioSource>().clip = BigAnimal;hit.transform.parent.parent.GetComponent<AudioSource>().Play();GameObject fenClone = (GameObject)Instantiate(GetSorce[5], new Vector3(hit.point.x, hit.point.y + 5, hit.point.z), Quaternion.Euler(new Vector3(0, 180, 0)));fenClone.transform.DOMoveY(fenClone.transform.position.y + 20, 0.6f).OnComplete(() => { Destroy(fenClone); }); ;//fenClone.GetComponent<SpriteRenderer>().material.DOFade(0, 0.8f).OnComplete(() => { Destroy(fenClone); });Observable.Timer(System.TimeSpan.FromSeconds(0.3f)).Subscribe(_ =>{GameObject fenClone1 = (GameObject)Instantiate(GetSorce[5], new Vector3(hit.point.x, hit.point.y + 5, hit.point.z), Quaternion.Euler(new Vector3(0, 180, 0)));fenClone1.transform.DOMoveY(fenClone1.transform.position.y + 20, 0.6f).OnComplete(() => { Destroy(fenClone1); }); ;//fenClone1.GetComponent<SpriteRenderer>().material.DOFade(0, 0.8f).OnComplete(() => { Destroy(fenClone); });});Observable.Timer(System.TimeSpan.FromSeconds(0.6f)).Subscribe(_ =>{GameObject fenClone2 = (GameObject)Instantiate(GetSorce[5], new Vector3(hit.point.x, hit.point.y + 5, hit.point.z), Quaternion.Euler(new Vector3(0, 180, 0)));fenClone2.transform.DOMoveY(fenClone2.transform.position.y + 20, 0.6f).OnComplete(() => { Destroy(fenClone2); }); ;//fenClone2.GetComponent<SpriteRenderer>().material.DOFade(0, 0.8f).OnComplete(() => { Destroy(fenClone); });});Score.Score1 += 90;}}}IEnumerator BOX(RaycastHit hit){hit.transform.GetComponent<BoxCollider>().enabled = false;yield return new WaitForSeconds(2f);if (hit.transform != null){hit.transform.GetComponent<BoxCollider>().enabled = true;}}
}
AR大屏互动自己整合基础框架相关推荐
- 超带感的AR大屏互动,多元化应用场景!
什么是AR大屏互动? 佩京科技AR互动大屏是通过AR技术将大屏上的内容进行虚拟景象的补充,让人们在视听方面都带来更真实的,通过各种传感设备使用户"沉浸"到该环境中,实现用户和环境直 ...
- AR大屏互动的原理是什么?可以应用在哪些场景中?
AR互动大屏是运用AR增强现实技术,利用计算机生成一种逼真的视.力.听.触和动等感官结合的虚拟环境,再通过各种信息传感设备,让用户在此环境中开启沉浸式互动体验,实现人和环境之间两者进行自然的交互. A ...
- 广州华锐互动提供商场AR大屏互动制作一站式解决方案
商场AR大屏互动体验是近年来越来越受到商家欢迎的一种营销方式,它通过AR技术和大屏幕互动展示,为商家带来了很多商业价值.以下是商场AR大屏互动体验为商家带来的优势: 增强品牌吸引力 商场AR大屏互动体 ...
- 房地产ar大屏互动展示更炫酷吸睛
AR大屏互动,利用AR图像识别.跟踪.输入.交互等技术,结合3D立体成像技术,将真实世界信息和虚拟世界信息无缝集成,参与者可与虚拟影像进行互动,营造出震撼的场景氛围,给人们更加真实的互动体验. AR大 ...
- AR体感游戏,体感互动游戏,AR大屏互动
体感游戏,用身体去感受的电子游戏.突破以往单纯以手柄按键输入的操作方式,体感游戏是一种通过肢体动作变化来进行(操作)的新型电子游戏. 通过互联网运营平台,进行人机互动,在线玩家在线互动.竞技运动,聚合 ...
- 大屏互动-大屏交互-大屏投影技术解决方案
新视野大屏互动(www.fgsxy.com)又称体感互动,是集3D体感摄影机.体感互动软件以及三维数字内容为一体的控制系统平台.是人和显示屏之间,通过简单姿势和特定的颜色等识别方式(如挥手.摆头.转身 ...
- Ar大屏幕互动,面向非专业领域的体验
随着科技网络技术逐渐提高,AR大屏通过生动.有趣.立体地再现,促使我们可以更好地理解产品/课件信息,活跃现场气氛,增强愉悦感.Ar大屏幕交互式解决方案刷新信息获取体验. 在交通.电力和工业领域,A ...
- LED大屏互动的互动方式有哪些
LED大屏幕一直以来都是拼接大屏的组成,大屏互动简单来说就是人与大屏之间的互动,可以是肢体动作的隔空互动,也可以是手指触摸式互动,还可以借助遥控器之类的设备达到人机交互,总而言之就是和大屏幕有交互的形 ...
- js 年会大屏_年会H5大屏互动游戏案例分享
原标题:年会H5大屏互动游戏案例分享 利用h5制作年会互动小游戏越来越火爆了,今天小编就给大家推荐两个年会h5案例,希望能给大家的设计带来灵感,参考网站:hui.cdlchd.com. 案例一:201 ...
最新文章
- modifiers在JAVA中_Java Modifier.classModifiers方法代碼示例
- oc 中随机数的用法(arc4random() 、random()、CCRANDOM_0_1()
- 采购申请不固定供应商怎么破?
- SVM(支持向量机)综述
- why my pricing procedure is not determined in QHD 504
- vue+Element-ui实现分页效果
- LeetCode之Maximum Depth of Binary Tree
- oracle数据库升级失败,Oracle 11.2.0.1 rac 升级失败后,数据库降级方案(flashback database)...
- 单片机Proteus7.8仿真和Proteus8.6仿真 LED点阵 温度采集 电子琴 温度报警 电子秤 音乐播放器 PWM 电压表 温度计 交通灯
- Myeclipse项目加入maven支持
- UILabel常用属性
- 计算机网络原理201810自考,2018年10月自考04741计算机网络原理试卷及答案
- JQuery与springmvc实现多个文件上传操作
- android5.1+xposed卡刷包,一加5 7.1 ROM刷机包 最终版王者高帧率极速吃鸡超多自定义Xposed...
- mac系统开机启动项
- 机场精细化管理_王晓鸿:BIM技术在机场工程精细化管理的应用
- 【渝粤题库】国家开放大学2021春2409中国古代文学(B)(1)题目
- 分水岭算法 c语言实现,分水岭算法的应用
- str中的join方法,fromkeys(),set集合,深浅拷贝(重点)
- 李宏毅2022机器学习HW2解析