【Unity】Visual Studioとの統合が上手くいかないとき

導入

Visual Studioとの統合で上手くいかない箇所をまとめました。

統合が出来ているか確認する方法

以下の通りだと、統合が正しく出来ています。

  • Visual StudioのRunボタン(緑色の▶)の右にある文字列が、「アタッチ」ではなく、「Unityにアタッチ」になっている
  • gaと打つと、GameObjectという予測変換が出てくる
  • 関数の上に、「Unityメッセージ〇個の参照」という文字が表示される

①基本的な問題

基本的には、以下の動画を見て下さい。

重要なポイントは、

  • Visual Studio Installerで、「Unityによるゲーム開発」をインストールすること
  • Preferences>External Tool>External Script Editorで、「Visual Studio」を選択すること

また、動画では、再インストールすれば絶対治ると言っていますが、そんなこと無かったです。自分の場合は、②で上手くいきました。

②強制的に読み込ませる

Preferences>External ToolのExternal Script EditorをVisual Studioにした後、下に沢山のチェックボックスが現れます。デフォルトでは、2箇所だけチェックが入っていると思いますが、これをとりあえず全部チェックします。

その後、Regenerate Project filesというボタンを押します。

更にその後、Visual Studioを開くと、ファイル変更の検出という名前のポップアップが出てくるので、再読み込みを選択します。

このようにすると、正しく読み込まれ、統合が上手くいきます。

③一部のクラスだけ読み込まれない

EditdorGUILayout、Selection、EditorWindow等の、エディタ上で動作するクラスが読み込まれず、赤線が表示されることがあります。

この問題は、該当ファイルをAssets/Editorというフォルダに配置すると治ります。

Assets/Editorは、Assets/Resourcesと同じような特殊フォルダで、エディタ用のスクリプトを配置するフォルダになっています。

④特殊フォルダ間の参照が出来ない

Assets/EditorとAssets/Editor以外のコードは、自動的にプロジェクトが分離されます。これにより、Assets/Editor内のコードから、Assets/Editor外にあるクラスを使おうとしても、クラスが存在しないというエラーが発生することがあります。

この問題は、ソリューションエクスプローラー(右側のウィンドウ)のプロジェクト(Assembly-CSharp.Player)を右クリックして、全ての依存関係ツリーの読み込みを選択して、全てのファイルを読み込むことで治ります。

【Unity】VSCode(Cursor)のシンタックスハイライトを修正する方法

状況

  • VSCodeもしくはCursorを使って、Unityのコードを書いている。
  • VSCodeを開いた直後やリロード直後に一瞬(もしくは数十秒)だけ良い感じのシンタックスハイライトが表示されるが、その後、色がおかしくなる。
  • Vector3などのUnity関連のクラスや自作クラスに正しい色が付かない。

原因の概要

UnityとVSCode(Cursor)との開発環境の統合が上手くいっていない。

解決策(VSCodeの場合)

下の動画のように、Unityのパッケージマネージャーで、

https://github.com/needle-mirror/com.unity.ide.visualstudio.gitを指定してインストールします。

その後、Unityを再起動すると、VSCodeでシンタックスハイライトが正常になります。

解決策(Cursorの場合)

この動画のように、Unityのパッケージマネージャーで、https://github.com/boxqkrtm/com.unity.ide.cursor.gitを指定してインストールします。

その後、Unityを再起動すると、Cursorでシンタックスハイライトが正常になります。

※boxqkrtm/com.unity.ide.cursorとneedle-mirror/com.unity.ide.visualstudioは、対象の開発環境が違うだけで内容は同じです。

【ブラウザゲーム】Fishing Days

操作方法

(PC・スマホ両対応)

クリック or タップ:浮きを投げる。浮きを引っ張る。

遊び方

浮きを投げて、魚を待ちます。浮きをよーく観察して、魚が来ていそうなら浮きを引っ張ります。魚が引っかかったら連打で岸まで寄せます。

【javascript】async、awaitの正確な仕様を理解する

前提知識

Microtask queueMacrotask queueー非同期処理が格納されるキュー。setTimeoutはMacrotask、Promiseのコールバック関数はMicrotask queueである。

・処理の優先順位は、コールスタックに入れられた関数>Microtask queue>Macrotask queue。コールスタックが空になったとき、Microtask queueが呼ばれ、その両方が空になったとき、Macrotask queueが呼ばれる。

・要するに、大まかに言うと、処理の順番は、「非同期じゃないコード」→「Microtask queueに入れられた関数(キュー入れられた順)」→「Macrotask queueに入れられた関数(キューに入れられた順)」である。(途中で優先度の高い処理が追加されると前に戻る)

仕様① awaitが読み込まれたときの挙動

・awaitの行に差し掛かった時、awaitの右に書かれた処理を実行した後、async関数を中断し、async関数を「Microtask queue」に入れる。

以下はコード例。

async function hello()
{
    console.log("hello")
    var b = await 1
    console.log("hello"+b)
}

console.log("start")
hello()
console.log("end")

上を実行すると、start→hello→end→hello1の順でログが出力される。

仕様② async関数の返り値

・async関数の返り値Promiseオブジェクト。

・async内の処理が終わっていない場合は、stateが「Pending」であるPromiseを返す。

・async内の処理が終わっている場合は、stateが「Fulfilled」であるPromiseを返す。

returnは関数の返り値とはならない。返り値は常にPromiseオブジェクトで、その中にreturnの結果が保存される。

以下はコード例。

async function hello()
{
    var b = await 1
    console.log("resume!")
    return b
}

a = hello()
console.log(a)

window.setTimeout(() => {
    console.log(a)
}, 1000)

上を実行すると、stateが「Pending」であるPromiseオブジェクトが出力された後、「resume!」が出力され、1秒後にstateが「Fulfilled」であるPromiseオブジェクトが出力される。

仕様③ 実行順序に気を付ける

・実は、仕様②で書いたコードのsetTimeoutの秒数を0にしても、結果は同じです。

・何故なら、「Microtask queue」→「Macrotask queue」の順に実行されるからです。

【ブラウザゲーム】ローグサバイバー

操作方法

A/W/D/Sー移動

R/Spaceーリセット(ゲームオーバー時)

・落ちている剣に近づくと武器を交換できます。

・右上のアイコンは剣に付与された追加効果を表します。

ゲームの概要

ヴァンサバライク+ローグ要素。

ただ生き残るゲームです。ゴール的なものはありません。

【javascript】厄介なビット演算の仕様を完全に理解する

導入

かなり厄介なので、正確な動きをかいておきます。

前提知識

・javascriptでは、数の型はNumberのみ。整数も小数も関係なくNumber型。

・Number型は、倍精度浮動点小数点数型であり、IEEE 754という規格が使われている。

・C#でいえばdouble。

・Number型の整数の精度は53bit。つまり、-2**53+1以上2**53-1以下の整数は正確に表記できる。(例えば、2*53+1のbit表記は2**53と同じ。)

・int32のbit表記には、補数表現が使われている。

javascriptのビット演算

ビット演算を行うときのみ、int32として扱われる。(>>>を含む計算は、uint32として計算されます。)

ビット演算が終了すると、int32(またはuint32)から通常のNumber型に戻る

Number→intへの変換

①小数の場合は、近い整数に変換される。

②整数x を ((x % 2**32)+2**32) % 2**32に変換する。簡単に言えば、mod 2**32において等しい、0以上2**32-1の整数に変換する。

③その整数の2進数表記をint32とみなす。(演算が>>>の場合はuint32としてみなす。)

int32→Numberへの変換

・int32における整数nの値は、そのまま、Number型におけるnに変換される。

(bit表記は変わるが、数の世界では変化なし。)

整理

・>>>が含まれない場合、-2**31以上2**31-1以下の整数は、ビット演算の前と後では変化しない。

・-2**31-1以下の場合や2**31以上の整数の場合、値は変化する。

整数の精度に注意

-2**53以下の整数と2**53以上の整数を扱う場合、意図していない値になるので注意。

例えば、(2**53+1)^0は、上の変換通りに計算すると、変換後は1になりそうですが、実際は0になります。これは、2**53+1のbit表記が2**53である為です。

・-2*31^0は、-2**31 mod 2**32 = 2**31より2**31に変換され、これを2進数を表すと、100…00(32bit)になる。これをint32で解釈すると-2**31となるので、計算終了後はNumber型の-2**31になる。

・2**31^0は2進数で表すと、100…00(32bit)になる。これをint32で解釈すると、-2**31となるので、計算終了後はNumber型の-2**31になる。

・-2**31^0は、-2**31-1 mod 2**32=2**31-1より2**31-1に変換され、これを2進数で表すと、01111…1111(32bit)になる。これをint32で解釈すると、2**31-1となるので、計算終了後はNumber型の2**31-1になる。

・-1^0は、2**32-1に変換され、これを2進数で表すと、111…111(32bit)になる。これをint32で解釈すると、-1となるので、計算終了後はNumber型の-1になる。

・(2**31^0) + (2**31^0)は、-2**32になる。

参考文献

↓ かなり分かりやすいjavascriptの数値型に関する記事です。

https://qiita.com/uhyo/items/f9abb94bcc0374d7ed23

【javascript】サイト上で音を鳴らす方法【2024年】

導入

2018年、Googleのポリシーが変更になり、javascriptでただAudioオブジェクトを作って、play()を呼ぶだけでは、音を鳴らすことができなくなりました。

様々なサイトで、すでに無効になった上記の方法が紹介されていて、2018年以降の方法を紹介しているサイトがあまりなかったので、ここに方法を書いておきます。

方法

①ユーザーにサイトをクリックをさせる。

②AudioContextオブジェクトのresume()を呼ぶ。

③その後に音を鳴らす。

(①と②は逆でも良いです。)

コード例

const atx = new AudioContext();
atx.resume();
const snd = new Audio("オーディオファイルへのパス.mp3");
document.addEventListener("click",() => {
     snd.currentTime = 0;
     snd.play();
})

上のコードは、クリックすると音が鳴るコードです。

currentTime = 0は、再生場所を設定しています。再生場所を元に戻さないと、連続再生しても、前の音が終わるまで次の音が鳴りません。

また、AudioContextのstateというプロパティで「音声が許可されたかどうか」が確認できます。stateが「running」の場合は許可あり、「suspended」の場合は許可なし、です。

ブラウザゲームを作る場合は、ミュートをデフォルトの設定するか、クリックするとゲームが始まるように設計すると良さそうです。

参考文献

https://developer.chrome.com/blog/autoplay

【ゲーム制作】敵AIを数学的理論を基に作成する① ~UCB1方策~

導入

スマブラなどの格闘ゲームからオセロなどの戦略ゲームに至るまで、敵のAIが必要になります。今回は、数学的に性能が保証された戦略AIを作成する方法を紹介します。

今回は、「UCB1方策」というものを紹介します。

UCB1方策の概要

UCB1方策というのは、多腕バンディット問題に対する戦略の一つです。

多腕バンディット問題とは、複数の「報酬の期待値が分かっていない」選択肢があるときに、報酬を最大化する選択肢の選び方を考える問題です。

多腕バンディット問題の例は、「勝率が不明な複数のスロットがあって、金貨をどういう風に入れたら報酬を最大化できるか」という問題です。

UCB1方策の具体的な手順

①まず、全ての選択肢を1回ずつ試します。

②その後、UCBスコアが最大になる選択肢を試します。(UCBスコア=μ+c√(ln(N)/n))

(μ:その選択肢の現時点の勝率。c:定数。理論上は√2だが問題によって調整する必要がある。小さくするほど現時点の勝率を重要視し、大きくするほど探索を重要視する。N:全ての選択師の探索回数の合計、n:その選択肢の探索回数。)

(※lnは自然対数で、logの底がネイピア数eであるものです。)

③手順②を繰り返します。

UCB1方策が戦略ゲームのAIに使える理由

戦略ゲームはモンテカルロ法を使うことにより「多腕バンディット問題」とみなすことができるからです。

モンテカルロ法とは、乱数を使って特定の値を推定する方法です。ランダムに点を打って、円の面積を推定するのもモンテカルロ法です。

ある選択肢を選んだとき、「それ以降の選択肢はどちらかが勝つまで完全にランダムに選び、勝敗を決める」とします。

1つの選択を選ぶと、ある特定の確率で「勝利」という報酬を得られるので、これは多腕バンディット問題になっています。

「選択肢を試す=1$失う」、「勝利=10$貰う」などと考えると分かりやすいです。

UCB1方策の実現例

RPGゲームの戦闘で、ドラゴンAIに最適な行動を選ばせる場合を考えます。

選択肢は、「A:殴る」「B:火を吐く」「C:力を溜める」です。

まずは手順①。Aを選ぶと結果は「敗北」。B、Cは「勝利」でした。

現在のUCBスコアは、Aは0、B、Cは1。

続いて手順②。定数c=√2とします。Bを選ぶと結果は「敗北」でした。

現在のUCBスコアは、Aは√(2ln2)≒1.18、Bは1/2+√(ln2)≒1.33、Cは1+√(2ln2)≒2.18

再度②。Cを選ぶと結果は「勝利」でした。

現在のUCBスコアは、Aは√(2ln3)≒1.48、Bは1/2+√(ln3)≒1.55、Cは1+√(ln3)≒2.05.

再度②。Cを選ぶと結果は「敗北」でした。

現在のUCBスコアは、Aは√(2ln4)≒1.67、Bは1/2+√(ln4)≒1.68、Cは2/3+√(2ln4/3)≒1.63

再度②。Bを選ぶと結果は「敗北」でした。

(本来は何十回、何百回とする必要がありますが、今回はここで終了します。)

現在、最も勝率が高い選択肢はCなので、ドラゴンはCを選択する。

問題点

UCB1方策は、原始モンテカルロ法を少し改良した程度の戦略です。なので、まだまだ全然弱いです。

※今回は、このUCB1方策に探索木を組み合わせたUCTという強力な方策を紹介する準備として紹介しました。

数学的理解

UCB1方策の手順②の式を導出したい人向け。

↓ 研究者の方が書かれている記事です

多腕バンディット問題におけるUCB方策を理解する · THINKING MEGANE (monochromegane.com)

↓ 多腕バンディットに使われる統計学の定理の紹介

参考文献

https://www.kurims.kyoto-u.ac.jp/~kyodo/kokyuroku/contents/pdf/1894-14.pdf

https://ja.wikipedia.org/wiki/%E3%83%A2%E3%83%B3%E3%83%86%E3%82%AB%E3%83%AB%E3%83%AD%E6%9C%A8%E6%8E%A2%E7%B4%A2

https://ja.wikipedia.org/wiki/%E5%A4%9A%E8%85%95%E3%83%90%E3%83%B3%E3%83%87%E3%82%A3%E3%83%83%E3%83%88%E5%95%8F%E9%A1%8C

【永久保存版】正規表現ライブラリ 全関数 まとめ

導入

pythonの正規表現ライブラリreの関数を簡略化してまとめたものです。

オブジェクト

正規表現オブジェクト:正規表現が格納されたオブジェクト。

マッチオブジェクト:一部の関数により返されるオブジェクト。マッチした際の情報が格納されている。

関数

patternは「正規表現」、textは「対象となる文章」が入ります。

replacedは「マッチした部分の置き換え後の文字列」が入ります。

関数名(引数)説明
re.match(pattern, text)文頭がマッチするか判定する。マッチした場合、マッチオブジェクトを返す。それ以外の場合、Noneを返す。
re.fullmatch(pattern, text)文全体がマッチするか判定する。マッチした場合、マッチオブジェクトを返す。それ以外の場合、Noneを返す。
re.search(pattern, text)一番最初にマッチした部分の情報をマッチオブジェクトとして返す。それ以外の場合、Noneを返す。
re.findall(pattern, text)マッチした文字列をリストとして返す。丸括弧がある場合、囲われた部分のみを返す。丸括弧が複数ある場合、囲われた部分を分けて、タプルのリストとして返す。
re.finditer(pattern, text)マッチした部分の情報をマッチオブジェクトのイテレータとして返す。
re.sub(pattern, replaced, text)マッチした部分をreplacedで置き換え、「置き換え後のtext」を返す。
re.subn(pattern, replaced, text)マッチした部分をreplacedで置き換え、「置き換え後のtext」と「置き換えた回数」をタプルとして返す。