転職を繰り返したサラリーマンの多趣味ブログ

30才未経験でSEに転職した人の多趣味ブログ

【Unity】TextがSpriteの後ろの隠れてしまう問題

タイトルそのまんまです。ゲーム作ってたら、こんな感じでTextオブジェクトがSpriteの後ろになってしまう問題が発生。
f:id:uuc1h:20200221200003p:plain
Sprite同士なら簡単にいくのだが、TextとSpriteだとどうしていいのかわからず、結構悩んでいた。
で、解決した方法がこちら。

  • Override Sortingにチェックをつける。
  • Order in Layerを1以上にする。

f:id:uuc1h:20200221200309p:plain
これで、さきほどSpriteに隠れていた「READY」というTextオブジェクトが、Spriteより上にくるようになった。
f:id:uuc1h:20200221200427p:plain

C#を勉強する⑩_初期化に関して

基本的には、変数の宣言と値の設定はセットで行うことがイディオム(慣用的なコード)とされている。そうしないと、コードの可読性が落ちるから。例としては、以下のような感じ。

int age;
Console.WriteLine("hoge");
// 宣言と値の設定の間に、別なコードが記載されているため可読性が落ちている
age = 25;

C#では、配列、Dictionary、オブジェクトでも初期化構文が用意されている。これを順に書いていく。

配列とリストの初期化

var langs = new string[] { "C#", "VB", "C++", };
var nums = new List<int> { 10, 20, 30, 40, };

Dictionaryの初期化

var dict = new Dictionary<string, string>() {
    {"ja", "日本語" },
    {"en", "英語" },
    {"es", "スペイン語" },
    {"de", "ドイツ語" },
};

オブジェクトの初期化

var person = new Person {
    Name = "山田太郎",
    Birthday = new DateTime(1995, 11, 22),
    PhoneNumber = "012-345-678",
};

ここらへんは便利機能というよりかは、あくまでコードの可読性をあげるためのお作法な気がする。

C#を勉強する⑨_可変長引数、オプション引数、コンストラクタ定義について

可変長引数

メソッド定義で、引数の数を限定しない書き方。引数は、配列として扱う。

public static void Main(string[] args) {

    // 3が出力される
    Console.WriteLine(LastNum(1, 2, 3));

    // 5が出力される
    Console.WriteLine(LastNum(1, 2, 3, 4, 5));

}

public static int LastNum(params int[] args) {

    return args[args.Length - 1];

}

オーバーロードのオプション引数

オーバーロードのオプション引数を使えば、メソッドの呼び出し方でデフォルト値を渡すことができる。

public static void Main(string[] args) {

    // 5fault3 と出力
    DoSomething(5);

    // 5success3と出力
    DoSomething(5, "success");

    // 5success15と出力
    DoSomething(5, "success", 15);

}

public static void DoSomething(int num, string message = "fault", int retryCount = 3) {

    Console.WriteLine(num + message + retryCount);

}

複数のコンストラクタ定義

コンストラクタ内で、引数の違うコンストラクタを呼ぶ場合の書き方。書く行は少なくて、引数の指定が色々できるので便利。

public Sale(int m, int n)
    : this(m, n, 0, 0) { // 引数4つのコンストラクタを呼び出し

}

public Sale(int m, int n, int b)
    : this(m, n, 0, b) { // 引数4つのコンストラクタを呼び出し

}

public Sale(int m, int n, int a, int b) {

}

C#を勉強する⑧_プロパティの初期化

これまでプロパティの初期化といったら、コンストラクタでやるものだと思ってた。

class Sale {
    public int number { get; set; }
 
    // コンストラクタ
    public Sale() {
        number = 10;
    }
}

けど、C#ではコンストラクタを使わずにプロパティの初期化ができる。これは便利。

public int number { get; set; } = 6;

上の書き方だと外部のクラスからプロパティが変更されてしまうので、読み取り専用プロパティの書き方も別途ある。

public int number { get; private set; } = 6;

読み取り専用は、こんな書き方もある。

public string Name => "山田太郎";

だが、参照型のプロパティを読み取り専用にするには、特別な書き方を必要とする。

// これで要素の変更などはできない
public IReadOnlyList<int> MyList { get; private set; }

C#を勉強する⑦_条件演算子、null合体演算子、null条件演算子

条件演算子

if文で書くと4行になるところが、条件演算子を使うと1行で書ける。たしかに便利だが、慣れないと普通にif文使ってしまいそう。

// ?より前が条件式
// trueなら1、falseなら0を返却
var num = list.Contains(key) ? 1 : 0;

null合体演算子

// GetMessageの戻り値がnullの場合、message変数にはDefaultMessageの戻り値をセットする
// GetMessageがnull以外を返したら、message変数にそのままセットする
var message = GetMessage(code) ?? DefaultMessage();

こちらもif文で書くと複数行になるところが、null合体演算子を使えば1行でまとめられる。

null条件演算子

// sale変数がnull以外なら、Productプロパティを返す
// sale変数がnullなら、そのままnullを返す
return sale?.Product;

これは条件演算子を使っても書ける。

return sale == null ? null : sale.Product;

null条件演算子は配列に対しても書けるが、その場合はドットが不要。

// customersがnull以外なら、配列の0番目の要素を返す
return customers?[0];

これらを使えこなせば、if文に頼らず簡潔なコードが書けそう!けど、常に意識しないと絶対if文を使っちゃいそうではある。。

C#を勉強する⑥_LINQ to Objects

LINQは「Language Integrated Query」の略。自分が勉強したイメージだと、SQLの構文をC#で使えるイメージ。LINQを使うには、usingディレクティブを使って名前空間System.Linqを指定する。
イメージでSQLと言ったのは、LINQにはクエリ演算子なるものが用意されているから。以下に例を示す。

var names = new List<string> {
                "Tokyo", "New Delhi", "Bangkok", "London", "Paris", "Berlin", "Canberra", "Hong Kong",
            };

// listより、文字列が5以下の要素を抽出
IEnumerable<string> query = names.Where(s => s.Length <= 5);

なお、クエリ演算子は数が多いため、必要に応じて都度調べることにする。

遅延実行

LINQの特徴に、遅延実行がある。これは、本当にデータが必要になったときにクエリが実行されることをさす。

var names = new List<string> {
                "Tokyo", "New Delhi", "Bangkok", "London", "Paris", "Berlin", "Canberra", "Hong Kong",
            };

// listより、文字列が5以下の要素を抽出
IEnumerable<string> query = names.Where(s => s.Length <= 5);

foreach(var item in query) {

    // TokyoとParisが出力
    Console.WriteLine(item);

}

// リストを更新
names[0] = "Osaka";

foreach(var item in query) {

    // OsakaとParisが出力される
    // Tokyoが出力されないのは、このタイミングでWhereメソッドが実行されているため
    Console.WriteLine(item);

}

逆に即時実行をしたい場合は、WhereメソッドとToArrayメソッドをメソッドチェーンでつなぎ、配列に変換してしまえばいい。

var names = new List<string> {
                "Tokyo", "New Delhi", "Bangkok", "London", "Paris", "Berlin", "Canberra", "Hong Kong",
            };

// listより、文字列が5以下の要素を抽出し、配列に変換
IEnumerable<string> query = names.Where(s => s.Length <= 5).ToArray();

foreach(var item in query) {

    // TokyoとParisが出力
    Console.WriteLine(item);

}

// リストを更新
names[0] = "Osaka";

foreach(var item in query) {

    // TokyoとParisが出力される
    Console.WriteLine(item);

}

C#を勉強する⑤_List<T>クラスとラムダ式の組み合わせ

Listクラスには、デリゲートを引数に受け取るメソッドが用意されている。
paizaなどで問題を解く際、Listの操作をするシチュエーションは多々ある。ラムダ式を使うことでListの操作を簡潔にかけるので、ここでまとめておく。
なおこれから書くメソッドは、以下のListオブジェクトがある前提とする。

var list = new List<string> {
                "Tokyo", "New Delhi", "Bangkok", "london", "Paris", "Berlin", "Canberra", "Hong Kong",
            };

Existsメソッド
引数で指定した条件に一致する要素が存在するかどうかをtrue / falseで返す。

var exists = list.Exists(s => s[0] == 'A'); // 再祚の文字列がA
Console.WriteLine(exists); // falseと出力される

Findメソッド
引数で指定した条件と一致する要素を検索し、最初に見つかった要素を返す。

var name = list.Find(s => s.Length == 6); // 文字列が6の要素
Console.WriteLine(name); // londonが出力される

FindIndexメソッド
条件と一致するインデックスを返す。

int index = list.FindIndex(s => s == "Berlin"); // 要素の文字列がBerlin
Console.WriteLine(index); // 5が出力される

FindAllメソッド
FindAllメソッドは、引数で指定した条件と一致するすべての要素を取得する。Findメソッドとの大きな違いは、条件に一致するすべての要素を返却する点。

var names = list.FindAll(s => s.Length <= 5); // 文字列が5以下の要素
foreach(var s in names) {
    Console.WriteLine(s); // Tokyo Parisが出力される
}

RemoveAllメソッド
引数で指定した条件に一致する要素をリストから削除し、削除した要素数を返す。

var removedCount = list.RemoveAll(s => s.Contains("on")); // onが含まれる要素を削除
Console.WriteLine(removedCount); // 2が出力される
foreach(var s in list) {
    Console.WriteLine(s); // london Hong Kongが削除されたリストが出力
}

ForEachメソッド
リストの各要素に対して、引数で指定した処理を実行する。

list.ForEach(s => Console.WriteLine(s)); // listの全要素を出力する

ConvertAllメソッド
リスト内の要素を別の型に変換し、変換された要素が格納されたリストを返す。

var lowerlist = list.ConvertAll(s => s.ToLower()); // listの全要素をToLowerメソッドで小文字に変換