// 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


Unity3D 에서 plyerPrefs 를 관리 할수 있게 singleTon으로 따로 묶어서 관리 하기 위해서 만들었다~!

소스는 아래 참고 입니다.~


using UnityEngine;

using System.Collections;


public class CPlayerPrefs : MonoBehaviour {


    private static CPlayerPrefs _instance;  

    public static CPlayerPrefs Instance  

{   

get  

{   

            if (_instance == null)  

_instance = new CPlayerPrefs();

                return _instance;  

        }  

    }  

 

    

    public void OnApplicationQuit()

    {

        _instance = null;

    }

 

    public int _mNoticeVal;

 

    public int mNoticeVal

    {

        get

        {

if(PlayerPrefs.HasKey("NoticeVal")) {

                 _mNoticeVal = PlayerPrefs.GetInt("NoticeVal");

else {

_mNoticeVal = 0;

}

                return _mNoticeVal;

   }

   set

        {

            _mNoticeVal = value;

            PlayerPrefs.SetInt("NoticeVal", _mNoticeVal);

        }

    }

}


/* 각 축별 각을 이용해 회전을 하는 함수 */

 

Rotate( Vector3 오일러각, Space.Self ); 

 

Rotate( Vector3, float 각도, Space Self );

 

Rotate( float X각, float Y각, float Z각, Space.Self ); 

 

 

 

 

/* 특정 점을 기준으로 축을 잡아 회전하는 메소드 */

 

RotateAround( Vector3 원점, Vector3 축, flaot 각도 );

 

 

 

 

/* Quaternion */

 

Quaternion.Lookrotation( Vector3 방향 ); // 해당 방향으로 쿼터니언 생성

 

Quaternion.Angle( Quaternion rotation, Quaternion rotation ); // 두 쿼터니언간의 각도 (flaot)

 

Quaternion.Euler( Vector3 오일러각 ); // 오일러각에 해당하는 쿼터니언 생성

 

Quaternion.Slerp( Quaternion from, Quaternion to, float time ); // to에서 from으로 시간에 따른 변화값

 

Quaternion.FromToRotation( Vector3 from, Vector3 to ); // to에서 from으로의 쿼터니언

 

Quaternion.Identity( ); // 회전 없음

 

 

 

 

/* Quaternion 활용 */

 

1. 특정 벡터에서 쿼터니언 얻어오기

 

Quaternion rotValue = Quaternion.LookRotation( target.position );

 

rotValue를 rotation객체에 넣으면 자동으로 해당 방향으로 회전처리한다

 

 

 

 

2. 특정 x,y,z각으로 회전

 

transform.rotation = Quaternion.Euler( X, Y, Z );

 

해당 각으로 회전한다. 오일러 회전처럼 축이 변화하지 않으므로, 동일한 값은 Update루틴에 넣어도 동일한 회전으로 유지된다. (오일러 회전은 계속 변한다)

 

 

 

 

3. 특정 지점을 원점으로 회전

 

float distance = Vector3.Distance( A, B ); // 기준점과의 거리 저장

 

Quaternion quat = Quaternion.Euler( new Vector3( 30, 0, 0 ); // X축을 기준으로 30도 회전

 

transform.rotation = quat; // 해당 쿼터니언을 rotation으로 지정

 

transform.position = Vector3 (기준점);

 

transform.position -= quat * Vector3.forward * distance; // 포워드벡터를 quat으로 회전시키고, 해당 축을 기준으로 distance만큼 뒤로 이동

 

transform.LookAt( Vector3 (기준점) ); // 이동처리 후 기준점을 바라본다

 

 

 

 

 

/* 캐릭터를 따라다니는 스무스 카메라 */

 

이 소스는 rotation 변수에 넣어 변환 파이프라인을 타지않고, 직접 포지션을 변경

 

타겟을 따라다니는 카메라는 타겟을 원점으로 Y축을 잡는다

 

카메라는 해당 Y축을 주변으로 회전하면 된다

 

 

public Transform target; // 따라다닐 타겟

 

// 카메라의 고정값 설정

public float distance = 10.0f;

 

public float height = 5.0f;

 

// 변경시 변위

float heightDamping = 2.0f;

 

float rotationDamping = 3.0f;

 

 

// 모든 업데이트 이후 호출

void LateUpdate( )

{

    // 현재 카메라의 Y축 앵글과 높이

    float currentAngle = transform.eulerAngles.y;

    float currentHeight = transform.position.y;

 

    // 타겟의 앵글과 높이

    float targetAngleY = target.eulerAngles.y;

    float targetHeight = target.position.y + height;

 

    // 원하는 앵글을 시간변위에 따라 현재 앵글값 얻음

    currentAngleY = Mathf.LerpAngle( currentAngleY, targetAngleY, rotationDamping * Time.deltaTime );

 

    // 높이도 똑같이

    currentHeight = Mathf.Lerp( currentHeight, targetHeight, heightDamping * Time.deltaTime );

 

    // 이동할 앵글을 회전으로 변환

    Quaternion newRotation = Quaternion.Euler( 0, currentAngleY, 0 );

 

    // 카메라의 포지션 이동

    Vector3 newPosition = transform.position;

 

    newPosition.position = target.position;

 

    newPosition.position -= newRotation * Vector3.forward * distance;

 

    // 높이 설정

    newPosition.y = currentHeight;

 

    // 최종 이동

    transform.position = newPosition;

 

    // 타겟을 바라보게 설정

    transform.LookAt( target );

 

}


 [출처] Rotate/Quaternion|작성자 라파공

[출처] Rotate/Quaternion|작성자 라파공


+ Recent posts