tag:crieit.net,2005:https://crieit.net/users/koya_bot2/feed
ドッグの投稿 - Crieit
Crieitでユーザードッグによる最近の投稿
2020-06-29T02:47:22+09:00
https://crieit.net/users/koya_bot2/feed
tag:crieit.net,2005:PublicArticle/15986
2020-06-29T02:39:09+09:00
2020-06-29T02:47:22+09:00
https://crieit.net/posts/koya-abc172-d
AtCoder Beginner Contest 172 D - Sum of Divisors
<h1 id="問題文"><a href="#%E5%95%8F%E9%A1%8C%E6%96%87">問題文</a></h1>
<p>要約:<br />
k=1からNまで、<img src="http://chart.apis.google.com/chart?cht=tx&chl=k%20*%20f(k)" alt="k * f(k)" /> を足し上げる。<br />
ただし、<img src="http://chart.apis.google.com/chart?cht=tx&chl=f(k)" alt="f(k)" />とは、正の整数であって、kの約数であるものの個数。</p>
<p><a target="_blank" rel="nofollow noopener" href="https://atcoder.jp/contests/abc172/tasks/abc172_d">https://atcoder.jp/contests/abc172/tasks/abc172_d</a></p>
<h1 id="O(N^2)"><a href="#O%28N%5E2%29">O(N^2)</a></h1>
<p><img src="http://chart.apis.google.com/chart?cht=tx&chl=1%20\le%20j%20\le%20k" alt="1 ≦ j ≦ k" /> なるすべての j について、ループを回して k の約数であるかを調べると <img src="http://chart.apis.google.com/chart?cht=tx&chl=O%28N^2%29" alt="O(N^2)" />になります。<br />
<a href="https://crieit.now.sh/upload_images/5b556d92f0305f87aa876d79c8c86a875ef8bb4e364c6.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/5b556d92f0305f87aa876d79c8c86a875ef8bb4e364c6.png?mw=700" alt="image" /></a></p>
<pre><code class="cpp">#include <iostream>
using ll = long long;
ll f_n2(int N)
{
ll ans = 0;
for (int k = 1; k <= N; ++k)
{
// 約数カウンタ
int c = 0;
for (int j = 1; j <= N; ++j)
{
// 割り切れるなら増やす
if (k % j == 0) ++c;
}
ans += (ll)k * c;
}
return ans;
}
int main()
{
int N;
std::cin >> N;
ll ans = f_n2(N);
std::cout << ans << '\n';
}
</code></pre>
<p><code>N <= 10^7</code> ですので、当然、3secには間に合いません。</p>
<h1 id="O(N√N)"><a href="#O%28N%E2%88%9AN%29">O(N√N)</a></h1>
<p>約数を数える部分は<img src="http://chart.apis.google.com/chart?cht=tx&chl=O%28\sqrt%20N%29" alt="O(√N)" /> にできます。</p>
<p>たとえば 20 の約数がいくつあるか数えることを考えましょう。<br />
20 = 1 * 20<br />
20 = 2 * 10<br />
20 = 4 * 5</p>
<p>このように、割り切れたときには必ず相方がいることが分かります。<br />
左側は必ず√20 より小さく、右側は必ず√20 より大きくなっているので、<br />
(そうしないと、掛けたときに20になりません)<br />
√20 = 4.47... まで探索して2倍すれば十分であることが分かります。</p>
<p>ただし、16のような平方数では、<br />
16 = 1 * 16<br />
16 = 2 * 8<br />
16 = 4 * 4</p>
<p>このようになることがあるので、<br />
√k ぴったりのときは1つしか数えないような工夫が必要です。<br />
<a href="https://crieit.now.sh/upload_images/d288b0b0de53bab5a2c736d5d6b63b955ef8bd84e9ace.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/d288b0b0de53bab5a2c736d5d6b63b955ef8bd84e9ace.png?mw=700" alt="image" /></a></p>
<pre><code class="cpp">#include <iostream>
#include <cmath>
using ll = long long;
ll f_nsqn(int N)
{
ll ans = 0;
for (int k = 1; k <= N; ++k)
{
// 約数カウンタ
int c = 0;
int sqk = (int)sqrt(k);
for (int j = 1; j <= sqk; ++j)
{
if (k % j == 0)
{
// k = j * j
if (k / j == j)
c++;
// それ以外
else
c += 2;
}
}
ans += (ll)k * c;
}
return ans;
}
int main()
{
int N;
std::cin >> N;
ll ans = f_nsqn(N);
std::cout << ans << '\n';
}
</code></pre>
<p>N = 10^7 のとき、N√N = 3 * 10^10 くらいになるので、これでも間に合いません。</p>
<h1 id="O(NlogN)"><a href="#O%28NlogN%29">O(NlogN)</a></h1>
<p>k の約数を探しにいくのではなく、k 自身が将来の数の約数である、というふうに考えてみます。</p>
<p>たとえば、k=2 とすると、<br />
2, 4, 6, 8, 10 はすべて 2 の倍数であり、<br />
言い換えると、これらはすべて 2 を約数にもつ数でもあります。<br />
したがって、f(2), f(4), f(6), f(8), f(10) は 2 が約数であることを知ることができます。<br />
約数の数がひとつ増えたことになるので、+1 しておきます。<br />
このようにすると、たとえば f(10) は、k=1, 2, 5, 10 のときに +1 されることになり、<br />
これはつまり約数の数になっています。<br />
<a href="https://crieit.now.sh/upload_images/3069b2ecca771b8ee9b57dee6b0b69425ef8c147ace0b.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/3069b2ecca771b8ee9b57dee6b0b69425ef8c147ace0b.png?mw=700" alt="image" /></a></p>
<p>図を見ると分かるように、これのループ回数は<br />
N + N/2 + N/3 + ...... + N/N<br />
になっています。</p>
<p>これの計算量を見積もるのは難しそうですが、<br />
1/1 + 1/2 + 1/3 + ...... + 1/N<br />
の形の和を調和級数と呼び、なんとその値はだいたいlogNになります。<br />
したがって、この解法の計算量は<img src="http://chart.apis.google.com/chart?cht=tx&chl=O(N%5Clog%20N)" alt="O(NlogN)" />です。</p>
<p>約数列挙の方針では「約数かどうかを判定してみたものの約数ではなかった」という場合があるのに対して、<br />
こちらでは必ず約数になっています。直感的にも、こちらのほうが効率がよさそうです。</p>
<pre><code class="cpp">#include <iostream>
#include <vector>
using ll = long long;
ll f_nlogn_memo(int N)
{
std::vector<int> p(N+1, 0);
for (int k = 1; k <= N; ++k)
{
for (int j = k; j <= N; j += k)
{
// k, 2k, 3k, ... の約数カウントを増やす
++p[j];
}
}
ll ans = 0;
for (int k = 1; k <= N; ++k)
{
ans += (ll)k * p[k];
}
return ans;
}
int main()
{
int N;
std::cin >> N;
ll ans = f_nlogn_memo(N);
std::cout << ans << '\n';
}
</code></pre>
<p>C++でギリギリ通ります。<br />
空間計算量がO(N)なので、10^7 ものメモリを確保するのが遅いのかもしれません。</p>
<h1 id="O(NlogN) その2"><a href="#O%28NlogN%29+%E3%81%9D%E3%81%AE2">O(NlogN) その2</a></h1>
<p>もとの問題に立ち返ってみると、求めたいものは k * f(k) の総和でした。</p>
<p>ここまでの図をじーっと見ていると、<br />
そもそも○を使う必要はなく、数字で埋めてしまっていいことがわかります。<br />
この表中の数字をすべて足しさえすればよいので、<br />
配列を使わなくても実装できます。<br />
<a href="https://crieit.now.sh/upload_images/dc494292a387e6a735bd8357d917d82a5ef8c6a103de3.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/dc494292a387e6a735bd8357d917d82a5ef8c6a103de3.png?mw=700" alt="image" /></a></p>
<pre><code class="cpp">#include <iostream>
using ll = long long;
ll f_nlogn(int N)
{
ll ans = 0;
for (int k = 1; k <= N; ++k)
{
for (int j = k; j <= N; j += k)
{
// 数字を直接足し込む
ans += j;
}
}
return ans;
}
int main()
{
int N;
std::cin >> N;
ll ans = f_nlogn(N);
std::cout << ans << '\n';
}
</code></pre>
<p>C++では余裕をもって通ります。<br />
言語によってはこれでもまだ通らないことがあるようです。<br />
(Rubyで6300ms前後でした)</p>
<h1 id="O(N)"><a href="#O%28N%29">O(N)</a></h1>
<p>「表中の数字をすべて足し上げる」という方針をもってさらに図を見つめていると、<br />
横方向の足し算は等差数列の和であり、O(1) で計算できてしまうことが分かります。<br />
横方向がO(1) で計算できたので、全体ではO(N)になります。<br />
<a href="https://crieit.now.sh/upload_images/b8bcba0c3337ab7fa5a44a20edcdd8a45ef8cc92edc77.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/b8bcba0c3337ab7fa5a44a20edcdd8a45ef8cc92edc77.png?mw=700" alt="image" /></a></p>
<pre><code class="cpp">#include <iostream>
using ll = long long;
// 1からnまでの和
ll sn(ll n)
{
return (ll)n * (n+1) / 2;
}
ll f_n(int N)
{
ll ans = 0;
for (int k = 1; k <= N; ++k)
{
ans += sn(N/k) * k;
}
return ans;
}
int main()
{
int N;
std::cin >> N;
ll ans = f_n(N);
std::cout << ans << '\n';
}
</code></pre>
<h1 id="O(√N)"><a href="#O%28%E2%88%9AN%29">O(√N)</a></h1>
<p>表中の数字をすべて足し上げればよいので、もはや見た目の順番通りに足す必要はありません。<br />
表の数字を左に詰めると、対称性が見てとれます。<br />
√N 個のL字型について、1つのL字は O(1) で計算できるので、<br />
全体で O(√N) で計算ができます。<br />
<a href="https://crieit.now.sh/upload_images/20514c2e76826449995092ca734237295ef8d09be4d0a.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/20514c2e76826449995092ca734237295ef8d09be4d0a.png?mw=700" alt="image" /></a></p>
<pre><code class="cpp">#include <iostream>
#include <cmath>
using ll = long long;
ll sn(ll n)
{
return (ll)n * (n+1) / 2;
}
ll f_sqn(int N)
{
int sqN = (int)sqrt(N);
ll ans = 0;
for (int k = 1; k <= sqN; ++k)
{
ans += (sn(N/k) - sn(k)) * k * 2 + k * k;
}
return ans;
}
int main()
{
int N;
std::cin >> N;
ll ans = f_sqn(N);
std::cout << ans << '\n';
}
</code></pre>
<h1 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h1>
<p>いろんなオーダーの解法があって、少しずつ改善されていく様子が面白かったです。</p>
<p>なお、<img src="http://chart.apis.google.com/chart?cht=tx&chl=O(N%5E%7B%5Cfrac%7B1%7D%7B3%7D%7D)" alt="O(N^1/3)" />の方法もあるらしいです。</p>
ドッグ
tag:crieit.net,2005:PublicArticle/15912
2020-05-27T00:37:49+09:00
2020-05-27T00:37:49+09:00
https://crieit.net/posts/3-5ecd37cd1df35
宴3でルート分岐チャートを実装する
<p>Unity上で動くノベルゲームエンジンはいろいろありますが、<br />
わたしは宴が好きです。<br />
日本式のノベルゲームに必要な機能は全部入っているくらいに機能が充実しているのはもちろんのこと、<br />
初心者でも扱える簡便さとスクリプトでの細かいカスタマイズを両立しているのが特徴です。<br />
そんな宴をベースに、今回はシナリオチャート画面を実装していきます。</p>
<p><a href="https://crieit.now.sh/upload_images/38c037300dffa5073d99be9d13c7ea795ecd36fed2ad4.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/38c037300dffa5073d99be9d13c7ea795ecd36fed2ad4.png?mw=700" alt="チャート" /></a></p>
<h2 id="「ボタンを押すと対応するシナリオラベルに飛ぶ」Buttonをつくる"><a href="#%E3%80%8C%E3%83%9C%E3%82%BF%E3%83%B3%E3%82%92%E6%8A%BC%E3%81%99%E3%81%A8%E5%AF%BE%E5%BF%9C%E3%81%99%E3%82%8B%E3%82%B7%E3%83%8A%E3%83%AA%E3%82%AA%E3%83%A9%E3%83%99%E3%83%AB%E3%81%AB%E9%A3%9B%E3%81%B6%E3%80%8DButton%E3%82%92%E3%81%A4%E3%81%8F%E3%82%8B">「ボタンを押すと対応するシナリオラベルに飛ぶ」Buttonをつくる</a></h2>
<p>チャート画面に必要なのは、この機能を持ったButtonを並べることです。<br />
対応するシナリオラベルから開始するのは、以下のコードで実現できます。</p>
<p>“Create New Adv Scene”で作成したノベルゲーム用のシーンの場合、<br />
AdvEngineではなく、MainGameのほうのメソッドを呼ぶ必要があります。</p>
<pre><code>[SerializeField]
private UtageUguiMainGame mainGame = default;
public void LoadLabel(string label)
{
Close();
mainGame.OpenStartLabel(label);
}
</code></pre>
<p>スクリプトから直接ジャンプしてしまうので、そのシナリオラベルが本当に存在するかどうかには十分注意しておきます。</p>
<h2 id="そのシーンが既読であるかどうか判定する"><a href="#%E3%81%9D%E3%81%AE%E3%82%B7%E3%83%BC%E3%83%B3%E3%81%8C%E6%97%A2%E8%AA%AD%E3%81%A7%E3%81%82%E3%82%8B%E3%81%8B%E3%81%A9%E3%81%86%E3%81%8B%E5%88%A4%E5%AE%9A%E3%81%99%E3%82%8B">そのシーンが既読であるかどうか判定する</a></h2>
<p>このままだと開始直後から好きなシーンにジャンプできてしまうので、<br />
シーンが既読であるかを判定して、未到達ならジャンプを拒否するようにします。</p>
<p>そこで、シナリオラベルから”*”を取って”済”を足したものをそれぞれ全てパラメータとして定義し(!)、<br />
シーンの最後に対応するパラメータをTRUEにするParamコマンドを挿入しておきます(!!)。<br />
スクリプト側ではそれを GetParameter() で取得するようにします。<br />
(このあたりは、1週間の短期開発だったこともあり、だいぶ力技になってしまっています)</p>
<pre><code>public bool IsSumi(string label)
{
string sumi_key = label.Replace("*", "") + "_済";
return Engine.Param.GetParameter(sumi_key);
}
public void LoadLabel(string label)
{
if (IsSumi(label))
{
Close();
mainGame.OpenStartLabel(label);
}
else
{
_Non.SetActive(true);
}
}
</code></pre>
<h2 id="Canvasにボタンを配置する"><a href="#Canvas%E3%81%AB%E3%83%9C%E3%82%BF%E3%83%B3%E3%82%92%E9%85%8D%E7%BD%AE%E3%81%99%E3%82%8B">Canvasにボタンを配置する</a></h2>
<p>あとはこれをいい感じにCanvas内に配置すれば完成です。<br />
<a href="https://crieit.now.sh/upload_images/036b781fd786bb6dd1de147ac274f2845ecd37316dc98.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/036b781fd786bb6dd1de147ac274f2845ecd37316dc98.png?mw=700" alt="bokusyu00.png" /></a></p>
ドッグ
tag:crieit.net,2005:PublicArticle/14709
2019-01-04T00:41:27+09:00
2019-01-04T00:41:27+09:00
https://crieit.net/posts/Unity-5c2e2d275da53
Unity+宴で動画を再生しようとしたらつまづいた話
<h1 id="Unity+宴で動画を再生しようとしたらつまづいた話"><a href="#Unity%2B%E5%AE%B4%E3%81%A7%E5%8B%95%E7%94%BB%E3%82%92%E5%86%8D%E7%94%9F%E3%81%97%E3%82%88%E3%81%86%E3%81%A8%E3%81%97%E3%81%9F%E3%82%89%E3%81%A4%E3%81%BE%E3%81%A5%E3%81%84%E3%81%9F%E8%A9%B1">Unity+宴で動画を再生しようとしたらつまづいた話</a></h1>
<p>宴というノベルゲームエンジンがあります。UnityのAsset Storeで提供されていて、機能も豊富で大変すばらしいのですが、<br />
動画を再生しようとしたらしんどかった話をします。</p>
<p>執筆時の環境<br />
Unity: 2017.4.5f1<br />
宴: 3.4.7</p>
<h2 id="普通にVideoコマンドを使う"><a href="#%E6%99%AE%E9%80%9A%E3%81%ABVideo%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%82%92%E4%BD%BF%E3%81%86">普通にVideoコマンドを使う</a></h2>
<p>宴には<a target="_blank" rel="nofollow noopener" href="http://madnesslabo.net/utage/?page_id=9581">Videoコマンド</a>が用意されていて、それを使えばムービーが再生されます。<br />
しかし、音が出ません。<br />
まあ音が出ないこと自体はドキュメントに描いてある通りなので、どうやって音を出すか考えました。</p>
<h2 id="宴3.4.7が出る"><a href="#%E5%AE%B43.4.7%E3%81%8C%E5%87%BA%E3%82%8B">宴3.4.7が出る</a></h2>
<p>宴3.4.7のリリースノートにVideoコマンド音声対応みたいに書いてある!やったー!やってみよう!</p>
<p>↓↓結果↓↓</p>
<p><strong>だめでした。</strong><br />
2018.2 では確かに音が出るようになっているのですが、2017.4 ではダメなようです。</p>
<p>2017.4.5f1でそこそこ開発が進んだ後だったので、2018へのアップデートはしたくありません。<br />
ドキュメントにはBgmコマンドと組み合わせるべし、と書いてありますが、<br />
その場合は自分で忘れずにStopBgmしなければいけませんし、動画と音声の同期にも不安が残ります。<br />
そもそも音が出ないのはUnity側のVideoPlayerの仕様が不安定なせいですので、<br />
2017.4.5用のWorkaroundを書くことでどうにかしようと考えました。</p>
<h2 id="宴のVideoPlayer再生処理を書き換える"><a href="#%E5%AE%B4%E3%81%AEVideoPlayer%E5%86%8D%E7%94%9F%E5%87%A6%E7%90%86%E3%82%92%E6%9B%B8%E3%81%8D%E6%8F%9B%E3%81%88%E3%82%8B">宴のVideoPlayer再生処理を書き換える</a></h2>
<p><a target="_blank" rel="nofollow noopener" href="https://qiita.com/gshirato/items/88096b0b350f5921f8d4">Qiitaの記事</a>などを参考にして試したところ、<br />
2017.4.5のVideoPlayerで音を出すにはDirectではダメで、VideoPlayerのAudioTrackにAudioSourceを設定してあげないといけないようでした。</p>
<p>実際にVideoPlayerを使って再生処理をしているファイルを書き換えます。</p>
<p>Utage/Scripts/ADV/Graphic/Video/AdvVideoManager.cs</p>
<pre><code class="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;
}
</code></pre>
<h2 id="再生されない"><a href="#%E5%86%8D%E7%94%9F%E3%81%95%E3%82%8C%E3%81%AA%E3%81%84">再生されない</a></h2>
<p>で、エディタ上で再生してみました。</p>
<p>↓↓結果↓↓</p>
<p><strong>だめでした。</strong><br />
……なんで?<br />
Edittor上でAudioSourceの参照を設定した場合はちゃんと再生されてるのに……スクリプト経由ではダメなのでしょうか?<br />
と、とりあえず、ビルドして確認してみましょう……</p>
<p>↓↓結果↓↓</p>
<p><strong>音が鳴りました。</strong><br />
……なんで? <br />
かなり腑に落ちませんが、ともかくビルドした実行ファイルでは正常に再生されているのでとりあえずこれで行くことにします。</p>
<h2 id="中断から復帰できない"><a href="#%E4%B8%AD%E6%96%AD%E3%81%8B%E3%82%89%E5%BE%A9%E5%B8%B0%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84">中断から復帰できない</a></h2>
<p>もう一つ、別の問題がありました。<br />
ムービー再生中にゲームウィンドウを非アクティブにしてゲームを中断状態にすると、<br />
そこから復帰するときにムービー再生が強制中断されてしまうのです。<br />
こちらの原因は<code>IsEndPlay()</code>にありました。<br />
<code>VideoPlayer.isPlaying</code>で再生中かどうかを判別しているのですが、このプロパティが復帰直後には<code>false</code>になるようなのです。</p>
<pre><code class="cs">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;
}
</code></pre>
<p>こちらに関しては、<br />
<a target="_blank" rel="nofollow noopener" href="https://forum.unity.com/threads/how-to-know-video-player-is-finished-playing-video.483935/">https://forum.unity.com/threads/how-to-know-video-player-is-finished-playing-video.483935/</a><br />
を参考にして終了判定を<code>VideoPlayer.loopPointReached</code>イベントを利用したものに書きかえました。</p>
<pre><code class="diff">--- 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
</code></pre>
<h2 id="結論"><a href="#%E7%B5%90%E8%AB%96">結論</a></h2>
<p>Unity2018.2を使いましょう。何もしなくても音が出ます。</p>
ドッグ