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

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

C#を勉強する11_文字列の比較

転職活動のなかで、paizaに出会った。
paiza.jp
paizaのスキルチェックでは、プログラミングの問題を解くことができる。この問題を解く際に、文字列やリストを操作するメソッドを知っていると、ソースを簡潔に書くことができる。C#には色々便利なメソッドが用意されているので、まずは文字列操作から色々まとめていく。

文字列の比較

Javaで慣れているとequalsメソッドを使おうとするが、C#では==演算子を使える。

if (str1 == str2) { }

ただ、この文字列比較は色々種類がある。さっきの==演算子を使った比較は、完全一致が条件になるが、大文字・小文字の区別なく比較したい場合などもでてくる。
そういった時は、Compareメソッドを使う。

var str1 = "windows";
var str2 = "WINDOWS";
// 第3引数をtrueにすることで、大文字・小文字の区別なく比較
if (String.Compare(str1, str2, true) == 0) { }

このCompareメソッドはオーバーロードされたメソッドがある。

var str1 = "カステラ";
var str2 = "かすてら";
var cultureInfo = new CultureInfo("ja-JP");
// ひらがなとカタカナの区別なく文字列比較
if(String.Compare(str1, str2, cultureInfo, CompareOptions.IgnoreKanaType) == 0) { }
var str1 = "HTML5";
var str2 = "HTML5";
var cultureInfo = new CultureInfo("ja-JP");
// 全角と半角の区別なく文字列比較
if(String.Compare(str1, str2, cultureInfo, CompareOptions.IgnoreWidth) == 0) { }
var str1 = "Computer";
var str2 = "COMPUTER";
var cultureInfo = new CultureInfo("ja-JP");
// 全角・半角、大文字・小文字の区別なく文字列比較
if(String.Compare(str1, str2, cultureInfo, CompareOptions.IgnoreWidth : CompareOptions.IgnoreCase) == 0) { }

【Unity】ダメージをくらったら、Spriteを点滅させて無敵時間を作る方法

横スクロールアクションや、シューティングゲームでよくあるあれです。
まずSpriteを点滅させる方法は、SpriteRendererコンポーネントのアルファ値を変化させてやれば、実装できる。そのときのソースコードがこれ。

public SpriteRenderer sp;

// ダメージ判定フラグ
private bool isDamage{get; set;}

void Update() {

    // ダメージを受けている場合、点滅させる
    if(isDamage) {

        float level = Mathf.Abs(Mathf.Sin(Time.time * 10));
        sp.color = new Color(1f, 1f, 1f, level);

    }

}

// トリガー発生時
private void OnTriggerEnter2D(Collider2D collider) {

    StartCoroutine(OnDamage());

}

public IEnumerator OnDamage() {

    yield return new WaitForSeconds(3.0f);
        
    // 通常状態に戻す
    isDamage = false;
    sp.color = new Color(1f, 1f, 1f, 1f);

}

このソースであれば、敵からダメージを受けたら3秒間は点滅する。

あと無敵時間を作るのは簡単で、このダメージ判定フラグを利用する。
OnTriggerEnter2Dメソッド内に、ダメージを受けた際の挙動を実装する場合、ダメージ判定フラグがTrueならば処理をスキップさせてやればいい。

// トリガー発生時
private void OnTriggerEnter2D(Collider2D collider) {

    // ダメージ中は処理スキップ
    if(isDamage) {
        return;
    }

    StartCoroutine(OnDamage());

}

【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文を使っちゃいそうではある。。