Java、Objective-C 傳送圖片到遊戲引擎

3 min

前言

我的工作內容之一,是把 iOS、Android 的原生功能串接進遊戲引擎,像是 IAP、Permission、AlertDialog 這類平台能力,盡量整理成遊戲端可以直接呼叫的形式,讓遊戲專案本身可以更專心在遊戲與商業邏輯上。

這次剛好遇到一個需求,要讓玩家從手機相簿挑選圖片,並把它送進 Unity 或 Unreal 內做後續處理,所以就順手整理一下這個做法。

Unity、Unreal、Native
Unity、Unreal、Native

封面圖片來源:Unity, Unreal, Native : Choose Better Game Engine for Mobile Game Development


功能需求

這次的需求起因,是遊戲專案需要讓玩家自訂頭像。

原本專案內使用的 Unity 套件已經沒有持續更新,對新版 Android 的隱私權政策支援也不夠完整,所以最後這個 case 就轉回原生端處理,再把結果傳回引擎。


作法簡介

整體做法其實很單純,就是先把圖片轉成 byte array,再編碼成 base64 字串送進引擎,由引擎端再做 decode 與 texture 建立。

處理順序如下:

  1. Convert to byte array
  2. Encode to base64
  3. Send message to engine
  4. Engine base64 decode
  5. Convert to engine texture

引擎注意事項

Unity 可以接受帶有換行的 Base64 字串,但 Unreal 對這件事比較嚴格。 為了避免跨引擎差異,原生端建議直接使用「不帶換行」的 Base64 內容。


Objective-C

// 選擇照片的 callback
- (void)onSelectPhotoSuccess:(UIImage *)chosenImage
{
    CGFloat quality = 0.8;
    NSData *data = UIImageJPEGRepresentation(chosenImage, quality);
    [self sendPhotoDataToEngine:data];
}

// 傳送處理後的 data 給遊戲引擎
- (void)sendPhotoDataToEngine:(NSData *)photoData
{
    if (photoData != nil)
    {
        // 使用 0 代表不插入換行,跨 Unity / Unreal 會比較穩定
        NSString *base64Str = [photoData base64EncodedStringWithOptions:0];

        // Use your way to Engine
    }
}

Java

// 選擇照片的 callback
private void onSelectPhotoSuccess(Bitmap bitmap) {
    int quality = 80;

    ByteArrayOutputStream out = new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.PNG, quality, out);
    sendPhotoDataToEngine(out.toByteArray());
}

// 傳送處理後的 data 給遊戲引擎
private void sendPhotoDataToEngine(byte[] data) {
    String resultString = "";

    // Unity 對 Base64.DEFAULT 的容忍度較高
    resultString = Base64.encodeToString(data, Base64.DEFAULT);

    // 若要兼容 Unreal,建議不要帶換行
    resultString = Base64.encodeToString(data, Base64.NO_WRAP);

    // Use your way to Engine
}

Unity

/// <summary>
/// 處理傳來的 base64
/// </summary>
/// <param name="base64Str">圖片資訊</param>
private void ConvertBase64ToBytes(string base64Str)
{
    byte[] bytes = System.Convert.FromBase64String(base64Str);
    ConvertBytesToTexture(bytes);
}

/// <summary>
/// 轉換為 Texture
/// </summary>
/// <param name="photoByteArray">圖片 byte array</param>
private void ConvertBytesToTexture(byte[] photoByteArray)
{
    if (photoByteArray != null)
    {
        // 如果有需要,也可以把長寬從 Java、iOS 一起傳過來
        var photoTexture = new Texture2D(width, height);
        photoTexture.LoadImage(photoByteArray);
    }
}

Unreal

// 略過相關的 C / JNI 類型轉換
void Sample::ConvertBase64ToTexture2D(FString base64Str)
{
    TArray<uint8> sourceData;
    FBase64::Decode(base64Str, sourceData);
    UTexture2D* outTexture = FImageUtils::ImportBufferAsTexture2D(sourceData);
}

Comments

Loading comments...