혹시 유니티 프로젝트 빌드시 


Error CS0241: 기본 매개 변수 지정자를 사용할 수 없습니다. (CS0241) (Assembly-CSharp-Editor)


위와 같은 에러가 나오게 된다면 


해결 방법


 Tools -> Options에서 제일 밑에 있는 Unity -> Debugger에서 Build project in MonoDevelop를 체크 해제하고 빌드하시면 됩니다. 또한 이것은 Windows 환경에서만 발생하고 Mac에서는 발생하지 않는 에러입니다.



이상입니다.

// iOSInAppPlugin.h


#import <StoreKit/StoreKit.h>

@interface iOSInAppPlugin : NSObject<
///< 상품 정보를 얻어올  쓰는 딜리게이트
SKProductsRequestDelegate,
///< 상품 구매 관련 옵저버
SKPaymentTransactionObserver>

+ (iOSInAppPlugin*) sharediOSInAppPlugin;
- (BOOL) initInApp;
- (void) requestProductData:(NSString*)strProductId;

- (void) completeTransaction:(SKPaymentTransaction*)transaction;
- (void) restoreTransaction:(SKPaymentTransaction*)transaction;
- (void) failedTransaction:(SKPaymentTransaction*)transaction;

- (void) restoreCompletedTransactions;

@end




// iOSInAppPlugin.m


#import "iOSInAppPlugin.h"

extern "C"
{
    void iOSInAppInit()
    {
        [[iOSInAppPlugin sharediOSInAppPlugininitInApp];
    }
    void iOSBuyItem(const char* pszProductId)
    {
        NSString* strProductId = [NSString stringWithUTF8String:pszProductId];
        [[iOSInAppPlugin sharediOSInAppPluginrequestProductData:strProductId];
    }
    void iOSRestoreCompletedTransactions()
    {
        [[iOSInAppPlugin sharediOSInAppPluginrestoreCompletedTransactions];
    }
}

@implementation iOSInAppPlugin

+ (iOSInAppPlugin*) sharediOSInAppPlugin
{
    static iOSInAppPlugin* pInstance;
    if(pInstance == NULL)
    {
        pInstance = [[iOSInAppPlugin allocinit];
    }
    return pInstance;
}

- (BOOL) initInApp
{
    ///< 인앱 결제 시스템을 사용 가능한지 체크
    if( [SKPaymentQueue canMakePayments] == NO )
        return NO;
    
    ///< Product 결제 진행에 필요한 딜리게이트 등록
    [[SKPaymentQueue defaultQueueaddTransactionObserver:self];
    
    NSLog(@"InAppPurchase init OK");
    return true;
}

///< 아이템 정보 요청
- (void) requestProductData:(NSString*)strProductId
{
    ///< iTunes Connect 설정한 Product ID
    NSSet* productIdentifiers = [NSSet setWithObject:strProductId];
    SKProductsRequest* request = [[SKProductsRequest alloc]initWithProductIdentifiers:productIdentifiers];
    request.delegate = self;
    [request start];
    NSLog(@"requestProductData %@", strProductId);
}

///< 아이템 정보 요청 결과 callback
- (void) productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
    NSLog@"InAppPurchase didReceiveResponse" );
    forSKProduct* product in response.products )
    {
        if( product != nil )
        {
            NSLog(@"InAppPurchase Product title: %@", product.localizedTitle);
            NSLog(@"InAppPurchase Product description: %@", product.localizedDescription);
            NSLog(@"InAppPurchase Product price: %@", product.price);
            //product.priceLocale
            NSLog(@"InAppPurchase Product id: %@", product.productIdentifier);
            
            ///< 구매 요청
            
            SKPayment* payment = [SKPayment paymentWithProduct:product];
            //payment.quantity = 10;
            [[SKPaymentQueue defaultQueueaddPayment:payment];
        }
    }
    
    [request release];
    
    for (NSString *invalidProductId in response.invalidProductIdentifiers)
    {
        NSLog(@"InAppPurchase Invalid product id: %@", invalidProductId);
    }
}

///< 새로운 거래가 발생하거나 갱신될  호출된다.
- (void) paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray*)transactions
{
    for (SKPaymentTransaction *transaction in transactions)
    {
        switch (transaction.transactionState)
        {
                ///< 서버에 거래 처리중
            case SKPaymentTransactionStatePurchasing:
                NSLog(@"InAppPurchase SKPaymentTransactionStatePurchasing");
                break;
                ///< 구매 완료
            case SKPaymentTransactionStatePurchased:
                [self completeTransaction:transaction];
                break;
                ///< 거래 실패 또는 취소
            case SKPaymentTransactionStateFailed:
                [self failedTransaction:transaction];
                break;
                ///< 재구매
            case SKPaymentTransactionStateRestored:
                [self restoreTransaction:transaction];
                break;
        }
    }
}

- (void) completeTransaction:(SKPaymentTransaction *)transaction
{
    NSLog(@"InAppPurchase completeTransaction");
    NSLog(@"InAppPurchase Transaction Identifier : %@", transaction.transactionIdentifier );
    NSLog(@"InAppPurchase Transaction Data : %@", transaction.transactionDate );
    ///< 구매 완료  아이템 인벤등 게임쪽  처리 진행
    /* 빌트 인 모델
    const char* pszProductId = [[[transaction payment] productIdentifier] UTF8String];
    UnitySendMessage("iOSManager", "ResultBuyItem", pszProductId);
     */
   
    NSString* strReceipt = [[NSString alloc]initWithBytes:transaction.transactionReceipt.byteslength:transaction.transactionReceipt.length encoding:NSUTF8StringEncoding];
    
    UnitySendMessage("iOSManager""ResultBuyItem", [strReceipt UTF8String]);

    // Remove the transaction from the payment queue.
    [[SKPaymentQueue defaultQueuefinishTransaction:transaction];
}

- (void) restoreTransaction:(SKPaymentTransaction *)transaction
{
    NSLog(@"InAppPurchase restoreTransaction");
    const char* pszRestoreProductId = [transaction.originalTransaction.payment.productIdentifier UTF8String];
    UnitySendMessage("iOSManager""ResultRestoreItem", pszRestoreProductId);
    [[SKPaymentQueue defaultQueuefinishTransaction:transaction];
}

- (void) failedTransaction:(SKPaymentTransaction *)transaction
{
    NSLog(@"InAppPurchase failedTransaction.");
    const char* pszResult = 0;
    if( transaction.error.code != SKErrorPaymentCancelled )
    {
        pszResult = "faileIAP";
        NSLog(@"InAppPurchase failedTransaction SKErrorDomain - %d", transaction.error.code );
    }
    else
    {
        pszResult = "cancelIAP";
        NSLog(@"InAppPurchase failedTransaction SKErrorPaymentCancelled");
    }
    UnitySendMessage("iOSManager""ResultBuyItem", pszResult);
    [[SKPaymentQueue defaultQueuefinishTransaction:transaction];
}

// 비소모성 아이템 복원 요청
- (void) restoreCompletedTransactions
{
    [[SKPaymentQueue defaultQueuerestoreCompletedTransactions];
}

@end



// iOSManager.cs


using UnityEngine;

using System.Runtime.InteropServices;

public class iOSManager : MonoBehaviour 
{
static iOSManager _instance;
private string strLog = "Unity3D iOS In App Purchase Sample";
public string strPostMsg = string.Empty;
[DllImport("__Internal")]
private static extern void iOSInAppInit();
[DllImport("__Internal")]
private static extern void iOSBuyItem(string strProductId);
[DllImport("__Internal")]
private static extern void iOSRestoreCompletedTransactions();
public static iOSManager GetInstance()
{
if( _instance == null )
{
_instance = new GameObject("iOSManager").AddComponent<iOSManager>();
}
return _instance;
}
public void InAppInit()
{
iOSInAppInit();
}

public void BuyItem(string strProductId)
{
iOSBuyItem(strProductId);
}
public void ResultBuyItem(string strResult)
{
// strResult is transaction.transactionReceipt or faileIAP or cancelIAP.
SetLog("ResultBuyItem " + strResult);
}
public void RestoreCompletedTransactions()
{
iOSRestoreCompletedTransactions();
}
public void ResultRestoreItem(string strRestoreItemId)
{
SetLog("ResultRestoreItem " + strRestoreItemId);
}

public void SetLog(string _strLog)
{
strLog = _strLog;
}
public string GetLog()
{
return strLog;
}
}

출처 : http://westwoodforever.blogspot.kr/2013/10/unity3d-integration-ios-in-app-purchase.html#links



Unity를 개발할때 MonoDevelop을 이용하여 Script를 작성하게 되는데,

MonoDevelop에서 한글 지원이 제대로 되지 않아서 많은 불편이 있다.

그래서 한번 웹서핑을 하면서 알아본 결과 Text Edit로 많이 쓰는 SublimeText를 이용하여 개발할 수 있는것을 찾았다.

 

SublimeText를 이용할때의 장점과 단점으로는

장점 :   - unity에서 script파일을 열때 실행속도가 빠르다. (script파일의 개수가 많을때)

- 한글 주석처리가 가능하다.

단점 :   - 디버깅을 하지 못한다.

 

일단, 이정도로 파악이 된다.

단점은 보안하고 장점을 살리면서 개발을 할 수 있는 방법을 설명해보도록 하겠다.

1. 단점 보안.

- MonoDevelop에서 디버깅을 해야되기 때문에 먼저 MonoDevelop에서 한글 지원 가능하도록 설정을 해보자.

메뉴에서 Preferences->Fonts->Text Editor->더블클릭 후에 Nanum폰트로 변경.

변경하게 되면 한글로 처리된 주석이 보이게 된다. 하지만 한글을 타이핑 하려고 하면 자음과 모음이 분리되는 현상을 볼수 있다.

 

2. SublimeText 설정.

 

2-1. 준비하기.

http://www.sublimetext.com/2 해당 사이트에서 SublimeText2를 다운 받는다.

http://wbond.net/sublime_packages/package_control/installation 해당 사이트에서 Package파일을 다운 받는다.

 

2-2. Unity 설정하기.

- unity 프로그램의 메뉴에서 Preferences->External Tool->External Script Editor 에서 Browser를 선택하여 응용프로그램에 있는 SublimeText2를 선택한다.

- 위와 같이 하게되면 unity에서 Script파일을 더블 클릭할때 MonoDevelop프로그램이 실행되는게 아닌 SublimeText2가 실행되는 것을 확인 할수 있다.

 

2-3. SublimeText2 설정하기.

- SublimeText2 프로그램의 메뉴에서 Preferences->Browser Packages를 선택하면 Finder창이 열린다.

Finder창이 열리면 2-1 준비하기에서 받은 Package파일을 Installes Packages에 옮긴다.

- SublimeText2를 재실행 한다.

- SublimeText2 프로그램의 메뉴에서 Tool->Command Palette를 선택하면 창이 하나 뜨는데 거기에서 'P'를 입력하면 Package Control: Install Package가 보이게 된다. Package Control: Install Package을 선택한 후에 입력창에 Unity3D를 선택한다.

- 위와 같은 방법으로 Unity3D Builder System, Unity3D Snippets and Completes를 설치한다.

 

2-4. SublimeText2 프로젝트 설정 및 빌드.

- 작업하고 있는 Unity프로그램의 Script파일을 더블 클릭한다.

- SublimeText2 프로그램이 열리면 메뉴에서 Project->Add Folder to Project를 선택하여 unity 프로젝트 폴더를 선택한다.

- 다시 Project->Save Project As...를 선택하여 unity 프로젝트 폴더안에 [프로젝트명].sublime-project  형식에 맞춰서 저장을 한다.

- 메뉴 Tools->Build System->Unity를 설정하여 준다.

- 그후 command + b 를 눌러서 빌드가 잘 되는지 확인하여 보면 된다.


출처 : http://blog.naver.com/gedog31?Redirect=Log&logNo=100196601003


이상입니다.





Unity - Preferences - Always Show Project Wizard (체크)


터미널에서 


open -na Unity


하면 됩니다.~



참고 하세요~~~


HashTable 사용법

HashTable로 인자를 넘길때 iTween.Hash() 함수를 통하여 넘기는방법과 직접 HashTable을 생성하여 전달하는 방법이 있다.

하지만 iTween.Hash() 를 써도 내부적으로는 HashTable을 직접생성하기때문에 HashTable을 직접생성하여 전달하는 방법을 알아야 한다.

Ex)

Hashtable hash = new Hashtable();

hash.Add("position", Vector3.zero);

hash.Add("orienttopath", true);
hash.Add("islocal", true);
hash.Add("speed", 5.0f);
hash.Add("easetype", iTween.EaseType.linear);
hash.Add("onstart", "ItweenStart");
hash.Add("onupdate", "ItweenUpdate");
hash.Add("oncomplete", "ItweenEnd");        

iTween.MoveTo(gameObject, hash);

혹은

아래와 같이 사용 하면 됩니다.~


iTween.MoveTo(mGrid.gameObject,iTween.Hash("x",(mGrid.localPosition.x - (mBossCount * 100)) ,"easeType","spring","loopType","none","time",1,"isLocal",true,"oncomplete","fBossAniEnd")); 

위 예제처럼 HashTable은 Key,Value을 한쌍으로 하는 자료구조이다.

iTween함수마다 내부적으로 사용하는 Key값이 다르며 함수마다 사용하는 Key값은

 http://itween.pixelplacement.com/documentation.php 에 잘나와있다.

 

위에 예제에서 사용한 Key값들은  MoveTo함수에서 자주 사용하는 옵션들이다.

"position" : 말그대로 위치값이다.

"orienttopath" : 이동하는 방향으로 Look 벡터를 자동 회전시켜준다.
"islocal" : 로컬좌표계로 이동
"speed" : 이동 속도이며 "time"대신 사용되어진다.
"easetype" : 보간 방법을 설정한다. iTween은 다양한 보간법을 지원하며 http://www.robertpenner.com/easing/easing_demo.html 에서 확인 가능하다.
"onstart" : Itween이 시작될때 호출되는 함수
"onupdate" : 매프레임마다 호출되는 함수
"oncomplete" : Itween이 끝날때 호출되는 함수

호출되는 함수 같은 경우 내부적으로 SendMessage로 구현되어 있다. 그래서 onupdate인자를 남용한다면 성능상 불이익이 올수 있다.



1.  NGUIMath.cs 의 맨 하단에 아래의 코드를 추가 한다.

static public Bounds CalculateRelativeWidgetBounds2 ( Transform root, Transform firstTemplate, Transform lastTemplate )

{

if( firstTemplate == null || lastTemplate == null )

return new Bounds(Vector3.zero, Vector3.zero);

UIWidget[] widgets1 = firstTemplate.GetComponentsInChildren<UIWidget>(true) as UIWidget[];

UIWidget[] widgets2 = lastTemplate.GetComponentsInChildren<UIWidget>(true) as UIWidget[];

if (widgets1.Length == 0 || widgets2.Length == 0 ) return new Bounds(Vector3.zero, Vector3.zero);

 

Vector3 vMin = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);

Vector3 vMax = new Vector3(float.MinValue, float.MinValue, float.MinValue);

 

Matrix4x4 toLocal = root.worldToLocalMatrix;

 

for (int i = 0, imax = widgets1.Length; i < imax; ++i)

{

UIWidget w = widgets1[i];

Vector2 size = w.relativeSize;

Vector2 offset = w.pivotOffset;

Transform toWorld = w.cachedTransform;

 

float x = (offset.x + 0.5f) * size.x;

float y = (offset.y - 0.5f) * size.y;

size *= 0.5f;

// Start with the corner of the widget

Vector3 v = new Vector3(x - size.x, y - size.y, 0f);

// Transform the coordinate from relative-to-widget to world space

v = toWorld.TransformPoint(v);

// Now transform from world space to relative-to-parent space

v = toLocal.MultiplyPoint3x4(v);

 

vMax = Vector3.Max(v, vMax);

vMin = Vector3.Min(v, vMin);

 

// Repeat for the other 3 corners

v = new Vector3(x - size.x, y + size.y, 0f);

v = toWorld.TransformPoint(v);

v = toLocal.MultiplyPoint3x4(v);

 

vMax = Vector3.Max(v, vMax);

vMin = Vector3.Min(v, vMin);

 

v = new Vector3(x + size.x, y - size.y, 0f);

v = toWorld.TransformPoint(v);

v = toLocal.MultiplyPoint3x4(v);

 

vMax = Vector3.Max(v, vMax);

vMin = Vector3.Min(v, vMin);

 

v = new Vector3(x + size.x, y + size.y, 0f);

v = toWorld.TransformPoint(v);

v = toLocal.MultiplyPoint3x4(v);

 

vMax = Vector3.Max(v, vMax);

vMin = Vector3.Min(v, vMin);

}

for (int i = 0, imax = widgets2.Length; i < imax; ++i)

{

UIWidget w = widgets2[i];

Vector2 size = w.relativeSize;

Vector2 offset = w.pivotOffset;

Transform toWorld = w.cachedTransform;

 

float x = (offset.x + 0.5f) * size.x;

float y = (offset.y - 0.5f) * size.y;

size *= 0.5f;

// Start with the corner of the widget

Vector3 v = new Vector3(x - size.x, y - size.y, 0f);

// Transform the coordinate from relative-to-widget to world space

v = toWorld.TransformPoint(v);

// Now transform from world space to relative-to-parent space

v = toLocal.MultiplyPoint3x4(v);

 

vMax = Vector3.Max(v, vMax);

vMin = Vector3.Min(v, vMin);

 

// Repeat for the other 3 corners

v = new Vector3(x - size.x, y + size.y, 0f);

v = toWorld.TransformPoint(v);

v = toLocal.MultiplyPoint3x4(v);

 

vMax = Vector3.Max(v, vMax);

vMin = Vector3.Min(v, vMin);

 

v = new Vector3(x + size.x, y - size.y, 0f);

v = toWorld.TransformPoint(v);

v = toLocal.MultiplyPoint3x4(v);

 

vMax = Vector3.Max(v, vMax);

vMin = Vector3.Min(v, vMin);

 

v = new Vector3(x + size.x, y + size.y, 0f);

v = toWorld.TransformPoint(v);

v = toLocal.MultiplyPoint3x4(v);

 

vMax = Vector3.Max(v, vMax);

vMin = Vector3.Min(v, vMin);

}

 

Bounds b = new Bounds(vMin, Vector3.zero);

b.Encapsulate(vMax);

return b;

}


2. SpringPanel.cs 에 아래의 코드를 추가 한다.

static public SpringPanel Begin (GameObject go, Vector3 pos, float strength, OnFinished finish )

{

 SpringPanel sp = go.GetComponent<SpringPanel>();

 if (sp == null) sp = go.AddComponent<SpringPanel>();

 sp.target = pos;

 sp.strength = strength;

 sp.onFinished = finish;

 if (!sp.enabled)

 {

  sp.mThreshold = 0f;

  sp.enabled = true;

 }

 

 return sp;

}


3. 첨부한 3개의 파일을 프로젝트에 포함 시킨다.

cUIScrollListBase.cs


UIDraggablePanel2.cs


UIListItem.cs



4. UIDraggablePanel.cs 에서 에러가 날 것이다.. 

virtual 을 해서 없애도 되고~ 

UIDraggablePanel.cs


위 파일로 교체를 해도 된다.~~


5. 사용 방법은 

transform.GetComponent<UIDraggablePanel2>().Init( count, delegate(UIListItem item, int index) {

CMsgUserItem scr = item.Target.GetComponent<CMsgUserItem>();

scr.transform.name = "clip_"+index;

scr.transform.localScale = Vector3.one;

} );


6. 마지막 가장 중요한 감사의 마음을 표시 한다.~ 

나 말고~ http://idmanner.blog.me/70176641036  

위에 링크 블러그 주인한테 감사의 마음을 표시 한다.~~~


감사 합니다.~!~!~!

^^ 즐코딩 하세요~!


// string -> base64Encoding 으로 바꾼 상태를 문자열로 표기 할때

private string StringConvertBase64(string _str) {

byte[] byteArr = utf8Enc.GetBytes(_str);

return Convert.ToBase64String(byteArr);

}


// base64Encoding 로 바뀐 문자열을 일반 문자열로 표기 할때

private string Base64ConvertString(string _str) {

byte[] byteArr = Convert.FromBase64String(_str);

return utf8Enc.GetString(byteArr);

}



System.Random r = new System.Random();

int keyValue = r.Next(0,7);


0~7사이 랜덤 숫자를 생성 합니다.


C#에서 암호화 할시 php에서와 암호화 할시 다르게 나오는 경우가 있어

구글 검색 후 
참고 링크 입니다.

아래 코드 같은 경우에는 흔히 구글에서 볼수 있지만 이 C# 코드와 동일하게 암호화 하기 위해서는 위의 링크에 들어 가서 
php암호화 코드를 사용 하여야만 한다..
사용 결과 잘 됩니다.~

private string Decrypt256(String Input, String key)

{

 RijndaelManaged aes = new RijndaelManaged();

            aes.KeySize = 256;

            aes.BlockSize = 128;

            aes.Mode = CipherMode.CBC;

            aes.Padding = PaddingMode.PKCS7;

            aes.Key = Encoding.UTF8.GetBytes(key);

            aes.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };


            var decrypt = aes.CreateDecryptor();

            byte[] xBuff = null;

            using (var ms = new MemoryStream())

            {

                using (var cs = new CryptoStream(ms, decrypt, CryptoStreamMode.Write))

                {

                    byte[] xXml = Convert.FromBase64String(Input);

                    cs.Write(xXml, 0, xXml.Length);

                }


                xBuff = ms.ToArray();

            }


            String Output = Encoding.UTF8.GetString(xBuff);

            return Output;

}

 

  private String AESEncrypt256(String Input, String key)

{

            RijndaelManaged aes = new RijndaelManaged();

            aes.KeySize = 256;

            aes.BlockSize = 128;

            aes.Mode = CipherMode.CBC;

            aes.Padding = PaddingMode.PKCS7;

            aes.Key = Encoding.UTF8.GetBytes(key);        

            aes.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };


            var encrypt = aes.CreateEncryptor(aes.Key, aes.IV);

            byte[] xBuff = null;

            using (var ms = new MemoryStream())

            {

                using (var cs = new CryptoStream(ms, encrypt, CryptoStreamMode.Write))

                {

                    byte[] xXml = Encoding.UTF8.GetBytes(Input);

                    cs.Write(xXml, 0, xXml.Length);

                }


                xBuff = ms.ToArray();

            }


            String Output = Convert.ToBase64String(xBuff);

            return Output;

}


+ Recent posts