宴というノベルゲームエンジンがあります。UnityのAsset Storeで提供されていて、機能も豊富で大変すばらしいのですが、
動画を再生しようとしたらしんどかった話をします。
執筆時の環境
Unity: 2017.4.5f1
宴: 3.4.7
宴にはVideoコマンドが用意されていて、それを使えばムービーが再生されます。
しかし、音が出ません。
まあ音が出ないこと自体はドキュメントに描いてある通りなので、どうやって音を出すか考えました。
宴3.4.7のリリースノートにVideoコマンド音声対応みたいに書いてある!やったー!やってみよう!
↓↓結果↓↓
だめでした。
2018.2 では確かに音が出るようになっているのですが、2017.4 ではダメなようです。
2017.4.5f1でそこそこ開発が進んだ後だったので、2018へのアップデートはしたくありません。
ドキュメントにはBgmコマンドと組み合わせるべし、と書いてありますが、
その場合は自分で忘れずにStopBgmしなければいけませんし、動画と音声の同期にも不安が残ります。
そもそも音が出ないのはUnity側のVideoPlayerの仕様が不安定なせいですので、
2017.4.5用のWorkaroundを書くことでどうにかしようと考えました。
Qiitaの記事などを参考にして試したところ、
2017.4.5のVideoPlayerで音を出すにはDirectではダメで、VideoPlayerのAudioTrackにAudioSourceを設定してあげないといけないようでした。
実際にVideoPlayerを使って再生処理をしているファイルを書き換えます。
Utage/Scripts/ADV/Graphic/Video/AdvVideoManager.cs
internal void Play(string label, string cameraName, VideoClip clip, bool loop, bool cancel)
{
VideoInfo info = new VideoInfo() { Cancel = cancel, };
Videos.Add(label, info);
GameObject go = this.transform.AddChildGameObject(label);
VideoPlayer videoPlayer = go.AddComponent<VideoPlayer>();
float volume = Engine.SoundManager.BgmVolume * Engine.SoundManager.MasterVolume;
videoPlayer.SetDirectAudioVolume(0, volume);
videoPlayer.isLooping = loop;
// Unity 2017.4.5f1 workaround
AudioSource audioSource = go.AddComponent<AudioSource>();
float volume = Engine.SoundManager.BgmVolume * Engine.SoundManager.MasterVolume;
audioSource.volume = volume;
videoPlayer.audioOutputMode = VideoAudioOutputMode.AudioSource;
videoPlayer.EnableAudioTrack(0, true);
videoPlayer.SetTargetAudioSource(0, audioSource);
// Unity 2017.4.5f1 workaround end
videoPlayer.isLooping = loop;
videoPlayer.clip = clip;
videoPlayer.targetCamera = Engine.EffectManager.FindTarget(AdvEffectManager.TargetType.Camera, cameraName).GetComponentInChildren<Camera>();
videoPlayer.renderMode = VideoRenderMode.CameraNearPlane;
videoPlayer.aspectRatio = VideoAspectRatio.FitInside;
videoPlayer.Play();
videoPlayer.started += (x => OnStarted(info));
info.Player = videoPlayer;
}
private void Update()
{
if (Videos.Count <= 0) return;
foreach (var keyValue in Videos)
{
var player = keyValue.Value.Player;
if (player == null || !player.isPlaying) continue;
float volume = Engine.SoundManager.BgmVolume * Engine.SoundManager.MasterVolume;
// Unity 2017.4.5f1 workaround
player.GetTargetAudioSource(0).volume = volume;
}
で、エディタ上で再生してみました。
↓↓結果↓↓
だめでした。
……なんで?
Edittor上でAudioSourceの参照を設定した場合はちゃんと再生されてるのに……スクリプト経由ではダメなのでしょうか?
と、とりあえず、ビルドして確認してみましょう……
↓↓結果↓↓
音が鳴りました。
……なんで?
かなり腑に落ちませんが、ともかくビルドした実行ファイルでは正常に再生されているのでとりあえずこれで行くことにします。
もう一つ、別の問題がありました。
ムービー再生中にゲームウィンドウを非アクティブにしてゲームを中断状態にすると、
そこから復帰するときにムービー再生が強制中断されてしまうのです。
こちらの原因はIsEndPlay()
にありました。
VideoPlayer.isPlaying
で再生中かどうかを判別しているのですが、このプロパティが復帰直後にはfalse
になるようなのです。
internal bool IsEndPlay(string label)
{
if (!Videos.ContainsKey(label)) return true;
//キャンセル済み
if (Videos[label].Canceled) return true;
//まだロード終ってないなら
if (!Videos[label].Started) return false;
//最初の0フレームで呼ばれることがある模様
return Videos[label].Player.time > 0 && !Videos[label].Player.isPlaying;
// return !Videos[label].Player.isPlaying;
}
こちらに関しては、
https://forum.unity.com/threads/how-to-know-video-player-is-finished-playing-video.483935/
を参考にして終了判定をVideoPlayer.loopPointReached
イベントを利用したものに書きかえました。
--- a/Assets/Utage/Scripts/ADV/Graphic/Video/AdvVideoManager.cs
+++ b/Assets/Utage/Scripts/ADV/Graphic/Video/AdvVideoManager.cs
@@ -28,7 +28,8 @@ namespace Utage
public bool Cancel { get; set; }
public bool Started { get; set; }
public bool Canceled { get; set; }
- public VideoPlayer Player { get; set; }
+ public bool Loop { get; set; }
+ public bool Ended { get; set; }
+ public VideoPlayer Player { get; set; }
}
Dictionary<string, VideoInfo> Videos { get { return videos; } }
@@ -41,20 +42,33 @@ namespace Utage
internal void Play(string label, string cameraName, VideoClip clip, bool loop, bool cancel)
{
- VideoInfo info = new VideoInfo() { Cancel = cancel, };
+ VideoInfo info = new VideoInfo() { Cancel = cancel, Loop = loop, Ended = false};
Videos.Add(label, info);
GameObject go = this.transform.AddChildGameObject(label);
VideoPlayer videoPlayer = go.AddComponent<VideoPlayer>();
- float volume = Engine.SoundManager.BgmVolume * Engine.SoundManager.MasterVolume;
- videoPlayer.SetDirectAudioVolume(0, volume);
- videoPlayer.isLooping = loop;
+
+ // Unity 2017.4.5f1 workaround
+ AudioSource audioSource = go.AddComponent<AudioSource>();
+ float volume = Engine.SoundManager.BgmVolume * Engine.SoundManager.MasterVolume;
+ audioSource.volume = volume;
+
+ videoPlayer.audioOutputMode = VideoAudioOutputMode.AudioSource;
+ videoPlayer.EnableAudioTrack(0, true);
+ videoPlayer.SetTargetAudioSource(0, audioSource);
+ // Unity 2017.4.5f1 workaround end
+
+ videoPlayer.isLooping = loop;
videoPlayer.clip = clip;
videoPlayer.targetCamera = Engine.EffectManager.FindTarget(AdvEffectManager.TargetType.Camera, cameraName).GetComponentInChildren<Camera>();
videoPlayer.renderMode = VideoRenderMode.CameraNearPlane;
videoPlayer.aspectRatio = VideoAspectRatio.FitInside;
videoPlayer.Play();
videoPlayer.started += (x => OnStarted(info));
- info.Player = videoPlayer;
+
+ // 終わったらフラグを立てる
+ videoPlayer.loopPointReached += (x => OnEnd(info));
+
+ info.Player = videoPlayer;
}
void OnStarted(VideoInfo info)
@@ -62,7 +76,13 @@ namespace Utage
info.Started = true;
}
+ // 終わったらフラグを立てる
+ void OnEnd(VideoInfo info)
+ {
+ info.Ended = true;
+ }
+
internal void Cancel(string label)
{
if (!Videos[label].Cancel)
{
@@ -81,9 +101,12 @@ namespace Utage
//まだロード終ってないなら
if (!Videos[label].Started) return false;
- //最初の0フレームで呼ばれることがある模様
- return Videos[label].Player.time > 0 && !Videos[label].Player.isPlaying;
-// return !Videos[label].Player.isPlaying;
+ // 終わってたら
+ return !Videos[label].Loop && Videos[label].Ended;
}
//終了処理
@@ -106,7 +129,9 @@ namespace Utage
if (player == null || !player.isPlaying) continue;
float volume = Engine.SoundManager.BgmVolume * Engine.SoundManager.MasterVolume;
- player.SetDirectAudioVolume(0, volume);
+ // Unity 2017.4.5f1 workaround
+ player.GetTargetAudioSource(0).volume = volume;
}
}
#else
Unity2018.2を使いましょう。何もしなくても音が出ます。
Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。
また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!
こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?
コメント