親戚のゲーム作ってるおじさんブログ

「そういえば、そんな人いるとか聞いたなあ」って思ったでしょ? 私です。

Visual Studio Community ツールキットと、テンプレートの導入

はじめに

VisualStudioの拡張が複雑すぎて、

作るのあきらめようと思ったら、簡単に実装できるライブラリ(ツールキット)と、穴埋めのように開発できるテンプレートを無償で提供しているらしい。

あきらめる前に、以下にその神パッケージの導入手順を示す。

手順

以下のURLからパッケージ落とす

Extensibility Template Pack 2022 - Visual Studio Marketplace

早速、テンプレートを使って、新規プロジェクトを作っていこう。

今回落としたテンプレートは、後ろに(Community)がついているので、目印にできる。

今回はVSIX Project w/Command(Community)を選択。

この状態で、デバッグをすると、すでに ツールメニューにマイコマンドが作成される状態になっている。

MyCommandクラスに、これを押したときの処理がかいてある。
ここにいろいろ処理を 追加すれば、いろいろできそう。

参考

GitHub - VsixCommunity/Community.VisualStudio.Toolkit: Visual Studio 拡張機能の作成を容易にする

VSIX Community Toolkit - Visual Studio (Windows) | Microsoft Learn

GitHub - VsixCommunity/Community.VisualStudio.Toolkit: Making it easier to write Visual Studio extensions

VisualStudioの拡張機能開発2 開発開始~デバッグ実行まで

はじめに

開発環境の準備はこちら

VisualStudioの拡張機能の開発の準備(拡張のインストールから、プロジェクトを開くまで) | まなピコ (taka108.com)

目的

拡張機能のテンプレートファイルを取り込み、ツールメニューに、コマンドを追加し、デバッグする方法を学ぶ

続き

プロジェクトを新規で追加したら、ソリューションエクスプローラーから、プロジェクトを右クリック。新しい項目の追加をする

Commandという項目を見つけて、適当な名前を付けて、追加ボタンを押す

その状態で、一度デバッグを押す

もう一つVisualStudioが起動する。コードなしで続行

拡張機能の管理に、今回追加したソリューション名がでていればOK。
この状態になっているということは、今作成中の拡張機能が反映された状態になっているということなる

実際、ツールメニューをみると、「Invoke 今回追加したクラス名」が表示されている

押すと、こんなダイアログが出る

次回は、実際にこのコマンドに機能を追加する

参考

Creating an Extension with a Menu Command - Visual Studio (Windows) | Microsoft Learn

VisualStudioの拡張機能の開発の準備(拡張のインストールから、プロジェクトを開くまで)

目的

VisualStudioを使っていて、使いずらい、または、この機能がほしいと思うことはありませんか?
今回は、拡張を作り始めるにはどうすればよいか紹介します

環境

OS:Widnows
VisualStudioバージョン:2022

やり方

Windowsのスタートメニューで検索するなどして、
VisualStudioInstallerを開く。

最新でなければ、更新

更新がおわったら、変更ボタンを押す

下のほうにある「VisualStudio拡張機能の開発」を押して、変更ボタンを押す

インストールが完了したら、VisualStudioを起動。新しいプロジェクトの作成を押す

VSIXProjectを押す

プロジェクト名を入力し、作成を押す

準備完了!次回は、実際作っていきます

参考

Visual Studio 拡張機能の開発を開始する - Visual Studio (Windows) | Microsoft Learn

Visual Studio SDK のインストール - Visual Studio (Windows) | Microsoft Learn

Gitのブランチ名を大文字と小文字で2つ作ってしまった場合の対処

目的

Gitのブランチ名大文字のものと小文字のもので2つ作ってしまった場合の対処法がわかる

環境

OS:Windows

リモートリポジトリ:GitHub

大文字と小文字のブランチはローカルでは作れない

そもそも、ローカルでは、大文字と小文字の違いしかないブランチを作成できません。

ためしに、masterブランチがある状態で、Masterブランチを作成してみようとすると

git branch Master
fatal: A branch named 'Master' already exists.

はじかれますね。

core.ignorecase をfalseにしたとしても、大文字と小文字の差異しかないブランチは作成できません。

というのも、ブランチを作成すると、以下のようにファイルができるのですが、Windows環境の場合、大文字と小文字が区別できないため、作成できるはずがないんですね。

Macはわかりませんが...

同名ブランチができてしまうのはどんなケース?

リモートブランチでGitHubにプッシュする際は、大文字と小文字で分けてブランチが作成されるので、以下を実施すれば、作成できてしまう

方法1

  1. feautre/Abcブランチを作成し、リモートブランチにプッシュ。
  2. その後ローカルブランチを削除。
  3. feature/abcブランチを作成し、リモートボランチにプッシュ。

方法2

  1. feautre/Abcブランチを作成し、リモートブランチにプッシュ。
  2. ほかのアカウントでfeature/abcブランチを作成し、リモートボランチにプッシュ。
  3. 別のアカウントでfeature/abcブランチを作成し、リモートボランチにプッシュ。

発生する問題

この状態になってしまうと、feature/Abcをチェックアウトすることはできなくなります。

git checkout feature/abc としても、 git checkout feature/Abcとしても、どちらにしてもfeature/abcがチェックアウトされてしまうのです。

解決策

前提として、コンフィグのcore.ignorecase をfalseにしたとしても、feature/Abcをチェックアウトすることはできません。

ではどうするのかというと、リモートリポジトリのブランチ名を、ローカルリポジトリ側で判別できる別の名前に変更すれば、通常のブランチとして捜査できるようになります。

対処手順

GibHubのリポジトリページから、「View all branches」をクリック

リネームしたいブランチの編集(ペンのマーク)をクリック

Rename欄にあたらしいブランチ名を入力し、「Rename branch」ボタンを押す。

git fetchしてから、リネーム後のブランチ名でチェックアウト

git fetch
git checkout feature/abc_2

これで、feture/Abcにあった変更は、fetaure/abc_2でアクセスできるようになりました。

あとは、feature/abcにマージするなり、一部cherry-pickするなりお好きにどうぞ

参考

ブランチの名前を変更する - GitHub Docs

【スマブラ】ワザのスクリプトを解析して隠し仕様を発見する

目的

スマブラをやっていて、ワザの仕様の知識が必要だと思ったことはないですか?

ググれば、いろいろな情報がでてきますが、できれば1次情報が知りたい...。
今回は、1次情報を確認するそんな方法を伝えられればと思います。

各ワザ1次情報はどこ?

ワザのコードを確認できればいうことはないのですが、

スマブラオープンソースなわけありません。

しかし、こちらの有志による解析ページをみれば、実際にスマブラで使用されているスクリプトがみれます。(他人の解析なら二次情報じゃん!というアナタ。スクリプトということで、1次情報に近いということでご勘弁を...)

Smash Ultimate Data Viewer (rubendal.github.io)

注意してほしいのは、あくまでスクリプトまでしか見れません。
スクリプトから呼び出している内部コードは見れないので、ある程度想像したり検証する必要があります。

簡単な見方の例

確認したいキャラをクリック。今回は試しにマリオを押してみます。

Articleをクリック

以下を選べます

mario:マリオ
mario_fireball:ファイアーボール
mario_hugeflame:最後の切り札「マリオファイナル」の火炎
mario_pumpwator:ポンプの水

今回はマリオを選択してみましょう。

そして次にScriptを選択。
どの名前が何を指しているかは、桜井さんのファイル名の説明動画をみればわかると思います。

ファイル名は合理的に 【プログラム・テクニカル】 - YouTube

いろいろありますね...
今回は、一発目の弱「Attack11」を選択します。

すると、スクリプトがでてきました。内容を見てみましょう。

frame(Frame=2)
if(is_excute){
ATTACK(ID=0, Part=0, Bone=hash40("top"), Damage=2.2, Angle=361, KBG=30, FKB=0, BKB=20, Size=1.2, X=0.0, Y=6.3, Z=6.0, X2=LUA_VOID, Y2=LUA_VOID, Z2=LUA_VOID, Hitlag=1.8, SDI=1.0, Clang_Rebound=ATTACK_SETOFF_KIND_ON, FacingRestrict=ATTACK_LR_CHECK_F, SetWeight=false, ShieldDamage=0, Trip=0.0, Rehit=0, Reflectable=false, Absorbable=false, Flinchless=false, DisableHitlag=false, Direct_Hitbox=true, Ground_or_Air=COLLISION_SITUATION_MASK_GA, Hitbits=COLLISION_CATEGORY_MASK_ALL, CollisionPart=COLLISION_PART_MASK_ALL, FriendlyFire=false, Effect=hash40("collision_attr_normal"), SFXLevel=ATTACK_SOUND_LEVEL_S, SFXType=COLLISION_SOUND_ATTR_PUNCH, Type=ATTACK_REGION_PUNCH)
ATTACK(ID=1, Part=0, Bone=hash40("top"), Damage=2.2, Angle=361, KBG=30, FKB=0, BKB=20, Size=1.5, X=0.0, Y=6.3, Z=8.7, X2=LUA_VOID, Y2=LUA_VOID, Z2=LUA_VOID, Hitlag=1.8, SDI=1.0, Clang_Rebound=ATTACK_SETOFF_KIND_ON, FacingRestrict=ATTACK_LR_CHECK_F, SetWeight=false, ShieldDamage=0, Trip=0.0, Rehit=0, Reflectable=false, Absorbable=false, Flinchless=false, DisableHitlag=false, Direct_Hitbox=true, Ground_or_Air=COLLISION_SITUATION_MASK_GA, Hitbits=COLLISION_CATEGORY_MASK_ALL, CollisionPart=COLLISION_PART_MASK_ALL, FriendlyFire=false, Effect=hash40("collision_attr_normal"), SFXLevel=ATTACK_SOUND_LEVEL_S, SFXType=COLLISION_SOUND_ATTR_PUNCH, Type=ATTACK_REGION_PUNCH)
ATTACK(ID=2, Part=0, Bone=hash40("top"), Damage=2.2, Angle=180, KBG=20, FKB=0, BKB=15, Size=1.8, X=0.0, Y=6.3, Z=12.0, X2=LUA_VOID, Y2=LUA_VOID, Z2=LUA_VOID, Hitlag=1.8, SDI=1.0, Clang_Rebound=ATTACK_SETOFF_KIND_ON, FacingRestrict=ATTACK_LR_CHECK_F, SetWeight=false, ShieldDamage=0, Trip=0.0, Rehit=0, Reflectable=false, Absorbable=false, Flinchless=false, DisableHitlag=false, Direct_Hitbox=true, Ground_or_Air=COLLISION_SITUATION_MASK_GA, Hitbits=COLLISION_CATEGORY_MASK_FIGHTER, CollisionPart=COLLISION_PART_MASK_ALL, FriendlyFire=false, Effect=hash40("collision_attr_normal"), SFXLevel=ATTACK_SOUND_LEVEL_S, SFXType=COLLISION_SOUND_ATTR_PUNCH, Type=ATTACK_REGION_PUNCH)
ATTACK(ID=3, Part=0, Bone=hash40("top"), Damage=2.2, Angle=361, KBG=20, FKB=0, BKB=15, Size=1.8, X=0.0, Y=6.3, Z=12.0, X2=LUA_VOID, Y2=LUA_VOID, Z2=LUA_VOID, Hitlag=1.8, SDI=1.0, Clang_Rebound=ATTACK_SETOFF_KIND_ON, FacingRestrict=ATTACK_LR_CHECK_F, SetWeight=false, ShieldDamage=0, Trip=0.0, Rehit=0, Reflectable=false, Absorbable=false, Flinchless=false, DisableHitlag=false, Direct_Hitbox=true, Ground_or_Air=COLLISION_SITUATION_MASK_GA, Hitbits=COLLISION_CATEGORY_MASK_ALL, CollisionPart=COLLISION_PART_MASK_ALL, FriendlyFire=false, Effect=hash40("collision_attr_normal"), SFXLevel=ATTACK_SOUND_LEVEL_S, SFXType=COLLISION_SOUND_ATTR_PUNCH, Type=ATTACK_REGION_PUNCH)
}
wait(Frames=2)
if(is_excute){
AttackModule::clear_all()
WorkModule::on_flag(Flag=FIGHTER_STATUS_ATTACK_FLAG_ENABLE_COMBO)
}
frame(Frame=7)
if(is_excute){
WorkModule::on_flag(Flag=FIGHTER_STATUS_ATTACK_FLAG_ENABLE_RESTART)
}

全部は読めないので、ためしに、攻撃判定を見てみます。

攻撃判定は、ATTACKです。
弱攻撃は、4つの円をつかっているので、スクリプト内にも、4つあります

...って、アレ?円が3つに見えますよね?

実は、一番右にある円は、2つ重なっているようです。(X,Y,Z,SIZEが一緒)

重なった2つの攻撃判定は、Angle(吹っ飛ばすベクトル)とHitbits(あたる対象)が違います。

Angle=180,Hitbits=COLLISION_CATEGORY_MASK_FIGHTER(ファイターのみ当たる設定と思われる)

Angle=361,Hitbits=COLLISION_CATEGORY_MASK_ALL(ファイターに限らず、すべてのやられ判定を対象にしていると思われる)

具体的には、以下の違いがでてきます。

ファイター:マリオに引き寄せられるように飛ぶ
それ以外(アイテム、ステージ等):マリオに離れるように飛ぶ

これにより、相手ファイターに弱1をギリギリ当てても、次のコンボがつながるようになっているのですね。

逆に、ファイター以外(サンドバック君)に弱1を当て続けると、あるタイミングで当たらなくなることがわかります。

そのほかのATTACKのパラメータの意味は、こちらが参考になります。

攻撃判定 - スマブラSPECIAL 検証wiki - atwiki(アットウィキ)

おわりに

リファレンスがないので、実機で確認したりしながら解析するのがよいと思います。

もはやゲームを遊ぶの域を超えている気がしますが、友達より1レベル上の解析をしたければ参考にしてみてください。。

参考

Smash Ultimate Data Viewer (rubendal.github.io)

Mario - Ultimate Frame Data

Smash Ultimate Calculator (rubendal.github.io)

攻撃判定 - スマブラSPECIAL 検証wiki - atwiki(アットウィキ)

【CodeComplete】トリッキーなコードを避けるべき理由

目的

芸術分野では、変わった手法が称賛されるが、業務でプログラムをする人が、意味もなく変わった実装をすると、害になってしまう。それはなぜかがわかるようになる

芸術分野との違い

なんといっても、複数人で作成すること。そして、作成者が途中で変わるかもしれないことがおおきい。変わった実装をしているということは、それを理解するハードルがあるということ。

エンジニアというだけで、ほかの人にはわからない専門性がでてきてしまっていて、人手不足が叫ばれていたりするのに、さらに入りにくい障害を作る必要はない。

それを避けて、標準的なコードをかく手法を、標準化手法という。

標準化手法とは?

標準化された手法を用いて作成する方法。

具体的に有益なのは、デザインパターンを使用すること。

まとめ

特殊なコードが必要な場合は、なるべくわかりやすく標準的なコードを書くと、組織的にもグッド。

デザインパターンはいろいろあるので、早い段階で学んでおくと、エンジニアとして強い。

参考

CodeComplete

【CodeComplete】要求仕様書は絶対一部変更される

目的

理想としては、どんな機能が必要か、どんなものがほしいかをはじめに100%決めて、実装できれば、
みつもりもしやすいし、設計に柔軟性がなくても、そこまで問題にならない。
でもそれは夢物語であるということがわかる

なぜ要求書は変わる?

だんだん作っているうちに、要求者が制作物を理解してきて、新しい問題や要求がでてくる

どのくらい変わる?

古いデータだが、当初の要求の25%が変わるとされている。

平均的 な プロジェクト では 開発 時 に 要求 の 約 25% が 変更 さ れる こと が わかっ て いる( Boehm 1981; Jones 2000)。 これ は 一般的 な プロジェクト での 修正 作業 の 75 ~ 85% を 占める( Leffingwell 1997; Wiegers 2003)。

Steve McConnell. 【電子合本版】Code Complete 第2版 完全なプログラミングを目指して (Kindle の位置No.1400-1402). 日経BP社. Kindle 版.

まとめ

  • 要求変更には無駄なコストが伴うので、なるべく減らす努力をする。
    →要求仕様の作成者は、制作物をよく理解することが大切。要求仕様を聞いたエンジニアは、
    気になる点があれば、億劫にならず、確認することで、大きな工数の削減になる。
  • それでも発生する要求変更に対応できるよう、対応する
    →コードを柔軟性のあるものにする。また、開発手法を、要求変更がある前提のもの(アジャイル開発など)にして、大きな設計の変更が発生する前に要求を把握できるようにする

参考

CodeComplete