興味の源泉

自分が興味を起こせるようなネタを雑多に書き綴るブログ

【Git】Git BashでGit操作【備忘録】

f:id:nanami_yamato:20200216010243p:plain

Git Bashでの作業を行うときの備忘録に書き残しておきます。

目次

カレントディレクトリ変更

cd d:GitTest

clone

git clone git@github.com:リポジトリパス

fetch

git fetch

ブランチ切り替え

git checkout ブランチ名

現在のブランチから新しいブランチを作成してcheckout

git checkout -b 新しいブランチ名

変更のあったファイルの表示

git status

変更差分の表示

git diff

個別で指定したい場合はファイル名を記述

git diff ファイル名

※管理外のファイルは表示されない

コミットしたいファイルに追加されているものの差分

git diff --cached

コミットしたいファイルに追加

git add ファイル名
git add .

コミットしたいファイルから外す

git reset HEAD ファイル名

コミット

git commit -m "コメント"

コミットを取り消す

git reset --hard HEAD^
git reset --soft HEAD^

「--hard」は編集内容が消えるので慎重に。

プッシュ

git push

ローカルのブランチをリモートにプッシュする

git push origin ブランチ名

作業ディレクトリ内のブランチを一覧を表示する

git branch

* master

のように*が頭についているブランチが現在のブランチ。


目次へ

【Unity】EditorWindow入門

EditorWindow入門

前回の続きでEditorWindowをもう少し掘り下げていきます。

nanami-yamato.hatenablog.com

実行中のみ表示する

実行中のみ表示したいということはよくあります。

そういう時には、EditorApplication.isPlaying の値を見て false だったらそこで return してその先の処理をしないようにすることで実現できます。

if (!EditorApplication.isPlaying)
{
    return;
}

テキストエリア

f:id:nanami_yamato:20200201231025p:plain

改行できるテキストボックスを利用したいときはこれを使います。

/// <summary>テキストエリアの編集用文字列 ←(宣言部)</summary>
private string textArea = string.Empty;

// テキストエリア ← OnGUIの中のコード
textArea = GUILayout.TextArea(textArea);

ポップアップ

f:id:nanami_yamato:20200201231100p:plain

選択式のポップアップを使いたいときはこれを使います。

// ポップアップ
string[] items = new string[] { "選択肢1", "選択肢2", "選択肢3" };
popupSelectIndex = EditorGUILayout.Popup(popupSelectIndex, items);

自動配置

f:id:nanami_yamato:20200201231119p:plain

GUILayout.HorizontalScopeを使うことで、その直後の{}内の表示物を水平方向に等分で配置してくれます。

垂直方向のGUILayout.VerticalScopeもあります。

using (new GUILayout.HorizontalScope())
{
    // テキストボックス
    textBox1 = GUILayout.TextField(textBox1);

    // テキストエリア
    textArea = GUILayout.TextArea(textArea);

    GUILayout.Label("テスト");

    GUILayout.Label("テスト2");
}

画像を表示

画像を表示するときはGUI.DrawTextureを使うのですが、座標を指定しないといけません。

なので、GUILayoutUtility.GetLastRect()でひとつ前の表示物のRectを取得し、その座標を使っています。

/// <summar>テクスチャ ←(宣言部)</summary>
private Texture2D texture = null;

// 画像表示 ← OnGUIの中のコード
if (texture != null)
{
    Rect rect = GUILayoutUtility.GetLastRect();
    GUI.DrawTexture(new Rect(rect.x, rect.y + rect.height + 10, texture.width, texture.height), texture);
}

画像表示した場合は、そこより下に続けて表示物を置いていく場合は一工夫が必要になります。

まとめ

今回の内容全てを反映させたのが以下です。

f:id:nanami_yamato:20200201231407p:plain

using UnityEngine;
using UnityEditor;

public class EditorWindowTest1 : EditorWindow
{
    /// <summary>テキストボックスの編集用文字列</summary>
    private string textBox1 = string.Empty;

    /// <summary>ラベル用文字列</summary>
    private string label2 = "ラベル2";

    /// <summary>ラベル用文字列</summary>
    private string label3 = "";

    /// <summary>ポップアップの選択中インデックス</summary>
    private int popupSelectIndex = 0;

    /// <summary>テキストエリアの編集用文字列</summary>
    private string textArea = string.Empty;

    /// <summar>テクスチャ</summary>
    private Texture2D texture = null;

    [MenuItem("Tests/テストツール/Test1")]
    private static void Create()
    {
        GetWindow<EditorWindowTest1>("テストウィンドウ");
    }

    /// <summary>
    /// 実行時に呼ばれる
    /// </summary>
    private void OnEnable()
    {
        // 画像読み込み Asset/Resources/green.png
        texture = Resources.Load<Texture2D>("green");
    }

    /// <summary>
    /// 描画
    /// </summary>
    private void OnGUI()
    {
        // 常に描画するものを描画
        alwaysDraw();

        // 描画開始チェック
        if (!checkDrawStart())
        {
            return;
        }

        // 描画開始チェックを通ったときに描画
        draw();
    }

    /// <summary>
    /// 描画するかチェック
    /// </summary>
    /// <returns></returns>
    private bool checkDrawStart()
    {
        // 実行中でなければ表示しない
        if (!EditorApplication.isPlaying)
        {
            return false;
        }

        return true;
    }

    /// <summary>
    /// 常に描画するもの
    /// </summary>
    private void alwaysDraw()
    {
        // ラベル
        GUILayout.Label("常に描画するラベル");
    }

    /// <summary>
    /// UIを描画
    /// </summary>
    private void draw()
    {
        using (new GUILayout.HorizontalScope())
        {
            // テキストボックス
            textBox1 = GUILayout.TextField(textBox1);

            // テキストエリア
            textArea = GUILayout.TextArea(textArea);

            GUILayout.Label("テスト");

            GUILayout.Label("テスト2");
        }

        // ボタン
        if (GUILayout.Button("ボタン"))
        {
            label2 = "ボタン押された。 Text:" + textBox1 + "\nTextArea:" + textArea;
        }

        // ラベル表示
        GUILayout.Label(label2);

        // ポップアップ
        string[] items = new string[] { "選択肢1", "選択肢2", "選択肢3" };
        popupSelectIndex = EditorGUILayout.Popup(popupSelectIndex, items);


        // ポップアップを選択していたら選択した文字列をラベルに追加
        if (popupSelectIndex > 0)
        {
            label3 = items[popupSelectIndex];
            GUILayout.Label(label3);
        }

        // 画像表示
        if (texture != null)
        {
            Rect rect = GUILayoutUtility.GetLastRect();
            GUI.DrawTexture(new Rect(rect.x, rect.y + rect.height + 10, texture.width, texture.height), texture);
        }
    }
}

OnEnable関数でテクスチャを読み込んでいます。

OnGUI関数は「常に描画するもの」「実行時チェック」「実行中の描画」でそれぞれ関数化し流れを追いやすくしました。

Editor拡張でのツール作成や利便性を上げるのは大事なことです。

まずは一歩、この記事が何かのきっかけになれば良いなと思いながら締めとさせていただきます。

【Unity】EditorWindow超入門

Unityはメニューからウィンドウを開いて、色々できるウィンドウを作成することができます。

さわり部分だけですが紹介します。


まずはEditorフォルダの下にEditorWindow用のクラスを作成します。

f:id:nanami_yamato:20200123234053p:plain


ソースコードは以下のように記述すると

using UnityEngine;
using UnityEditor;
public class EditorWindowTest1 : EditorWindow
{
    [MenuItem("Tests/テストツール/Test1")]
    private static void Create()
    {
        GetWindow<EditorWindowTest1>("テストウィンドウ");
    }
}

メニューに追加されます。

f:id:nanami_yamato:20200123234456p:plain

メニューから選択するとウィンドウが開きます。

まだウィンドウ内について何も記述していないので空のウィンドウが表示されます。

f:id:nanami_yamato:20200123234728p:plain


基本の基本として、「ラベル」、「テキストボックス」、「ボタン」を配置したいと思います。

まずは全て置いたソースコードと実行結果を張ります。

using UnityEngine;
using UnityEditor;

public class EditorWindowTest1 : EditorWindow
{
    /// <summary>テキストボックスの編集用文字列</summary>
    private string textBox1 = string.Empty;

    /// <summary>ラベル用文字列</summary>
    private string label2 = "ラベル2";

    [MenuItem("Tests/テストツール/Test1")]
    private static void Create()
    {
        GetWindow<EditorWindowTest1>("テストウィンドウ");
    }
        
    private void OnGUI()
    {
        // ラベル
        GUILayout.Label("ラベル");

        // テキストボックス
        textBox1 = GUILayout.TextField(textBox1);

        // ボタン
        if (GUILayout.Button("ボタン"))
        {
            label2 = "ボタン押された。 Text:" + textBox1;
        }

        // ラベル
        GUILayout.Label(label2);
    }
}

f:id:nanami_yamato:20200123235356p:plain


OnGUIで描画時に毎回各パーツは処理されます。

ラベルは以下で表示できます。

GUILayout.Label(”表示したい文字列”);

テキストボックスは編集したものを入れる変数が必要になります。
サンプルのコードだとtextBox1に入っている値をテキストボックスの中に表示し、編集した値を入れなおしています。

textBox1 = GUILayout.TextField(textBox1);

ボタンは押されたときに if 分の中が実行されます。

if (GUILayout.Button("ボタン"))
{
    label2 = "ボタン押された。 Text:" + textBox1;
}

ボタンを押されたら変数label2に設定するので、そのあとのラベル表示で設定した文字を表示しています。


EditorWindowはUnityEditorで実行するツールづくりに最適です。
データを変換かけたり、ファイルを検索して中身を表示・編集して保存など、色々なものを作っていけます。

有効活用していきたいですね。

変数の精度には気をつけろ!【プログラミング】

注意※この話はC#を元にしますが、どの言語でも同じ概念があります。

有効数字の桁数

変数には扱える数が決まっています。

int なら -2,147,483,648 ~ 2,147,483,647
float なら ±1.5 x 10−45 ~ ±3.4 x 1038

扱える数値の桁数を有効数字の桁数と呼びます。
※以降、長ったらしいので有効桁数と呼ぶ

int の有効桁数は9桁(10桁目は9まで表すことができないので省く)
float は6 ~9 桁(.NetのC#リファレンス参照)

キャスト

有効桁数の話を進めたいところですが、その前に話をしなければならないのがキャストです。

キャストとはある型を別の型に変換することです。

まず下記を見てください。

    int a = 1;
    int b = 3;
    float result = a / b;

resultを出力した結果の値は0です。

なぜか。

int型 を int型 で割り、結果も int 型だからです。
結果をfloatに入れる前にint型として小数点以下は切り捨てられているので0になります。

ではどうすればいいかというと、

    int a = 1;
    int b = 3;
    float result = (float)a / b;

上記のように 変数a または 変数b を floatにキャストすると、計算が floatで行われ、結果が floatになります。

キャストと有効桁数

次に見てもらいたいのがこちら

    int a = 987654321;
    float b = a;
    int result = (int)b;

このresultの出力結果は私の環境では987654336になりました。

ここで有効桁数の話に戻りますが、float の有効桁数は約7桁です。
※なぜ約7桁なのか知りたい場合は浮動小数点数で検索してみてください

int から float に入れられるときに暗黙的に変換が起こり、桁数が足りなくなります。

なので、再度キャストをして int に戻したときに値が不定の桁があり、同じにならなかったということです。

これを解消するためには float ではなくdoubleにキャストすれば同じ値になります。


では次の場合はどうでしょうか。

    int a = 1234567;
    float b = 300.3f;
    float result = a * b;

この計算結果、本当ならば「370740470.1」なのですが、resultは「3.707404E+08」と出力され、intにキャストした場合「370740455」と出力されました。

この場合も計算結果が有効桁数より足りていないのが原因です。

float と double の変換の注意点

ではfloatをdoubleにキャストすれば良いじゃん、ということでやってみると

    int a = 1234567;
    float b = 300.3f;
    double c = (double)b;
    double result = a * c;

cの値は「300.299987792969」となり、resultの出力は「370740455.029602」となり、正しい値にはなりませんでした。

こういう挙動になる原因はおそらく、浮動小数点数は値を近似値として扱っているのが原因なのではと思います。
ここでの解決方法は、floatをdoubleにキャスト後、指定の桁数で丸めることです。

    int a = 1234567;
    float b = 300.3f;
    double c = (double)System.Math.Round((double)b, 1);
    double result = a * c;

これで cの値は「300.3」になり、resultの出力は「370740470.1」となって正しい値になりました。


まとめ

今回まとめてみて、floatとdoubleの変換でずれるのはやばいなと。

数字を扱う以上は小数点以下の扱いをどうするかは付きまといます。

どの型を使うのか。

小数点第何位までを有効として扱うか。

切り上げるのか、切り捨てなのか、四捨五入なのか。

意識して処理しないといけないなと今更ながらかみしめるのでした。

PlantUMLでUMLを書く

f:id:nanami_yamato:20191116211254p:plain

分析、設計においてUMLは強力なツールになります。 UMLは図で表すので文章だけに比べて理解しやすいです。

PlantUMLについて紹介したいと思います。

PlantUMLとは

PlantUML は、以下のようなダイアグラムを素早く作成するためのコンポーネントです。

図を書くツールですが、文字列の組み合わせで図を自動的に作ることができます。

ソースコードを書くように図が書けます。

何が一番メリットかというと、画像を作っているものをテキストとして扱えるということです。

テキストで扱えるということはバージョン管理でき差分がわかるようになるということです。

PlantUMLのサイト

下記がPlantUMLを説明してあるサイトです。

http://plantuml.com/ja/

また、書いたPlantUMLのテキストをオンラインサーバーに送って画像として表示または出力するページもあります。

気軽に使いたいときにはこのページを使うと良いでしょう。

オンラインで書いて出力できるページ  http://www.plantuml.com/plantuml/uml/SyfFKj2rKt3CoKnELR1Io4ZDoSa70000

エディタ+PlantUML

業務で使う場合などはオンラインサーバーに送りたくない場合もあるでしょう。

VSCodeatomなどで使用できます。

インストール方法は「エディタ名 PlantUML」などで検索すれば見つかるでしょう。

VSCodeは下記を参考にしたらいいんじゃないかな。

Visual Studio Code で UML を描こう! - Qiita

実際に書いてみる

冒頭のクラス図は以下のように書くと作れます。

@startuml
title クラス図
class people {
    -name
    -age
    +GetName()
    +GetAge()
}

class car {
    +typeName
    -color
    +GetTypeName()
    -getColor()
}
note "注釈文" as carNote
car .right. carNote

class money
{
    +type
    +Use()
    {static} yen
    {abstract} GetType()
}

car -left- people:乗る <
money -up- people:持つ <
@enduml

うん、これで図が描けるのはいいですね。

詳しく説明はしないので、PlantUMLのクラス図のページを見て実際に書いていってください。

シーケンス図も書いてみました。

仮想の課金処理のシーケンス図です。

@startuml
title 課金処理のシーケンス図

participant アプリ
participant サーバ
participant ストア

activate アプリ

アプリ -> ストア : 決済要求
ストア --> アプリ : レシート

アプリ -> サーバ : レシート
activate サーバ

サーバ -> ストア : レシート
activate ストア

ストア -> サーバ : 検証結果
deactivate ストア

サーバ -> サーバ : 結果保存

サーバ -> アプリ : 結果
deactivate サーバ

@enduml

f:id:nanami_yamato:20191116225601p:plain

シンプルに書けるようになっていることがわかります。(処理自体がシンプルということもあるのですが)

まとめ

PlantUMLについて紹介しました。

とにかくこういうのは自分で実践してみないことにはわかりません。

設計って難しいそう、とっつきづらそうなどという前に、手を動かしてみましょう。

そうやっているうちに痛い目も見てレベルアップもして、気が付いたらできなかったことができるようになっている。

そういうものですよ。

たぶん。

ビット演算の使いどころ

ビット演算はプログラムの基本ですが、今時は知らない人も多いかもしれません。
使いどころがあまり無くなってしまったことが原因な気がしますが、使いどころは今でもあります。

ビット演算とは何かを説明しようかと思ったのですが、うまくまとめてある記事があったのでそちらを見てもらうことにして。

ビット演算入門 - Qiita

ビット演算のメリット

ビット演算を使うメリットとは「計算速度が速い」「複数の情報を一つの変数に入れて扱える」の二点かなと思います。

デメリットはわかりにくくなりやすいことかなと思います。

容量の大きくなり端末の処理速度が上がった今では、使いどころが難しいのは確かです。

ビット演算の使いどころ

個人的に使うべきところと思うのは、ファイルやデータベースへの保存時に一つの変数やカラムに複数のフラグや数値を設定して保存するという使い方です。

例えばデータベースにONかOFFかを表す32個のフラグを保存する場合、1個1バイトのカラムで保存するとしたら32バイトになります。
そこを4バイト(32ビット)のカラム一つに保存すると8分の1の容量で済みます。
そのまま送り通信量を減らすこともできます。


ビット演算とは率先して使うものではないですが、使うと効果が出る状況は存在します。

ビット演算に限らず、色々な手法を知って選択肢を増やしていければいいですね。

ガチャの確率について考える

f:id:nanami_yamato:20190704005009p:plain

基本無料のゲームでガチャ主体で課金する体系のゲームが多いブラウザ、アプリゲーム(いわゆるソーシャルゲーム)業界。
ガチャガチャ私もするのですが、当たらないことも多々あります。辛い。

今回はガチャの確率について考えてみようと思います。


ここに最高レアリティが1%の確率で出るガチャがあるとします。

なんとなく、100回くらい引いたら出そうな気がしますが、確率的には期待値はそうではありません。

1回ガチャを引いて最高レアリティの出ない確率は99%です。

2回ガチャを引いて1回も最高レアリティの出ない確率は99%かける99%です。
数式で表すとは 0.99 * 0.99 = 0.9801 で約98%です。

この式になるのは何度ガチャを引いても1回の確率が同じだからです。

100回ガチャを引いて1回も最高レアリティの出ない確率は
0.99の100乗で0.366...
で約36.6%です。

なので、100回ガチャを引いて1回最高レアリティが出る確率は約63.4%です。
確率上は3人に2人は100回ガチャを引いて1回は出るということです。

裏を返せば3人に1人は100回ガチャを引いて1回も最高レアリティがでないことになります。
これは辛い。


さてここで最高レアリティのあるキャラを最高レアリティが出たら50%で引けるガチャがあったとします。
いわゆるピックアップガチャというやつです。

同じ感じで計算すると100回で引ける確率は
0.995の100乗で0.605…を1から引いた約0.4で40%ぐらいです。
このピックアップガチャの期待値は100回までに引ける人は5人に2人ということです。
これはマジで当たらなそう。

200回にして計算してみても
0.995の200乗で0.366…を1から引いた約0.65で65%ぐらいです。

さらに300回にして計算してみても
0.995の300乗で0.222…を1から引いた約0.77で77%ぐらいです。

あれれー?おかしいぞー?
ここでおかしいと思った方もいるかもしれません。
200回引いてるうちに1回引ける確率が65%なのに300回引いてるうちに1回引ける確率は77%なんです。

これはどこまで行っても1回を引く確率が5%だからなんですよね。
500回引こうが1000回引こうが、100%に近づくことはあっても100%にはなりません。
100%に近づく量がどんどん緩やかになります。

ほぼないけど、1000回引いてピックアップガチャで目当てのキャラが当たらない人はいるということです。怖いですね。
参考までに1000回引いて当たらない確率的には0.66%です。言い換えると1000人に6人くらい。

天井というシステムは救済措置としては最強ということが改めてわかります。
※天井とは例えば300回引くと指定のキャラと交換できる、またはピックアップキャラが当たるというシステムのことを指しています


ガチャのご利用は計画的にですよね。