Unity3D技巧
2015-09-15 19:35
573 查看
转发,请保持地址:http://blog.csdn.net/stalendp/article/details/46707079
相关的文章:【Unity】技巧集合
1. 调试相关
[csharp] view
plaincopy
Debug.DrawRay(transform.position, newDir, Color.red);
2. uGui的层级问题。(参考Canvas中的Draw Order of Elements)
uGUI的元素的渲染循序和Hierarchy中的循序一致,从上往下渲染(后面的会覆盖之前的)。在脚本中可以通过transform的SetAsFirstSibling, SetAsLastSibling, and SetSiblingIndex.函数来设置循序。比如下面的代码,把当前选择的物体置顶。
[csharp] view
plaincopy
curSelected.transform.SetAsLastSibling();
3. 摄像机移动代码
[csharp] view
plaincopy
public class DragMap : MonoBehaviour {
public Vector3 speed = Vector3.zero;
public bool isFlying = false;
public float threshold = 0.2f;
Camera mainCam;
Vector3 startPos;
int groundLayer;
Vector3[] speedCache ;
int idx = 0;
bool isDragging = false;
// Use this for initialization
void Start () {
groundLayer = 1 << LayerMask.NameToLayer ("ground");
mainCam = Camera.main;
speedCache = new Vector3[5];
isFlying = false;
}
// Update is called once per frame
void Update () {
if (Input.GetMouseButtonDown (0)) {
RaycastHit hit;
if (Physics.Raycast (mainCam.ScreenPointToRay (Input.mousePosition), out hit, Mathf.Infinity, groundLayer)) {
startPos = hit.point;
speed = Vector3.zero;
idx = 0;
for(int i=0; i<speedCache.Length; i++) {
speedCache[i] = Vector3.zero;
}
isDragging = true;
}
} else if(Input.GetMouseButtonUp(0)) {
speed = Vector3.zero;
foreach(Vector3 s in speedCache) {
speed += s;
}
speed /= 5;
isFlying = speed.magnitude > threshold;
isDragging = false;
}
if (isDragging) {
RaycastHit hit;
if (Physics.Raycast (mainCam.ScreenPointToRay (Input.mousePosition), out hit, Mathf.Infinity, groundLayer)) {
Vector3 offset = hit.point - startPos;
mainCam.transform.position -= offset;
speedCache [idx++ % 5] = offset;
}
} else if (isFlying) {
speed *= 0.9f;
isFlying = speed.magnitude > threshold;
mainCam.transform.position -= speed;
}
}
}
4. 协同的用法(IEnumerator)
[csharp] view
plaincopy
IEnumerator Start() {
Debug.Log ("zero: " + Time.time);
yield return StartCoroutine (mywait (3f));
Debug.Log ("one: " + Time.time);
yield return StartCoroutine (mywait (2f));
Debug.Log ("two: " + Time.time);
}
关于Coroutines,以便能够获取更多的功能:
1)Coroutines – More than you want to know:http://twistedoakstudios.com/blog/Post83_coroutines-more-than-you-want-to-know
2)Unity coroutine (Coroutine) principle deeply again:http://www.programering.com/a/MTOzgjNwATI.html
3)Wrapping Unity C# Coroutines for Exception Handling, Value Retrieval, and Locking:http://www.zingweb.com/blog/2013/02/05/unity-coroutine-wrapper
Coroutine的实现参考:https://github.com/rozgo/Unity.Coroutine/blob/master/Coroutine.cs
5. 回调相关:UnityEvent和System.Action和System.Func;
都是delegate,相当于函数指针;前者没有返回值,后者有返回值。其中UnityEvent和System.Action基本相同,但是UnityEvent可以被序列化,最显著的优点是可以在Inspector上被编辑(比如新UI控件ScrollRect中的OnValueChanged属性),两者差异性参考这里的讨论,用法:
5a) System.Func的用法:
[csharp] view
plaincopy
public struct AstarWorkItem {
//....
public System.Func<bool, bool> update;
//....
public AstarWorkItem (System.Func<bool, bool> update) {
this.update = update;
}
}
//...
AddWorkItem (new AstarWorkItem (delegate (bool force) {
InternalOnPostScan ();
return true;
}));
也可以简写为:
[csharp] view
plaincopy
public struct AstarWorkItem {
public System.Func<bool, bool> update;
}
// ...
AddWorkItem (new AstarWorkItem () {
update = (force) => {
InternalOnPostScan ();
return true;
}
});
5b)UnityEvent的用法
[csharp] view
plaincopy
[Serializable]
public class ScrollRectEvent : UnityEvent<Vector2> {}
// class members
[SerializeField]
private ScrollRectEvent m_OnValueChanged = new ScrollRectEvent();
public ScrollRectEvent onValueChanged { get { return m_OnValueChanged; } set { m_OnValueChanged = value; } }
// invoke ...
onValueChanged.AddListener (offset => {
Debug.Log("ScrollRect is changed, offset is : " + offset.ToString());
});
6. 在Raycast中忽略trigger Colliders的方法:
Edit > Project Settings > Physics > Uncheck "Raycasts Hit Triggers"
7. 粒子系统操作:
[csharp] view
plaincopy
// stop particalSystem
waterEffect.Stop();
// restart particalSystem
waterEffect.Simulate(0);
waterEffect.Play();
8. C#中的特殊的操作符:https://msdn.microsoft.com/en-us/library/6a71f45d.aspx
其中NullableTypes,参考:https://msdn.microsoft.com/en-us/library/1t3y8s4s.aspx
8-1)Boxing nullable types: int? float? double? 把基本类型变为object类型;其值可以为null,也可以有相关转化操作。
[csharp] view
plaincopy
//## Example 1: Nullable objects and their boxed counterpart can be tested for null:
bool? b = null;
object boxedB = b;
if (b == null) {
// True.
}
if (boxedB == null) {
// Also true.
}
//## Example 2: Boxed nullable types fully support the functionality of the underlying type:
double? d = 44.4;
object iBoxed = d;
// Access IConvertible interface implemented by double.
IConvertible ic = (IConvertible)iBoxed;
int i = ic.ToInt32(null);
string str = ic.ToString();
8-2) Null-conditional Operators: ?. ?[] 在访问自对象之前,先判断null,这样可以简化代码。C#
6的新特性,在Unity中好似无法使用
[csharp] view
plaincopy
int? length = customers?.Length; // null if customers is null
Customer first = customers?[0]; // null if customers is null
int? count = customers?[0]?.Orders?.Count();
// null if customers, the first customer, or Orders is null
[csharp] view
plaincopy
var handler = this.PropertyChanged;
if (handler != null)
handler(…)
===简化为==》
PropertyChanged?.Invoke(e)
8-3) Null-coalescing Operator: x ?? y
[csharp] view
plaincopy
class NullCoalesce
{
static int? GetNullableInt()
{
return null;
}
static string GetStringValue()
{
return null;
}
static void Main()
{
int? x = null;
// Set y to the value of x if x is NOT null; otherwise,
// if x = null, set y to -1.
int y = x ?? -1;
// Assign i to return value of the method if the method's result
// is NOT null; otherwise, if the result is null, set i to the
// default value of int.
int i = GetNullableInt() ?? default(int);
string s = GetStringValue();
// Display the value of s if s is NOT null; otherwise,
// display the string "Unspecified".
Console.WriteLine(s ?? "Unspecified");
}
}
8-4)How
to: Safely Cast from bool? to bool
[csharp] view
plaincopy
bool? b = null;
if (b) // Error CS0266.
{
}
===改成==>>
bool? test = null;
// Other code that may or may not
// give a value to test.
if(!test.HasValue) //check for a value
{
// Assume that IsInitialized
// returns either true or false.
test = IsInitialized();
}
if((bool)test) //now this cast is safe
{
// Do something.
}
9. Unity中“单例“的一般实现方案:
[csharp] view
plaincopy
public static EventSystem current { get; set; }
...
protected void OnEnable()
{
if (EventSystem.current == null)
EventSystem.current = this;
#if UNITY_EDITOR
else
{
Debug.LogWarning("Multiple EventSystems in scene... this is not supported");
}
#endif
}
10. 初始化变量的一种简略方式
[csharp] view
plaincopy
PointerEventData ped = new PointerEventData (EventSystem.current);
ped.position = Input.mousePosition;
EventSystem.current.RaycastAll (ped, hits);
===简化为==>
EventSystem.current.RaycastAll (new PointerEventData (EventSystem.current) {
position = Input.mousePosition
}, hits);
11. Unity中新UI的消息处理方式(借助EventSystem中的Raycast获取当前的UI,并发送消息)
具体参考文章:http://gregandaduck.blogspot.com/2015/02/using-unitys-c-message-system-unity-46.html
消息接受方,实现如下:
[csharp] view
plaincopy
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Collections;
// refer to http://gregandaduck.blogspot.com/2015/02/using-unitys-c-message-system-unity-46.html
public interface IMyMouseOver : IEventSystemHandler {
void mouseOver(string str);
void mouseLeaving();
}
public class MyDisplayText : MonoBehaviour, IMyMouseOver {
public Text text;
public void mouseOver(string str) {
if (!text.enabled) {
text.text = str;
text.enabled = true;
}
}
public void mouseLeaving() {
if (text.enabled) {
text.enabled = false;
}
}
}
消息发送方,实现如下:
[csharp] view
plaincopy
using UnityEngine;
using UnityEngine.EventSystems;
using System.Collections;
using System.Collections.Generic;
public class MyMouseOver : MonoBehaviour {
GameObject prevObject;
void Update () {
GameObject target = getMouseOver ();
if (target) {
prevObject = target;
ExecuteEvents.Execute<IMyMouseOver> (target, null, (handle, data) => {
handle.mouseOver ("Mouse Over Active, frame: " + Time.frameCount);
});
} else {
if(prevObject) {
ExecuteEvents.Execute<IMyMouseOver>(prevObject, null, (handle, data) =>{
handle.mouseLeaving();
});
prevObject = null;
}
}
}
private GameObject getMouseOver() {
List<RaycastResult> hits = new List<RaycastResult>();
EventSystem.current.RaycastAll (new PointerEventData (EventSystem.current) {
position = Input.mousePosition
}, hits);
foreach (RaycastResult rr in hits) {
GameObject go = rr.gameObject;
if(go)
return go;
}
return null;
}
}
12. 在C#中模拟Java中的匿名类写法(有点Javascript的味道):
[csharp] view
plaincopy
public class HpBarHandler { // 当然这里用struct会显得把delegate更加看作为数据
public System.Action<float> changeHp;
public System.Action hidde;
public System.Action show;
public System.Action destory;
}
public void registerHPBarEvent(HpBarHandler _hphandler) {
hphandler = _hphandler;
}
fightUnit.registerHPBarEvent (new HpBarHandler () {
changeHp = hp => {
size.x = 200 * hp;
if(rectTrans) {
rectTrans.sizeDelta = size;
if(hp<=0) {
GameObject.Destroy (gameObject);
}
}
},
hidde = delegate{
gameObject.SetActive(false);
},
show = delegate {
gameObject.SetActive(true);
},
destory = delegate {
GameObject.Destroy (gameObject);
}
});
13. 工作中总是遇到初始化某个单位时,依赖其他的单位还未初始化,导致了NullReferenceException。这个是因为所有的初始化都写在了Start方法中,这样由于代码初始化的前后顺序,导致了上面的问题。解决方案就是把初始化分阶段进行。能够导致NullReferenceException的,比如GetCompent,Find等操作,写在Awake或OnEnable方法中等。逻辑初始化写在Start中等。下面是Script Lifecycle的示意图,官方文档为:http://docs.unity3d.com/Manual/ExecutionOrder.html
相关的文章:【Unity】技巧集合
相关的文章:【Unity】技巧集合
1. 调试相关
[csharp] view
plaincopy
Debug.DrawRay(transform.position, newDir, Color.red);
2. uGui的层级问题。(参考Canvas中的Draw Order of Elements)
uGUI的元素的渲染循序和Hierarchy中的循序一致,从上往下渲染(后面的会覆盖之前的)。在脚本中可以通过transform的SetAsFirstSibling, SetAsLastSibling, and SetSiblingIndex.函数来设置循序。比如下面的代码,把当前选择的物体置顶。
[csharp] view
plaincopy
curSelected.transform.SetAsLastSibling();
3. 摄像机移动代码
[csharp] view
plaincopy
public class DragMap : MonoBehaviour {
public Vector3 speed = Vector3.zero;
public bool isFlying = false;
public float threshold = 0.2f;
Camera mainCam;
Vector3 startPos;
int groundLayer;
Vector3[] speedCache ;
int idx = 0;
bool isDragging = false;
// Use this for initialization
void Start () {
groundLayer = 1 << LayerMask.NameToLayer ("ground");
mainCam = Camera.main;
speedCache = new Vector3[5];
isFlying = false;
}
// Update is called once per frame
void Update () {
if (Input.GetMouseButtonDown (0)) {
RaycastHit hit;
if (Physics.Raycast (mainCam.ScreenPointToRay (Input.mousePosition), out hit, Mathf.Infinity, groundLayer)) {
startPos = hit.point;
speed = Vector3.zero;
idx = 0;
for(int i=0; i<speedCache.Length; i++) {
speedCache[i] = Vector3.zero;
}
isDragging = true;
}
} else if(Input.GetMouseButtonUp(0)) {
speed = Vector3.zero;
foreach(Vector3 s in speedCache) {
speed += s;
}
speed /= 5;
isFlying = speed.magnitude > threshold;
isDragging = false;
}
if (isDragging) {
RaycastHit hit;
if (Physics.Raycast (mainCam.ScreenPointToRay (Input.mousePosition), out hit, Mathf.Infinity, groundLayer)) {
Vector3 offset = hit.point - startPos;
mainCam.transform.position -= offset;
speedCache [idx++ % 5] = offset;
}
} else if (isFlying) {
speed *= 0.9f;
isFlying = speed.magnitude > threshold;
mainCam.transform.position -= speed;
}
}
}
4. 协同的用法(IEnumerator)
[csharp] view
plaincopy
IEnumerator Start() {
Debug.Log ("zero: " + Time.time);
yield return StartCoroutine (mywait (3f));
Debug.Log ("one: " + Time.time);
yield return StartCoroutine (mywait (2f));
Debug.Log ("two: " + Time.time);
}
关于Coroutines,以便能够获取更多的功能:
1)Coroutines – More than you want to know:http://twistedoakstudios.com/blog/Post83_coroutines-more-than-you-want-to-know
2)Unity coroutine (Coroutine) principle deeply again:http://www.programering.com/a/MTOzgjNwATI.html
3)Wrapping Unity C# Coroutines for Exception Handling, Value Retrieval, and Locking:http://www.zingweb.com/blog/2013/02/05/unity-coroutine-wrapper
Coroutine的实现参考:https://github.com/rozgo/Unity.Coroutine/blob/master/Coroutine.cs
5. 回调相关:UnityEvent和System.Action和System.Func;
都是delegate,相当于函数指针;前者没有返回值,后者有返回值。其中UnityEvent和System.Action基本相同,但是UnityEvent可以被序列化,最显著的优点是可以在Inspector上被编辑(比如新UI控件ScrollRect中的OnValueChanged属性),两者差异性参考这里的讨论,用法:
5a) System.Func的用法:
[csharp] view
plaincopy
public struct AstarWorkItem {
//....
public System.Func<bool, bool> update;
//....
public AstarWorkItem (System.Func<bool, bool> update) {
this.update = update;
}
}
//...
AddWorkItem (new AstarWorkItem (delegate (bool force) {
InternalOnPostScan ();
return true;
}));
也可以简写为:
[csharp] view
plaincopy
public struct AstarWorkItem {
public System.Func<bool, bool> update;
}
// ...
AddWorkItem (new AstarWorkItem () {
update = (force) => {
InternalOnPostScan ();
return true;
}
});
5b)UnityEvent的用法
[csharp] view
plaincopy
[Serializable]
public class ScrollRectEvent : UnityEvent<Vector2> {}
// class members
[SerializeField]
private ScrollRectEvent m_OnValueChanged = new ScrollRectEvent();
public ScrollRectEvent onValueChanged { get { return m_OnValueChanged; } set { m_OnValueChanged = value; } }
// invoke ...
onValueChanged.AddListener (offset => {
Debug.Log("ScrollRect is changed, offset is : " + offset.ToString());
});
6. 在Raycast中忽略trigger Colliders的方法:
Edit > Project Settings > Physics > Uncheck "Raycasts Hit Triggers"
7. 粒子系统操作:
[csharp] view
plaincopy
// stop particalSystem
waterEffect.Stop();
// restart particalSystem
waterEffect.Simulate(0);
waterEffect.Play();
8. C#中的特殊的操作符:https://msdn.microsoft.com/en-us/library/6a71f45d.aspx
其中NullableTypes,参考:https://msdn.microsoft.com/en-us/library/1t3y8s4s.aspx
8-1)Boxing nullable types: int? float? double? 把基本类型变为object类型;其值可以为null,也可以有相关转化操作。
[csharp] view
plaincopy
//## Example 1: Nullable objects and their boxed counterpart can be tested for null:
bool? b = null;
object boxedB = b;
if (b == null) {
// True.
}
if (boxedB == null) {
// Also true.
}
//## Example 2: Boxed nullable types fully support the functionality of the underlying type:
double? d = 44.4;
object iBoxed = d;
// Access IConvertible interface implemented by double.
IConvertible ic = (IConvertible)iBoxed;
int i = ic.ToInt32(null);
string str = ic.ToString();
8-2) Null-conditional Operators: ?. ?[] 在访问自对象之前,先判断null,这样可以简化代码。C#
6的新特性,在Unity中好似无法使用
[csharp] view
plaincopy
int? length = customers?.Length; // null if customers is null
Customer first = customers?[0]; // null if customers is null
int? count = customers?[0]?.Orders?.Count();
// null if customers, the first customer, or Orders is null
[csharp] view
plaincopy
var handler = this.PropertyChanged;
if (handler != null)
handler(…)
===简化为==》
PropertyChanged?.Invoke(e)
8-3) Null-coalescing Operator: x ?? y
[csharp] view
plaincopy
class NullCoalesce
{
static int? GetNullableInt()
{
return null;
}
static string GetStringValue()
{
return null;
}
static void Main()
{
int? x = null;
// Set y to the value of x if x is NOT null; otherwise,
// if x = null, set y to -1.
int y = x ?? -1;
// Assign i to return value of the method if the method's result
// is NOT null; otherwise, if the result is null, set i to the
// default value of int.
int i = GetNullableInt() ?? default(int);
string s = GetStringValue();
// Display the value of s if s is NOT null; otherwise,
// display the string "Unspecified".
Console.WriteLine(s ?? "Unspecified");
}
}
8-4)How
to: Safely Cast from bool? to bool
[csharp] view
plaincopy
bool? b = null;
if (b) // Error CS0266.
{
}
===改成==>>
bool? test = null;
// Other code that may or may not
// give a value to test.
if(!test.HasValue) //check for a value
{
// Assume that IsInitialized
// returns either true or false.
test = IsInitialized();
}
if((bool)test) //now this cast is safe
{
// Do something.
}
9. Unity中“单例“的一般实现方案:
[csharp] view
plaincopy
public static EventSystem current { get; set; }
...
protected void OnEnable()
{
if (EventSystem.current == null)
EventSystem.current = this;
#if UNITY_EDITOR
else
{
Debug.LogWarning("Multiple EventSystems in scene... this is not supported");
}
#endif
}
10. 初始化变量的一种简略方式
[csharp] view
plaincopy
PointerEventData ped = new PointerEventData (EventSystem.current);
ped.position = Input.mousePosition;
EventSystem.current.RaycastAll (ped, hits);
===简化为==>
EventSystem.current.RaycastAll (new PointerEventData (EventSystem.current) {
position = Input.mousePosition
}, hits);
11. Unity中新UI的消息处理方式(借助EventSystem中的Raycast获取当前的UI,并发送消息)
具体参考文章:http://gregandaduck.blogspot.com/2015/02/using-unitys-c-message-system-unity-46.html
消息接受方,实现如下:
[csharp] view
plaincopy
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Collections;
// refer to http://gregandaduck.blogspot.com/2015/02/using-unitys-c-message-system-unity-46.html
public interface IMyMouseOver : IEventSystemHandler {
void mouseOver(string str);
void mouseLeaving();
}
public class MyDisplayText : MonoBehaviour, IMyMouseOver {
public Text text;
public void mouseOver(string str) {
if (!text.enabled) {
text.text = str;
text.enabled = true;
}
}
public void mouseLeaving() {
if (text.enabled) {
text.enabled = false;
}
}
}
消息发送方,实现如下:
[csharp] view
plaincopy
using UnityEngine;
using UnityEngine.EventSystems;
using System.Collections;
using System.Collections.Generic;
public class MyMouseOver : MonoBehaviour {
GameObject prevObject;
void Update () {
GameObject target = getMouseOver ();
if (target) {
prevObject = target;
ExecuteEvents.Execute<IMyMouseOver> (target, null, (handle, data) => {
handle.mouseOver ("Mouse Over Active, frame: " + Time.frameCount);
});
} else {
if(prevObject) {
ExecuteEvents.Execute<IMyMouseOver>(prevObject, null, (handle, data) =>{
handle.mouseLeaving();
});
prevObject = null;
}
}
}
private GameObject getMouseOver() {
List<RaycastResult> hits = new List<RaycastResult>();
EventSystem.current.RaycastAll (new PointerEventData (EventSystem.current) {
position = Input.mousePosition
}, hits);
foreach (RaycastResult rr in hits) {
GameObject go = rr.gameObject;
if(go)
return go;
}
return null;
}
}
12. 在C#中模拟Java中的匿名类写法(有点Javascript的味道):
[csharp] view
plaincopy
public class HpBarHandler { // 当然这里用struct会显得把delegate更加看作为数据
public System.Action<float> changeHp;
public System.Action hidde;
public System.Action show;
public System.Action destory;
}
public void registerHPBarEvent(HpBarHandler _hphandler) {
hphandler = _hphandler;
}
fightUnit.registerHPBarEvent (new HpBarHandler () {
changeHp = hp => {
size.x = 200 * hp;
if(rectTrans) {
rectTrans.sizeDelta = size;
if(hp<=0) {
GameObject.Destroy (gameObject);
}
}
},
hidde = delegate{
gameObject.SetActive(false);
},
show = delegate {
gameObject.SetActive(true);
},
destory = delegate {
GameObject.Destroy (gameObject);
}
});
13. 工作中总是遇到初始化某个单位时,依赖其他的单位还未初始化,导致了NullReferenceException。这个是因为所有的初始化都写在了Start方法中,这样由于代码初始化的前后顺序,导致了上面的问题。解决方案就是把初始化分阶段进行。能够导致NullReferenceException的,比如GetCompent,Find等操作,写在Awake或OnEnable方法中等。逻辑初始化写在Start中等。下面是Script Lifecycle的示意图,官方文档为:http://docs.unity3d.com/Manual/ExecutionOrder.html
相关的文章:【Unity】技巧集合
相关文章推荐
- Kinect结合Unity3D引擎开发体感游戏(一)
- Unity3D中脚本的执行顺序和编译顺序
- Unity3D动态对象优化代码分享
- unity3d发布apk在android虚拟机中运行的详细步骤(unity3d导出android apk)
- Unity3D游戏引擎实现在Android中打开WebView的实例
- unity3d调用手机或电脑摄像头
- 分享一个开源的网络游戏服务器架构—HouHai
- Unity3D插件详细评测及教学下载
- Unity3D上路_01-2D太空射击游戏
- Unity3D上路_02-第一视角射击游戏
- Unity3D上路_03-塔防游戏
- Unity3D上路_04-基础资源介绍
- Unity3D上路_05-网络相关
- Unity3d TransformPoint 函数研究
- Unity3d 动态加载fbx模型文件
- unity3d地形系统总结