Unityメモ5:JSONデータ、多言語、広告設定

オリジナルゲーム作成中のUnityのメモ、その5

LitJSONで大量のJSONデータを読み込む

Unityで大量のJSONデータを読み込む場合はLitJSONを使う。

LitJSON
Zipでダウンロードして解凍してその中にsrcフォルダにLitJsonフォルダがあるので、それをそのままUnityのAssetsへ投げ込む。AssemblyInfo.cs.inだけいらない。

LitJsonの使い方

JSONデータ(Assets/Resources/JSON/Data.json)
ステージごとの味方や敵の位置のデータが入っている
[
{
 "id": 0,
 "hoge": 100,
 "players": [
  {"x": 0,"z": -2.34}
 ],
 "enemies": [
  {"x": 0,"z": 2.34}
 ]
},
{
 "id": 1,
 "hoge": 200,
 "players": [
  {"x": -1.06,"z": -2.34},
  {"x": 1.06,"z": -2.34}
 ],
 "enemies": [
  {"x": -1.06,"z": 2.34},
  {"x": 1.06,"z": 2.34}
 ] 
}

JSONデータを取り出して使える状態にしてみるスクリプト
using UnityEngine;
using LitJson;
using System;
using System.Collections;
using System.Collections.Generic;

public class DataController : MonoBehaviour {
	public List<LevelData> levelList = new List<LevelData>();

	void Awake(){
		TextAsset json = Resources.Load("JSON/Data") as TextAsset;
		LevelData[] json_data = JsonMapper.ToObject<LevelData[]>(json.text);
		levelList.AddRange (json_data);
	}

	void Start(){
		for(int i=0; i<levelList.Count; i++){
			LevelData levelData = levelList[i];

			//下記のようにデータが取れる
			levelData.hoge;
			levelData.players;
			levelData.enemies;
		}
	}
}

public class Position
{
	public double x;
	public double z;
}

public class LevelData {
	public int id;
	public int hoge;
	public List<Position> players;
	public List<Position> enemies;
}
味方や敵の配置データなどをJSONで作成しておいて、ゲームの起動ごとに読み込むようにする。

簡易な多言語対応

ちょっとした多言語対応なら下記のようにしてしまえば良い。
using UnityEngine;
using UnityEngine.UI;
using System.Collections;

public class Localization : MonoBehaviour {
	public Text localizedText;

	void Start () {
		if (Application.systemLanguage == SystemLanguage.Japanese) {
			localizedText.text = "日本語のテキストだよ";
		}
	}
}

Admobのメディエーションで広告設定

UnityでiOSとAndroidの両方でAdmobのメディエーションで広告を表示させます。iOS側の設定がやっかい。普通の320×50の広告とインタースティシャル広告(全画面広告)ができるようにする。

Google Play Games plugin for Unityをダウンロードして解凍して、その中になるcurrent-buildフォルダの中のGooglePlayGamesPlugin-0.9.11.unitypackageをダブルクリックしてUnityのプロジェクトにインポートする。

Google Mobile Ads Unity Plugin v2.1のunitypackageのやつをクリックしてUnityのプロジェクトにインポートする。

Androidの場合、このままビルドすると下記のエラーが出ます。
Error building Player: CommandInvokationFailure: Failed to re-package resources. See the Console for details.
D:\Android\sdk\build-tools\21.1.2\aapt.exe package --auto-add-overlay -v -f -m -J gen -M AndroidManifest.xml -S "res" -I "D:/Android/sdk/platforms/android-21\android.jar" -F bin/resources.ap_ --extra-packages 

stderr[
ERROR: No argument supplied for '--extra-packages' option
Android Asset Packaging Tool

Android\sdk\extras\google\google_play_services\libproject\google-play-services_lib

上記のような場所にあるフォルダ(google-play-services_lib)をAssetsのPluginsのAndroidにドロップする。


とりあえずこれで一旦準備完了です。(iOSの場合は、Xcode側でいくつかファイルのダウンロードと設定が必要になりますが、あとで記載します)

AdmobでAndroidアプリ用とiOSアプリ用を両方作って、バナー広告を設定します。
バナー広告のIDを下記のスクリプトのadUnitIdに入れます。

320×50または幅いっぱい×50のバナー広告をアプリの下にずっと表示させるスクリプト。
using System;
using UnityEngine;
using GoogleMobileAds;
using GoogleMobileAds.Api;

// Example script showing how to invoke the Google Mobile Ads Unity plugin.
public class GoogleMobileAdsBannerScript : MonoBehaviour
{
	private BannerView bannerView;

	void Awake()
	{
		RequestBanner();
		bannerView.Show();
	}
	
	private void RequestBanner()
	{
		#if UNITY_EDITOR
		string adUnitId = "unused";
		#elif UNITY_ANDROID
		string adUnitId = "INSERT_ANDROID_BANNER_AD_UNIT_ID_HERE";
		#elif UNITY_IPHONE
		string adUnitId = "INSERT_IOS_BANNER_AD_UNIT_ID_HERE";
		#else
		string adUnitId = "unexpected_platform";
		#endif
		
		// Create a 320x50 banner at the top of the screen.
		bannerView = new BannerView(adUnitId, AdSize.SmartBanner, AdPosition.Bottom);
		// Register for ad events.
		bannerView.AdLoaded += HandleAdLoaded;
		bannerView.AdFailedToLoad += HandleAdFailedToLoad;
		bannerView.AdOpened += HandleAdOpened;
		bannerView.AdClosing += HandleAdClosing;
		bannerView.AdClosed += HandleAdClosed;
		bannerView.AdLeftApplication += HandleAdLeftApplication;
		// Load a banner ad.
		bannerView.LoadAd(createAdRequest());
	}


	// Returns an ad request with custom ad targeting.
	private AdRequest createAdRequest()
	{
		return new AdRequest.Builder()
			.AddTestDevice(AdRequest.TestDeviceSimulator)
				.AddTestDevice("0123456789ABCDEF0123456789ABCDEF")
				.AddKeyword("game")
				.SetGender(Gender.Male)
				.SetBirthday(new DateTime(1985, 1, 1))
				.TagForChildDirectedTreatment(false)
				.AddExtra("color_bg", "9B30FF")
				.Build();
		
	}

	#region Banner callback handlers
	
	public void HandleAdLoaded(object sender, EventArgs args)
	{
		print("HandleAdLoaded event received.");
	}
	
	public void HandleAdFailedToLoad(object sender, AdFailedToLoadEventArgs args)
	{
		print("HandleFailedToReceiveAd event received with message: " + args.Message);
	}
	
	public void HandleAdOpened(object sender, EventArgs args)
	{
		print("HandleAdOpened event received");
	}
	
	void HandleAdClosing(object sender, EventArgs args)
	{
		print("HandleAdClosing event received");
	}
	
	public void HandleAdClosed(object sender, EventArgs args)
	{
		print("HandleAdClosed event received");
	}
	
	public void HandleAdLeftApplication(object sender, EventArgs args)
	{
		print("HandleAdLeftApplication event received");
	}
	
	#endregion
}

Admobでインタースティシャル広告を設定します。
インタースティシャル広告のIDを下記のスクリプトのadUnitIdに入れます。

ボタンをタップするとOnAd()が呼び出されてインタースティシャル広告が表示されるスクリプト。
using System;
using UnityEngine;
using UnityEngine.UI;
using GoogleMobileAds;
using GoogleMobileAds.Api;

public class GoogleMobileAdsInterstitial : MonoBehaviour {
	private InterstitialAd interstitial;

	public Text adButtonText;
	public Button backButton;

	void Awake(){
		RequestInterstitial();
	}

	void Start(){
		backButton.enabled = false;
	}

	public void OnAd(){
		ShowInterstitial();
	}

	public void BackToMenu(){
		Application.LoadLevel("TheMenu");
	}

	private void RequestInterstitial()
	{
		#if UNITY_EDITOR
		string adUnitId = "unused";
		#elif UNITY_ANDROID
		string adUnitId = "INSERT_ANDROID_INTERSTITIAL_AD_UNIT_ID_HERE";
		#elif UNITY_IPHONE
		string adUnitId = "INSERT_IOS_INTERSTITIAL_AD_UNIT_ID_HERE";
		#else
		string adUnitId = "unexpected_platform";
		#endif
		
		// Create an interstitial.
		interstitial = new InterstitialAd(adUnitId);
		// Register for ad events.
		interstitial.AdLoaded += HandleInterstitialLoaded;
		interstitial.AdFailedToLoad += HandleInterstitialFailedToLoad;
		interstitial.AdOpened += HandleInterstitialOpened;
		interstitial.AdClosing += HandleInterstitialClosing;
		interstitial.AdClosed += HandleInterstitialClosed;
		interstitial.AdLeftApplication += HandleInterstitialLeftApplication;
		// Load an interstitial ad.
		interstitial.LoadAd(createAdRequest());
	}

	private AdRequest createAdRequest()
	{
		return new AdRequest.Builder()
			.AddTestDevice(AdRequest.TestDeviceSimulator)
				.AddTestDevice("0123456789ABCDEF0123456789ABCDEF")
				.AddKeyword("game")
				.SetGender(Gender.Male)
				.SetBirthday(new DateTime(1985, 1, 1))
				.TagForChildDirectedTreatment(false)
				.AddExtra("color_bg", "9B30FF")
				.Build();
		
	}

	private void ShowInterstitial()
	{
		if (interstitial.IsLoaded())
		{
			interstitial.Show();
		}
		else
		{
			print("Interstitial is not ready yet.");
		}
	}

	#region Interstitial callback handlers
	
	public void HandleInterstitialLoaded(object sender, EventArgs args)
	{
		adButtonText.text = "Check Game Ad";
		backButton.enabled = true;

		print("HandleInterstitialLoaded event received.");
	}
	
	public void HandleInterstitialFailedToLoad(object sender, AdFailedToLoadEventArgs args)
	{
		adButtonText.text = "Failed to Load Ad";
		backButton.enabled = true;

		print("HandleInterstitialFailedToLoad event received with message: " + args.Message);
	}
	
	public void HandleInterstitialOpened(object sender, EventArgs args)
	{
		print("HandleInterstitialOpened event received");
	}
	
	void HandleInterstitialClosing(object sender, EventArgs args)
	{
		print("HandleInterstitialClosing event received");
	}
	
	public void HandleInterstitialClosed(object sender, EventArgs args)
	{
		adButtonText.text = "Thank you!";
		print("HandleInterstitialClosed event received");
	}
	
	public void HandleInterstitialLeftApplication(object sender, EventArgs args)
	{
		print("HandleInterstitialLeftApplication event received");
	}
	
	#endregion
}

インタースティシャル広告を読み込み中にシーンを移動するとクラッシュする。私の場合、インタースティシャル広告を読み込み中は、backButtonを無効にしてシーンを移動できなくさせることにした。

空のゲームオブジェクトにGoogleMobileAdsBannerScriptを追加するとバナーが下部に表示されるようになる。空のゲームオブジェクトにGoogleMobileAdsInterstitialを追加して、ボタンか何かのアクションでOnAd()を呼び出してやれば、全画面の広告が表示されるようになる。


Androidの場合、これだけで広告の追加は完了する。

問題はiOS。
いろいろ設定が必要になる。


とりあえずiOS用にUnityプロジェクトをビルドする。
ビルドしてできたフォルダをMacbookなどに移して、ここからはMacbook側で作業する。

Setupフォルダを作って、iOSで広告を表示するのに必要なファイルをダウンロードする。

downloads page

Play Games C++ SDK Version 1.3(Zip)
解凍してiosフォルダの中にあるGooglePlayGames.bundleとgpg.frameworkをSetupフォルダに移動する。

Google+ iOS SDK
Google+ iOS SDKをダウンロードして解凍して、その中にあるGoogleOpenSource.frameworkとGooglePlus.bundleとGooglePlus.frameworkをSetupフォルダに移動する。

これでSetupフォルダに必要なファイルの準備は完了。

ビルドしてできたフォルダの中にあるUnity-iPhone.xcodeprojをダブルクリックしてXcodeを起動させる。
ClassesにSetupフォルダを投げ込む。


次にBuilds Settingsを変更する。
Library Search Pathsの右側をダブルクリッくする。
下記の項目があるので”を削除する。
"$(SRCROOT)/Libraries"
// "を削除して下記のようにする。
$(SRCROOT)/Libraries

Other Linker Flagsに-ObjCを追加する。


Builds PhasesのLink Binary With Librariesに下記のフレームワークなどを追加する。
・AddressBook.framework
・AssetsLibrary.framework
・CoreData.framework
・CoreTelephony.framework
・CoreText.framework
・Security.framework
・libc++.dylib
・libz.dylib
・AdSupport.framework
・EventKit.framework
・EventKitUI.framework
・MessageUI.framework
・StoreKit.framework


iOSだとなぜか広告の表示がおかしくなるので、GADUBanner.mの一部を変更する。

LibrariesのGADUBanner.m
- (id)initWithSmartBannerSizeAndBannerClientReference:(GADUTypeBannerClientRef *)bannerClient
                                             adUnitID:(NSString *)adUnitID
                                           adPosition:(GADAdPosition)adPosition {
  // Choose the correct Smart Banner constant according to orientation.
  GADAdSize adSize;
    
    if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad){
        adSize = GADAdSizeFromCGSize(CGSizeMake(728, 90));
    } else {
        adSize = GADAdSizeFromCGSize(CGSizeMake(320, 50));
    }
    
  return [self initWithBannerClientReference:bannerClient
                                    adUnitID:adUnitID
                                      adSize:adSize
                                  adPosition:adPosition];
}


iOSデバイスがインターネットにつながっていないと、表示されていないのに広告が上部画面を邪魔してタップができなくなる。GADUBanner.mの一部を変更する。

- (void)adView:(GADBannerView *)view didFailToReceiveAdWithError:(GADRequestError *)error {
  NSString *errorMsg = [NSString
      stringWithFormat:@"Failed to receive ad with error: %@", [error localizedFailureReason]];
  self.adFailedCallback(self.bannerClient, [errorMsg cStringUsingEncoding:NSUTF8StringEncoding]);
    
    if (self.bannerView) {
        self.bannerView.hidden = YES;
    }
}

これでようやくiOSデバイスで広告が表示されるようになります。

iAdは設定しないほうが良い。バナーの高さが異なり、Admobの広告と一緒だとうまく表示されない。あとiAd用の不思議ファイルを入れないとたまにクラッシュする。とりあえずAdmobだけ表示させて、アプリがヒットした時に本格的に広告のメディエーションに取り組むのが無難。

コメントを残す

メールアドレスが公開されることはありません。