- 投稿日:2021-07-20T23:09:03+09:00
C#の基本イディオムについてその2~条件文・判定編~
C#で条件分岐や判定をしたい場合の基本的なイディオムについてまとめた。 変数の値を比較するだけの場合 (例)valという数値型の変数が5以上かどうかを判定したい時、 if(val >= 5) 変数を左にして書く。 if(5 <= val) でも間違いではないが、基本的に文字は右から左に読むので、読みづらい。 変数の値が特定の範囲内にあるかどうかを判定する場合 (例)valという数値型の変数が5より大きく、10未満かどうかを判定したい時、 if(5 < val && val < 10) 判定したい値が指定した数値の中にあるかどうかが分かるように書く。 数学の5<x<10をイメージするといい。 複数の条件があり、その全ての条件を満たすときだけ処理をしたいとき (例)nameがジョルノ・ジョバーナ、partが5、ageが15のときのみ何か処理をしたい時、 if(name != "ジョルノ・ジョバーナ") return; if(part != 5) return; if(age != 15) return; (実行したい処理を書く) 1つのifで1つの条件を判定するようにする。 「return;」とだけ書くと、実行をその場でやめる。 if(name != "ジョルノ・ジョバーナ" && part != 5 && age != 15) return; まとめて書くと条件が多ければ多いほど見にくくなってしまうので、分けて書く場合がベター。 ただbool値を返したい (例)nameがジョルノ・ジョバーナかどうかだけを判定したい場合、 return name == "ジョルノ・ジョバーナ"; returnの後に条件分を書けばいいだけ。 「==」や「!=」は比較演算子なので、変数や値を比較演算子つなげて書くと、trueかfalseのbool値を返すので、 if(name == "ジョルノ・ジョバーナ") { return true; } else { return false; } のように書くと冗長的な書き方になってしまうので、特にこだわりがなければ、上記の書き方はしない。 「name == "ジョルノ・ジョバーナ";」がtrueかfalseを返すことが分かっているので、余計に書く必要はない。 参考文献
- 投稿日:2021-07-20T22:35:51+09:00
C#の基本イディオムについてその1~変数の初期化編~
C#でコードを書く際の基本的なイディオムについて、まとめてみた。 変数の初期化 変数名と値は一緒に定義する。 var name = "aiueo"; もちろん、 var name; name = "aiueo"; と書くこともできるが、2行で各理由が特になければ、1行で済ませる。 配列の変数の初期化 変数名と同様に、変数名と値を一緒に定義する。 var arrayData1 = new string[] {"あいうえお", "かきくけこ", "さしすせそ"}; var arrayData2 = new int[] {0, 1, 2}; var arrayData3 = new List<int>() {3, 4, 5, 6, 7, 8, 9}; 以下の書き方も間違ってはいないが、コードが増えてしまうので、基本的に1つでまとめられる場合は1行でまとめてしまうのがベター。 var arrayData1 = new string[] {}; arrayData1[0] = "あいうえお"; arrayData1[1] = "かきくけこ"; var arrayData3 = new List<int>() {}; arrayData3.Add(1); arrayData3.Add(2); オブジェクトの初期化 public class Person { public string FirstName { get; set; } public string LastName { get; set; } public int Age { get; set; } } というPersonクラスが定義されていたとする。(コンストラクタはない。) 新しいオブジェクトを作成する際は、 var person1 = new Person { FirstName = "太郎", LastName = "山田", Age = 22, } のようにまとめて定義してしまう。 クラスの中にコンストラクタがあった場合 public class Person { public string FirstName { get; set; } public string LastName { get; set; } public int Age { get; set; } public Person(string fn, string ln, int age) { FirstName = fn; LastName = ln; Age = age; } } 上記のように、Personクラスの中にコンストラクタがある場合、person1を作ったときのように初期化しようとすると、構文エラーになるので、注意。 この場合は、 var person1 = new Person("太郎", "山田", 12); コンストラクタの引数順に値をセットすること。 参考文献
- 投稿日:2021-07-20T15:35:27+09:00
UnityでNavMeshを使わず、特定のGameObjectを巡回させるスクリプト
Patrol.cs using UnityEngine; using System.Collections; public class Patrol : MonoBehaviour { [SerializeField, TooltipAttribute("経由地点の数を入力し,シーン上に配置した空のオブジェクトをアサインします")] public Transform[] wayPoints; public Transform target; public float speed; public int currentRoot; void Update() { //配列に入れたTransformを順に巡る.AIを使っていればスムーズに曲がるがこれは鋭角に曲がる float step = speed * Time.deltaTime; transform.position = Vector3.MoveTowards(transform.position, wayPoints[currentRoot].position, step); Vector3 pos = wayPoints[currentRoot].position; float test = Vector3.Distance(target.position, pos); transform.LookAt(pos); if(Vector3.Distance(transform.position, pos) < 0.5f) { currentRoot = (currentRoot < wayPoints.Length - 1) ? currentRoot + 1 : 0; } } }
- 投稿日:2021-07-20T14:02:30+09:00
Unityで音ゲーを作った!!(アルゴリズムとソース付き)
はじめに 音ゲーを作ろうとした時に調べても具体的なソースコードやアルゴリズムに関する記事が無かったので、自己解決した方法を載せます。 分からないことがあったり、間違いがあればコメントお願いします。 手順 1.譜面を作る 2.ノーツを作る 3.ノーツをタイミングに合わせて生成する 4.ノーツのタップ判定を作る 5.音楽を再生する 1.譜面を作る 私はNoteEditorという外部Assetを使用して作りました。 NoteEditorの使い方はコガネブログさんが説明されてますので、そちらを参考にしてください。 ちなみにBPMが分からないものはBPMカウンターという便利なサイトがあるので使用してみてください。 2.ノーツを作る 生成したいノーツを作りましょう。 後でノーツ生成から判定場所までかかる時間を取得するので、それを考慮したものの方が良いと思います。 今回は簡単に横移動のみのノーツでやっていきます。 とりあえずこんな感じです。 これはPrefabにしておきます。 3.ノーツをタイミングに合わせて生成する ①譜面の解説 ②譜面を読み込む ③読み取った情報からノーツを生成する の順で説明していきます。 ①譜面の解説 先ほど作った譜面はJson形式で保存されています。 まず、そのファイルを見てみましょう。 Score.json { "name": "MusicName", "maxBlock": 5, "BPM": 130, "offset": 0, "notes": [ { "LPB": 8, "num": 2, "block": 4, "type": 1, "notes": [] }, { "LPB": 8, "num": 137, "block": 1, "type": 1, "notes": [] }, こういった形式になっています。 こちらに書かれているもので使用しないものもあるので、使用したものを上から順に説明していきます。 BPM 一分間に何回拍が打たれるかを数値にしたものです。 例えば、BPM120なら60秒間に120拍、つまり60/120で1拍0.5秒ということになりますね。 この1拍の時間というのは後々使うことになるので覚えておいてください。 notes 1つのノーツの情報をまとめた配列になってます。 ここに書いてあるものも使うので説明していきます。 LPB 私の知る限り音楽用語ではありません。 NoteEditor独自の用語ではないでしょうか? これは1拍を何分割してノーツを置くかというものです。 NoteEditorでは下記のようになっています。 太い縦線が拍を意味していて、細線がここでいうLPBを意味しています。 例えば、BPM120でLPB8で、細線に二連続で置くと、その間隔は 60/120/8[秒] となりますね。 これも後々使います。 途中でLPBを変えると色々おかしくなってしまうので注意してください。 num これは開始の縦線を0、次の縦線を1としてどこの縦線に置かれているかの情報です。 ということは、縦線の間隔は均等なので開始からどのくらいの時間が必要なのかは『60/BPM/LPB*num』で分かりますね。 block これは横線の位置を意味しています。 上から0,1,2,3,4です。 私はノーツの種類を分ける時に使いました。 ②譜面を読み込む UnityでJSONファイルを読み込むを参考に読み込みます。 NotesGenerator.cs using UnityEngine; using System; public class NotesGenerator : MonoBehaviour { [Serializable] public class InputJson { public Notes[] notes; public int BPM; } [Serializable] public class Notes { public int num; public int block; public int LPB; } private int[] scoreNum;//ノーツの番号を順に入れる private int[] scoreBlock;//ノーツの種類を順に入れる private int BPM; private int LPB; void Awake() { MusicReading(); } /// <summary> /// 譜面の読み込み /// </summary> void MusicReading() { string inputString = scoreData.ToString(); InputJson inputJson = JsonUtility.FromJson<InputJson>(inputString); scoreNum = new int[inputJson.notes.Length]; scoreBlock = new int[inputJson.notes.Length]; BPM = inputJson.BPM; LPB = inputJson.notes[0].LPB; for (int i = 0; i < inputJson.notes.Length; i++) { //ノーツがある場所を入れる scoreNum[i] = inputJson.notes[i].num; //ノーツの種類を入れる(scoreBlock[i]はscoreNum[i]の種類) scoreBlock[i] = inputJson.notes[i].block; } } } これでscoreNum[]にすべての音符の場所データが入りました。 さてここから音楽のタイミングに合わせて生成を行います。 ③読み取った情報からノーツを生成する 一番の難所であろうところです。 いやぁ・・・苦戦したな・・・。 先に生成部分のソースコードを載せます。 NotesGenerator.cs using UnityEngine; using System; public class NotesGenerator : MonoBehaviour { [SerializeField] private GameObject notesPre; private float moveSpan = 0.01f; private float nowTime;// 音楽の再生されている時間 private int beatNum;// 今の拍数 private int beatCount;// json配列用(拍数)のカウント private bool isBeat;// ビートを打っているか(生成のタイミング) void Awake() { InvokeRepeating("NotesIns", 0f, moveSpan); } /// <summary> /// 譜面上の時間とゲームの時間のカウントと制御 /// </summary> void GetScoreTime() { //今の音楽の時間の取得 nowTime += moveSpan; //(1) //ノーツが無くなったら処理終了 if (beatCount > scoreNum.Length) return; //楽譜上でどこかの取得 beatNum = (int)(nowTime * BPM / 60 * LPB); //(2) } /// <summary> /// ノーツを生成する /// </summary> void NotesIns() { GetScoreTime(); //json上でのカウントと楽譜上でのカウントの一致 if (beatCount < scoreNum.Length) { isBeat = (scoreNum[beatCount] == beatNum); //(3) } //生成のタイミングなら if (isBeat) { //ノーツ0の生成 if (scoreBlock[beatCount] == 0) { } //ノーツ1の生成 if (scoreBlock[beatCount] == 1) { Instantiate(notesPre); } beatCount++; //(5) isBeat = false; } } } (1)InvokeRepeatingを使いmoveSpan(0.01秒)ごとに処理を行っているためです。 (2)NoteEditorでいう、今どこの縦線にいるかの取得をします。 (3)scoreNum[]はノーツの場所の情報を順に入れているものなので、いまどこの縦線にいるかを見ているbeatNumと等しかったらノーツ生成のタイミングになります。 (4)生成が終わったら次のscoreNum[]の要素を見たいので足します。 さあこれでノーツの生成が終わりました。 4.ノーツのタップ判定を作る タップした時の判定を作っていきます。 生成からタップさせたいタイミングのところまでの移動でかかる時間からカウントダウンしていき、その差で判定します。 NotesMove.cs using UnityEngine; using System; public class NotesMove: MonoBehaviour { [SerializeField] private float notesSpeed; [SerializeField] private Vector2 startPos;//ノーツの開始位置 [SerializeField] private Vector2 judgePos;//判定したい場所 public static float moveSpan = 0.01f;//回すスパン private float notesTime; void Start() { notesTime = (startPos.x - judgePos.x) / notesSpeed; InvokeRepeating("NotesMove", 0, moveSpan); } void NotesMove() { transform.position += new Vector3( -notesSpeed, 0f, 0f); notesTime -= moveSpan; NotesJudge(); } void NotesJudge() { if(Math.Abs(notesTime) < 0.5f) { //判定した時の処理を書く } } } こんな感じです。 これを使い次の工程に移ります。 5.音楽を再生する 音ゲーに欠かせないのが音楽です。 先ほどの生成のタイミングと音楽が噛み合わなかったら元も子もないですよね。 今のコードでは本来ノーツが判定されるタイミングで生成を行っています。 つまり、生成から判定したい場所までにかかる時間分ずれていることになります。 このずれを直していきます。 まず、譜面のnotes[0]に Score.json "notes": [ { "LPB": 8, "num": 0, "block": 0, "type": 1, "notes": [] }, を追加します。LPBは各自合わせてください。 次にNotesGeneratorに NotesGenerator.cs using UnityEngine; using System; public class NotesGenerator : MonoBehaviour { [SerializeField] private AudioSource gameAudio; public static isAudioPlay=false; //ノーツ0(音再生用ノーツ)の生成 if (scoreBlock[beatCount] == 0) { } //音再生開始 void AudioPlay() { gameAudio.enabled = isAudioPlay; } } を追加します。 そして、音再生用ノーツの設定です。 先ほど作ったノーツのprefabを複製し、タグをAudioPlayとしておきます。 コードは NotesMove.cs using UnityEngine; using System; public class NotesMove: MonoBehaviour { void NotesJudge() { if(this.gameObject.tag=="AudioPlay") { if(notesTime =< 0)//判定位置に来たら { NotesGenerator.isAudioPlay= true; } } } } を追加します。 これはどういうことかというと、NoteEditorでは音楽が開始したときにnum0になっています。 これはプレイヤーがノーツをタップしたいタイミングですよね。 ということはすべてnum0からの差分で生成するタイミングを取っているので、num0が判定場所に来てそのタイミングで音を開始したらずれません。 完成 これで完成です。 誰かの力になれたら嬉しいです。
- 投稿日:2021-07-20T11:56:38+09:00
LINQPadでODataのサービスに対して検索して、ODataクエリを確認する
はじめに Office 365のAPIの動作確認をするために、ODataクエリの動作確認を簡単にできるものが無いかな?と思いLINQPadのOData ドライバーについて調査しました。 残念ながらOIDCやAOuthなどのクレームベースの認証には対応していないので、Outlookなどの認証が必要なODataエンドポイントに対して利用する場合は、前段で認証を処理してくれるCDATAのアダプターなどを導入する必要がありそうです。 ただ、認証が必要ないか、後述するいくつかの認証方式で良い場合はそのまま利用できそうなので導入方法を書いておきます。 導入 コネクション作成時に表示されるView more driversから新しいドライバーの追加を行うことができます。 ドライバーの検索画面でodataなどのキーワードで検索し、OData v4 Driverを選択してinstallボタンからインストールします。 正常にインストールされると、コネクションの一覧に先ほどインストールしたOdata v4 Connectionが表示されるので、このドライバーを使って接続を作成していきます。 コネクションの作成 odata.orgで提供されているサンプルサービスを参照してみます。LinqPadはこのURLをベースにmetadataを探しに行くようですね。 現在はAccept invalid certificatesにチェックをしないと下記のようにエラーになってしまうようなので注意が必要です。 接続作成時にはLog ondetailsにある次の認証方式のクエリだけがサポートされています。 - No authentication - Windows authentication - Basic authentication - Client certificate authentication OAuthでの認証ができないか?といった内容がLINQPadのフォーラムに挙がっていましたが、現在のところサポートされていないようです。 https://forum.linqpad.net/discussion/113/odata-service-and-oauth コネクションが登録できると、コネクションツリーにプロパティーが表示されます。 クエリの実行 クエリを実行するとResultsタブに結果が表示され、 SQLタブにODataのクエリが表示されます。 C#のコードでフィルタしたりソートすると、ODataクエリが変更され 結果がその通りに表示されることが分かります。 ただし、ODataのクエリに変換できないような式はエラーになってしまいます。