您的位置:首页 > 移动开发 > Unity3D

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. 回调相关:UnityEventSystem.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】技巧集合
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  unity3d