白峯のソース

IT なことのメモなど

Claude Code で 『NIZ』 を Unreal Engine に移植してみる #1

*筆者は AI に関してはやや慎重派.でも時代に抗ってても仕方ないので有効に利用しつつ AI だけではできないことをしていこうというスタンスです

話題の Claude Code を使って、TypeScript & WebGL で動いているゲーム『NIZ』を C++Unreal Engine に移植できるか、という実験プロジェクトです。
途中で「ダメだこりゃ」と思った瞬間に中止しますので予めご了承ください。
しかし、「こりゃいける」となったら諦めざるを得なかったプラットフォーム(Switch など)で 『NIZ』 が動くかもしれません(多分もし出すなら派生タイトルですが)。

前提

(a) 話中に出てくる、『NIZ』, 『MIZ』, 『Nyaz』 はブラウザ上で動く WebGL のダンジョン RPG
(b) アプリ版はトップビューに WebView や CEF を全面張りしたもの
(c) プログラムは TypeScript(以下、TS)で書かれ、JavaScript にトランスパイルして実行している
(d) 『NIZ』, 『MIZ』, 『Nyaz』 は同じプログラムで動いている(乱暴にいえば、if で切り替え)
(e) 例外的に 『Nyaz』 Switch 版のみはパブリッシャーさんが1から書いたプログラムで動いている(本テーマの対象外)
(f) 筆者は C++ は扱えるものの、Blueprint は苦手でとんちんかんなことを言うかも
(g) Unreal Engine は 5.x を使う(当面は、5.5.4)
(h) 技術的に「どうやるんぢゃ?」な点は線画.特に遠くても等幅の線を描けるものかが最大のチャレンジポイントか
(i) TS 版で利用しているライブラリは three.js、zlib, pngjs

作戦

(1) Claude Code Pro を契約する
    → 多分利用量が足りない
(2) 『Nyaz』 を Unreal Engine で動かす
    → 線画ではないので有利
    → 一番最近に作ったので記憶が新しく正誤判定がしやすい
(3) 『NIZ』 を移植
    → 実際はコンパイルスイッチ
    → 前提 (h) の線画がポイントか

* Claude Code には利用量制限があるが、本作はそれなりの規模はある、従って何日か空けないと再開できないと予想

実行

Visual Studio Code (以下、VS Code) に Claude Code の Extension を入れ、Pro を契約。月 $20 らしい。
なお、同時進行で Open AI Codex もやってみているんだけど、なんかちょっとイマイチ感があったのでそちらは中止。

さっそく、いい感じに移植してね的なプロンプトを入れ(Codex よりも色々察してくれている感あり)、まずは実行プランを提示してもらう。

・Phase1: .uproject ファイルを使用して UE5 プロジェクト構造を作成(1週間)
・Phase2: データシステムの構築を完了(1~2週間)
・Phase3:キャラクターとバトルシステム(3~4週間)
・Phase4:UI実装(3週間)
・Phase5:ダンジョン3Dレンダリング(2~3週間)
・Phase6:サウンドと統合(1~2週間)
・Phase7:最適化とデバッグ(1~2週間)

とのこと。

すごーい。
ちゃんとゲームの内容とか理解している感じだ!

というわけで、さっそく Phase1 実行。
.uproject 作成。
が、コンパイルが通らず、Unreal Editor が起動しない。

Visual Studio のソリューションファイル(.sln)を生成し、中身を見てみると、
Development Editor、Debug Game Editor、Shipping などのコンフィギュレーションがない。
そりゃ Unreal Editor が起動しませんがな。

上記を指摘すると、さっそくコンフィギュレーションを作り直してくれた。
…多分、この段階で Visual StudioUnreal Engine に詳しくない人はドロップですな…。

さっそくコンパイルするもビルドが通らない。

見るとインクルードパスが間違えている。
指摘すると直すもまだ通らない。
いやいや、ご自分で切り分けたフォルダ構成ですがな!
もう面倒なので、手動でインクルードパスを直す。

その他、細かいミスを直して、なんとかビルドが通るように。
Unreal Editor が起動した。

Unreal Editor 起動

中を見てみると、コンテンツに StartarContent(不要じゃない?)しかなく、新規の空のレベルがあるだけ。
あー、「UE5 プロジェクト構造を作成」って超ベースのプロジェクトファイルを作るだけなのね。

でもよく見ると、ちょびっとだけ TS のフレームワークの一部プログラムは C++ 化してあるっぽい。
「ここがプログラムの一番の元でしょう!」的な。
それがわかるのはなかなかすごいと思う。
それに Phase1 に1週間とか言ってたけど、1時間足らずで完了できたのはなかなか優秀なのではないでしょうか。

それでは、引き続き Phase2 へ!
…といったところで、Pro 版の利用量オーバー…。
まぁ正直、ここまでなら、UE でプロジェクトを新規作成すれば良かっただけだなぁ、と思いましたとさ。

容量オーバー…

Pro のままだと1週間後に利用量が復活するらしい。
Max を契約しますかねぇ?

つづく。

Visual Studio Code, Emscripten (C++), Makefile, Debug (ブレークポイント)

(1) 各種インストール

 

環境は Windows を想定

それぞれシステムの混乱を防ぐため Windows システムに環境変数(PATH)は設定しないものとする

 

Emscripten をインストールしておく

  例として、パスを D:\11_System\Emscripten とする

  ※activate 時のパスや環境変数はメモしておく

・Make for Windows をインストールしておく

  例として、パスを D:\11_System\GnuWin32 とする

  ※パスに半角スペースを含まないこと

VS Code に Extension「WebAssembly DWARF Debugging」をインストールしておく

 

(2) プログラムソース構成

 

例として、VS Code プロジェクトフォルダのルートに

hello.cpp

#include <stdio.h>

extern "C" const char* getWorld();

int main() {
    printf("Hello %s!\n", getWorld());
    return 0;
}

world.c

const char* getWorld() {
    return " * World * ";
}

を置く

 

(3) VSCode の設定

 

VS Code プロジェクトフォルダ下の .vscode フォルダ下に、launch.json と tasks.json を設置する

 

launch.json 設定例:

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "chrome",
            "request": "launch",
            "name": "localhost",
            "url": "http://localhost:8080",
            "webRoot": "${workspaceFolder}",
            "preLaunchTask": "make_all_emrun_start",
            "postDebugTask": "emrun_end"
        },
        {
            "type": "chrome",
            "request": "launch",
            "name": "file",
            "file": "${workspaceFolder}/index.html",
            "runtimeArgs": [
                "--allow-file-access-from-files",
                "--autoplay-policy=no-user-gesture-required"
            ],
            "trace": true,
            "preLaunchTask": "make_all",
        }
    ]
}

 

task.json 設定例:

{
    "version": "2.0.0",
    "tasks": [
      {
        "label": "make_all",
        "type": "shell",
        "command": "make",
        "args": ["all"],
        "options": {
            "env": {
                "PATH": "D:\\11_System\\Emscripten\\upstream\\emscripten;D:\\11_System\\GnuWin32\\bin",
                "EMSDK_PYTHON": "D:\\11_System\\Emscripten\\python\\3.9.2-nuget_64bit\\python.exe",
            }
        }
      },
      {
        "label": "make_clean",
        "type": "shell",
        "command": "make",
        "args": ["clean"],
        "options": {
            "env": {
                "PATH": "D:\\11_System\\Emscripten\\upstream\\emscripten;D:\\11_System\\GnuWin32\\bin",
                "EMSDK_PYTHON": "D:\\11_System\\Emscripten\\python\\3.9.2-nuget_64bit\\python.exe",
            }
        }
      },
      {
        "label": "emrun_start",
        "type": "shell",
        "command": "emrun",
        "args": [".", "--no_browser", "--serve_after_exit", "--port", "8080"],
        "options": {
            "env": {
                "PATH": "D:\\11_System\\Emscripten\\upstream\\emscripten",
                "EMSDK_PYTHON": "D:\\11_System\\Emscripten\\python\\3.9.2-nuget_64bit\\python.exe",
            }
        },
        "isBackground": true,
        "problemMatcher": [
          {
            "pattern": [
              {
                "regexp": ".",
                "file": 1,
                "line": 1,
                "message": 1
              }
            ],
            "background": {
              "activeOnStart": true,
              "beginsPattern": "Web server root directory:.*",
              "endsPattern": "Now listening at.*"
            },
          }
        ]
      },
      {
        "label": "emrun_end",
        "type": "shell",
        "command": "${input:terminate_emrun_start}",
      },
      {
        "label": "make_all_emrun_start",
        "type": "shell",
        "command": "echo start...",
        "dependsOn": [
            "make_all",
            "emrun_start"
        ]
      },
    ],
    "inputs": [
        {
            "id": "terminate_emrun_start",
            "type": "command",
            "command": "workbench.action.tasks.terminate",
            "args": "emrun_start"
        }
    ]
}

※ PATH や EMSDK_PYTHON の値は、Emscripten インストール時 emsdk.bat activate latest の表示内容に合わせること

 

(4) Makefile の用意

 

Makefile の例:

SRCS = \
    hello.cpp \
    world.c
WASM = index.wasm

$(WASM): $(SRCS)
    emcc -o index.html -O0 -g3 $(SRCS)

all: $(WASM)

clean:
    del $(WASM) index.html index.js

 

(5) 動作確認

 

hello.cpp の printf 行などにブレークポイントをかけて、RUN AND DEBUG から実行

localhost なら emrun によるデバッグ用 Web サーバーによる実行

・file なら直接ローカルファイルを開いて実行

ブレークポイントで停止、およびステップ実行できていることを確認する

 

意外と file の方がブレークポイントの反応が良かったりするので、たいていは file でいける

(しかし、React を利用する場合などは CORS の問題があるのでやはりデバッグ用 Web サーバー起動が良いだろう)

 

その他・・・

 

最小構成として設定したが、実用的には -O0 だけでなく -O3 最適化した、いわゆる Release 版的な task も用意しておくと良さそう

Windows の共有ドライブを Mac から Time Machine する

1. Windows 上で exFAT フォーマットのボリュームを用意し、共有する
    [ 例 ]
    共有名:「WinTimeMachine」
    ボリュームサイズ:931GB

2. Mac から Finder で Windows に「サーバーへ接続..」する

3. Mac の設定 -> 「プライバシーとセキュリティ」-> 「フルディスクアクセス」-> 「ターミナル」を ON

4. ターミナルから以下のつのコマンドを実行する

sudo hdiutil create -size 930g -type SPARSEBUNDLE -nospotlight -volname "WinTimeMachine" -fs "Case-sensitive Journaled HFS+" -verbose /Volumes/WinTimeMachine/WinTimeMachine.sparsebundle

sudo tmutil setdestination -a "/Volumes/WinTimeMachine/"

5. Mac の TimeMachine から見えているはずのあので、バックアップを設定する

元保護猫コルタンと「乗っ取りのうた」のこと

コルタン と もちか

うちには、以前から友達に譲渡してもらったキジシロのメスの「もちか」がいた。
もちかの母ちゃんは元野良猫で、もちか出産の際にニンゲンのもとに身を寄せた賢いコだったらしい。
その母ちゃんは猫エイズを患っており、既に虹の橋を渡っている。
幸い、もちかには猫エイズは伝染らなかった。

2019年に一軒家に引っ越した筆者は、仕事もコロナ禍前からリモートワークに移行しており、友達やパートナーが家に出入りするようにもなって、もちかを独りにさせることはかなり減った。
それでも、筆者にばかり依存している姿は不憫に見えて、もうひとり保護猫を迎えることにした。

家の近くのとある保護施設では、頻繁に譲渡会を開催しており、そこでオスの黒猫「コルタン」に出逢った。
当時コルタンは推定2歳。
施設の人は「去年のコ」と言っていた。
保護猫の譲渡率は子猫が断然高いそうだが(当猫の柔軟性や負担を考えれば当然ともいえる)、コルタンは既に子猫ゾーンではなく施設のレギュラー猫ゾーンにおり、少なくとも引く手アマタではないのは明らかだった。
後から知ったことだが、どうやら一回トライアルに失敗した経緯もあるらしい。

コルタンは、譲渡会見学中ずっと筆者の足元につきまとい、「ねぇねぇねぇねぇ」と話しかけているように見えた。
部屋を移動するときもドアで挟まないか注意しないといけないくらいの絡み様である。

そんな彼の熱意?に負けて、筆者はその日中にコルタンの譲渡願いを出した。
翌日電話で施設の方から、右目にハンデかあることを伝えられたが、気にしなかった。

来たばかりのコルタン.痩せていた

数週間後、所定の手続きを経て、コルタンは施設の方に連れられてうちに来た。
最初の怯え様は猫飼いなら想像に難しくないと思われるが、新しいコが不満なもちかの不機嫌と重なって、自宅内はやや不安モードに包まれていた。

特に下痢が酷い。
最初は緊張から来るものかとも思ったが、どうもその垂れ流しぶりが激しい。
すぐに動物病院にいったらジアルジア症とのこと。
予想外の事態であったが、もう四の五の言ってられない。
とにかく必死に対処する。

まず、譲渡いただいた施設に連絡し、おそらく周囲の猫ズも危ないであろうことを伝える。
そして、嫌がるコルタンにだましだまし薬を飲ます。
おかげで薬やりはうまくなった。
隔離してる不機嫌もちかをなだめ、とにかく二次感染しないように手や皿、毛布等を洗いまくる。
ふたりの餌の好みが違うので、下痢で痩せゆくコルタンが好むものを探す。

戦いの2週間を終えると、無事コルタンのジアルジアは駆除され、もちかとも合流できるようになった。
の、前に、その辺に散らばる下痢便を掃除&アルコール消毒……。

もちかはどこか好みではないのか、コルタンと仲良くする気はないらしい。
とはいえ、ケンカする様子もないので良しとする。
以前、フェレットをふたり8年間飼ってたことがあるのだが、ふたりが仲良すぎて上のコが亡くなると追うように下のコも亡くなってしまった。
そういうのも悪くはないのだが、そうでなくてもかまわないだろう。
ちなみに、今では1cm空いてれば近づくのはOKで、たまにシャーシャー言いながら追っかけっこをしている。

その後、また想定外の事態が発生する。
保護施設の方から電話があり、コルタンの母ちゃんの猫白血病が発覚したらしい。
人には伝染らないが、猫には伝染る。
急ぎ、もちかと再度隔離し、動物病院へ。

もちかは母ちゃんの猫エイズをもらわなかった。
どうか、コルタンも無事で。
そんなことを祈る診察室だった。

結果、陰性。
ホッと胸を撫で下ろす。
おっさんの疲れがドッと出る。

それにしても、まー色々あるコである。
予想外のところに登ったり、紐飲み込んじゃったかも事件を起こしたり。
とはいえ、問題の多いコというのも可愛いもの。
地震が起きようが富士山が噴火しようが、決して見捨てないぜ、もちか、コルタンよ。
でも、同時に、コルタンが過去トライアルに失敗したらしい流れもわかるような気も…。
聞くところによると、未だに黒猫に偏見持ってる人もいるらしいし。

そんなこんなで、やんちゃな黒猫コルタンも今は落ち着き、毎日文句垂れながらへっついて来てます。

近い.どうも右目もぼんやり見えているっぽい

で、歌の宣伝。
そんなコルタンが譲渡会でお尻フリフリ猛アピールしてるところを歌にした。
基本的には今作ってるかゲームのプロモーションに使う歌だけど、保護猫、譲渡会への応援の意を込めて。
なかなか決まらない猫の、ちょっと切ない歌詞だけど、最後には希望を持たせたつもり。
良かったら聴いてやってください。
ついでに、イイネとコメントもらえると嬉しいです。

youtu.be

長文お付き合いありがとうございました。

Stable Diffusion で 裸サンザ を描こう!〜ざっくり手順

0. はじめに

 

ウィザードリィ古参ファン@ヒッポンスーパー民の嗜み“裸サンザアート”

でもワシ、絵が描けない……?

大丈夫。

話題の AI、Stable Diffusion 様に描いてもらいましょう。

この記事は、AI による“裸サンザアート”を楽しむためのざっくりした手順とコツをお伝えいたします。

 

AI による画像生成は、

(a) オンラインサービスを利用する

(b) パソコンにインストールして実行する

の2パターンがあるかと思いますが、(a) の場合は、高品質なものができる反面、有料なのと、テイストが決まりがち。

(b) だと、時間と電気代はかかりますが作りたい放題、テイストもモデルを選べば変えられます。

この記事では、(b) で行きます。

もちろん、高速な GPU があるに越したことはないですが、要は待てばいいのです。

 

 

1) Stable Diffusion のインストール

 

お約束の、Python, Git, Stable Diffusion web UI を、環境に合わせてインストールしましょう。

インストール方法は、検索エンジンで「Stable Diffusion web ui インストール方法」と検索すればたくさん出てくるので、そちらを参照ください。

テクニカルな側面が強いため、PC に詳しくないとちょっとツラいかもしれませんね。

 

ちなみに筆者は、GPURadeon RX 6600 XT なので、AUTOMATIC1111 の派生 DirectML 版

https://github.com/lshqqytiger/stable-diffusion-webui-directml

を使ってます。

Sampling steps 20 の 512x512 画像を1枚生成するのが、だいたい 70 秒ぐらいです。

 

 

2. モデルを取得

 

画像生成は、元となるモデルデータが肝心。

ネット上から良さそうなモデルをもらってきましょう。

 

モデルのインストールの仕方もネットに転がってますが、

{インストールフォルダ}/models/Stable-diffusion

に、.ckpt や .safetensors を置けば認識してくれるはずです。

 

筆者は、「DreamShaper」がお気に入りでよく使わせてもらってます。

https://civitai.com/models/4384/dreamshaper

 

なお、ネットで公開するなら、ライセンスも気にしておきましょう。

「Creative ML OpenRAIL-M」だと、“営利、非営利を問わず使用できる寛容なライセンス” とされているので安心かと思われます。

 

参考:

https://cloud.watch.impress.co.jp/docs/column/infostand/1441102-2.html

 

 

3. 呪文を入れる

 

ここまでで準備完了です。

プロンプトに裸サンザの呪文を入れていきましょう。

 

まず、

full body shot, 1man, solo,

この辺りは定型?

 

裸サンザさんなので、

sanza, naked man, ninja, wizardry, manga,

は必須かと。

AI 様が、「サンザ」や「ウィザードリィ」を認識しているかは不明ですが、これがないと裸サンザアートにはならんでしょう、的な。

 

容姿的な面で、

middle aged man, old man, muscle body, gray hair, swept back hair,

あたり。

若い黒髪のヒョロ男だとサンザ感がなくなりますしね。

まぁ、マッチョボディは正当なる後継者たるモンキー先生の流儀かもしれませんが。

 

お好みで背景を、

indoor, dark underground cave, labyrinth, maze,

など。

ま、地下迷宮内の方がウィザードリィっぽいかな、と。

 

あと、TIPS 的なところで、“サンザが脱いでくれない!”“下着つけたらAC10!”でお悩みの場合は、

男子の下っかわについている ●enis 関連を呪文に含めると、比較的 AI 様が脱がせてくれます。

モロダシになるので、その後の修正を忘れぬよう、お気をつけください。

 

反呪文(ネガティブ・プロンプト)は、ネットから拝借してきました。

後半のワードは「服着るな」関係が多いですが、効いているのかは不明です。

flat color, flat shading, nsfw, retro style, poor quality, bad face, bad fingers, bad anatomy, missing fingers, low res, cropped, signature, watermark, username, artist name, text, beard, clothes, cloak, underwear, pants, trunks, bikini

 

その他の設定は、

・Batch Count: 時間かかってもいいから複数候補見たい、という場合は 2 以上にしましょう.2 なら 2 枚描いてくれます

・Batch Size: 1 で良いかと(多いと効率的に生成してくれそうなものの、VRAM を食うみたいです)

・CFG Scale: プロンプト指示従い度.7 〜 11が適切と言われています.迷ったら、とりあえず 7

あたりで良いかと。

 

参考:

https://gigazine.net/news/20220909-automatic1111-stable-diffusion-webui-how-to-use/

 

 

4. 良いのができるまで繰り返す

 

あとは、微調整ととにかく多く描いてもらうことです。

 

Batch Count を 100 にして数時間放置しても良いかもしれません。

その際は、OS(WindowsMac)のスリープの設定には気をつけてください。

AI 画伯活躍中は、スリープを切ると良いかもしれません。

Stable Diffusion



気に入った画像があれば、どんどん別フォルダに保存していきましょう。

 

 

5. 加工

 

おそらく、そのまま公開したら何かとまずいものが描かれていることでしょう。

 

まずは、消しゴムマジック的な機能を搭載した画像編集アプリで Pe●is を消しましょう。

感慨深い作業ですが何も考えず黙々と作業しましょう。

ただし、周囲の目にはご注意を。

下手をするとご家族の中で特別枠に入れられてしまうかもしれません。

 

次に、股間の謎光です。

これも、画像編集アプリで入れます。

筆者はもう新しいアプリを調べるのが面倒なおっさんなので、Photoshop 使ってます。

謎光入れ



 

6. 公開

 

別に公開しなくてもいいですが、このまま保存していても虚しくなるだけでしょう。

ハッシュタグ #裸サンザ を付けると同志(特別枠?)リツイートしてくれるかもしれません。

完成!



あと、応用で作った本来の性癖のものは当方では関与しませんのでご了承ください。

ただ、捕まらないようにお気をつけてくださいね。

 

 

それでは、よき裸サンザライフをお送りください!

冗談なんだから本気のレスは勘弁してね。

ウィザードリィ外伝 五つの試練 ポートレートの保存先

*そもそも* 【2022年12月6日現在】今まだ早期アクセス版なのですが−−−

 

STEAM版 『Wizardry外伝 五つの試練』楽しいですね。
でも、ポートレート画像の保存先が分からない!ってなってませんか?
そんな、Wizfo ポートレート難民に…

 

ポートレートの場所は、
 (インストール先)\Data\User\face 
です!

 

具体的には、64bit Windows の場合は、
 C:\Program Files (x86)\Steam\steamapps\common\Wizardry The Five Ordeals\Data\User\face
になります。

 

以前は、ドキュメント/59studio の下だったんですが変わったんですよね…。
ネット検索すると、大抵この頃の情報が出てくるという、ランダムジャンプ石の中的罠です。

 

このフォルダの下に、
 faceNN (NN は数字。18 以降を使うのが良さげ)
というフォルダを作り、その中に、
・face_a.png ・・・ 96x96ピクセルの顔アイコン(以前は faceNN.png だった)
・face_c.png ・・・ HDステータス画面用ポートレート
・face_d.png ・・・ HD戦闘画面用ポートレート
を入れれば良いかと。
(_e など、その他のアイコンについては、以下の『「カスタムポートレート機能」の追加仕様について』リンク参照のこと)

 

変更経緯やらは以下を参照。

▼【2021年12月15日】「カスタムポートレート機能」の追加仕様について
https://twitter.com/wizardry_fo/status/1471067823598620678

▼【2022年3月22日】ポートレートのファイル名の変更
https://store.steampowered.com/news/app/1308700/view/3110303461503227854

▼【2022年8月25日】ポートレートのフォルダの位置変更と一部ファイル名の変更
https://store.steampowered.com/news/app/1308700?emclan=103582791470179247&emgid=3243175505178485064

※将来的にまだ変わるニオイも?

 

最後に…こちらもよろしくね!😅

召喚の書✕MIZコラボ企画

透過は96x96 だし、C とか D とか…わかりますよね?😆

Mac から Microsoft Remote Desktop で Windows に接続するとキーボードが 101(US 配列)なる問題

レジストリエディタ(regedit.exe)から
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\KeyboardType Mapping\JPN

00000000
の値を
kbd101.dll
から
kbd106n.dll
に変更し、Windows を再起動すると JP 配列になった。

macOS 11.6.5
Microsoft Remote Desktop 10.7.6
Windows 10 Pro