Hollow Knight: Silksong(ホロウナイト・シルクソング)

Hollow Knight: Silksong」を遊んでみましたが、見切り発車で感想を書こうかと思います。

ネタバレしますので、ご注意ください。

 

最初、この池から出られなくて、ゲームを終了してしまったのですが、実は花を下攻撃すると上昇できます。というか、チュートリアルとか無いのか。素早く方向を下に入れないといけないので、十字ボタン付きのコントローラを使ったほうがいいです。

 

このボスは攻撃範囲が広すぎ。予備動作が短すぎ。頑丈すぎ。そして、ザコを呼ぶ。ザコはレッドアリーマみたいな攻撃で意地が悪い。

アップデート後にこのボスが弱体化して、やっと倒すことができました。これで、壁登りができるようになって、行動範囲が広がります。

 

第1章の終盤、「最後の審判」。やっとボスを倒した!と思ったら、大爆発に巻き込まれて、ゲームオーバー。

 

第2章の後半の難所。フェイの山。ボタンのタイミングがシビアすぎ。時間制限も厳しい。「これ作った人、何考えてんだ」と100回くらい思いました。ここをクリアしないと、二段ジャンプを獲得できないので、先に進めません。

最初、シルクの銛(もり)+ジャンプでプレイヤーを余分に上昇させるっていうのが上手くできなくて苦戦しました。

 

第2章の終盤。高貴の広間でザコ軍団との死闘。助っ人キャラと毒入りの道具でどうにかクリアしました。

 

超不快ステージ「胆液の沼」。ザコと連戦した後にボスを倒さないといけません。

 

超不快ステージその2「悪臭の水路」。視認性が悪い。弾を3つ発射する蚊みたいなのが居るのですが、5回くらい斬らないと死にません。

 

前作に引き続きお届け物のミッションもあります。今回は時間制限があるものもあって難易度が上がってます。先に敵を倒すことでミッションクリアしました。

 

第2部のラスボス手前のボス「レース」。わけがわからないうちに連続で攻撃を食らってゲームオーバーに。

 

このゲームにはエンディングが何パターンかあるのですが、2番目のエンディングを出すのに140時間かかりました。そのエンディングの後にサプライズとして第3章がスタートします。第3章はさらに難しくて、敵が頑丈になって、2倍ダメージの攻撃をしてきます。

 

仮面の破片を取り忘れていたので回収。

「絶対に届かない」と思ってた場所は、ダッシュと2段ジャンプとシルクの銛を組み合わせたら届きました。

 

アビスからの脱出。溶岩に追われながらトゲトゲの洞窟を垂直に登っていきます。すさまじい緊張感。

 

前作にもありましたが、トゲトゲだらけのステージ。これはストーリーに関係ないので、クリアしてなくてもいいみたいです。あまりにも難しすぎて途中で引き返しました。

 

現在までに189時間遊んでいますが、自分の達成率は「97%」。

ボスまで行って、負けて、セーブポイントからやり直し。この作業の繰り返しで、心が折れます。

難しすぎて、ここから先に進めません。「難しさ」の正体は何かというと、敵の予備動作が短いとか、ワープして襲ってくるとか、ランダムに襲ってくるとか、当たり判定が大きいとか、頑丈だとか、被ダメージが大きいとか、大量に襲ってくるとか、いろいろあるんですが、第3章の後半からはタガが外れしまってます。もう理不尽の領域。

2300円のゲームとは思えない大々ボリューム。操作性もビジュアルもサウンドも素晴らしい。褒めるところは一杯あるのですが、プレイ中のストレスが大きすぎです。このへんの感じ方で評価が分かれますね。

ちなみに前作の「Hollow Knight」は250時間遊んで、結局、真のラスボス(神様みたいなやつ)を倒せませんでした。

PS/2キーボードをX68000に接続する変換器(update)

Googleサイトの趣味ページで公開していたプログラムや回路図をちょっとずつGitHubに移行しています。最終的には、もうGitHubだけあれば良いという状態を目指します。

 

PS/2 X68000キーボード変換

https://github.com/nicotakuya/ps2_x68_converter/

 

インベーダーっぽいゲームの自作

https://github.com/nicotakuya/diy-video-game/

 

PS/2キーボードの自作

https://github.com/nicotakuya/diy-keyboard1

 

wavファイルをAVRマイコンで鳴らす

https://github.com/nicotakuya/AVR-play-wav/

 

メガドラ用6ボタンパッドの自作

https://github.com/nicotakuya/diy-MD-gamepad

 

ATtiny2313でビデオ出力

https://github.com/nicotakuya/attiny2313-videoout

 

www.youtube.com

AVRマイコンのビデオ出力のプログラムは昔、ひょいさんという方が超絶技巧でATmega168用に作ってくれたものです。私がアセンブラからC言語に書き直して、パフォーマンスが落ちているので、ある意味改悪です。GitHubで公開するにあたって、プロジェクトファイルをMicrochip Studio 7.0にアップデートしてみました。コンパイラはavr-gccのままです。

ラズパイPicoと接続するデモの動画を作ってみました。ラズパイPicoが単体でVGA出力できるくらいハイスペックなので、こんなことするメリットがないかも。

C言語でスーファミ用のソフト開発(5)効果音を鳴らす

前回の続きです。

C言語でスーファミ用のソフト開発(4)スプライトの表示 - takuya matsubara blog

今回は効果音を鳴らします。

効果音を鳴らすには音源のファイルが必要です。PVSnesLibが対応しているファイルの形式は「it」または「brr」です。ここではitファイルにします。

 

 

まずは、音源を用意します。オリジナル音源にしたいので、スマホで撮影します。

爆発時の「ドカーン」という音が欲しかったので、ビニール袋を膨らませてから割ってみました。結果、「バン」と鳴るだけの短い音になってしまいました。

コインを取った時の「チャリーン」という音も欲しくて、実物のお金を鳴らしたら「ジャリッ」というだけの音になりました。

難しいです。


スプレー缶を叩いたり、ホッチキスを鳴らしてみたり。いろいろ試行錯誤しながら5種類の音を撮ってみました。

 

撮影した動画(MOVファイル)を動画編集ソフトの「AVIUTL」で開きます。そして、使いたい部分だけを切り取って、「WAV出力」をメニュー選択して、WAVファイルで保存します。

設定は「32kHz」「16ビット」「モノラル」にしました。容量の都合により、あまり長い音は扱うことができません。場合によっては、音質を犠牲にして周波数を落とした方が良いです。周波数は4kHz、8kHz、16kHzにも対応していると思います。

 

「OpenMPT」という音楽ソフトを使って、itファイルを作成します。こういうソフトを「トラッカー」と呼ぶみたいです。サンプルの「effect」にある「effectssfx.it」というファイルをダウンロードして、音だけ入れ替えることにします。

https://github.com/alekmaul/pvsneslib/tree/master/snes-examples/audio/effects

 

「OpenMPT」を起動して、ツリーから「Samples」を選択します。サンプル番号を選択したら、インポートのボタンをクリックして、先ほど作ったwavファイルを読み込みます。ノーマライズのボタンをクリックすると、波形の振幅が最適化されます。

 

5種類の音を読み込みました。全部で88KBくらいあります。

 

自作ゲーム「SUPER JUMP GAME」の「makefile」です。書式は「effect」をコピペしました。

「effectssfx.it」は返還前のファイル名です。

「soundbank」は変換後のファイル名です(拡張子は不要)。

「-b 5」という設定は、バンク5という意味らしいです。

 

ビルドすると、「Compression」がどうのというエラーが出てしまいました。ググったら、FAQに対策方法が書いてありました。OpenMPT側の設定を変更する必要があります。

Community FAQ · alekmaul/pvsneslib Wiki · GitHub

 

itファイルを変換中の様子です。「32204 bytes free」と書いてあります。たぶん、SPC700のRAMの空き容量だと思います。

 

itファイルを変換すると、「soundbank.h」「soundbank.asm」「soundbank.bnk」という3つのファイルが生成されます。これが音のデータです。88KBくらいあったデータが26KBくらいに圧縮されました。

 

鳴らすために必要な処理は次の通りです。

・spcBoot関数でサウンド機能の初期化する。

・spcSetBank関数で効果音のデータを設定する。

・spcLoadEffect関数で効果音のデータをSPC700に読み込む。(楽曲の場合はspcLoad関数)

・ spcEffect関数で音を鳴らす。(楽曲の場合はspcPlay関数)

・メインループで spcProcess関数を毎回呼び出す。

あとは公式のWikiを参照してください。

https://github.com/alekmaul/pvsneslib/wiki/Sounds-and-Musics

 

www.youtube.com

ゲームの実行中の様子です。

効果音を鳴らすことに成功しました。

 

ROMイメージの中身はこんな感じです。まだ容量に余裕があります。

音のデータ(soundbank)が離れた場所に存在します。makefileで設定したバンク5ってこの場所なのでしょうか。

複数のsoundbankを置くこともできるようです。

日経ソフトウエア2025年11月号

日経ソフトウエア2025年11月号」にRoblox特集・後編の記事を書かせて頂きました。

 

スクリーンショットを150枚くらい撮ったけど、ほとんど使いませんでした。ボツ画像の一部です。新旧のソルジャーとゾンビを動かした様子です。古いソルジャーは棒立ちですが、新しいソルジャーは積極的に走り回ります。

 

古いモデルのゾンビで作った例です。新しいゾンビはリアルすぎて好きじゃないという人には良いかもしれません。

 

これもボツ画像。カメラアングルが肩越しなので、プレイヤーが銃を持っているのがわかりにくいと思って、複数のプレイヤーで実行してみました。

 

あと、RobloxのCEOが「インタラクティブ・フィジックス」を作ったという話はこの動画で知りました。

https://www.youtube.com/watch?v=VL6rYNmfrjM

 

本誌のコラムで書きましたが、昔、「ロボコンマガジン」という雑誌で「インタラクティブ・フィジックス」の記事を連載していたことがあったのですが、その証拠の画像がこちら。これは2003年のNo.32です。確か3年くらい連載していたはず。

 

C言語でスーファミ用のソフト開発(4)スプライトの表示

前回の続きです。

C言語でスーファミ用のソフト開発(3)BGの表示 - takuya matsubara blog

今回はスプライトを表示します。

PVSnesLIbでのスプライト表示する方法は大きく分けて2つあります。「ダイナミックスプライト」というエンジンを使う方法と、それを使わない方法です。

 

公式ページにダイナミックスプライトを使ったサンプルがあります。

https://github.com/alekmaul/pvsneslib/tree/master/snes-examples/graphics/Sprites/

「DynamicEngineSprite」の実行画面です。64個のスプライトがアニメーションしながら同時に動いています。ピンとこないかもしれませんが、スーファミはCPUが遅いので、ここまでやって処理落ちしないのは凄いことなのです。ただし、Wikiのダイナミックスプライトのページがまだ未完成で使い方がよくわからないのが難点です。

 

ダイナミックスプライトを使わず、普通にスプライトを表示したいだけなら、簡単です。

・oamInitGfxSet関数を呼んで、VRAMにパターンとパレットを登録する。

・oamSet関数を呼んでスプライトを動かす。

・メインループでWaitForVBlank関数を毎回呼ぶ。

これだけです。この他、表示サイズを変更したい場合にはoamSetExを呼び出します。

 

スプライトでオリジナルの画像を動かす例を紹介します。

まず、スプライトの画像を用意します。512枚のパターン(タイル)を登録する場合、128×256ピクセルの画像が必要です。使える色は16色までです。自分の場合は16色のbmpファイルで保存しました。ファイル名が「resource_sp.bmp」の場合だと、makefileの書式は次のようになります。

resource_sp.pic: resource_sp.bmp
$(GFXCONV) -s 8 -o 16 -u 16 -p -t bmp -i $<

これでパターンとパレットのファイルが作成されます。前回のBGの時と違って、パレット番号を指定する必要がありません。

 

スプライトを画面内でバウンドさせて、fps(frame per second)を測定するというプログラムを作ってみました。タイマー(snes_vblank_count)で1秒を計測して、その間にメインループが何周したかでfpsを求めています。

上記の画面だと、スプライトを32個表示しつつ、60fpsを維持しています。満足な結果です。

 

スプライトには、SMALLとLARGEの2種類があります。

LARGEでも全く問題なく60fpsを維持できています。SMALLでもLARGEでもCPUの負担は変わらないようです。

 

スプライトを48個表示すると、30fpsに落ちてしまいました。処理落ちです。静止画だと伝わりませんが、スローモーションのようにスプライトの動きがノロノロです。VSyncまでに処理が終わらないので、次のVSyncまで待ってしまうので、速度が半減してしまいます。

スーファミにはCPUの速度を変更する機能があります。デフォルト設定では「SLOWROM」ですが、これを「FASTROM」に変更します。

 

FASTROMにするには、makefileの先頭に「FASTROM=1」と記述するだけです。これで動作周波数が2.68MHz → 3.58MHzになります。

、、、期待したほど速くなってくれません。2年前に発売されたメガドライブが7.67MHzってことを考えると、かなり遅いと思います。

 

FASTROMに変更した結果、30fps → 60fpsに上がりました。

 

スプライトが64個だと、FASTROMでも30fpsに処理落ちしてしまいます。

やはり、たくさん表示したい場合にはダイナミックスプライトを導入したほうが良いですね。

 

スプライトを128個表示してみました。20fpsにまで落ちました。

一応、対策方法はあって、oamSet関数を極力呼ばないようにすれば、処理落ちを軽減できます。2フレームに1回だけ動かすとか、細かい工夫が必要です。

 

エミュレータによる処理落ちの再現がどこまで正確なのかが不明です。そこで、ROMに焼いて、実機で動かしてみました。

 


www.youtube.com

動画にしてみました。実機でもスプライトが64個になった時点で処理落ちします。エミュレータによる処理落ちの再現はかなり正確であると実感しました。

 

コードはGitHubで公開しています。

github.com

 

続き

nicotakuya.hatenablog.com