ゴマちゃんフロンティアV2へようこそ!

本ブログはゲーム統合開発環境「Unity」を使用したゲーム開発の日記です!
ときどきイラストを描いたり、写真を交えた日記も書いています!

【開発環境】

OS Windows7 SP1 64bit
CPU Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz
メモリ 12GB
グラボ GeForce GTX 645
使用ソフト Microsoft Visual Studio(C#)
Blender
GIMP

旧ブログの記事について

本ブログは2015年9月にFC2ブログから移転しております。
過去記事につきまして、「開発方針が変わっている」「Unityの仕様が現状と異なる」等、そのままでは不適切と判断しました。
なので、知識・技術面で重要そうな記事のみをピックアップし、再編集して新ブログに追加している段階です。
Googleのインデックスの関係上、検索内容とブログ内容に差異が発生する可能性がありますので、ご了承ください。
また「前のブログのこの記事読みたい!」というものがありましたら、ご連絡頂ければ追加致します!

お問い合わせフォームはこちら

【Unity】StandardAssetsの「Water4」で水中から水面上をレンダリングする方法

※本記事は「Unity5.4.1」時点の内容です。

というわけで、今回は Unity のシェーダーに関するお話です。
StandardAssets の Environment に「Water4」という水面シェーダーがあります。

shot2ss20161218223706980

Unity4 まではPro専用でしたが、Unity5 から無料でも使えるようになりました。
これによって水面のレンダリングがすごく楽に出来ます。

shot2ss20161218224017428

が、カメラが水中に入っている場合、水面上が見えなくなってしまいます。
ステージに陸上のエリアと水中エリアがある場合、かなり致命的な問題です。

適当に試行錯誤したところ、Water4 のシェーダーを修正すれば(とりあえずは)直るようです。
自分はシンプルの方を使っているので、「FXWater4Simple.shader」を修正します。
215行目付近の edgeBlendFactors が書かれている行をコメントアウトします。

baseColor = lerp (lerp (rtRefractions, baseColor, baseColor.a), reflectionColor, refl2Refr);
baseColor = baseColor + spec * _SpecularColor;

// baseColor.a = edgeBlendFactors.x; // ←この行をコメントアウト
UNITY_APPLY_FOG(i.fogCoord, baseColor);
return baseColor;

水色なので分かりにくいですが、 水面上が表示されるようになりました!

shot2ss20161218225529184

少し上に「half4 edgeBlendFactors = half4 (1.0, 0.0, 0.0, 0.0);」という宣言があるので、水面の少し上を baseColor のアルファ値に設定しているからかなーと察しています。
とはいえ、自分はシェーダーがほとんど分からないので、このアプローチがよろしいかは微妙です。
修正する場合は自己責任でお願いします!

【Unity】メッセージやパラメータをYAMLファイルで定義・参照する

この記事は「Unity 2 Advent Calendar 2016」の15日目です。

今回のお題は「Unity から YAML で定義したメッセージやパラメータを読み込む」です!
Unity 上で直接設定せずに外部の YAML ファイルに定義し、一元管理するのが目的です。

元々は仕事で「EC-CUBE3」を使う機会があり、そこで YAML が使われていたことが知ったきっかけです。
そのため、今回紹介する実装も EC-CUBE3 と似たようなものになっています。
あちらは Symfony2 というフレームワーク内でパースしており、DIコンテナ越しにキーをメッセージに変換できます。

この手のフォーマットは他に「JSON」とか「XML」とか「ini」とかありますが、私的には YAML が一番取っつきやすいです。
書き方が何種類かあることや、インデントにタブが使えない等の癖はありますが、慣れてしまえばサクサク書けます。
このあたりは好みの問題かもしれません。

ちなみに YAML は「ヤムル」or「ヤメル」と読むらしいですが、自分は前者派です。
最近は ISO も人によって「アイエスオー」だったり「イソー」だったりすることに衝撃を覚えたりしましたが・・・。

YAMLファイル読み込み用クラスの作成

YAML ファイルの読み込みに関しては、以前投稿した記事で紹介しております。

【Unity】YAMLファイルの読み込みと表示用メッセージの管理

基本は「YamlDotNet for Unity」を使用して YAML ファイルを読み込み、キーから対応する値を取得します。
単に列挙されたキー/値を取得するだけであれば YamlDotNet のドキュメント通りでいけますが、ネストさせた場合に特定の値をピンポイントで取得することが出来ませんでした。
EC-CUBE3 っぽく取得できるようにユーティリティを作成していたりしますが、取得する度に YAML を毎回ロードしていたり、所々ハードコーディング気味でイケてないです。

そんなわけで、専用に管理するクラスを作成し、インスタンス化して処理させてみます。

 
using UnityEngine;
using System.IO;
using YamlDotNet;
using YamlDotNet.RepresentationModel;

public class YamlManager {

    public YamlStream messageYaml;

    private static YamlManager yamlManager;

    // YAMLファイル保存パス
    private const string ymlPath = "Assets/Yaml/";

    private YamlManager() {
        // メッセージ用YAMLのロード
        StreamReader inputFile = new StreamReader(ymlPath + "message.yml", System.Text.Encoding.UTF8);
        messageYaml = new YamlStream();
        messageYaml.Load(inputFile);
    }

    /// <summary>
    /// 指定されたキーを元にメッセージを取得する
    /// </summary>
    public string getMessageValue(string key) {
        string message = getValue(key, messageYaml);
        return message;
    }

    /// <summary>
    /// 指定されたキーを元にYAMLから値を取得する
    /// </summary>
    private string getValue(string key, YamlStream file) {
        // キーをドットで分割
        string[] keys = key.Split('.');

        // キーの配列数(=ネストレベル)取得
        int keyCount = keys.Length;

        // ルートのマッピング取得
        YamlMappingNode mapping = (YamlMappingNode)messageYaml.Documents[0].RootNode;
        YamlScalarNode node = null;

        for (int i = 0; i < keyCount; i++) {
            // キー配列が最後の要素になった場合は ScalarNode を取得
            if (i == keyCount - 1) {
                node = (YamlScalarNode)mapping.Children[new YamlScalarNode(keys[i])];
            } else {
                // キーを元に1つ深いネストのマッピングを取得
                mapping = (YamlMappingNode)mapping.Children[new YamlScalarNode(keys[i])];
            }
        }

        return node.ToString();
    }

    /// <summary>
    /// インスタンスを取得する
    /// </summary>
   public static YamlManager getInstance() {
        if (yamlManager == null) {
            yamlManager = new YamlManager();
        }

        return yamlManager;
    }
}

シーン上のオブジェクトとして用意する必要はないと思うので、MonoBehaviour は継承しません。
またインスタンスは1つあれば十分なため、Singleton パターンを適用してみました。

getValue() 内で渡されたキーを.(ドット)毎にパースし、ネストした YAML ファイル のキーを参照→取得を繰り返します。
キーが最後まで取得し終えたら、そのノードの値を ToString() で出力します。

見直してみると、キーを間違えたり定義していなかった場合のアフターケアがないのが微妙です。
YamlDotNet.Core に YamlException があるので、例外として投げちゃうのが手っ取り早そうです。

using System.IO;
using System.Collections.Generic;
using UnityEngine;
using YamlDotNet.Core;
using YamlDotNet.RepresentationModel;

public class YamlManager {

    public YamlStream messageYaml;

    private static YamlManager yamlManager;

    // YAMLファイル保存パス
    private const string ymlPath = "Assets/Yaml/";

    private YamlManager() {
        // メッセージ用YAMLのロード
        StreamReader inputFile = new StreamReader(ymlPath + "message.yml", System.Text.Encoding.UTF8);
        messageYaml = new YamlStream();
        messageYaml.Load(inputFile);
    }

    /// <summary>
    /// 指定されたキーを元にメッセージを取得する
    /// </summary>
    public string getMessageValue(string key) {
        string message = null;

        try {
            message = getValue(key, messageYaml);
        } catch (YamlException e) {
            message = "メッセージ設定エラー";
            Debug.LogError(e.ToString());

            return message;
        }

        return message;
    }

    /// <summary>
    /// 指定されたキーを元にYAMLから値を取得する
    /// </summary>
    private string getValue(string key, YamlStream file) {
        // キーをドットで分割
        string[] keys = key.Split('.');

        // キーの配列数(=ネストレベル)取得
        int keyCount = keys.Length;

        // ルートのマッピング取得
        YamlMappingNode mapping = (YamlMappingNode)messageYaml.Documents[0].RootNode;
        YamlScalarNode node = null;
        YamlNode outNode;

        for (int i = 0; i < keyCount; i++) {
            YamlScalarNode currentNode = new YamlScalarNode(keys[i]);

            // キーから値を取得できない場合はエラー
            if (!mapping.Children.TryGetValue(currentNode, out outNode)) {
                throw new YamlException();
            }

            // キー配列が最後の要素になった場合は ScalarNode を取得
            if (i == keyCount - 1) {
                node = (YamlScalarNode)outNode;
            } else {
                // キーを元に1つ深いネストのマッピングを取得
                if (outNode.GetType() != typeof(YamlMappingNode)) {
                    throw new YamlException();
                }
                mapping = (YamlMappingNode)outNode;
            }
        }

        return node.ToString();
    }

    /// <summary>
    /// インスタンスを取得する
    /// </summary>
   public static YamlManager getInstance() {
        if (yamlManager == null) {
            yamlManager = new YamlManager();
        }

        return yamlManager;
    }
}

getValue() と getMessageValue() を修正してみました!
TryGetValue() で取得できない場合と、1つ下のマッピング取得時に typeof で判定した場合で投げています。
例外で処理が止まってしまうのはまずいので、getMessageValue() 内で受け止めて仮のメッセージを表示します。

メッセージやラベルをYAMLで定義する

例えば、「ステージ○○の4つ目の看板のメッセージを~」なんてことがあった場合、「シーンを開く→ヒエラルキーから看板選択→インスペクターから修正」と考えると、げんなりしそうになりますね。
これを YAML のキーを設定する形にしておき、実行時に対応するメッセージを取得すれば、YAML ファイルを開いて直すだけになります。

パス Assets/Yaml/ の下に message.yml というファイルを作成し、メッセージを定義していきます。

# 操作
control:
  jump_input: スペースキーを押すとジャンプします
  throw_action: |-
    アクションキーを押すと物を持ち上げます
    再度押すと投げます

# ステージ
stage:
  break_block: ブロックは攻撃することで破壊できます
  trampoline: タイミングよくボタン入力で大ジャンプ!
  climbWall: 壁に近づいてボタン入力で更にジャンプできます


# システムメッセージ
gameover:
  continue: スタート地点又は直前のチェックポイントから再開します
  end: タイトル画面に戻ります

YAML の文法については割愛しますが、
・セミコロン後の半角スペースは必須
・#以降はコメント扱い
・ネストさせる場合はスペース(タブはNG)
あたりを抑えておけば何とかなると思われます。

取得する時は YamlManager をインスタンス化して getMessage() を呼びます。
Start() あたりで取ってしまうのがベターでしょうか。

 
void Start () {
    string message = YamlManager.getInstance().getMessageValue("stage.trampoline");
    Debug.Log(message);
}

以下はキーに「stage.trampoline」を設定した場合の出力です。

shot2ss20161205003818664

後は message を UI 等に出力すればOKです。
(出力方法は記事の趣旨から逸れるので割愛します)

読み込むYAMLファイルを切り替える

もし英語のゲームをやっているとき、「SELECT LANGUAGE」なんてオプション項目があったらステキですよね!
今日の家庭用ゲームでも、「日本語」「英語」を切り替えられるゲームはそれなりに見受けられます。
キーを変えずに値だけを変えた YAML ファイルを複数用意すれば、多言語への対応ができたりします。

ある程度命名規則を決めた方がやりやすいので、ここも EC-CUBE3 っぽくいきます。
先程の message.yml は日本語なので message.ja.yml に修正し、新しく作るファイルは message.en.yml にします。
しかし自分は英語が全くダメなので、最近パワーアップしたとウワサの「Google翻訳」に変換してもらいます。

# 操作
control:
  jump_input: Press space key to jump.
  throw_action: |-
  Press the action key to lift the object.
  Press again to throw.

# ステージ
stage:
  break_block: Blocks can be destroyed by attacking.
  trampoline: Timely well with big button jump!
  climbWall: You can jump further by button input as you approach the wall.

# システムメッセージ
gameover:
  continue: Restart from the start point or the previous checkpoint.
  end: Return to title screen.

何かエキサイト翻訳っぽい直訳気味なものもありますが、何となく伝わればそれでいいです(ぁ

次に先程の YamlManager を修正します。
ゲーム内で動的に切り替えることを考慮し、YAML ファイルをロードする処理を関数化しておきます。
以下、YamlManager のコンストラクタとロード用関数のみ記載します。

 
private YamlManager() {
    // メッセージ用YAMLのロード
    loadMessageYaml();
}

/// <summary>
/// メッセージ用YAMLファイルをロードする
/// </summary>
public void loadMessageYaml(string lang = "ja") {
    StreamReader inputFile = new StreamReader(ymlPath + "message." + lang + ".yml", System.Text.Encoding.UTF8);
    messageYaml = new YamlStream();
    messageYaml.Load(inputFile);
}

デフォルトは ja としてロードし、必要に応じて loadMessageYaml() で YAML ファイルを切り替えます。

void Start() {
    YamlManager yamlManager = YamlManager .getInstance();
    yamlManager.loadMessageYaml("en");
    string message = yamlManager.getMessageValue("stage.trampoline");
    Debug.Log(message);
}

キーは先程と同じく「stage.trampoline」です。

shot2ss20161205003840118

言語を2文字で指定しなければならないのが微妙ですが、とりあえず読込先を変えることができます。
後は message を UI で(ry

パラメータをYAMLで定義する

完全固定な値はC#の定数で定義しますが、ある程度固定だけど変化する値は YAML で管理してしまいます。
例としては、音量や言語などのオプション設定的なものが挙げられます。
キーコンフィグも YAML で扱いたかったのですが、InputManager を動的に変えるのはかなり面倒なようなのでパスしました。

メッセージ定義の時は文字列しかなかったので問題ありませんでしたが、パラメータとなると数値が入ってくることも考慮しなければなりません。
C# では単一の型しか返すことが出来ないわけですが、返り値を string 固定にしている時点で数値を扱うのは絶望的です。
こういった場合は自分で型や構造体を定義して返すのが良いらしいので、適当に返却用のクラス ReturnYamlNode を作成しています。
それに合わせて string で処理していた部分も ReturnYamlNode で返すように修正しました。

最終的な YamlManager が以下になります!

 
using System.IO;
using System.Collections.Generic;
using UnityEngine;
using YamlDotNet.Core;
using YamlDotNet.RepresentationModel;
using YamlDotNet.Serialization;

public class YamlManager {

    public YamlStream messageYaml;
    public YamlStream configYaml;

    private static YamlManager yamlManager;

    // YAMLファイル保存パス
    private const string ymlPath = "Assets/Yaml/";

    private YamlManager() {
        // メッセージ用YAMLのロード
        loadMessageYaml();

        // 設定用YAMLのロード
        loadConfigYaml();
    }

    /// <summary>
    /// 指定されたキーを元にメッセージを取得する
    /// </summary>
    public string getMessageValue(string key) {
        ReturnYamlNode messageNode = null;

        try {
            messageNode = getValue(key, messageYaml);
        } catch (YamlException e) {
            string message = "メッセージ設定エラー";
            Debug.LogError(e.ToString());

            return message;
        }

        return messageNode.value;
    }

    /// <summary>
    /// メッセージ用YAMLファイルをロードする
    /// </summary>
    public void loadMessageYaml(string lang = "ja") {
        StreamReader inputFile = new StreamReader(ymlPath + "message." + lang + ".yml", System.Text.Encoding.UTF8);
        messageYaml = new YamlStream();
        messageYaml.Load(inputFile);
    }

    /// <summary>
    /// 設定用YAMLファイルをロードする
    /// </summary>
    public void loadConfigYaml() {
        StreamReader inputFile = new StreamReader(ymlPath + "config.yml", System.Text.Encoding.UTF8);
        configYaml = new YamlStream();
        configYaml.Load(inputFile);
    }

    /// <summary>
    /// 指定したキーを元に設定ファイルの値を取得する
    /// </summary>
    public ReturnYamlNode getConfig(string key) {
        return getValue(key, configYaml);
    }

    /// <summary>
    /// 指定されたキーを元にYAMLから値を取得する
    /// </summary>
    private ReturnYamlNode getValue(string key, YamlStream file) {
        // キーをドットで分割
        string[] keys = key.Split('.');

        // キーの配列数(=ネストレベル)取得
        int keyCount = keys.Length;

        // ルートのマッピング取得
        YamlMappingNode mapping = (YamlMappingNode)file.Documents[0].RootNode;
        YamlScalarNode node = null;
        YamlNode outNode;

        for (int i = 0; i < keyCount; i++) {
            YamlScalarNode currentNode = new YamlScalarNode(keys[i]);

            // キーから値を取得できない場合はエラー
            if (!mapping.Children.TryGetValue(currentNode, out outNode)) {
                throw new YamlException();
            }

            // キー配列が最後の要素になった場合は ScalarNode を取得
            if (i == keyCount - 1) {
                node = (YamlScalarNode)outNode;
            } else {
                // キーを元に1つ深いネストのマッピングを取得
                if (outNode.GetType() != typeof(YamlMappingNode)) {
                    throw new YamlException();
                }
                mapping = (YamlMappingNode)outNode;
            }
        }

        ReturnYamlNode returnNode = new ReturnYamlNode(key, node.ToString());
        return returnNode;
    }

    /// <summary>
    /// インスタンスを取得する
    /// </summary>
    public static YamlManager getInstance() {
        if (yamlManager == null) {
            yamlManager = new YamlManager();
        }

        return yamlManager;
    }
}

public class ReturnYamlNode {
    public string key;
    public string value;

    public ReturnYamlNode(string key, string value) {
        this.key = key;
        this.value = value;
    }

    public int getIntValue() {
        int intValue;
        if (int.TryParse(value, out intValue)) {
            return intValue;
        }

        throw new UnityException();
    }
}

そもそも取得時に数値だろうが文字列だろうが ToString() し始めるあたり、純正の PHPer であることは隠しようもありません。
PHP でコーディングした後に C# や Java をやったりすると、型のガチガチっぷりにビックリしたりします。
まあその型の緩さのせいで PHP も面倒なことがありますが・・・。

取得する場合はインタタンス化して getConfig() を使います。
数値が欲しい場合は更に getIntValue() で取得します。

void Start () {
    YamlManager yamlManager = YamlManager.getInstance();
    int bgm_volume = yamlManager.getConfig("bgm_volume").getIntValue();
    Debug.Log(bgm_volume);
}

ただし、最大HPや攻撃力などの「勝手に変えられると困るもの」は YAML で管理すべきではありません。
YAML は所詮テキストファイルなので、簡単に書き換えられてしまいます。
また、所謂バリデーションチェックは必ず行う必要があります。
ということを考えると、意外とパラメータを外部化するのは面倒な気もします。

ビルド後のYAMLファイル保存先について

Unity 上で開発する分には /Assets/Yaml/ で問題ありませんが、ビルドして書き出すと話が違ってきます。
というのも、Assets 以下のデータは全てまとめられてしまうため、パスで指定しても参照できなくなってしまいます。

そのため、プロジェクト直下に専用のディレクトリを作成し、そこに保存するようにします。
フィールドの ymlPath と Start() 内を修正します。

// YAMLファイル保存パス
private const string ymlPath = "Settings/";

void Start () {
    string basePath = System.IO.Directory.GetCurrentDirectory();
    System.IO.Directory.CreateDirectory(basePath + "/Settings");
}

これでビルド後も参照できるようになりました。
ただ、Unity エディタ上からアクセスできなくなるので、開発時は不便な感じです。
このあたりは割り切るしかないのかもしれません。

まとめ

そんなわけで、Unity 上で YAML をあれこれしてみました!
外部ファイルに書いている分、Unity 上で直接設定するより手間ですが、後々の修正や管理がしやすいです。
反面、入力時にエディタ側で補完してくれないので、(定数よりも)キーの指定を間違えやすいです。

余談ですが、Qiita のアドベントカレンダーとして投稿したのは今年が初めてだったりします。
他の投稿を見ると記事に自信がなくなってきますが、来年もネタがあったら書いていきたいです。

明日は @WheetTweet さんです!

【Unity】シーン上のオブジェクト取得時にシングルトンっぽい動きの実現

というわけで、時々「ブログ名変なの」とか言われるりべるんです。
「ゴマちゃん」で「フロンティア」で「バージョン2」ってだけなのですが・・・。

今回もよく分からないタイトルですが、要は「シーン上に1つしかないオブジェクトのコンポーネント」を取得する際に、シングルトンパターンっぽく出来ないかというお話です!

「Unityでシングルトン」的な話題はぐぐると幾らでもヒットしますが、MonoBehaviour を継承していないクラスでのお話だったりします。
(MonoBehaviour を継承しなければ new 演算子でインスタンス化できます)
しかし、Unity 的にはシーン上に管理用オブジェクトを配置し、インスペクターから必要なパラメータやプレハブの設定をしたい・・・という場面があります。

自分のゲームで言うと、ゲーム内の共通エフェクトをまとめた EffectManager 何かが正にそれです。
エフェクト毎にプレハブを設定しておき、マネージャから生成・破棄の管理をしています。

shot2ss20161203194259608

そんなシーン上に1つしかないオブジェクトを効率よく取得する方法について考えてみました!

単一オブジェクトのコンポーネント取得

シーン上に存在するオブジェクトを取得するには Find() か何かしてくるわけですが、そのオブジェクトを複数のクラスから参照する場合、いちいち Find() → GetComponent() は避けたいところです。
ということで、「自身の静的フィールドにインスタンスを保持し、あったらそれを返す、なかったら Find()&GetComponent() する」という動きを実装してあげます。

using UnityEngine;
using System.Collections;

public class TestManager : MonoBehaviour {

    private static TestManager testManager;

    public void hoge() {
        Debug.Log("hoge");
    }

    public static TestManager getInstance() {
        if (testManager == null) {
            testManager = GameObject.Find("TestManager").GetComponent<TestManager>();
        }

        return testManager;
    }
}

取得時はシンプルに getIntance() を呼ぶだけです。

void Start() {
    TestManager testManager = TestManager.getInstance();
    testManager.hoge();
}

GameObjectで応用

別にクラスのインスタンスに限らず、シーン上に1つしか存在しない GameObject を取得する場合にも使えます。
ちょっと変えるだけでいけそうな雰囲気。

using UnityEngine;
using System.Collections;

public class TestManager : MonoBehaviour {

    private static GameObject testManager;

    public void hoge() {
        Debug.Log("hoge");
    }

    public static GameObject getInstance() {
        if (testManager == null) {
            testManager = GameObject.Find("TestManager");
        }

        return testManager;
    }
}

取得方法も変わりません。
GameObject に対して操作するときはこれでもOKですね。

GameObject testManager = TestManager.getInstance();
Debug.Log(testManager.ToString());

シーン上に1つしかないもの・・・DirectionalLight や mainCamera とかですね。
特にカメラはあれこれ動かす機会が多くなりそうなので重宝します。
実現のために1つスクリプトを作成しなければなりませんが、複数クラスから Find() を連発するよりはマシかと思われます。

まとめ

そんなわけで、MonoBehaviour を継承したオブジェクトを何度も取得する場合について考えてみました!
Unity5 で早くなったとはいえ、Find() や GetComponent() を繰り返すのは避けたいところですね。

河口湖紅葉祭り(2016)に行ってきました!

というわけで、最近やたらと多い「行ってきました」シリーズです。
秋といえば紅葉!ということで、「河口湖紅葉祭り」に行ってきました!

cimg2443_r

去年も来ているので2年連続になります。
前は11月3日に行ったので、今年は2週間ほど遅れて行くことになりました。
3日ではまだ見頃とは言い難い感じであり、今年は色付きが遅いらしいので、時期的にはよろしい感じです。

去年の様子は↓の記事をご参照下さい。

河口湖紅葉祭り(2015年)に行ってきました!

もみじ回廊

去年は夜行ったのでライトアップされておりましたが、今年は朝方に来ました。

家を出たときは曇でしたが、河口湖まで行くと綺麗に晴れていました。
が、近隣の専用駐車場は凄まじく混雑しており、9時半には全て満車になってしまっていました。
また、誘導員がかなり適当な誘導をするため、満車のところをぐるぐる回っている車ばかりでした。

仕方ないので猿回し劇場の駐車場に2時間500円で停めることに。
それでもかなり埋まっていたので、紅葉シーズンに行く場合は覚悟した方がよさそうです。

ということで、以下ひたすら紅葉です!

cimg2448_r

cimg2393_r

cimg2407_r

cimg2438_r

cimg2435_r

cimg2417_r

cimg2436_r

人が多いため、家族揃った写真を綺麗に撮るのは厳しいです。
その手のサービスをやっている業者がいたので、抵抗がなければ利用するのが確実です。
大きい写真で出力したものは1000円かかりますが、自分のカメラを渡せば撮ってくれます。

ほうとう不動

山梨県民なのでほうとうにはときめかないのですが、本番のしっかりしたほうとうを食べたことがなかったので、昼に家族で行ってみました。
もみじ回廊の駐車場からは700mほどです。

cimg2453_r

山梨といえばほうとうという風潮がありますが、うどんを更に太くしたような麺なので人を選ぶ食感な気がします。
かぼちゃを溶かして食べると非常に馴染んで美味しくなるのでオススメです。

まとめ

そんなわけで、今年も河口湖紅葉祭りに行ってきました!
秋は寒すぎず暑すぎず、景色も綺麗とお出かけにはもってこいですね。
これから冬にかけて出歩くのもきつくなってくるので、今のうちに秋を堪能しておくべきでしょうか。

【Windows10】電源オプションが正常に表示されない現象と格闘した件について

というわけで、今回は自分のPCでちょっとしたトラブルがあったので、そのお話になります。
いつの間にか電源オプションの項目が正常に表示されなくなり、電源プランの変更や作成も「お使いの電源プランの情報が利用できません」と言われてしまいます。

shot2ss20161119215938247

shot2ss20161119215958327

shot2ss20161119220006969

結論から言うと、レジストリの値がおかしかったのが原因だったようです。
「powrprof.dll」というファイルを見に行っているようですが、そのファイルパスが変になっていました。

以下、自分が試したことを書いていきます!
参考になれば幸いです。

※レジストリを変更した場合、最悪OSが起動できなくなってしまいます。
一切の責任は負いかねますので、変更する際は自己責任で!

試したこと

ぐぐるとよく出るのは、コマンドプロンプトから電源プランの設定を初期化する方法。
以下のコマンドでいけるみたいです。

powercfg -restoredefaultschemes

自分の場合はこれでは解決しませんでした。
powercfg /l で電源プランの一覧を表示すると、下のように普通に表示されるので、完全に逝っているわけではなさそうでした。

既存の電源設定 (* アクティブ)
———————————–
電源設定の GUID: 381b4222-f694-41f0-9685-ff5bb260df2e *
電源設定の GUID: 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c
電源設定の GUID: a1841308-3541-4fab-bc81-f71556f20b4a

お次はサービス「Power」の確認。
これが無効になっていたりすると表示されないみたいです。

・・・が、

shot2ss20161119224820063

元気に(?)動いておりました!
ぐぐった感じでは、電源プランのメッセージ「RCPサーバーを利用できません」といった旨が表示されている場合はこの可能性が高いかもです。

レジストリ修正

以下のサイトで (Windows7ですが) 似たような事例が紹介されておりました。

http://jutememo.blogspot.jp/2013/01/windows-7-cpu.html

ということでレジストリを疑ってみることに。
弄る前に復元ポイントは必ず作成しておきましょう。

自分の場合、以下のレジストリ直下のキーに原因がありました。
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Power\User\PowerSchemes

ここに2つの値が保存されており、powrprof.dll へのファイルパスが登録されているわけですが・・・

shot2ss20161119225936089

空白部分は自分のユーザ名なので消してありますが、Users\Music\Windows~というなかなかぶっ飛んだパスになっておりました。
これを現在 powrprof.dll があるパスに修正したところ、上手く表示されるようになりました!
カスタムプランも問題なく作れます。

shot2ss20161119231901938

思えば Windows7→10 にアップグレードしたとき、幾つかのプログラムが「Music」フォルダ直下に移動したという珍現象が起きましたが、それの影響なのかもしれません。
また、プラン作成時に「指定されたファイルが見つかりません」と言われたので、それも怪しかったです。
何故アップグレード時に Music に移動したのかは永遠の謎ですが・・・。

しかしこれで終わりではなく、この記事を書いている過程で上で紹介した「電源プランの初期化」コマンドを実行したところ、また Music 下を参照するようになってしまいました。
どうやらデフォルト設定のキーも逝っているため、初期化では解決しなかったようです。
ということで、以下のレジストリ直下のキーも修正しました。

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Power\User\Default\PowerSchemes

まとめ

そんなわけで、電源オプションが表示されない現象を頑張って調べてみました。
元々は高速スタートアップを無効化しようと始めた作業ですが、レジストリまで弄る厄介な作業になってしまいました。
ともかく正常に直ってよかったです。

重ねてになりますが、壊れても責任は負いかねますので、試す場合は自己責任でお願いします!