selfが多すぎる

3連休ということで、やはりプログラミングをしている。

Webの領域にばかり閉じこもっているのももったいない気がするので、ゲームプログラミングを開始してみることにした。 もっぱらChatGPTに相談してみたところPyGameが出てきたので、やはり初心者が一番ゲームを書くのにあたって手っ取り早いのはPyGameなのかもしれない。

同じく初心者であって、ゲームプログラミングの領域に手を付けようと思うとUnityが出てくる。 最近ライセンスの問題で世間を騒がせたことは記憶に新しい。 しかしUnityはゲームを作るまでが大変である。 私もUnityのチュートリアル書籍をAmazonのセールのときに購入したり、Udemyのコースを購入したこともあったので興味が全くないわけではない(これはこれで消化しておきたいけれども)。 バージョンは良くも悪くも頻繁に変わるし、インストーラーのサイズが非常に大きいためナローバンド回線とはいかなくとも、Steamで購入した大作ゲームくらいのダウンロードに対する時間はかかる。 そして最大の問題はこのためにわざわざWindowsを起動しなければならないことである。

PyGameならあっけないほどに早い。 インストールはpip install pygameだけでよい。 かつてはもう少し苦労した気がしないでもないけれども、かなり簡単になった気がする。 自分の好きなテキストエディタを使えるのもポイントが高い。 VSCodeは果たしてテキストエディタなのかという疑問はさておき、普段の環境で始められるというのがやはり最大の魅力だと思う。

Visual StudioのダウンロードはおそらくVisual Studioを生涯起動した時間よりもダウンロードに費やした時間のほうが間違いなく長い。 IDEは起動するまでが長いので、XcodeやAndroid Studioですら同様で、そういったプログラミングが長続きした試しがない。 だからゲーム開発もPyGameが出てきてすんなり受け入れられたのだと思う。 ChatGPTはそんな私の性格をきっと見越してコメントしてくれたに違いない。

生成系AIの中でも最もChatGPTの出すコードは一番品質が高い気がする。 そもそもプログラムのコードを生成できるAIはまだそこまで種類は多く試せていないけれども、3~4種類くらい試してきた上での感想だ。 少なくともRubyの出力に関しては間違いなくそう思っている。 そんなChatGPTでも2Dプラットフォーマーのコードの生成はなんだかあまりよくない気がする。

以下のコードはShow me a basic 2D platformer code?というプロンプトによって生成されたコードである:

import pygame

# Initialize Pygame
pygame.init()

# Constants
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
PLAYER_WIDTH = 50
PLAYER_HEIGHT = 50
WHITE = (255, 255, 255)
RED = (255, 0, 0)

# Create the window
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption('Basic 2D Platformer')

# Player properties
player_x = 50
player_y = SCREEN_HEIGHT - PLAYER_HEIGHT
player_velocity = 7
player_is_jumping = False
jump_count = 10

# Main game loop
running = True
while running:
    screen.fill(WHITE)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT] and player_x > 0:
        player_x -= player_velocity
    if keys[pygame.K_RIGHT] and player_x < SCREEN_WIDTH - PLAYER_WIDTH:
        player_x += player_velocity
    if not player_is_jumping:
        if keys[pygame.K_SPACE]:
            player_is_jumping = True
    else:
        if jump_count >= -10:
            neg = 1
            if jump_count < 0:
                neg = -1
            player_y -= (jump_count ** 2) * 0.5 * neg
            jump_count -= 1
        else:
            player_is_jumping = False
            jump_count = 10

    # Draw the player
    pygame.draw.rect(screen, RED, (player_x, player_y, PLAYER_WIDTH, PLAYER_HEIGHT))

    pygame.display.update()

pygame.quit()

確かに動作はするのだけれども、そもそも論としてまずプラットフォームが存在しない。 画面の下部でせわしなく赤い箱が動き回るだけである。 Snakeなどの単純なプログラムはこの手の生成AIの基本なのかもしれないが、すくなくともChatGPTにする質問に対しては一度に出力できるコード量の関係もあって、2D Platformerというジャンルは荷が重いのかもしれない。

私がこれまでしてきた質問も、もっとどちらかといえば作りたい指標があってそこに対する指示があればChatGPTもそれに応えてくれるのだが、こんなほぼ無茶振りのようなプログラムでは出力した結果がうまくいかないのも当然なのかもしれない。

ChatGPTのみでひとつのゲームを作る試みも楽しそうだけれども、私が試してみた限りではこのコードベースで改良していくにはあまりにも試練が多い。 本当はこのコードで衝突判定のコードを知りたかったのだけれども、そこに至るまでのプロンプトを的確に出し続けなければならない。 そう考えるとあまり無駄な質問で試行錯誤するわけにもいかない。 仮に使用制限が入ってしまえば目も当てられない。 そういった背景があって、やはり基本に忠実にYouTube上のチュートリアル動画を見ることにした。

私はあまりこれまで本格的にPyGameに触れていなかったので、まだまだ戸惑う箇所は多い。 そういえばデフォルトで画面は白だったなとか、そういった懐かしさはあるのだけれどもほとんど初学者のつもりで臨んでいる。 だけども思った以上に集中力がすぐに切れるし、自分で主体的にコードを書けない時間はやはり苦痛を伴う。 できないのだから教えを請うているのに、こんなことばかり考えている生徒は我ながら教にくいと思う。

普段あまり書かない言語ではあるものの、一通りチュートリアルを勧めていくとPythonという言語が少し見えてきた気がする。 この言語は良くも悪くもやはり私の普段書いている言語とは異なる。 ふと自分の写経しているコードを眺めてみると、この言語はやたらとselfが多いことに気づいた。

前置きが長くなってしまったが、ここからが本題である。

クラスベースで書いているのでselfが多いのは当然なのだけれども、Rubyとは異なりインスタンス変数とインスタンスメソッドにselfを使わなければならないのでselfが多くなるのは必然かもしれない。 だけどもひとつの言語として捉えるとあまりにもselfの登場頻度が多いので困惑した。 それもわざわざエディタを起動してこれだけでブログのネタにしたいと思わせられたのだから相当なものである。 例えばRubyのように@fooとするのか、self.fooとするのかでもだいぶ違うし、Rubocopは逆にselfは可能な限り取り除いてくれるのでとにかくRubyとはまた違った意識を強いられる。

つまりRubyでは省略していても見える力が要求されるのに対して、Pythonでは常に見えているものを無視する力が要求されるのだろう。

案の定なのかわからないが、決して多くはないけれども私と同様の感想を得ている人は存在するようだ。 とはいえPythonにおけるselfはそれが明確な役割を持っているので、1+1=2の等式とプログラミング言語のa=1+1の代入は=の持つ意味がおかしいと思う違和感に近いのでこれはもうそういうものだと受け入れるしかない。 そんな疑問を持った彼らに対してもそういった回答がなされているのは理解できる。

頭ではそう言い聞かせてもふとエディタを見ると(私の環境では)selfが赤文字で強調されるのでなお目立つというか、まあそれがかえってよいのだと思えるくらいにPythonのコードを見続けると逆にRubyのselfの少なさにストレスを感じてしまうようになってしまうのかもしれない。 JSXも最初は拒否反応が凄まじかったが、今ではすんなり馴染むのできっとそういうことなんだろう。 ただそれ以上に見ているであろうGitHubの新デザインは未だに最悪だと思っている。

多すぎるselfはいっそ変数にしてしまうとか、工夫のしがいはあるけれどもまずはPythonという言語に今後ももう少し向き合ってみたいと思う。 selfを遠ざけることが目的になるとかえって見づらいコードになることは想像に難しくない。 やはりそれごと受け入れてしまうのが一番良いと思う。

単にライブラリを呼び出すだけのコードや、私が書いてきたPythonのプログラムはシェルスクリプトのような書き方が多かった。 ゲームのプログラミングでは各シーンや各オブジェクトの役割が重要なのでこれまでとは全く違ったプログラミングをするという目的は果たせてはいる。 その結果Pythonでオブジェクト指向のようなコードを書くとselfは避けられないというのが今回の発見である。

この投稿の後半はやたらにselfの出現率が高いことに気づいただろうか。 わざとに思うかもしれないが、ほぼ無意識に書いていた。 ただの文章ですらこうなるのだから、やはりselfという単語の扱い方は難しいのだろう。

Pythonでプログラムを書くことはself、つまり自己と向き合うことなのかもしれない。