AI と 2 か月で VRChat ゲームワールド「Takt of Tact」を作った話

# AI と 2 か月で VRChat ゲームワールド「Takt of Tact」を作った話 ― 開発ガイドと導入手順

AI 集会の LT「AI と 2 か月で VRChat ゲームワールドを作ったら 10 万 visits になった話」の補足記事です。
発表で話しきれなかった **導入手順** と、開発中に AI(Claude Code)と一緒に育てた **ルール集** をまとめました。

– 発表スライド(PDF): ai集会のDiscordに貼ってあります
– ワールド: [Takt of Tact](https://vrchat.com/home/world/wrld_21caa170-53db-4ec2-bc77-fe1dc4ce43f7)

ゲームデザインの深い話や課金アイテムの設計は、別の記事で書く予定です。

—

## 結果の数字

| | |
|—|—|
| 作り始め → β公開 | **35 日** |
| 作り始め → 正式公開 | **約 2 か月(63 日)** |
| 正式公開 → 10 万 visits | **16 日** |
| visits(2026-10-12 時点) | 約 12.7 万(正式公開ワールドのみ) |
| コミット数 | 2,159(うち 99% が AI との共同作業) |
| アップデート | 39 版(β 24 版+正式公開から 1 か月で 15 版) |

## 先にお伝えしたいこと:AI を使った範囲

| | 担当 |
|—|—|
| 3D モデル・イラスト | **自作+購入アセット(生成 AI 不使用)** |
|  └ 例外 | アイテム枠の装飾のみ AI 出力 |
| プログラム | AI(シェーダー修正も) |
| セリフ | AI が下書き → 人が監修(日本語・英語) |
| 翻訳(英・中・韓) | AI(英語は人が確認。中国語・韓国語は AI 翻訳のまま) |

指揮棒のモデルはすべて自作、マップやモンスターは購入したアセットです。
シェーダー修正は「買ったアセットを VR で正しく映すためのコード修正」で、見た目は元のアセットのままです。

## 去年の自分との違い

| | KatanaSurvivor(2025) | Takt of Tact(2026) |
|—|—|—|
| AI の使い方 | Gemini に相談して、コードは自分で書く | Claude Code が Unity を直接さわって実装する |
| 開発期間 | 1 か月 | 約 2 か月 |
| 想定プレイ時間 | 2 時間 | 50 時間 |
| visits | 約 4.8 万 | 約 12.7 万 |

変わったのは道具です。AI が Unity エディタを直接操作できるようになったことで、自分の仕事は
「コードを書く」から「仕様書を書いて、判断して、VRChat で確かめる」に変わりました。

実は今年の 2〜3 月に一度、このゲームを作りかけて止まっています。理由のひとつが
「使いたいエフェクトのアセットが VR に対応していない(右目と左目でパーティクルの出る場所が全然ちがう)」ことでした。
7 月に Claude Code で再挑戦したところ、開発 1〜2 日目でシェーダーを直してくれて、そのまま最後まで作りきれました。

—

## 導入手順

### 必要なもの

– **Unity 2022.3.22f1**(VRChat SDK が指定するバージョン)と **VRChat Creator Companion(VCC)**
– **Claude Code**(有料プラン。私は Max 20x を使いました)
– **Python 3.10 以上** と **uv**(Unity MCP のサーバーを動かすのに使う)
– **Node.js**(UdonSharp 用のスキルを入れるのに使う)

### 1. Claude Code を入れる

公式の手順に従ってインストールします: https://code.claude.com/docs
Unity プロジェクトのフォルダで `claude` を起動すれば、そのプロジェクトの作業相手になります。

### 2. Unity MCP を入れる(AI が Unity を直接さわれるようにする)

Unity 公式の MCP は Unity 6 以降が必要で、VRChat の Unity 2022.3 では使えません。
そこで、ローカルで動く **CoplayDev の MCP for Unity** を使います(私は v10.0.1)。

1. uv を入れる(PowerShell)
“`
winget install –id=astral-sh.uv -e
“`
2. Unity の Package Manager → **Add package from git URL** に次を貼る
“`
https://github.com/CoplayDev/unity-mcp.git?path=/MCPForUnity#v10.0.1
“`
3. Unity のメニュー `Window > MCP for Unity` の Connect タブで **Start Server**
(Transport: HTTPLocal / `http://127.0.0.1:8080`)
4. プロジェクトのルートに `.mcp.json` を置く
“`json
{ “mcpServers”: { “UnityMCP”: { “type”: “http”, “url”: “http://127.0.0.1:8080/mcp” } } }
“`
5. Claude Code を再起動して、プロジェクトの MCP サーバーを承認する
6. 動作確認: 「原点に Cube を作って Rigidbody を付けて」と頼んで、シーンに出てくれば成功

### 3. UdonSharp 用のスキルとチェックを入れる

UdonSharp は普通の C# と違って使えない書き方が多いので、コミュニティ製のスキル
[niaka3dayo/agent-skills-vrc-udon](https://github.com/niaka3dayo/agent-skills-vrc-udon) を入れています。

“`
npx skills add niaka3dayo/agent-skills-vrc-udon
“`

`.cs` を書き換えるたびに自動で走る静的チェック(`List`・`async/await`・`try/catch`・LINQ などを警告)も付いてきます。
ただしこれはパターン検査で、本物のコンパイルではありません。最終確認は Unity のコンパイル結果で行います。

### 4. CLAUDE.md に「現場のルール」を書く

`CLAUDE.md` は、Claude Code が毎回最初に読むルールブックです。
**破ると取り返しがつかないことだけ**を短く書き、ルールには「なぜか(いつ何が起きたか)」を 1 行添えます。
理由のないルールは「この場合は例外だろう」と判断されがちだからです。

Takt of Tact で育てたものを縮めたひな形です。`<>` の中は自分のプロジェクトに合わせてください。

“`markdown
# CLAUDE.md — <ワールド名>(VRChat ワールド)

Unity + UdonSharp + VCC。全体像は Docs/ProjectMap.md を最初に読むこと。

## 環境前提
– Unity <版> / VRChat SDK3 Worlds(VCC 管理。.unitypackage で入れない)
– スクリプトは UdonSharp のみ(MonoBehaviour は VRChat 上で動かない)
– ターゲット:

## UdonSharp で使えないもの
– List などのジェネリック・async/await・LINQ・try/catch
– static メソッドを持つユーティリティクラス(const だけの static class は可)

## ⚠ コンパイルは通るのに VRChat でだけ止まるもの
– Unity コンポーネントの設定値を Udon から実行時に書かない → prefab やアセットに焼く
– (byte) などの縮小キャストは範囲外で例外 → その部品が止まる。`& 0xFF` でマスクしてから
– [UdonSynced] 配列は null や短い長さで届くことがある → 受信時に長さを直してから使う
– 新しい同期・API を入れたら「要 VRChat 実機確認」と書く。エディタで動いただけで完成扱いしない

## 値と配線
– 数値・文言は Inspector に焼かない(コードを直しても古い値が勝つ)。コードの定数か CSV に置く
– Inspector の参照は手でつながない。エディタ拡張(Setup メニュー)で毎回同じ結果になるようにつなぐ

## パフォーマンス
– Update はワールドに 1 本(GameManager)だけ。各ギミックは Tick(now) を出して呼ばれる側になる
– サーバー時刻の取得は 1 フレーム 1 回

## Git
– テキストだけ管理。重いアセットは VCC の Make Backup(クラウド同期)で守る
– git add -A 禁止。変更したファイルを明示して add する

## 確認の要否
– 削除・上書き・大きなシーン変更・履歴の書き換え・外部への公開は、やる前に聞く
– それ以外は前提を置いて進め、最後に【今回置いた前提】を列挙する
“`

—

## うまく回すコツ

### 「エディタで動いた」は「VRChat で動く」の証明にならない

Udon は例外が 1 回出ると、その部品が二度と動かなくなります。しかもエディタでは再現しないことが多い。
新しい同期や API を入れたら必ず「要 VRChat 実機確認」と書かせ、実機で確かめる台帳(実機試験表)を作りました。

### 失敗を仕組みに変える

AI は VRChat 固有の罠を最初から知っているわけではありません。そこで次のルールで回しました。

– 1 回目の失敗 → AI のメモリに「症状・原因・対処」を記録する
– 2 回目 → CLAUDE.md に書くか、機械で検出するチェックを作る
– 繰り返す作業 → 手順書(スキル)にする

例えば「セーブデータの鍵になる ID が書き換わっていないか」は、コミット前に自動でチェックしています。
チェックを機械に任せられたので、細かいアップデートを短い間隔で何度も出せました。

### 配線は手でやらない

Inspector で参照をドラッグしてつなぐ作業は、AI に任せると不安定になりがちです。
「配線するエディタ拡張(Setup メニュー)を AI に書かせて、それを実行する」形にすると、何度やっても同じ結果になります。
全部の配線を順番に流す `Wire All` と、配線漏れを調べる `Validate` を用意して、ビルド前に必ず流していました。

### 開発者だけが見る画面ほどリッチにする

武器・モンスター・セリフなどの表データは CSV にまとめ、ブラウザで編集する専用の HTML エディタを AI に作らせました
(表 39 種・エディタ 24 本)。保存してボタンを 1 つ押せばゲームに反映されます。
プレイヤーは見ない画面ですが、見た目が良いと触るのが楽しく、モチベーションの維持にも効きました。

### Unity MCP の作法

– MCP の呼び出しは 1 つずつ順番に(並べて投げると接続が切れやすい)
– Play 中に強制コンパイルしない(Unity が落ちることがある)
– 「エラー 0 件」は Unity の `Editor.log` で確かめる(コンソール読み取りは取りこぼすことがある)
– ユーザーが保存していないシーンの変更を捨てさせない

### 使用量の節約

Max 20x でも 1 週間の使用量の枠がかつかつでした。
出力の質が高い Fable に設計(プラン)を書かせ、実装は Opus に任せて使用量を浮かせていました。

—

## AI にまだ任せられないこと

– **同期の取捨選択**: 同期処理そのものは仕様どおりに作れます。でも「何をどの速さで同期するか」「どこはズレても許せて、どこは完全に一致させたいか」はゲーム体験の判断で、人が決める必要がありました
– **UI の設計**: 「この画面で何をしたいか」を決め、どの順番で何を見せるかは人の仕事でした
– **実機試験**: AI もテストはかなりしてくれますが、最後は人が VRChat で確かめるしかありません
– **セリフの監修**: 6 つの性格・呼び方・価値観を決めて AI にセリフの下書きを作らせました(4 言語で約 8,000 通り)。
そのうち日本語と英語の約 4,000 通りは人が目で確認しています。監修は必須でした

まとめると、AI に任せて良かったのは「量」と「機械的な正しさ」、人に残ったのは「体験のための取捨選択」でした。

## お金の話(ちらっと)

– AI 代: Claude の Max 20x(月 200 ドル)× 2 か月で約 6 万円
– 売上: ワールド内の販売が正式公開から 1 か月で約 84,000 クレジット(1 クレジット ≒ 0.005 ドル換算で約 6.3 万円)
– アセット代: 約 4 万円

アセット代まで入れるとちょっと赤字ですが、AI 代はほぼ回収できました。

## おわりに

質問があれば【連絡先(X など)】までどうぞ。

【DQM3】レジェンド構築キラマアグロについて構築解説

ドラゴンクエストモンスターズ3のランクマ、シーズン1において
14番目にレジェンドに到達したパーティの紹介になります。

ひかりの番人とアルミラージと強く、ほとんどのL入り構成に対して勝てる構築となります。

構築の詳細は以下で紹介しているので、確認してみてください。

本記事では上記動画で紹介した構築のプレイング方法やカスタマイズ候補などの紹介します。

■アタッカーの入れ替え候補
1-2回行動枠はある程度融通が利きます。
ただチームコンセプトとして、素早さと攻撃の合計値を可能な限りあげたいので、
この点に注目すると
【キラーマシン2】と【メタルライダー】の2匹を採用すればよいです。

ただしメタルライダーは以下の点から採用をしませんでした。
1. 特性いてはを開幕に行われるとアルミラージや一部Lサイズを抜くことができなくなる
2. 基礎の素早さが低いため、息吹が発動したとしても素早さに恩恵がなく、上からたたけない
3. 番人も攻撃2回で死んで、3回行動しなかった回の番人が重い
4. ひかりの番人の攻撃を2回耐えない

以上の点から、メタルライダーは最も攻撃と素早さの効率がいいのですが、採用をしませんでした。
ひかりの番人は75%で倒せるからいいのですが、別の敵に1回攻撃が飛んで行ったときや、倒しきれなかった際に、
アタッカーが残っている数が1か2かは全然違うので、メタルライダーを採用する価値は低いと思います。

メタルライダーは範囲攻撃を採用できる点が強みですが、使ってみたうえで『範囲攻撃を使いたい』場面がほとんどありませんでした。
範囲攻撃をうちたい場合はメタルライダーを採用してもいいかもしれません。

まず1匹目はキラーマシン2がステータスの数値だけ見る場合はおすすめです。

では2枠目は誰を採用すればよいのか?
候補は【ハデスナイト】と【キラーマシン】、次点で【メタルハンター】と【ナイトリッチ】です。
【スライムナイト】と【ナイトキング】は今回候補となりませんが、環境次第で採用するかもしれないです。

まずは採用候補となるメンバーの耐性を見ていきましょう

基本的に上から殴るため、耐性はそんなに意識しなくてもいいかもしれません。
ただし、スカルがルーが増える場合は混乱耐性を、ラブリーが増える場合は休み耐性が高いモンスターを採用した方が勝率が高くなります。

またメタルハンターに関しては恩恵は特性「メタルハンター」の効果により、攻撃力が実質25高くなると考えていいです。
メタルハンターは耐性が優秀で、ビリビリボディによる直接攻撃耐性があり、使ってみたかったのですが育成はしませんでした。

スライムナイトに関しては、ラージキラーがあるため、火力の確保がしやすいと思いきや、攻撃力150-200分の価値しかなく、
素早さを盛るためにキラキラとアクセ枠がとられてしまい、うまく火力を出すことができませんでした。
すばやさのラインをめっちゃ下げる場合はスライムナイトがかなり強くなるのですが、今回の早くてターミネーターする構築には適切ではありませんでした。
また、スライム族なせいで番人の攻撃を2回耐えません。

ナイトキングに関してはちからためが魅力的です。
しかし、ちからためは奇数ターンの終了時に確定発動のため、1ターン目に火力が欲しいこのチームとは相性が悪いと判断して採用しませんでした。

次に
系図の基礎知識として、系図では素早さと攻撃の両方を増やす種族は存在しません。
そのため、祖父母を1ポイント、両親を2ポイント、未重複ボーナス2を2ポイントとして、
攻撃と素早さのポイントの合計は最大でも12ポイントのみ振ることができます。

基本的に系図は基礎値が高いステータスにかけるべきですが、キラーマシン等は素早さを936以下にしようとした場合、
数値がきれいに整わなくなるため、高くない基礎値に対して系図補正を載せる場合があります。

こうしてみると、攻撃+素早さの合計値がハデスナイトと比べてキラーマシンの方が10ほど高くなっているのがわかります。
素早さを大きく盛る場合はハデスナイトの方が高くなる場合があります。

■フェアリードラゴン入れ替え候補
フェアリードラゴンはこのチームの素早さを定義するもののため、抜くことはないです。
ただし、身代わり解除手段がおたけびしかないため、右側が休み150だと重いです。
そのため、Lベロリンマンなどを切って、休み100にして、いてつくはどうを搭載したフェアリードラゴンを用意して、
環境に応じて持ち帰るのはアリかもしれません。

■キングスライム入れ替え候補
このチームにおいて、いては→おたけび→攻撃2匹の行動順であることは作戦を立てやすいです。
しかし、状態異常が多い場合や選択肢を増やしたい場合は違う生き物に変更してもよいです。
候補となるのは
1: はぐれメタル
→ 速度がキングスライムに匹敵する速さで攻撃手段を搭載することができる
2: おおがらす
→ いきなりピオラでめちゃくちゃ早いところから行動できる。最速にするとピオラが消えてもアタッカーが895以下なら先に動ける
などです。
身代わり要因だとわるぼうなど候補に入りそうですが、わるぼうの最速は980前後なのでこのパーティは速度があわないため、おすすめはしません。
3: リリパッド
→ 汎用性の化身。Sラインが気になる

■アクセ入れ替え候補
実は魔神の指輪も強いと思う

【プレイングガイド】
対L1S2構成

L1S2構成で意識する点はSモンスターがなにをしてくるか?です。

■相手がみがわりを2匹で実行する場合
1: 右側のモンスターが休み耐性が150となりうるか

休み耐性が150となりうるとはなんでしょうか?
読んで字のごとく、身代わりのスキルを搭載した上で【休み耐性が150にできるかどうか】です。

実はSサイズモンスターは基礎に休み50耐性がないと、休み150にすることができません。
こちらの休み異常を巻くフェアリードラゴンは休みブレイクを持っているため、休み150未満であれば上から休み状態にすることができます。
休み100あると休み状態にできないことがあるのですが、身代わりを使っている場合、相手の残っているモンスターの数に応じて複数回判定があるため、
『身代わりをしていれば、休み150でなければ休む』と思っていただいて大丈夫です。

【代表的な休み150にできるモンスター】
リリパッド、シャンタク、フェアリードラゴン、ぽんぽこたぬき

【代表的な休み150にできないモンスター】
わるぼう、スピンスライム、わたぼう、はぐれメタル、メタルキング、どろにんぎょう

ちなみに『よるのていおう』は休み150にできるモンスターですが、
おじゃま虫というスキルラインをとることを目的に採用されるので、休み150ないと思っていただいてよいです。

複数人身代わりを行っている場合、左側が優先されます。

このキラーマシンアグロのパーティでは、まずはいてつくはどう、次におたけびを使うため、
『右側にいるモンスターが休み150』でないかぎり、いてつくはどう→おたけびで身代わりを解除することができます。

一般的に強いL1S2パーティは左が休み150が多いです。(フェアリードラゴンやリリパッド意識のため)
S4パーティで休み150採用している場合は右が休み150なことが多いです。(ベロリンマン意識のため)

フェアリードラゴンは最速仕様のため、一部モンスター以外は上からおたけびができるため、
相手が状態異常を選択していても上からつぶすことができるため、雄たけびが安定行動になります。

では右側が休み150だった場合はどうでしょうか。

相手の構築次第、としかいいようがないのですが、よくやる行動としては
キラーマシン: 防御
キラーマシン2 : 防御 or 通常
フェアリードラゴン: おたけび
キングスライム : いてつくはどう以外

になります。
凍てつく波動→雄たけびをした場合は右に雄たけびがあたりますが、
いてつく波動をしない場合、左におたけびが当たります。

状態異常『休み』は次の行動タイミングのとき休むと回復します。
左の身代わりにおたけびがヒットすると、すでにそのターンは行動してから休みとなっているため、
次のターンは動くことができません。

そのため、次のターンはメタルキングがいてつくはどうをすれば相手のLアタッカーを触れます。
※このときフェアリードラゴンが死んでいてもかまいません。

リスクがない場合、いてつくはどうでなくマダンテをうつ場合があります。

■身代わり+異常を巻いてくる場合

相手のSサイズがが身代わり+異常を巻く場合、
巻かれる異常の種類と速度が大事になります。

巻いてくる状態異常が『休み』である場合、相手がフェアリードラゴンやSベロリンマンの場合はフェアリードラゴンが身代わりをします。
相手がLフェアリードラゴンやLベロリンマンの場合はひかりのはどうを置いておくと、状態異常を直してアタッカーが行動できます。

巻いてくる状態異常が『休み以外』である場合、フェアリードラゴンやメタルキングより早い場合はメタルキングがみがわり
フェアリードラゴンはおたけびかひかりのはどうの2択になります。
相手の身代わりを突破して決着をつけたい場合はおたけびを選択し、次のターンもメタルキングでみがわりしたい場合はひかりのはどうを置きます。

■身代わり+攻撃してくる場合
みがわり+ハデスナイト+番人で発生する行動です。

攻撃をしてくる場合、25%で2回しか攻撃できなかった際にこちらは全滅してしまいます。
相手のハデスナイトは身代わりを使わないので、『身代わり+攻撃』のパターンとみていいでしょう。

ここで考えることは『だれが相手の身代わりを解除するのか?』です。

上でも登場した【休み耐性が150にできるかどうか】が大事になります。

リリパッドなど休みに150にできる場合→フェアリードラゴンが身代わり、メタルキングがいてつくはどう
わるぼうなど、休み150にできない身代わりの場合→状況によって分ける(メタキンで身代わりすることが多い)

メタルキングの耐久力で攻撃を防ぎきりたいのか?フェアリードラゴンの最後の息吹が欲しいのかで判断を分けます。

リスクがない場合、いてつくはどうでなくマダンテをうつ場合があります。
ただし、根に持つをマダンテで倒すと身代わりがはがれるため、根に持つにマダンテをうつのはやめましょう

■攻撃+攻撃をしてくる場合
相手のSがどちちらも攻撃してくる場合、2種類の択があります

1: フェアリードラゴン身代わり、メタルキング身代わり
2: フェアリードラゴン雄たけび、メタルキング身代わり

フェアリードラゴンで止めらるかどうかで判断が分かれます。

■スクルト+身代わりをしてくる場合
耐久力を上げることで、突破されないようにしてくるタイプです。
この場合、メタルキングでバイキルトをすることで上昇した防御を抜くことができます。

————————————————
対LL構成

基本的にアタッカーを落とします。
火力が足りない場合はマダンテやバイキルトで火力を追加します。
相手がアルミラージの場合、速度負けしたリスクを軽減するために、フェアリードラゴンとメタルキングはどちらもみがわりすることが多いです。

————————————————
対S4構成

アタッカーだらけの場合は以下のいずれかをする場合があります
【相手がいきなりピオラでない場合】
・フェアリードラゴンで身代わりして防御攻撃素早さをあげて、耐えてから上から一掃。メタキンはどうか身代わり
【相手がいきなりピオラの場合】
・いては+おたけびで止める
【相手がフェアリードラゴンを採用している場合】
フェアリードラゴンが身代わり

基本的に異常巻きが2入っているS4構築には不利です。

————————————————
対Lサイズ???
アタッカーの作戦を”とくぎつかうな”に変更して、まじん斬りしましょう。
余裕があればバイキルトを行います。
何発か通常が入って、HPが減らすことができたら、通常を選び、削り切ります。

【よくある質問】
Q 早く殴るならいきなりピオラでよくない?
いきなりピオラで1-2行動が2匹いるならそれでもよかった。いないのでコドラ採用とかはこのコンセプトの場合めちゃくちゃ弱いのでやめたほうがいいです
いきなりピオラでないおかげで開幕いてはに強く、最後の息吹の恩恵をとても大きくうけることができます。

Q 運ゲーじゃない?
75%でぶっ飛ばせるなら運ゲーじゃないです

Q 状態異常きつくない?
きついです。1枠までならなんとかしましょう。
メタキンとフェアリードラゴン左右入れ替えても対応できるものが変わります。

Q 苦手な編成は?
異常2からめたS4や選択肢の多いL1S2、シャドーベビーやベビパンが重めです

Q アルミラージに抜かれるんだけど
アルミラージはキラキラ粘りしてないラインを抜くようにしています。
相手がキラキラを粘ると乱数になってしまうため、身代わりを挟んで先に行動されても通せるケースを作るか
単純に素早さのラインをあげましょう。
死ぬほど足を速くしているアルミラージは無視していいです。他のパーティに勝てないので上がってきません。

Q ???系どうしてるの?
魔人斬りゲーしてます。有利かは怪しいけど割と命中して勝ってます

Q なんでメタキンなの?
速度がはぐメタだと足りないからです。
乱数でフェアリードラゴンに抜かれてもいいならはぐメタでいいです。
メタキンは封じブレイクあるので、マホトーンや口を塞ぐ、意外と強いですよ

【まとめ】
環境の移り変わりが早いため、このチームでもなかなか勝てなくなる時代はすぐくると思います。
ただし、状態異常を絡めない環境やS2L1環境、L2環境において強力な対策パーティとなるため、
もっておいてもいいのかな?とは思います。

VRChat Examplesがない時の対処法(フォルダが見つからない)

VRChatでワールドを制作しようとガイドを読みながらやるも、

「Project」の「VRChat Examples」→「Prefabs」のVRCWorldを配置

みたいに言われても、そもそもProject配下にVRChat Examplesがなくて苦しむ。

SDK2は「Assets/VRChat Examples/Prefabs2」にあり、
SDK3は「Assets/VRChat Examples/Prefabs」にあるといわれるが、ない。

CreatorCompanionを使った新しいやり方をしている場合、
「Packages」の「VRChat SDK – Worlds」の「Samples」の「UdonExampleScene」の「Prefabs」内にVRCWorldがある。

場所変えんなや と思いつつ、同じことで悩む方もいると思うので備忘録でした。

VRChatで.(ドット/ピリオッド)を含む名前の検索ができないときの対処法

VRチャットでドット(ピリオッド)を含む名前を検索してフレンド登録をしようとしたときにできなかったので解決方法をメモ
ドット(ピリオッド)を含む名前とは「fumiya.shibamata」みたいな名前のこと。

VRChatではなんか知らんけど「.」が「․」になっている。

人によっては文字がつぶれていたり、視覚的にわからないかもしれない。

もう一度言おう。「.」が「․」になっている。

「.」(ドット)が「․」(一点リーダー)になっている!!!

なんだそれ・・・

なので、「fumiya.shibamata」を検索したいときは「fumiya․shibamata」にすれば検索できます。

文字化けしててもコピペすれば大丈夫ですよ。

キーボードでの入力方法はしらん・・・

Windows11のSteamVRでブルートゥースが有効化できなかった話

最近、htc viveを利用して、SteamVRをやっている。
Windows11に移行した際にブルートゥースが有効化できなくて困ったので忘却録。

まずは公式のQAをあたった。
https://help.steampowered.com/ja/wizard/HelpWithGameIssue/?appid=250820&issueid=374&nodeid=83&return_nodeid=71

上記はSteamVR用のドライバインストール方法なので、関係がなかった。
デバイスマネージャーを開いて、BluetoothDevices -> VMC20703 Bluetooth 4.1 USB Deviceなるドライバが入っていれば問題ない(環境によって多少違うかも)

しかし、それでもBluetoothの有効化にチェックを入れると、『ブルートゥースで接続可能なリンクボックスが検出されませんでした。』と表示される。
検索してもまさかのGithubのソースしかない。こまった。

色々海外も含めて調べた結果、以下の方法でブルートゥースを有効化できた

Windowsセキュリティのコア分離のメモリ整合性をオンからオフに変更する。
※セキュリティが低下する可能性とでるが、かなり特殊な状況な上、少し古いPCだと関係がないのでOFFにした。一応自己責任でどうぞ。

その後、ブルートゥースを有効化を押すことで有効化し、ベースステーションの設定を行うことができた。

ちなみにquestで同様のエラーが起きた場合はそういう仕様らしい(未検証)

スプレッドシートを疑似wikiとして活用した話

本記事はWeb API Advent Calendar 2021の12日目の記事となります。

■概要
最近、スプレッドシートを活用して複数人で情報修正編集できる機能を活用し、twitchという動画配信サイト向けのプラグインを作った。
スプレッドシートをプログラム側で制御する手順等は日本語の記事がそれなりにあるので,そちらに任せるとして、
スプレッドシートを活用するまでの至った経緯などを紹介。
実際に使ってみたい方はGoogle Sheets APIで検索することをおすすめする。

■ツール概要
temtemというポケモンのようなモンスター同士を戦わせるゲームを生配信する際に視聴者が任意のモンスターの情報をカーソルをあわせることで配信上(overlay)で確認ができるというもの。

↓実際に動いている様子

プラグイン配信ページ(twitch)

ハースストーンというカードゲームでは有名な「HearthStone Deck Tracker」というプラグインがあり、プラグインの種類としてはにたようなもの。

格闘ゲームのような画面に動きがあるゲームは、そのゲームを知らない人でもなんとなくみることができる。
ただ、ターン制ゲームの視聴者はどうしても実際にそのゲームを今遊んでいる人が対象になってしまう課題がある。
なぜなら、プレイヤーであればカードゲームの絵柄を見るだけで、一体そのカードがどんなカードなのかわかるが、しばらくプレイしていない人ややったことがない人は何が起きているか分からないからだ。
(配信者も親切に使うときに効果を読み上げてくれたりはしない。遊戯王は親切だった。)

そのため、視聴者毎の知識差を埋めるためにこのプラグインを開発した。

視聴者の言語設定に応じて表示する言語を変えてくれる機能もつけることができる。(この機能は実装中)

■スプレッドシートはどこにでてくるの?
さて、ここまで来るとスプレッドシートが何も関係ないように思える。
スプレッドシートを使うに至る経緯を説明させてほしい。

■スプレッドシートを使うにいたった経緯
情報を表示するということは情報を入力する必要がある。

上であげたハースストーンというカードゲームはゲーム自体がログを出力しており、
それを集計するツールを利用してユーザーに表示する情報を取得している。

メモリを参照するようないわゆるリバースエンジニアリングは利用規約で禁止されている。
悪いことをしないホワイトなプログラマーとして、リバースエンジニアリングは行わない。

ではどのように情報入力をするか?

人間の力で解決する。

つまり配信者が”JSON形式で入力”である

ただ、この情報を毎回配信者が入力しているようではとてもじゃないが、不便である。

そのため、表示したい情報を選択すると自動でjson化してくれるサイトを作成した。(例えば技名を選べば、技の威力や説明などは自動で用意される。)

・実際のJSON出力するサイト
・HTMLを出力するgulpソース

使うモンスターを選べば覚える技リストが表示され、そこから選ぶ仕組みだ。
モンスターの情報を入れ終わった後に「CSV」というボタンを押せば何故かJSONが出力される。
(以前はCSV出力だったので残ったままだった・・・今気づいた)
出力されたJSONをtwitchの配信管理画面にコピペすれば、視聴者側に反映される。

ただ、それすらも私はめんどくさいと思うので、ゲームのスクリーンショットをアップロードすれば自動で入力される仕組みにした。
プログラマーたるもの怠けるべきで、簡単に”人間の力で解決する”などとはいってはいけない。

open CVとGCPのCloudFunctionを利用した仕組みになっているが、この記事のテーマとずれるため、
興味ある方は12/19にきっと更新されるであろう下記、AdventCalendarからどうぞ。
・opencv AdventCalendar

じゃあそのサイトに乗せる情報はどこから持ってくるのか。
公式wikiからスクレイピングする。(selenium)
※ちなみにwikiの情報はCC BY-NC-SA 3.0で利用することができるので、ホワイトなプログラマーからジョブチェンジはしていない

スクレイピングした情報をcsvとしてローカルで管理し、gulpというタスクランナーでHTMLに変換している。

海外のゲームなので、wikiの情報は基本的に英語である。

しかし、日本ユーザーに日本語で表示したいし、日本語ユーザーが英語で情報入力するのはとても大変だ。

Google Translate APIなどを利用し、翻訳するロジックをいれたい所だが、
ゲーム内では日本語設定があり、独自の日本語訳があるため、自動翻訳は難しい。

ではどうするか。

人間の力で解決する。

しかし、僕一人でゲーム内の情報を確認して、この英語に対応する日本語はなにかなと入力する作業は現実的でないし、ホワイトなプログラマーのタイピング速度を持ってしても指が辛い。

英語のリストはスクレイピングで取得したので作成できる。
あとは日本語の情報入力を有志の方々にやっていただく。(この場を借りてお礼申し上げます。)

ある程度のアカウント管理が出来て、誤った修正を戻す事ができて、
ないとは思うが、万が一悪意ある修正が行われた時、誰が行ったかわかるようにしたい。
また、情報入力する人はITに詳しくない方もいるので、タグや区切り文字など気にせずに作業をしてもらいたい。

このwikiのような機能を自前で実装するのは大変だ。

そこで登場するのがスプレッドシートだ。

ご存知のとおり、スプレッドシートは多人数でブラウザ上から編集できるEXCELのようなもの。

スプレッドシートの編集はGoogleアカウントで実施し、編集履歴の確認などもできる。
シートの所有者がどのアカウントに閲覧権限をつけるか、保護されない箇所の編集を許可するかを決めることができる。
保護箇所も修正・編集できる管理者、編集者、閲覧者をアカウントごとに指定できる。
※ただし、細かいロールのような仕組みは企業アカウントでないとできないようで、自前で別に管理シートを用意すればプログラム上で制御できそうだが、今回は用意していない。

そしてgoogleスプレッドシートをソースコード上から制御するのがGoogle Sheets APIである。

■処理の流れ
今回作ったバッチは以下の処理を行える。
Wikiからスクレイピングで取得した情報(英語)をCSVとして保存
↓
CSVの情報をスプレッド載せる
↓
プログラムで管理しているフラグ列やwikiから取得した情報にはロックをかけて編集できないようにする(現在列ロックは手動)
↓
有志の方々に日本語訳を入力してもらう
↓
プログラム側からスプレッドシートの情報を取得し、CSV化
↓
作成したCSVを元にgulpでHTML(情報入力サイト)を出力

といった処理の流れでwikiのような仕組みを作った。

実際に有志の方に入力してもらう画面(一般ユーザーは閲覧のみが可能)

・翻訳スプレッドシート
・ローカルで動かすスプレッドシートを管理しているソースコード

複数人での文章編集作業が必要なコンテンツの作成に利用してみてはいかがでしょうか!

このプラグインにまつわる話は、他にも
GCPの無料枠でe-Sports配信をリッチにした話Google Cloud Platform Advent Calendar 2021
ゲームのステータス画面のスクショをデータ化して活用した話OpenCV Advent Calendar 2021
などでご紹介するつもりです!

以上、スプレッドシートをwikiのように活用した話でした!

なお、MMOポケモン、TemtemはSteam/PS5で好評販売中です。

CloudFunctionのアクセス制限メモ

特にアクセス制限を設けず、設定の権限でallUserが「Cloud Functions 起動元」の権限を持つと外部から無制限にアクセスすることができる。
想定外の実行をされたくない場合はロールを設定する。
ただしロールを決めると認証を1時間おきにやらないといけなくてめんどくさい
そのため、同VPC内のみにアクセス制限をかけて、allUserに「Cloud Functions 起動元」の権限をもたせるなどのやり方がある

windowsのvimからwslのファイルを使う上で困ったこと

windowsのvim上からwsl内のファイルを編集したい。

■背景
gulpでのビルドが非常に遅く、原因を調べていたところ、
win上のファイルをwsl上のgulpで更新した場合、ファイル形式の変換が走るためめちゃくちゃ遅くなる現象があった。
基本はwsl内のファイルはwsl内のvimから実施するべきだが、win上のvimでないと利用できないプラグイン等があるため、wsl上のファイルを編集したい

■事前知識
wslからwinのファイルを操作する場合は /mnt/c/hogehogeにアクセスすればいい。
逆にwinからwsl上のファイルにアクセスする場合は \\wsl$にアクセスすればいい。

■問題と解決策
nerdTreeで\\wsl$配下のファイルが取得できない。
→vimfilerなら取得できたのでそちらに移行した。

【ポケモンユナイト】ゲーム上手くない奴がソロでマスターになるには【ソロマスター】

先日、ポケモンユナイトでソロにてマスターランクに到達した。(到達時世界ランキング191位)
僕は決してリアルタイムで進行するゲームは上手くなく、どちらかと言えば平均以下だ。
これは謙遜でもなんでもなく一緒に遊んだことがある人ならわかると思うがマジで下手くそに部類される人間なのだ。
真面目に勝つためのプレイをしてスプラはAいけるか行けないかくらい。
ましてやMOBA系はほぼ未経験、一緒にやってくれる友達はβテストで満足してしまった。(僕は未プレイ)

では何故そんな僕がソロでマスターランクにまでこれたのか?
考え方ややってきた事を紹介しよう。

もくじ
・勝率51%を目指せ。プレイ時間でカバーしよう。
・味方が弱い!?仲間運ゲー?萎えないためのマインド
・仲間のバリューを最大化する
・強いキャラを使う。使うキャラをゲームの最初に交換する。
・アイテムレベルを上げる。
・最後まで諦めない。アクティブポイントを意識しよう。
・リスクはとらない

■勝率51%を目指せ。プレイ時間でカバーしよう。
マスターになれる人はどんな人だろう?
強い人?うまい人?課金した人?
どれもあっているが、間違ってもいる。
マスターランクになれる人は正確には
「一定以上の勝率を出すことができ、規定の試合数をこなした人」だ。
このゲームは勝てば1増えて、負けると1減るポイントが一定数貯まるとランクアップする。

では、”一定以上の勝率”とは何か?
その基準となるのは切り上げて51%だ。
※実際にはプレイヤーに有利に働くアクティブポイントの存在から50%、または50%を若干下回っていてもマスターに到達できるが、一旦はアクティブポイントについては考慮しないものとする。

ビギナーランクまでは負けてもポイントが下がらないので、スーパーからが本番だ。
スーパー4クラス、ハイパー以降は5クラス、各クラス3ポイントと、計57ポイント分勝ち越せばマスターに上がることができる。
勝率が100%の人であればビギナー+57試合でマスターになることができ、勝率51%の人はその50倍の試合をこなせばマスターに上がることができる。
ちなみに勝率60%ある場合は100%の人に比べて5倍の試合数をこなすだけで良い。
実際にはアクティブポイントの存在によってこの試合数よりは遥かに少ない数でマスターにあがることができる。

メインのカビゴンが56%、ほぼ同じ数使ったサブのワタシラガが52%、どちらも取られたときに使う他の面々が20%程度の勝率で平均勝率が53%しかないが、マスターにあがれた。
今マスターに上がっている人は勝率70-75、低くても60%だ。

では何故勝率がそこまで高くない僕がマスターになったのか?
僕のマスター到達時点での試合数が420試合だからだ。(強い人は大体250試合以下)
サービス開始から6日でマスターに上がったが、1日およそ70試合回している。僕がマスターになれた理由はそこに尽きる。
あなたのトレーナーカードをみてほしい。ゲーム慣れしている人は僕よりも勝率が高いと思うが、結構やっている人と比べても試合数は僕の方が多いだろう。(記事掲載時点)

マスター以降はレーティングとなるため、同じようにはいかないが、マスターに到達するだけであれば、強い人がなれるものではないと理解いただけたと思う。
さらにこのゲームはなぜか2ランク下の人とも普通にマッチングするため、エキスパート10人の中で平均戦果を出す必要がない。エキスパート帯はエキスパート帯としかマッチングしないのであれば僕は勝ち越せなかったと思う。

勝率55%の人よりも勝率60%の方が強いが、試合数を倍以上こなせば勝率55%の方が先にマスターに到達する。
強い人間がマスターになるのでなく、”勝率に見合った試合数を先にこなした人”がマスターになるのだ。
勝率60%の固定を組める時間の倍の時間勝率55%のソロを回すことができるのであれば、マスター到達はほぼ同時になる。

とはいえ、勝率が高ければ試合数も少なく済むためどうやって上手くないなりに勝率をあげるか以下にまとめる。

■味方が弱い!?仲間運ゲー?萎えないためのマインド
とんでもない動きをして敗因を作っているように見える味方にあたることがある。
ソロは味方運ゲーと言われる事もあるが、ちょっと待ってほしい。

このゲーム、というかランダムマッチ系のゲーム全てにおいて共通していえることがある。
実は”ゲームを破壊するような弱い人”が味方にくる確率より、敵に行く確率の方が高いのだ。
なぜなら、敵は5人いるが、味方は4人のため、単純に抽選枠が少ないからだ。

勝率を80%目指したい人は仲間に引っ張られて勝率をあげられないかもしれない。
しかし、マスターを目指す上でとればいい勝率は51%だ。
そして目指すのは勝利でなく勝率なので、(実際にそうかどうかはおいておいても)ある特定の味方で負けたとしても、
同レベルの人が敵に行って勝つ確率の方が高い。
勝率51%+αを目指す場合は長期的にみて味方がルールをわかっていなくて負けたとしても、関係がないのだ。

とはいいつつ、僕はプレイしているときはとても配信できないような言動と小学生並みの語彙力でプレイしているが、それはそれである。
一定の勝率を出しつつ、試合数を稼ぐことが大事なので萎えない心が大事なので、誰にも聞こえない・見えない所でこっそりキレ散らかそう。

■仲間のバリューを最大化する
5対5のゲームなので、1人が試合に貢献できる総量はたかがしれている。
もちろん、圧倒できる強さやゲームの上手さがあれば試合に蹂躙して圧倒できるかもしれない。
ただし、この記事の趣旨はそんな蹂躙する強さを持たない人がどのようにマスターに行くか?だ。
最低限の知識やタブーを覚える事は必要だが、それ以上に大切なことがある。
それは仲間のバリューを最大化することだ。
相手の5人の平均戦力と、コチラの4人の平均戦力はランダムマッチの性質上ほとんど同じといえる。
勝率51%を目指すのであれば、各々のバリューをしっかりとだしてもらうことで、自分がたとえ平均以下の実力でも勝率51%を超えることは容易だ。
なぜなら、仲間のバリュー最大化ができていない人が多いので、最大化していない相手の試合は勝ち越すことができるからだ。

仲間のバリュー最大化を簡単にできる方法が2つある。

・好きなモンスターを選ばせる。
・意思の疎通をとり、クイックチャットを活用する

以上2つだ。

まず、「好きなモンスターを選ばせる」について。
こういったキャラクターを選ぶゲームは少なからず、”○○専門”と言った人が必ずいる。
1キャラだけ熱心に練習している人たちだ。
特にこのゲームはアイテムレベルの存在から、普段プレイしていないモンスターを使うときに不利になりやすい。
なので、最低2キャラ、できれば3キャラは使えるようにして、仲間に好きなモンスターを選んでもらった後に自分は選ぼう。
これをやれるかどうかで、相手が専門被りした試合は勝ち越せるので勝率51%を超えることが容易になる。

そしておすすめは中央レーン以外でタイプが異なるモンスターを使えるようにすることだ。

なぜなら中央レーンは勝利に直結しやすいから。
ゲームがうまい人なら絶対にアタッカーや中央レーンをやることがおすすめだ。
しかし、この記事はゲームが上手くない人へ向けたものなので、中央レーンは選んではならない。
勝率70%を目指すなら間違いなく中央レーンを練習したほうがいい。
逆にいえば自分が中央レーンになった場合、相手の中央レーンに勝ち越せないと勝率が大きく下がるため
そのため中央レーン以外をやったほうがいい。自分でプレイしなければ敵の中央レーンより味方の中央レーンがうまい確率はほぼ50%になる。
勝率51%を目指す場合は”勝利に直結しないポジションで平均戦果を出す”そして、”仲間のバリューを最大化させる”だけでいい。

次に「意思の疎通を取り、クイックチャットを活用する」について。
簡単にいえば仲間に指示を出すということ。
マイナスボタンでマップを開くと、”拠点の防衛”であったり、クイックチャットで撤退の意思表示ができる。
クイックチャットをいったところで意味のない味方も頻繁に遭遇するかもしれないが、その味方の事は考えなくていい。
なぜなら敵にいったところで同じような行動をするからだ。
だが、”クイックチャットをくれれば気づく・動ける・撤退できる”といった層は決して少なくない。
そんな味方がきたときにちゃんとクイックチャットを打てるチームと打てないチーム、勝てるチームはどちらだろうか。
ちょっと自分一人が良いプレイをする以上にクイックチャットをすることは価値のある行動といえる。

今の環境でのおすすめクイックチャットは
・前に出すぎた味方に対して”撤退”を打つ
・カジリガメが湧く45秒前に”下レーンに移動を打つ”、20-30秒前に”集合”を打つ
この2つを意識するだけで平均以下の実力でも勝率51%を出すことは容易だ。なぜならやらない人が多いから。

全てに言えることだが、”他人を変える事は難しい。一番簡単に変えることができるのは自分の行動と環境”である。
自分一人の行動改善によって勝率を数%上げるより、環境を変えることで味方の行動改善し勝率を上げるほうが容易と思う。

■強いキャラを使う。使うキャラをゲームの最初に交換する。
2-3キャラ使うとして何を使えばいいだろう?
それは強いと言われているキャラを使うことだ。
もちろん、[モチベーションを維持するために好きなモンスターを使う]といった観点も大事だ。
なぜなら[プレイしなくなったらマスターにはなれない]から。モチベーションを維持できる範囲で強いモンスターを持ちキャラにしよう。
また、1-2キャラまでは人に譲るため、ポジションがかぶらないほうがいい。
例えば、カビゴンメインの、サブヤドランにすると、ヤドランを使うときはカビゴンが必ずチームにいるため、バランスが悪い。
また、上レーン用キャラであれば、サブは下レーン用キャラが良い。(なぜなら、上レーンを譲るということは余る湧く上1下2になるから。)
今のおすすめはディフェンス+サポート。アタッカーは中央レーンにいかされがちなので、アタッカーを使う場合は上下レーンを先に宣言して中央レーンに行かない宣言をしよう。

また、このゲームのキャラクター選択画面は”ライセンス取得順”で並んでいる。(早いもの勝ちの仕様も微妙だけど、この仕様が微妙さに拍車をかける)
そのため、メインかサブキャラが可能な限り少ない操作で選べる場所に配置されている必要がある。
まずメインキャラにカーソルがあってる状態にし、同じライセンスを最初にとった人は”何もモンスターを選んでいない”ような表示になる。
その状態でいることはチェックマークが付くまで持ちキャラからカーソルが外れるのを待っている状態だ。
サブキャラが誰も使っていないようなら、メインは譲ってあげよう。
サブキャラが誰かに取られている場合は空気を読まずにメインをそのまま選択する。なぜなら自分が使えないキャラを使うより、○○専門勢のサブの方がまともな確率が高いから。
逆に自分のメインが先に選択されている場合は、急いでサブキャラを選択しにいく。
そしてメインもサブも全部取られている場合はアタッカーキャラクター以外はクイックチャットをうつといい
「サポート型のポケモンで戦うよ!」「ディフェンス型のポケモンで戦うよ!」である。どちらも2回くらい言えば、複数キャラ使える人が譲ってくれる可能性が高い。
それでも譲ってもらえない場合は適当なモンスターを使おう。その試合は負けても良い。
なんにしても、たくさん持ちキャラを持たないのであれば、自分の持ちキャラが最初にカーソルがあっていることは非常に大事だ。

■アイテムレベルを上げる。
このゲーム、アイテムレベルが20あるかないかでかなりの違いがでる。
そのため、利用するアイテムは全て最低でも20、可能なら30を目指そう。
特に課金を気にしないのであればまずはジェム購入して、アイテムきょうかキットをひたすら交換したほうがいい。
課金した人が勝つゲームではないが、課金すれば勝率があがるので、51%を目指す上では課金してしまうのが手っ取り早い。
というかゲームが上手くない自覚があってマスターに行きたいのであれば課金しよう。「そんなに変わらないよー」ってレベル以上の差はある。
上限も比較的安いため、あなたがマックスまで課金すればチームの平均道具レベルは相手より上になる。

■最後まで諦めない。アクティブポイントを意識しよう。
このゲームは今の環境だと亀を2-3匹倒すゲームである。
しかし、亀を倒したチームが勝つわけではなく、レベル差3以上あってもサンダーで逆転したりと逆転することも多い。
そのため、本当に詰むまで最後まで諦めてはいけない。
ただ、もうまず無理な試合のとき、針の穴の勝利を目指したり、降参したりするよりもやることがある。
アクティブポイントの獲得(ゴール)だ。

アクティブポイントとはゲーム参加で10点、連勝や獲得したゴールポイント数によって試合後にもらえるポイントのこと。
例えばエキスパート帯では、
・100ポイント以上ある場合は100ポイントを失いランクダウンをしない。(実質1敗がなくなる)
・400ポイント貯まると400ポイント消費し、1勝したことになる。
このポイントは非常に大事で、勝ったら1増えて負けたら1減るゲームだとポイントの総量はほとんど変わらない。
しかしこの制度によってポイントの総量はめちゃくちゃ増えている。
これが勝率50%をちょっと切っていてもマスターになれる所以だ。

ではアクティブポイントの獲得とはなにか?
アクティブポイントはゲーム中に獲得したゴールの点数によって、最後の5ポイント~のポイントがもらえる。
50ポイント、100ポイント、200ポイント・・・がその基準だ。
そのため、勝ち確の場面や負け確の場面では放棄せずにしっかりとポイントを入れて上記点数を超えるように意識するといい。
特にラストスパート中は得点が2倍になるので、50点にぎりぎり届いていない場合は特攻してでもポイントを入れよう。
※だたしその行動によって試合結果が変わるようなことがあってはならない
50点いれていない試合を入れるように、100点入れてない試合を入れるように意識を変えるとどうなるか?
なんと20試合で1敗がなくなる分のポイントがたまるのだ。
これは本当に大きくて、勝率1%あげるよりも簡単に勝率1%以上の価値がでる。
もうだめな試合でも諦めずに勝ちを目指すこと、そしてどうあがいても勝てない試合はポイントをとることを意識する。

■リスクはとらない
対戦ゲームにおいて全てにいえることだが、勝因を作る事よりも敗因を作らない事を意識したほうがいい。
常にリスクには敏感になる。ファインプレーよりもクソプレイをしないことを心がける。
ワンチャンかける(ハイリスクハイリターン)はもうそうしないと負けるときだけでいい。どっちが勝つか分からない状態でリスクをとってはいけない。

やってはいけないことを知ることが大事なので、そのあたりは僕ではなくうまい人のガイドを参考にすると良い。