PlayMaker」タグアーカイブ

[Unity, PlayMaker]:DontDestroyOnLoadの不具合

PlayMaker 1.7.8.2

アクションカテゴリ「Level」のアクション「DontDestroyOnLoad」で指定したGameObjectがシーンロード時に消えてしまいます。

DontDestroyOnLoadアクションのソースを見てみると…

// (c) Copyright HutongGames, LLC 2010-2013. All rights reserved.

using System.Collections;
using UnityEngine;

namespace HutongGames.PlayMaker.Actions
{
	[ActionCategory(ActionCategory.Level)]
	[Tooltip("Makes the Game Object not be destroyed automatically when loading a new scene.")]
	public class DontDestroyOnLoad : FsmStateAction
	{
		[RequiredField]
        [Tooltip("GameObject to mark as DontDestroyOnLoad.")]
		public FsmOwnerDefault gameObject;

		public override void Reset()
		{
			gameObject = null;
		}

		public override void OnEnter()
		{
			// Have to get the root, since the game object will be destroyed if any of its parents are destroyed.
			
			Object.DontDestroyOnLoad(Owner.transform.root.gameObject);

			Finish();
		}
	}
}

せっかく引数で指定したgameObjectが指定されていません。
代わりにこのアクションを実行しているFSMを持つGameObjectがDontDestroyOnLoadになっているようです。

25行目を以下のように変更します。

			if (gameObject != null) Object.DontDestroyOnLoad(gameObject.GameObject.Value);

[Unity, PlayMaker]:Androidビルドで勝手にパーミッションが追加される

検証バージョン:Unity 4.5.5f1, PlayMaker 1.7.7f6

PlayMakerをインポートしたプロジェクトをAndroid向けにビルドすると、以下の権限(パーミッション)が勝手に追加されます。

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.WAKE_LOCK" />

Unity自体が、特定のAPIを使用した場合にビルド時に自動的に権限を追加する仕様になっています。
一旦Androidプロジェクトを吐き出してからビルドする場合は変更できますが、直接apkを書き出す場合は厄介です。

もし該当する機能を使っていないのならば、PlayMakerのアクションを記述してあるスクリプトファイルを最初に削除してしまえば済むことです。

・android.permission.INTERNET
/PlayMaker/Actions/Network フォルダごと削除

・android.permission.VIBRATE
/PlayMaker/Actions/DeviceVibrate.cs

・android.permission.ACCESS_FINE_LOCATION
/PlayMaker/Actions/GetLocationInfo.cs
/PlayMaker/Actions/StartLocationServiceUpdates.cs
/PlayMaker/Actions/StopLocationServiceUpdates.cs

・android.permission.WAKE_LOCK
/PlayMaker/Actions/DevicePlayFullScreenMovie.cs

[参考]:apkに付与されている権限を調べる方法
aaptというADT付属のツールで調べることが出来ます。
詳しくはこちらを参考にさせて頂きました。
Yukiの枝折 – 「apkからマニフェストの内容を読み取る方法」

[Unity]:PlayMaker カスタムアクション入門

PlayMakerではアクションという処理の単位を組合せて、処理を記述していきます。

PlayMaker公式アクションリファレンス(英語)

標準でもかなりの数のアクションが用意されていますが、実際にPlayMakerを使って作業していると標準のものでは処理を実現できそうもない場合が出てきます。
その場合はカスタムアクションを自分で作成して、標準のアクションと同様にPlayMakerで使用することができます。

ここではPlayMaker標準で用意されている「IntOperator」アクションを例にとり、アクションの記述の仕方を解説していきます。
「IntOperator」は2つのInt値と計算方法を指定し、その結果を指定のInt型変数に代入するアクションです。

namespace HutongGames.PlayMaker.Actions
{
	・・・
}

独自のネームスペースを使うことも可能ですが、特に理由が無い限りはHutongGames.PlayMaker.Actionsを使用するのが無難です。

namespace HutongGames.PlayMaker.Actions
{
	[ActionCategory(ActionCategory.Math)]
	[Tooltip("Performs math operation on 2 Integers: Add, Subtract, Multiply, Divide, Min, Max.")]
	public class IntOperator : FsmStateAction
	{
		・・・
	}
}

PlayMakerのアクションブラウザに表示される時のカテゴリを指定します。

PlayMakerActionBrowser

標準のカテゴリに追加することもできますし、独自のカテゴリに追加することもできます。
独自のカテゴリに追加したい場合は以下のようにカテゴリ名を文字列で指定します。

	[ActionCategory("CustomCategory")]
namespace HutongGames.PlayMaker.Actions
{
	[ActionCategory(ActionCategory.Math)]
	[Tooltip("Performs math operation on 2 Integers: Add, Subtract, Multiply, Divide, Min, Max.")]
	public class IntOperator : FsmStateAction
	{
		・・・
	}
}

アクションブラウザに表示するアクションの説明文を指定します。

PlayMakerActionBrowserPreview

省略しても構いません。

namespace HutongGames.PlayMaker.Actions
{
	[ActionCategory(ActionCategory.Math)]
	[Tooltip("Performs math operation on 2 Integers: Add, Subtract, Multiply, Divide, Min, Max.")]
	public class IntOperator : FsmStateAction
	{
		・・・
	}
}

HutongGames.PlayMaker.FsmStateActionを継承させます。

		[RequiredField]
		public FsmInt integer1;
		[RequiredField]
		public FsmInt integer2;
		public Operation operation = Operation.Add;
		[RequiredField]
		[UIHint(UIHint.Variable)]
		public FsmInt storeResult;
		public bool everyFrame;

PlayMakerIntOperator

PlayMakerエディタ上に表示されるパラメータとなります。
「RequiredField」属性を指定すると省略不可となり、エディタ上で適切な値を指定しない場合にエラーとなります。

「UIHint」属性を指定することで、エディタ上での表示の仕方を変えることができます。
「UIHint.Variable」を指定した場合には、FSMで用意した変数から選択することしかできなくなります。

メンバ変数の型を「Fsm〜」という型で指定することにより、エディタの機能を利用した便利な指定ができるようになります。
ここではFsmIntしか登場しませんが、他にFsmFloatやFsmStringなど様々な型が用意されています。

また、通情のC#の型も使用することができます。ここでは「everyFrame」がbool型で宣言されています。

		public override void Reset()
		{
			integer1 = null;
			integer2 = null;
			operation = Operation.Add;
			storeResult = null;
			everyFrame = false;
		}

新規にアクションを追加した場合の初期値、またはエディタ上でリセットをかけた場合にセットされる値を指定します。

		public override void OnEnter()
		{
			DoIntOperator();
			
			if (!everyFrame)
				Finish();
		}

アクションが実行される時に呼び出されます。
この中に直接処理を記述しても構いませんが、ここでは実際の処理は「DoIntOperator()」の中に記述されています。
処理の終了には必ず「Finish()」を呼び出す必要があります。
ただし、ここでは毎フレームの処理を行う場合は処理を終了させたく無いのでeneryFameフラグにより条件分岐されています。

		// NOTE: very frame rate dependent!
		public override void OnUpdate()
		{
			DoIntOperator();
		}

毎フレーム実行される処理を記述します。

		void DoIntOperator()
		{
			int v1 = integer1.Value;
			int v2 = integer2.Value;

			switch (operation)
			{
				case Operation.Add:
					storeResult.Value = v1 + v2;
					break;

				case Operation.Subtract:
					storeResult.Value = v1 - v2;
					break;

				case Operation.Multiply:
					storeResult.Value = v1 * v2;
					break;

				case Operation.Divide:
					storeResult.Value = v1 / v2;
					break;

				case Operation.Min:
					storeResult.Value = Mathf.Min(v1, v2);
					break;

				case Operation.Max:
					storeResult.Value = Mathf.Max(v1, v2);
					break;
			}
		}

「Fsm〜」型の変数はValueプロパティにより実際の値にアクセスすることができます。
注意点としてはin/outの区別が無いので、処理を記述する際に余計な値を変更してしまわないようにしましょう。

ーーーーー
以上のようにカスタムアクションはとても簡単に作成することができます。
GameObjectの参照をとったり、より複雑な処理をする場合は、標準のアクションの中から似たような処理をするものを見つけ、そのスクリプトを参考にすると良いでしょう。
アクションブラウザ上でアクションの右クリックメニューから簡単にスクリプトを参照することができます。

[Unity]:PlayMaker実践解説 (2)

今回はタイトル画面でスタートボタンが押された時の処理を解説していきます。

ArchuTitle ArchuTitleHierarchy2

○ StartButton
NGUIのUIButtonコンポーネントを持つボタンのGUI部品です。
NGUIのイベントをFSMに通知するためにPlayMakerの開発元から提供されているNGUIアドインをセットしてあります。

スタートボタンを押すと初回はプロローグ画面へ、その後はゲーム画面へ遷移するようになっています。

ArchuStartButtonFSM

ArchuStartButtonFSMEvent

ArchuStartButtonFSMVariable

1. Init
シーンが読込まれPlayMakerFSMが動き出した時に初めに到達する状態(ステート)です。
前回紹介したTitleControllerのInitとはほぼ同時(順不同)で動作します。
UnityのスクリプトにおけるAwake()の実行順と同じとイメージすれば良いでしょう。
ただしPlayMakerの場合は実行順を制御する機構がないようですので、FSM同士の関連には注意が必要です。
(※:未確認ですがUnityのスクリプトの実行順制御によりPlayMakerFSMの実行順も制御できるかもしれません。PlayMakerFSM自体も一種のコンポーネントですので。)

ArchuStartButtonInit

1-1. Stop Activity Indicator(カスタム)
処理中を示すインジケーター(くるくる回転するアイコン)を停止・非表示にします。

2. Idle
何も行いません。
ボタンが押下された時に「NGUI / ON CLICK」イベントが来るのを待ち受けます。

ArchuStartButtonIdle

3. OnClick
Idleの状態からボタンが押下された時に遷移する状態です。

ArchuStartButtonOnClick

3-1. Stop BGM(カスタム)
再生中のBGMを停止します。

3-2. Play Start Button SE(カスタム)
スタートボタン押下の効果音を再生します。

4. CheckPrologue
スタートボタン押下後に到達するステートです。
初回起動かどうかを判断して、プロローグかゲーム画面に遷移を振り分けます。
上記のOnClick中に書いても良い処理ですが、分かり易さのために分けてあります。

ArchuStartButtonCheckPrologue

4-1. PlayerPrefs Get Int(PlayerPrefs)
PlayerPrefに保存されている物語の進行度を表す数値を取り出し、変数storyにセットします。
Unity標準のPlayerPrefs.GetInt()と同様のアクションですが、複数の値を同時に扱えるのが少し便利です。

4-2. Int Compare(Logic)
さきほど取り出したstoryの値が1以上なら「START_GAME」イベントを発生しゲーム画面へ遷移する処理へ、1未満なら「FINISHED」イベントを発生しプロローグへ遷移する処理へ移ります。

5. StartPrologue
初めてスタートボタンを押した時に到達するステートです。

ArchuStartButtonStartPrologue

5-1. Activate Game Object(GameObject)
インスペクタ上で指定したフェードアウト用のNGUIスプライトを有効にします。
Unity標準のGameObject.SetActive()と同様のアクションです。

5-2. Wait(Time)
1.1秒間待機した後に指定のイベント(今回は指定してないのでFINISHEDイベント)を発生します。
このように待機した後に処理を行いたい場合は、別の状態を用意してイベントにより遷移させる必要があります。
このアクションが途中に挟まれていたとしても、以降のアクションも全て実行される点に注意が必要です。

6. LoadLevelPrologue
プロローグ画面へ遷移します。

ArchuStartButtonLoadLevelPrologue

6-1. Move Off Ad Banner(カスタム)
広告バナーを画面外に隠します。

6-2. Load Level(Level)
「Prologue」という名前のシーンをロードします。
UnityのApplication.LoadLevel()にあたるアクションですが、Additive/Asyncなどがオプションとして選択できるようになっています。

7. StartGame
すでにゲームをやったことがある場合にスタートボタンを押すと到達するステートです。
内容は前述の「5. StartPrologue」とほぼ同様なので説明は省略します。

ArchuStartButtonStartGame

8. LoadLevelGame
ゲーム画面へ遷移します。
さきほどのプロローグ画面への遷移と違いロード中画面を挟んだ遷移なので、アクションの内容が異なっています。

ArchuStartButtonLoadLevelGame

6-1. Play Game BGM(カスタム)
ゲーム画面用のBGMの再生を開始します。

6-2. Load Lovel Transition(カスタム)
ロード中画面を表示した上で「Stage01」という名前のシーンをロードします。

ーーーーー
今回の中では「2. Idle」の何もアクションの無い状態が特徴的だったと思います。
こういう状態を用意することで、外部からの操作でイベントを飛ばしてもらって処理を行うというような記述が可能になります。

また、プロローグの場合とゲーム画面の場合でフェードアウトの処理を変えていたり、BGMを止めたり、ロード中画面を挟んだりなど微妙な調整を色々としています。
これがどのような違いを生むかは、もうじきリリース予定の「あ〜ちゃ〜の大冒険」でぜひ確認してみて欲しいと思います。

[Unity]:PlayMaker実践解説 (1)

スマホアプリ「あ〜ちゃ〜の大冒険」(2014年12月下旬リリース予定)は、実験的にPlayMakerというコーディング無しで処理を記述できるアセットを全面的に利用して作りました。
そこで実際にPlayMakerを使ってどのように処理を記述しているかを公開します。

PlayMaker自体の詳細に関しては、公式の紹介動画・チュートリアル動画で概要は掴んで頂けると思います。
また少ないながらも日本語で解説されているサイトもありますのでそちらを参照して下さい。

PlayMaker
公式サイト
アセットストア

初回は、小手調べということでアプリのタイトル画面の初期化を管理しているFSM(PlayMakerの処理内容を記述したもの)をご紹介します。

タイトル画面
ArchuTitle TitleControllerHierarchy

○ TitleController
ここでは広告の初期化、またアプリ内で唯一となる音源を管理するゲームオブジェクトAudioManagerを作成しBGMを再生します。

TitleControllerFSM

TitleControllerEvent

TitleControllerVariable

1. Init
シーンが読込まれPlayMakerFSMが動き出した時に初めに到達する状態(ステート)です。

TitleControllerInit

1-1. Init Ad Banner(カスタム)
自分で作成したカスタムアクションでiOS/Androidそれぞれのネイティブプラグインを呼び出し、広告バナーの初期化・表示を行います。
カスタムアクションに関しては下記を参考にして下さい。

 [Unity]:PlayMaker カスタムアクション入門

1-2. Find Game Object(GameObjectカテゴリ)←括弧内はPlayMakerで用意されたアクションのカテゴリを示します。
「AudioManager」というタグが付けられたGameObjectを取得し、変数audioManagerにセットします。
存在しなければnullになります。

1-3. Game Object Is Null(Logic)
audioManagerがnullかどうかを調べます。
nullの場合は「NO_AUDIO_MANAGER」というイベントを発生し遷移、nullでない場合は通常終了し「FINISHED」イベントによる遷移を行います。

2. CreateAudioManager
InitでAudioManagerが存在しなかった場合に到達するステートです。
このステートでは特に遷移イベントを指定していませんが、その場合は全てのアクション実行後に自動的にFINISHEDイベントによる遷移が行われます。

TitleControllerCreateAudioManager

2-1. Create Object(GameObject)
インスペクタで指定してあるAudioManagerのプレファブからインスタンスを作成し、変数audioManagerにセットします。

2-2. Dont Destroy On Load(Level)
audioManagerがシーンロード時に破棄されないように設定します。

3. PlayTitleBGM
タイトル画面のBGMを再生します。

TitleControllerPlayTitleBGM

3-1. Play Title BGM(カスタム)
AudioManagerの機能を利用してタイトル画面のBGMを再生するカスタムアクションです。

ーーーーー
状態(ステート)が3つ、それぞれのアクションも少ないですが、PlayMakerによる実装の感じは掴んで頂けたと思います。
状態遷移というよりは処理の固まりを遷移していくようなイメージになっているのは私のクセという部分もあります。

変数がFSM単位で用意され、スクリプトでいうところのメソッドのローカル変数のようなものが存在しないのが特徴と言えます。
また条件分岐の場合には必ず状態遷移を引き起こすというのもクセのあるところです。

今回、これだけ少ないアクションの中で2ヶ所もカスタムアクションが登場しましたが、少し込み入ったことをしようと思うとカスタムアクションを作成した方が楽です。
PlayMaker標準でMonoBehaviourのメソッドを呼び出すアクションが存在しますが、上手く利用出来ませんでした。

次回はタイトル画面でスタートボタンを押した時のFSMを紹介する予定です。