2014年4月27日 星期日

2014年4月24日 星期四

[Unity3D] animation material 動畫材質的作法

我這邊寫了一個class,還不夠完美,先湊合著用吧^^
=========================================================
using UnityEngine;
using System.Collections;

public class AnimPlane : MonoBehaviour {

public Texture[] frames;
public bool loop = false;
public float delayTime = 0.01f;
public bool bAlwaysFaceToUser = false;

Quaternion offset=Quaternion.Euler(-90, 0, 0);
Transform  cam;
bool       bEnableAnim = false;

void Start () {

}

        // Use this for initialization
protected void Init(){
gameObject.SetActive(false);

cam=Camera.main.transform;
}

// Update is called once per frame
void Update () {
if(bAlwaysFaceToUser){
Quaternion rot=cam.rotation*offset;

transform.rotation=rot;
Vector3 dirRight=transform.TransformDirection(-Vector3.right);
}
}

public void PlayAnim()
{
gameObject.SetActive(true);
bEnableAnim = true;
StartCoroutine(IEPlayAnim());
}

public void StopAnim()
{
bEnableAnim = false;
StopCoroutine("IEPlayAnim");
gameObject.SetActive(false);
}

IEnumerator IEPlayAnim()
{
int index = 0;
while(bEnableAnim)
{
renderer.material.mainTexture = frames[index];
index++;
if(index >= frames.Length) {
if(loop) index = 0;
else{
gameObject.SetActive(false);
break;
}
}
//yield return null;
yield return new WaitForSeconds(delayTime);
}
}

}
==========================================================
然後寫一個新的script繼承它

using UnityEngine;
using System.Collections;

public class RunnerSpray :AnimPlane {

// Use this for initialization
void Start () {
base.Init();

PlayAnim();
}

}

=========================================================
然後在unity editor裡建立一個plane
將RunnerSpray腳本拖ㄅ放到plane裡

再將多張texture依序拖放到Frames 底下
(這裡有個缺點,萬一圖片有幾百張不就拖到死了,暫時沒空去處理)

然後拖一張texture到這平面上
shader設定成 Mobile/Particles/Additive 

設定大概參考圖片



然後執行一下Run
就能看到效果囉^^








[Unity3D] 關於character controller 的 isGrounded 的問題

原本是用
character.isGrounded 來判斷
但是自己使用的感想覺得不是非常準確
常常偵測不到
(當然可能是某個條件未滿足所造成的)

參考了這兩篇文章後

http://answers.unity3d.com/questions/424047/character-controller-isgroundedfalse-while-moving.html

http://answers.unity3d.com/questions/196381/how-do-i-check-if-my-rigidbody-player-is-grounded.html

整理出以下的方法
用Raycast去偵測
確實能work
參考看看^^

private float distToGround;

bool IsGrounded() {
//return Physics.Raycast(transform.position, -Vector3.up, distToGround + 0.1f);
return Physics.Raycast(transform.position, -Vector3.up, distToGround + 1.1f);
}

原本網友是用0.1f 但是我跑了以後偵測不到
可能跟每個人的collider大小有關
我調到1.1f後就能正常偵測了^^




2014年4月22日 星期二

[Unity3D] [單位] 取得gameobject的單位大小

有時候你會想知道這個3d 物件在unity裡到底是佔有多大的單位(unit)
可以用此語法

gameObject.renderer.bounds.size  (回傳值type是  vector3 )

[Unity3D] [Sync MonoDevelop project 的作用] 解決 4.3.4版unity monodevelop 程式的autocomplete功能失效

自從將unity3d從4.2.1升級到4.3.4後
我發現我的monodevelop裡的程式的autocomplete的功能都失效了
這樣往後寫程式都很麻煩,要自己去找reference,
主要是因為這版的unity產生的project,
都沒有自動產生monodevelop相對應的sln文件,
因此造成用mono打開腳本後,
無法使用autocomplete的功能。

後來找到解決的方法
就是在unity editor裡 -> Assets -> Sync MonoDevelop Project





















這樣回到你的unity project資料夾底下一看
就會發現相關的sln文件自動產生了
如此一來autocomplete功能也能正常使用囉^^

2014年4月21日 星期一

[Unity3D] (native plugins) 用unity 取得IDFA 的方法

首先參考了這兩篇的文章

Building Plugins for iOS 

(進去下載  Bonjour Browser Sample 來修改 )


然後再參考這篇
Unity- 实现 Building Plugins for iOS(含Demo)

另外要知道  objective-c 取得IDFA的語法 :
[[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];

1. 你要先確定你的程式在xcode底下是可以正確build不會出錯的

2. 把xcode寫好的程式碼移到 unity專案底下的 Assets -> Plugins ->iOS 底下(放在別地方沒有用)

3. 因為要取得IDFA需要 AdSupport.framework 所以在BonjourClientImpl.h
    記得加入 #import <AdSupport/AdSupport.h>

所以整個BonjourClientImpl.h是長這樣
-----------------------------------------------------------------------------------------
#import <Foundation/Foundation.h>
#import <AdSupport/AdSupport.h>


@interface NetServiceBrowserDelegate : NSObject
{
    // Keeps track of available services
    NSMutableArray *services;

// Keeps track of search status
NSString* status;
    BOOL searching;
}



// NSNetServiceBrowser delegate methods for service browsing
- (void)netServiceBrowserWillSearch:(NSNetServiceBrowser *)browser;
- (void)netServiceBrowserDidStopSearch:(NSNetServiceBrowser *)browser;
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser
didNotSearch:(NSDictionary *)errorDict;
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser
  didFindService:(NSNetService *)aNetService
  moreComing:(BOOL)moreComing;
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser
didRemoveService:(NSNetService *)aNetService
  moreComing:(BOOL)moreComing;

// Other methods

- (int)getCount;
- (NSString*) getIDFA;
- (NSNetService *)getService:(int)serviceNo;
- (NSString *)getStatus;

@end
-------------------------------------------------------------------------------------------

然後  BonjourClientImpl.mm 是改成這樣:

-------------------------------------------------------------------------------------------

#import "BonjourClientImpl.h"

@implementation NetServiceBrowserDelegate


- (id)init
{
    self = [super init];
    services = [[NSMutableArray alloc] init];
    searching = NO;
status = @"Initializing";
    return self;
}



- (void)dealloc
{
    [services release];
    [super dealloc];
}



// Sent when browsing begins
- (void)netServiceBrowserWillSearch:(NSNetServiceBrowser *)browser
{
    searching = YES;
status = @"Searching";

[services removeAllObjects];
}



// Sent when browsing stops
- (void)netServiceBrowserDidStopSearch:(NSNetServiceBrowser *)browser
{
    searching = NO;
status = @"Done";
}



// Sent if browsing fails
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser
didNotSearch:(NSDictionary *)errorDict
{
    searching = NO;
NSString * msg = @"Failed.";
status = [msg stringByAppendingString:[[errorDict objectForKey:NSNetServicesErrorCode] stringValue]];
}



// Sent when a service appears
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser
  didFindService:(NSNetService *)aNetService
  moreComing:(BOOL)moreComing
{
    [services addObject:aNetService];
}



// Sent when a service disappears
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser
didRemoveService:(NSNetService *)aNetService
  moreComing:(BOOL)moreComing
{
    [services removeObject:aNetService];
}


- (int)getCount
{
return [services count];
}

- (NSString*) getIDFA
{
return [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
}

- (NSNetService *)getService:(int)serviceNo
{
return [services objectAtIndex:serviceNo];
}

- (NSString *)getStatus
{
return status;
}

@end

static NetServiceBrowserDelegate* delegateObject = nil;
static NSNetServiceBrowser *serviceBrowser = nil;

// Converts C style string to NSString
NSString* CreateNSString (const char* string)
{
if (string)
return [NSString stringWithUTF8String: string];
else
return [NSString stringWithUTF8String: ""];
}

// Helper method to create C string copy
char* MakeStringCopy (const char* string)
{
if (string == NULL)
return NULL;

char* res = (char*)malloc(strlen(string) + 1);
strcpy(res, string);
return res;
}

// When native code plugin is implemented in .mm / .cpp file, then functions
// should be surrounded with extern "C" block to conform C function naming rules
extern "C" {

void _StartLookup (const char* service, const char* domain)
{
if (delegateObject == nil)
delegateObject = [[NetServiceBrowserDelegate alloc] init];


if (serviceBrowser == nil)
serviceBrowser = [[NSNetServiceBrowser alloc] init];

[serviceBrowser setDelegate:delegateObject];

// Call "searchForServicesOfType" and pass NSStrings as parameters. By default mono
// marshals all .Net strings as UTF-8 C style strings.
[serviceBrowser searchForServicesOfType: CreateNSString(service) inDomain: CreateNSString(domain)];
}

const char* _GetLookupStatus ()
{
// By default mono string marshaler creates .Net string for returned UTF-8 C string
// and calls free for returned value, thus returned strings should be allocated on heap
return MakeStringCopy([[delegateObject getStatus] UTF8String]);
}

int _GetServiceCount ()
{
return [delegateObject getCount];
}

const char* _GetIDFA()
    {
      return MakeStringCopy([[delegateObject getIDFA] UTF8String]);
    }
 
const char* _GetServiceName (int serviceNumber)
{
// By default mono string marshaler creates .Net string for returned UTF-8 C string
// and calls free for returned value, thus returned strings should be allocated on heap
return MakeStringCopy([[[delegateObject getService:serviceNumber] name] UTF8String]);
}

void _Stop()
{
[serviceBrowser stop];
}

}

-------------------------------------------------------------------------------------------

因為是obj-c++  所以為了要讓unity script 可以呼叫到,
被unity呼叫的function必須包在 extern "C" { } 裡面才呼叫的到

然後用_GetIDFA() 去呼叫 obj-c 的方法 getIDFA

這樣xcode要寫的部分就完成了

再來講一下Plugins底下的Bonjour.cs 這隻程式
官方是建議寫一隻獨立的class來跟native ios做溝通
所以才會有這隻Bonjour.cs
一樣我在這隻程式底下加了這行
[DllImport ("__Internal")]
private static extern string _GetIDFA ();

然後再加了個方法
public static string GetIDFA(){
return _GetIDFA ();

}

最後就是主程式  BonjourTest.js
我在function OnGUI () 的最後加入了這行

//jojospeed666
print("IDFA = "+Bonjour.GetIDFA());

//Display IDFA
GUI.Label(new Rect(centerx - 50, 175, 100, 25), "IDFA = "+Bonjour.GetIDFA(), labelStyle);

這樣一來程式部分都改寫完畢
然後去unity build專案
沒出錯的話它會要求你新建一個Xcode專案
把它存在你想存的地方,等build好後去把那專案開啟

這邊要記得做一件很重要的事
就是要去xcode那邊把 AdSupport.framework 這個import進來
而且每次unity build完 打開xcode都要重做一次
不然run xcode會報錯
不知道unity有沒有地方可以設定build好就自動讓xcode import好會用到的
framework呢?  有同學知道的話麻煩告知一下
不然就只能用我這蠢方法
每次unity build好 進xcode後又要在import一次

沒問題後就run看看吧
手機自動開啟unity  app後,點下qurey 看看下方是否有出現IDFA,
如果有的話就表示成功取得IDFA囉^^

sample下載位置









2014年4月20日 星期日

[Unity3D] [NGUI] Multi-Object Editing not supported 錯誤訊息

今天更新NGUI版本到3.5.6
import package進去後
想說把NGUI整個資料夾移動到plugins底下會比較整齊
沒想到開始出現慘劇了
所有元件的script的編輯區都出現

Multi-Object Editing not supported

趕緊把整個NGUI的資料夾都移回原本的地方(根目錄)
問題才得以解決
估計是unity editor 那邊找不到NGUI腳本的位置所造成的。

2014年4月15日 星期二

[Unity3D] 找尋gameobject的child gameobject

[實作]

ObjectUltility.FindChildTransform

public static Transform FindChildTransform(Transform root ,string name ){
      if (root == null) {
        return null;
      } else if (root.name == name) {
        return root;
      }

      foreach(Transform child in root) {
        Transform childResult  = FindChildTransform(child, name);
        if (childResult != null) {

            return childResult;
          }
       }
    return null;
}

[用法]

GameObject flashLight;

flashLight = ObjectUltility.FindChildTransform( transform , "flashLight").gameObject;