Prefab の名前を Revert する

Prefab は、大元のほうの名前を変えても、シーンに配置されているほうの Prefab の名前は変わりません

f:id:Gigacee:20191101013228g:plain

Revert したくても、それらしいメニューは無い……。

と思いきや、Inspector を Debug モードに切り替えたらできました。

f:id:Gigacee:20191101014310g:plain

ただ、何か別の変更を Apply した時点で再び名前が変わらなくなってしまうので、あまり意味はないかもです😥

シーン中のすべての Prefab を Revert / Apply する

using Unity.Linq;
using UnityEditor;
using UnityEngine;
using UnityEngine.SceneManagement;

public class AllPrefabEdit
{
    [MenuItem("Tools/Edit/Revert All Prefab Instances %F1")]
    public static void RevertAllPrefabInstances()
    {
        foreach (var rootObj in SceneManager.GetActiveScene().GetRootGameObjects())
        {
            foreach (var obj in rootObj.DescendantsAndSelf())
            {
                if (PrefabUtility.IsAnyPrefabInstanceRoot(obj))
                {
                    PrefabUtility.RevertPrefabInstance(obj, InteractionMode.AutomatedAction);

                    Debug.Log($"Revert succeeded: {obj.name}");
                }
            }
        }
    }

    [MenuItem("Tools/Edit/Apply All Prefab Instances %F2")]
    public static void ApplyAllPrefabInstances()
    {
        foreach (var rootObj in SceneManager.GetActiveScene().GetRootGameObjects())
        {
            foreach (var obj in rootObj.DescendantsAndSelf())
            {
                if (PrefabUtility.IsAnyPrefabInstanceRoot(obj))
                {
                    PrefabUtility.ApplyPrefabInstance(obj, InteractionMode.AutomatedAction);

                    Debug.Log($"Apply succeeded: {obj.name}");
                }
            }
        }
    }
}

メニューの Tools > Edit か、Ctrl+F1, Ctrl+F2 で実行できます。

LINQ to GameObject が必要です。

複数の ReactiveProperty をまとめて監視する

UniRx を使っていて、複数の ReactiveProperty をまとめて監視して何か処理を行いたいときがたまにあります。

例えば、「デバッグモードが ON」かつ「ミュート設定が ON」になったときのみ音声をミュートする、とか。

ベタ書き

デバッグモードとミュート設定をそれぞれ BoolReactiveProperty で持ち、どちらかの値が変わったらミュート状態を切り替える、という実装を考えます。

とりあえず、何も考えずそのままベタ書きしたのが以下のコードです。

public BoolReactiveProperty debugMode;
public BoolReactiveProperty muteAllSounds;

public AudioSource audioSource;

void Start()
{
    debugMode.Subscribe(x => ToggleMute());
    muteAllSounds.Subscribe(x => ToggleMute());
}

void ToggleMute()
{
    audioSource = debugMode.Value && muteAllSounds.Value;
}

そのままだ。そのままですが、だいぶ頭の悪いコードですね……。

せっかく ReactiveProperty を使っているのに、流れてきた値 (x) を使っていないあたりに頭の悪さが滲み出ています。

ストリームを合成する

「ストリームは合成できる」ということを知っていれば、先程のコードは以下のように書き換えることができます。

public BoolReactiveProperty debugMode;
public BoolReactiveProperty muteAllSounds;

public AudioSource audioSource;

void Start()
{
    Observable.Merge(debugMode, muteAllSounds)
        .Subscribe(x => ToggleMute());
}

void ToggleMute()
{
    audioSource = debugMode.Value && muteAllSounds.Value;
}

10 点だったのが、20 点くらいにはなったかな……。

しかしこのやり方だと、流れてくるxの値がdebugModeのものなのかmuteAllSoundsのものなのか判らないので、やっぱり使えないままです。

両方の値が流れてくるようにする

ストリームを Merge で合成すると、debugModeの値が変わった時にはdebugModeの値のみが、muteAllSoundsの値が変わった時にはmuteAllSoundsの値のみが流れて来るので、良くなかった、と。

なら、debugModeの値が変わろうとmuteAllSoundsの値が変わろうと、両方の値が流れてくるようになれば良いわけです。

そのようにしたのがこちら。

public BoolReactiveProperty debugMode;
public BoolReactiveProperty muteAllSounds;

public AudioSource audioSource;

void Start()
{
    Observable.CombineLatest(debugMode, muteAllSounds)
        .Subscribe(list =>
        {
            audioSource = list.All(x => x);
        });
}

だいぶ賢いコードになりましたね!

ストリームを CombineLatest で合成すると、どれかの値が変わったら全部の値が List にまとめられて流れてくるので、「list 内の全要素が true だったら*1ミュート」とすれば、やりたいことが実現できるというわけ。

補足

先程、CombineLatest の説明で「どれかの値が変わったら全部の値が List にまとめられて流れてくる」と書きましたが、これは微妙に違くて、すべてのストリームに一回以上値が流れていないと List は流れてきません。

それなのになぜ上記のコードが valid なのかというと、ReactiveProperty は値が変化した時だけでなく Subscribe した瞬間にもその時点での値が一回流れるので、自動的に「一回以上値が流れている」が満たされるからですね。

参考:

neue cc - Unityにおけるコルーチンの省メモリと高速化について、或いはUniRx 5.3.0でのその反映

(UniRxの)ReactivePropertyはSubscribe時に必ず値をプッシュするようになってる

*1:list.All(x => x) の部分。

DOTween が "This Tween has been killed and is now invalid" と警告してきた

f:id:Gigacee:20191012211701p:plain

DOTween の警告

ある日のこと。

DOTween を使っていたら、特に動作に問題はないけどなぜか警告を吐いてきました。

DOTWEEN ► This Tween has been killed and is now invalid

「あなたが操作しようとしたトゥイーンはすでに無効になってますよ~」とのこと。

該当のコードはこんな感じ:

if (tweener != null && tweener.IsPlaying())
{
    tweener.Complete();
}

トゥイーンが再生中だったら即完了にするよっていう処理です。

何の変哲もないコードだと思うけどなぁ……。null チェックもちゃんとしてるし、何がいけないんだろう🤔

調査

似たようなメソッドを並べてみて、片っ端から調べてみました(雑……!)。

if (tweener != null)
{
    Debug.Log(tweener.fullPosition);
    Debug.Log(tweener.CompletedLoops());
    Debug.Log(tweener.Delay());
    Debug.Log(tweener.Duration());
    Debug.Log(tweener.Elapsed());
    Debug.Log(tweener.ElapsedDirectionalPercentage());
    Debug.Log(tweener.ElapsedPercentage());
    Debug.Log(tweener.IsActive());
    Debug.Log(tweener.IsBackwards());
    Debug.Log(tweener.IsComplete());
    Debug.Log(tweener.IsInitialized());
    Debug.Log(tweener.IsPlaying());
    Debug.Log(tweener.Loops());
}

上記のコードを実行してみたところ、なんとtweener.IsActive()のみ警告が発生しないという結果に! どうやら、再生し終わったトゥイーンに対しては、有効かどうか以外を調べるのは非推奨のようです。tweener.IsPlaying()と書けば一応 false を返してくれるけど、そもそも tweener 自体がもう無効になっているからそんなこと聞いてくるな、ということか。

解決

ということで、以下のように書き換えると、無事警告は出なくなりました。*1

if (tweener != null && tweener.IsActive() && tweener.IsPlaying())
{
    tweener.Complete();
}

*1:この if 文中の tweener.IsPlaying() が警告されないのは、直前の tweener.IsActive() が false だったらその時点で式の評価が終了するからですね(短絡評価)。

Visual Studio Code が白っぽくなったときの対処法

新しく買った PC *1 に Visual Studio Code をインストールしたら、なんか白い。

f:id:Gigacee:20191010233621p:plain

調べたところ、どうやら内蔵 GPU *2 との相性が良くないらしく、ハードウェアアクセラレーションを無効にして起動したら直りました。

起動オプションに--disable-gpuを付けてやれば OK。

*1:DELL New XPS 13 2-in-1

*2:Intel Iris Plus Graphics

OpenPyXL を使って Excel ファイルを読み書きしたら画像が全部消えた

表題のとおりです。

哀しい😢

公式ドキュメントに記載があった

Simple usage — openpyxl 3.0.3 documentation

Warning

openpyxl does currently not read all possible items in an Excel file so images and charts will be lost from existing files if they are opened and saved with the same name.

ライブラリを使うときはちゃんと公式を読もう!(戒め)

使用したスクリプト

一応スクリプトも置いておきます。

################################################################################
# Excel ファイルを扱うテストです。
################################################################################

import glob
import openpyxl
import os

# 作業ディレクトリのパス
WORKING_DIRECTORY_PATH = os.path.dirname(os.path.abspath(__file__))

# 作業ディレクトリと同階層にあるすべての xlsx ファイルに対して処理を行う
for xlsx_file in glob.glob(f"{WORKING_DIRECTORY_PATH}\\*.xlsx", recursive=True):
    # xlsx ファイルをロード
    book = openpyxl.load_workbook(xlsx_file)
    print(f"{xlsx_file} loaded.")

    # 処理

    # xlsx ファイルをセーブ
    book.save(xlsx_file)
    print(f"{xlsx_file} saved.")

Visual Studio Code で .NET Core をやろうとしたらエラーが起きたので解決した

最近は Visual Studio Code でも C# が動くんですね!

Visual Studio なんていらんかったんや!

docs.microsoft.com

ということで、公式チュートリアルの通りにやってみたところ……。

問題発生

f:id:Gigacee:20190209025920j:plain

本来ならアプリのビルドとデバッグに必要なアセットの追加を求められるべきところで、なにやら怪しげな警告が。

恐る恐る内容を開いてみると……。

[info]: OmniSharp.Stdio.Host
        Starting OmniSharp on Windows 6.2.9200.0 (x64)
[info]: OmniSharp.Services.DotNetCliService
        DotNetPath set to dotnet
[info]: OmniSharp.MSBuild.Discovery.MSBuildLocator
        Located 2 MSBuild instance(s)
            1: Visual Studio Community 2017 15.8.28010.2048 - "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin"
            2: StandAlone 15.0 - "C:\Users\Gigacee\.vscode\extensions\ms-vscode.csharp-1.17.1\.omnisharp\1.32.8\msbuild\15.0\Bin"
[info]: OmniSharp.MSBuild.Discovery.MSBuildLocator
        Registered MSBuild instance: Visual Studio Community 2017 15.8.28010.2048 - "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin"

// 中略

[fail]: OmniSharp.MSBuild.ProjectManager
        Attemped to update project that is not loaded: c:\Users\Gigacee\Sandbox\dotnet\Hello World.csproj

どうやら、 Visual Studio Code の C# 拡張ではなく、 Visual Studio Community 2017 の MSBuild を呼んでしまってエラーが起こっているようです。

Visual Studio をアンインストールしてしまえば解決しそうですが、 Unity でゲーム開発をするときとかにまだ使うんですよね……。

(さっき「いらんかったんや!」と言ったばかりですが……)

解決

なんとか Visual Studio を生かしたまま解決できないかと色々試した結果、 Visual Studio 自体に .NET Core をインストールすることでうまくいきました。

Visual Studio Installer を起動し、「変更」から、「.NET Core クロスプラットフォームの開発」をインストールすれば OK !

f:id:Gigacee:20190209034637p:plain

なんで自分自身の MSBuild より外部の MSBuild の方が優先されるんですかね……謎です。

なお OmniSharp の GitHub では

github.com

問題自体は認識されているようです。

早く直ると良いですね。

The coloring of this site is Dracula PRO🧛🏻‍♂️
This website uses the FontAwesome icons licensed under CC BY 4.0.

2020 GIGA CREATION