【C#】VB.NETのコードを書き直す (3)

Beach Seashore Sand - Free photo on Pixabay - Pixabay C#
Beach Seashore Sand - Free photo on Pixabay - Pixabay

マップエディタの開発後記です。
しばらくはこの関連の記事が続きます。

最近C#.NETコーディングが楽しくて仕方がないです。
どうしよう。
色々できるようになるとプログラミングは楽しいですね。
食事の時間も忘れるほどに熱中してPCとの闘いに勤しんでいます。

進捗状況

まずは進捗報告。

とりあえずマップエディタの基本要件である読み込んだグラフィックチップをマップに配置する部分を実装しきりました。

開発中のマップエディタ
開発中のマップエディタ

画面上にはボタンアイコンがたくさんありますが、これらはほとんどマップフィールドのぺージ操作の機能なので今はほとんど使ってません。

アプリケーションとしてはこれで全体の半分以上実装済みと言ってもいいかな、と。
あとの主要機能はバイナリファイルI/O(Inputは実装済)くらいです。

後はやっぱり前回記事でもお話しましたが、Undo/Redoの機能の使い勝手が良すぎて素敵ですね。

ゲーム開発会社では、プロジェクトを進める時にまず最初に開発用のエディタを制作するところからスタートするそうです。

男性プログラマーとコードのイメージ1 - No: 23713917|写真素材なら「写真AC」無料(フリー)ダウンロードOK

私もそれを聞いていたので同じようにエディタを作る事から始めてるのですが、このエディタの自由度(というかユーザビリティ)がゲーム開発の効率を左右すると言ってもいいと思います。
何よりプレイしていて楽しい作品を作るなら、開発も楽しくないと面白いゲームなんてそうは作れないです。

せっかくなら作り手にとってもハッピーでいたいのが本音ですし(^^)

カプセル化の恩恵

コーディングをしていて気づいた事があって、

機能を実装してデバッグ実行で確認中に機能漏れがあった場合に
「オブジェクトを削除する処理ってなになにあったっけ・・・(´・ω・`)」
となるのは日常茶飯事です。

目的のコードを追加していざ動かすと、
Aの処理とBの処理が同じようになるはずがBの処理はAの処理となんか違う・・・(;’∀’)
そうなってくると、ああでもないこうでもない、あたふたし始めコード改変しまくって、挙句の果てにプログラムが動かなくなった。。なんて末路になる事もあります。

今はバージョン管理システムが主流なのでリベースは簡単にできますが、常にそんな都合の良い状況ではないと思いますし、ぶっちゃけ元に戻すとそれだけ反復作業が発生するわけでモチベーションが腐ってきます。。。

そうならないためには、コードの追加が簡単にできる環境が必要です。
コードの追加というよりかは、メソッド(ファンクション、関数)の追加になりますかね。

そこで重要になってくるのが「カプセル化」です。
これについて詳しくは以下をご覧ください(外部サイト)。

カプセル化とは – 意味をわかりやすく – IT用語辞典 e-Words

カプセル化を利用するとコードの修正・加筆がめちゃくちゃ楽になります。

これに気づいたのはやはりプログラムが形になり始めた頃以降だと思います。

プログラムを組み始めた頃はコード量も少ないので、メソッドの中にコードをつらつら書いていくだけでなんの苦もなく事は運ぶと思います。

しかし、ソースが300、400、500行・・・となってくると目的のコードまで辿り着くのにカリカリマウスホイールを回して画面を追っていかないといけなくなります。

このブログでも何度か取り上げている私が6年くらい前にコーディングしたソースコードはまさにその堕落を具現化したものです。

旧エディタのソースコード(一部)
旧エディタのソースコード(一部)

今見るとなぜこんな糞コードを書いたのか不思議でなりませんが、いずれにしてもこの状況でプログラムを作り続けるのは超ハードです。
一つのイベントメソッドに行うべきロジックが全て書いてあって、同じ処理構文が何度も出てきます。
こんなプログラミングは相当神経を尖らせられる人か、神PGMerでないと無理でしょうね・・・

そもそもイベントハンドラ登録用メソッドに詳細ロジックを書いてはいけないと思います。
再利用性が皆無なのはメンテナンスが困難になります。

まあ当時の私はオブジェクト指向プログラミングを一切した事がない未経験者だったのはありますが・・・😅

ちなみにですがVB.NETの過去コードは完成版は存在しません。
アプリケーションに主要機能は全部乗っかっていますが、意図しないタイミングで強制終了する致命的なバグがあり、まともに使用する事はできません(笑)

見づらい構文について

進行中のgitリポジトリのコミット履歴を見てみると所々に「リファクタリング」が書いてあります。

「リファクタリング」は機能追加や改修を伴わないコード修正の事を言います。
簡単に言うと整理整頓の事です。

例えば新居に引っ越してきた時の事を考えて、
物が増えてきたら収納ケースを買って部屋の中の整理や模様替えをしたりしますよね。
そんな感じの整理の事です。

プログラミングにおけるコードの整理は非常に重要で、コードは一方的に増えていくのに対して、メンテナンスは(アプリケーションの動作に影響しないため)任意であるために、不要なコードや統一性のない記述などが出てきます。

それを直すのが「リファクタリング」です。

実はその話をしたいわけではなく、ここでお話するのはそのリファクタリングをしている時に気になった事です。
例えば以下。

if (reset)
    RangeModeOff();

if (reset) RangeModeOff(); の部分は、

if (reset)
{
    RangeModeOff();
}

もともとこのようなif文でした。

何を言っているのかという事ですが、中かっこがないとRangeModeOffメソッドはいつ実行されるのかが分かりづらいかな、と私は思いました。

この記述はずっと昔からある記法なので慣れている人にとっては何言ってるの?感があるかと思いますが、私はこの記述をするかどうか悩みました。

何度か中かっこを付けたり消したりしてましたが、最終的に消してます。

これらに違和感があるのは、私がC言語やJavaなどのレガシーコーダーだからかもしれません。

これはC#.NET公式に認められた記法なのでもちろんダメではありません。
この記法はコード量を減らす事ができ、シンプルに情報を伝える事もできているでしょう。
それで言うと、改行も取ってしまってもいいと思いますけどね。

それでは次。

bool transparents = MAPFIELD_MODE_RANGE == (int)cursorSelectButton.Tag;

これは三項演算子・・・ではなく、三項演算子特有の書き出し部分を利用した構文です。

そもそも三項演算子自体が見づらい(とか言いたくないですが・・・)構文じゃないですか?
これが世間プログラミング的に浸透しているなんて・・・😯

論理型の変数に「MAPFIELD_MODE_RANGE == (int)cursorSelectButton.Tag」の比較結果を代入しています。
これは条件分岐の際に比較式の結果が論理型なので、これを利用しているだけです。

上記の文を使わない場合は、

bool transparents = false;
if (MAPFIELD_MODE_RANGE == (int)cursorSelectButton.Tag)
{
    transparents = true;
}

このようになるかと思います。

最後にもう一つ。

MapAddress = (MapPages * MAP_PAGESIZE) + MAP_HEADERSIZE + (0x10 * row) + col;

これは何でしょうか。

実はテーブルの縦横セルの位置を特定する場所の計算式なのですが、ぱっと見では何を計算してるのか全く分からないと思います。

MapAddressという名前が付いているからなんとなく用途は分かるから、その数値が入ってるんでしょ?という方向に持っていってますね😅

これは賛否あると思います。

実はこれをばらして書くと以下のようにも書く事ができました。

int pagenum = MapPages * MAP_PAGESIZE;
int rownum = 0x10 * row;
int colnum = col;
MapAddress = pagenum + MAP_HEADERSIZE + rownum + colnum;

これは圧倒的に後者のほうが分かりやすいですし、rownumなどの仕様が変更された場合にフレキシブルに対応できる形です。

しかしなぜ前者の書き方にしたのか?

それはリソースを量産しないためです。

リソースというのは、ここでは変数を指しています。
つまり一時期しか使われない変数なんかいらないでしょ、という事を言いたいのです。

いやいや、内容を伝えるためにいるでしょ。という話が対面で起りえますが、これについては答えは出せないと思います。

正直な事を言いますと、

変数を大量に生み出すとバグの温床になります。

これは本当の事です。

しかしそれは、管理が煩雑になって変数へのアクセスが多数に上っている場合に限って問題になる話です。
ローカルスコープの場合は不必要に変数を生み出しているわけでもないし、変数を作りすぎたからってメモリが圧迫されるかと言ったらもうそんな時代でもないと思います。

なので、あくまで可読性を優先してコードは書かれるべきでしょうね。

上記のMapAddressの計算式を一行で終わらせている構文については、
「これはマップフィールドのアドレスを格納しているから、必要に応じて使ってね、計算式は気にしなくていいよ」
という意思表示をしているものと考えられます。
(考えられますと言ったら私がコーディングしたのに変な言い回しですが)
(お察しください)

このプロジェクトはコード全体としての構造について意識しながらプログラムを作成する企画ですので、今回は色々と構文についてお話してみました。

次回以降もこの話題が中心になるかもしれません。
通りすがりの方でもしよければアドバイス、愚痴など溢していって戴けると幸いです😊

私の本業はシステム管理者ですが、プログラマーっぽい事をしているだけで、中身はシステム屋の最下層ぐらいの技術レベルしかありません。

コーディングについてもほとんどはネットの情報をかき集めるのと、GPT-4で構築したものを私が厳選してプログラム化しているだけです。

そんなわけでここで紹介したコードをそのまま流用するのはちょっと危険かなと思うので、お気を付けくださいね😇

その他課題点について

現在進行中のソースコードはgitリポジトリに配置しております。

https://github.com/unlimitedloop-admin/aa-mapeditor
(現在アクティブになっているブランチは ‘feature/mapedit’ です)

頃合いをみて ‘develop’ ブランチへマージします。

残っている課題点ですが、

  • XMLコメント未記載のメソッド(及びメンバ)
  • テキストボックステーブル表示時のUndo/Redo
  • マップの範囲選択時に使用しているリストコレクションの解放処理を実装しないといけない
  • 例外処理

があります。

次コンテンツは、

  • マップフィールドのぺージ移動・ぺージ追加・ぺージ削除
  • ファイルヘッダー編集機能
  • バイナリファイル出力機能

になります。

これらが全部実装できたら、’develop’ ブランチと統合ですかね。

いずれにしても先は長そうです。
今結構モチベーション上がってるので、一気に作っていきたいです。

コメント

タイトルとURLをコピーしました