2015年4月17日 星期五

string vs. char

C# 中在處理字串問題時,建議盡量用string宣告,少用char,尤其當你用來接收資料時

舉例來說:
1.
[StructLayout(LayoutKind.Sequential)]
public struct Msg_List
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string Message; //訊息.
};
2.
[StructLayout(LayoutKind.Sequential)]
public struct Msg_List
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
public char[] Message; //訊息.
};


資料由指標傳遞,再將此指標轉換成msg時
(Msg_List)Marshal.PtrToStructure(ptrM, typeof(Msg_List));

用第一種struct會比第二種struct來的好

原因是使用第二種struct有可能會漏訊息,一樣會收到資料,但char Message的內容會是空的

至於為什麼,我也不知道,或許是unity的原因也或許是C#語法的關係,就沒有追究下去了...

2014年8月29日 星期五

PC,行動平台讀檔寫檔方式

/**
 * 方法1: 使用Application.persistentDataPath
 * PC、Android,IOS適用
 * 但因為不知道如何將檔案放在此位置,所以此方法需要自行開檔寫資料進去,然後才讀取。
 * */
using UnityEngine;
using System.Collections;
using System.IO;
using System.Collections.Generic;
using System;

public class Text1 : MonoBehaviour
{
//文本中每行的內容.
ArrayList infoall;
//skin資源,這裡用來顯示中文.
public GUISkin skin;

// Use this for initialization
void Start ()
{
//刪除文件.
DeleteFile(Application.persistentDataPath,"FileName.txt");

//創建文件.
CreateFile(Application.persistentDataPath,"FileName.txt","test");
//得到文本中每一行的內容.
infoall = LoadFile(Application.persistentDataPath,"FileName.txt");
}


/**
   * path:文件創建目錄.
   * name:文件的名稱.
   * info:寫入的內容.
   */
void CreateFile(string path,string name,string info)
{
//文件流信息.
StreamWriter sw;
FileInfo t = new FileInfo(path+"//"+ name);
if(!t.Exists)
{
//如果文件不存在則創建.
sw = t.CreateText();
}
else
{
//如果此文件存在則打開.
sw = t.AppendText();
}
//以行的形式寫入信息.
sw.WriteLine(info);
//關閉流.
sw.Close();
//銷毀流.
sw.Dispose();
}


/**
   * path:讀取文件的路徑.
   * name:讀取文件的名稱.
   */
ArrayList LoadFile(string path,string name)
{
//使用流的形式讀取.
StreamReader sr =null;
try{
sr = File.OpenText(path+"//"+ name);
}catch(Exception e)
{
//路徑與名稱未找到文件則直接回傳null.
return null;
}
string line;
ArrayList arrlist = new ArrayList();
while ((line = sr.ReadLine()) != null)
{
//一行一行的讀取.
//將每一行的內容存入數組鏈表容器中.
arrlist.Add(line);
}
//關閉流.
sr.Close();
//銷毀流.
sr.Dispose();
//將數組鏈表容器返回.
return arrlist;
}

/**
   * path:刪除文件的路徑.
   * name:刪除文件的名稱.
   */

void DeleteFile(string path,string name)
{
File.Delete(path+"//"+ name);
}

void OnGUI()
{
//用新的skin資源,顯示中文.
GUI.skin = skin;
//讀取文件中的所有內容.
foreach(string str in infoall)
{
//繪製在螢幕上.
GUILayout.Label(str);
}

GUILayout.Label(Application.persistentDataPath);
GUILayout.Label(Application.dataPath);
GUILayout.Label(Application.streamingAssetsPath);
GUILayout.Label(Application.temporaryCachePath);
//PC上的位置.
// C:/Users/[用戶名稱]/AppData/LocalLow/[CompanyName]/ReadWrite
// D:/Unity/ReadWrite/Assets
// D:/Unity/ReadWrite/Assets/StreamingAssets
// C:/Users/[用戶名稱]/AppData/Local/Temp/[CompanyName]/ReadWrite
//Android上的位置.
// /data/data/com.CompanyName.ReadWrite/files
// /data/data/com.CompanyName.ReadWrite-1.apk
// jar:file:///data/app/com.CompanyName.Readrite-1.apk!/assets
// /data/data/com.CompanyName.ReadWrite/cache
}
}


/**
 * 方法2: 使用Application.streamingAssetsPath
 * PC、Android,IOS適用
 * 但是Android平台必須用WWW加載.
 * 註:xml檔內的格式不符合此文件規格所以會報錯,沒時間研究XML,所以先這樣囉!!
 * */
using UnityEngine;
using System.Collections;
using System.Xml;   
using System.Xml.Serialization;   
using System.IO;  
using System.Text;   

public class Reward
{   
public int taskNo;  
public Task[] task = new Task[15];  
//public Attribute attribute;   
public Reward () {}   
public struct Task  
{   
[XmlAttribute("taskReward")]   
public string taskReward{ get; set;}   
public Id id1;   
public Id id2;  
public Id id3;  
}  
public struct Id  
{
[XmlAttribute("flag")]   
public bool flag{ get; set;}   
[XmlAttribute("name")]   
public string name{ get; set;}  
[XmlText()]  
public string description{get;set;}  
}    
}

public class Text2 : MonoBehaviour {

Reward reward ;   
FileInfo fileInfo;  
string _data;   

// Use this for initialization
void Start ()
{
reward = new Reward();  
LoadXML();  
}
void LoadXML()   
{   
if(Application.platform == RuntimePlatform.IPhonePlayer)  
{  
fileInfo = new FileInfo(Application.dataPath + "/Raw/" + "FileName.xml");   
StreamReader r = fileInfo.OpenText();   
_data = r.ReadToEnd();   
r.Close();   
}
else if(Application.platform == RuntimePlatform.Android)  
{  
fileInfo = new FileInfo(Application.streamingAssetsPath+"/FileName.xml");  
StartCoroutine("LoadWWW");  
}  
else  
{  
fileInfo = new FileInfo(Application.dataPath + "/StreamingAssets/"+ "FileName.xml");   
StreamReader r = fileInfo.OpenText();   
_data = r.ReadToEnd();   
r.Close();   
}     
if(_data.ToString() != "")   
{   
reward = (Reward)DeserializeObject(_data);                
}   
}  
void OnGUI()  
{  
GUI.Label(new Rect(0,0,Screen.width,Screen.height), _data);      
if(Input.GetKey(KeyCode.Space))  
{  
Application.Quit();   
}  
}  
IEnumerator LoadWWW()  
{
//底下兩種路徑方法都可以用.
//方法1:
//string filepath = "jar:file://" + Application.dataPath + "!/assets/FileName.xml";
//WWW www = new WWW(filepath);  
//方法2:
WWW www = new WWW(Application.streamingAssetsPath+"/FileName.xml");
yield return www;  
_data =www.text;  
}  
public void Save()  
{       
_data = SerializeObject(reward);  
StreamWriter writer;   
fileInfo.Delete();      
writer = fileInfo.CreateText();   
writer.Write(_data);  
writer.Close();   
}  
string UTF8ByteArrayToString(byte[] characters)   
{        
UTF8Encoding encoding = new UTF8Encoding();   
string constructedString = encoding.GetString(characters);   
return (constructedString);   
}   
byte[] StringToUTF8ByteArray(string pXmlString)   
{   
UTF8Encoding encoding = new UTF8Encoding();   
byte[] byteArray = encoding.GetBytes(pXmlString);   
return byteArray;   
}   
// Here we serialize our Reward object of reward   
string SerializeObject(object pObject)   
{  
string XmlizedString = null;   
MemoryStream memoryStream = new MemoryStream();   
XmlSerializer xs = new XmlSerializer(typeof(Reward));   
XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);   
xs.Serialize(xmlTextWriter, pObject);   
memoryStream = (MemoryStream)xmlTextWriter.BaseStream;   
XmlizedString = UTF8ByteArrayToString(memoryStream.ToArray());   
return XmlizedString;   
}   
// Here we deserialize it back into its original form   
object DeserializeObject(string pXmlizedString)   
{   
XmlSerializer xs = new XmlSerializer(typeof(Reward));   
MemoryStream memoryStream = new MemoryStream(StringToUTF8ByteArray(pXmlizedString));   
//XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);   
return xs.Deserialize(memoryStream);   
}
}


/**
 * 方法3: 使用Resources
 * PC、Android,IOS適用
 * 但在行動平台上似乎只能讀,不能寫(未深入研究)
 * */
using UnityEngine;
using System.Collections;
using System.IO;  
using System.Collections.Generic;
using System;

public class Text3 : MonoBehaviour {

//文本中每行的內容.
ArrayList infoall;
//skin資源,這裡用來顯示中文.
public GUISkin skin;

// Use this for initialization
void Start ()
{
//創建文件.
//CreateFile(Application.dataPath + "/Resources/", "FileName.txt", "test");
//得到文本中每一行的內容.
infoall = LoadFile(Application.dataPath + "/Resources/","FileName.txt");
}
/**
   * path:文件創建目錄.
   * name:文件的名稱.
   * info:寫入的內容.
   */
void CreateFile(string path,string name,string info)
{   
if(Application.platform == RuntimePlatform.Android || Application.platform == RuntimePlatform.IPhonePlayer)
{
return;
}

//文件流信息.
StreamWriter sw;
FileInfo t = new FileInfo(path+"//"+ name);

if(!t.Exists)   
{   
//如果文件不存在則創建.
sw = t.CreateText();
}
else
{
//如果此文件存在則打開.
sw = t.AppendText();
}
//以行的形式寫入信息.
sw.WriteLine(info);
//關閉流.
sw.Close();
//銷毀流.
sw.Dispose();   
}  
/**
   * path:讀取文件的路徑.
   * name:讀取文件的名稱.
   */
ArrayList LoadFile(string path,string name)
{
#if UNITY_EDITOR || UNITY_STANDALONE_WIN
//使用流的形式讀取.
StreamReader sr = null;
#elif UNITY_ANDROID || UNITY_IPHONE
StringReader sr = null;
#endif

try
{
#if UNITY_EDITOR || UNITY_STANDALONE_WIN
sr = File.OpenText(path+"//"+ name);
#elif UNITY_ANDROID || UNITY_IPHONE
TextAsset logFile = (TextAsset)Resources.Load("FileName");
sr = new StringReader(logFile.text);
#endif
}
catch(Exception e)
{
//路徑與名稱未找到文件則直接回傳null.
return null;
}
string line;
ArrayList arrlist = new ArrayList();
while ((line = sr.ReadLine()) != null)
{
//一行一行的讀取.
//將每一行的內容存入數組鏈表容器中.
arrlist.Add(line);
}
//關閉流.
sr.Close(); 
//銷毀流.
sr.Dispose();
//將數組鏈表容器返回.
return arrlist;
}   
/**
   * path:刪除文件的路徑.
   * name:刪除文件的名稱.
   */
void DeleteFile(string path,string name)
{
File.Delete(path+"//"+ name);
}
}

2014年8月24日 星期日

手機/平版的平台上,OnGUI對應螢幕解析度做縮放的方式

方法1:

//建議不要在Awake函式做,因為Awake太早被呼叫,此時螢幕解析度可能有誤.
void Start()
{
  //宣告一個Vector3的參數,將X、Y被縮放的比例填入,Z不會縮放所以填1就好.
  //1280x800為原始設計螢幕大小,Screen.widthxScreen.height為目前螢幕真實大小.
  GUIScaleValue = new Vector3((float)Screen.width/1280.0f, (float)Screen.height/800.0f, 1);
}

void OnGUI()
{
  //scale to fit, when screen change.
  GUI.matrix = Matrix4x4.Scale(GUIScaleValue);
}



方法2:

//建議不要在Awake函式做,因為Awake太早被呼叫,此時螢幕解析度可能有誤.
void Start()
{
  //1280x800為原始設計螢幕大小,Screen.widthxScreen.height為目前螢幕真實大小.
  pivotScale = new Vector2((float)Screen.width/1280.0f, (float)Screen.height/800.0f);
  pivotPoint = new Vector2(Screen.width/2, Screen.height/2);
}

void OnGUI()
{
  //scale to fit, when screen change.
  GUIUtility.ScaleAroundPivot(pivotScale,Vector2.zero);
  //也可以直接旋轉整個UI,底下例子:以pivotPoint為原點旋轉90度.
  GUIUtility.RotateAroundPivot(90,pivotPoint);
}

2014年1月13日 星期一

script於Inspector中,enable、disable(script前可打勾的方框)功能消失?

於Unity編輯器中建立一新script檔,內容會自動產生Start()與Update()函式
有時我們的script中可能沒用到Start()、Update()這兩個函式,而將其刪除
此時將此沒有Start()、Update()兩個函式的script加入Unity專案中,在Inspector欄中可看到此script原先可透過打勾來控制enable、disable的方框變成反灰而不能點擊了
此時只要將 Start()、Update()任一個函式放回script中,方框就會出現了

切記,Start()、Update()這兩個函式若沒用途,仍需保留在script中呀~~~

2013年8月5日 星期一

退出(結束)Unity遊戲

呼叫下列函式退出遊戲
Application.Quit();


若退出時畫面會閃,可用下列方法試試
System.Diagnostics.Process.GetCurrentProcess().Kill();