見出し画像

PyxelとChatGPTを使ってPythonを勉強してみる【第2回】

第1回はこちらです。

前回では、ChatGPTにお願いして「プレイヤーを動かして星を1つ集める」というPyxelで動かせるゲームのコードを出してもらいました。

↓がコードの内容です。

import pyxel

#初期化
class Simplegame:
    def __init__(self):
        pyxel.init(160,120)
        
        self.player_x = 72
        self.player_y = 56
        
        self.star_x = pyxel.rndi(0,160)
        self.star_y = pyxel.rndi(0,120)
        
        self.score = 0
        
        pyxel.run(self.update,self.draw)
        
                
    def update(self):
    #playerの移動  
        if pyxel.btn(pyxel.KEY_UP):
            self.player_y = max(self.player_y - 2,0)
        if pyxel.btn(pyxel.KEY_DOWN):
            self.player_y = min(self.player_y + 2,112)
        if pyxel.btn(pyxel.KEY_LEFT):
            self.player_x = max(self.player_x - 2,0)
        if pyxel.btn(pyxel.KEY_RIGHT):
            self.player_x =min(self.player_x + 2,152)
            
    #スターとの衝突判定
        if (self.player_x <= self.star_x <= self.player_x + 8 and
            self.player_y <= self.star_y <= self.player_y + 8):
            self.score += 1
            self.star_x = pyxel.rndi(0,160)
            self.star_y = pyxel.rndi(0,120)
            
    def draw(self):
        pyxel.cls(0)
        pyxel.text(5,4,f"Score:{self.score}",pyxel.COLOR_WHITE)
        pyxel.rect(self.player_x,self.player_y,8,8,pyxel.COLOR_RED)
        pyxel.circ(self.star_x,self.star_y,3,pyxel.COLOR_WHITE)
        
Simplegame()

相変わらず長い・・・

前回は、

import pyxel

#初期化
class Simplegame:
    def __init__(self):
        pyxel.init(160,120)
        
        self.player_x = 72
        self.player_y = 56
        
        self.star_x = pyxel.rndi(0,160)
        self.star_y = pyxel.rndi(0,120)
        
        self.score = 0
        
        pyxel.run(self.update,self.draw)

ここまでをChatGPTと一緒に勉強しました。

”class”や”def”といった見知らぬアメリカ語に戸惑いましたが、ChatGPT君に教えてもらった所、自分なりに解釈して理解しました。

↑のコードに自分なりの注釈をのせました。

import pyxel #pyxel使いますよーっていう宣言!

#初期化
class Simplegame: #ゲームのパッケージみたいなやつ!
    def __init__(self): #初期設定をまとめる時に使うやつ!
        pyxel.init(160,120) #画面の大きさを決める!
        
        self.player_x = 72 #プレイヤーの最初の横の位置を決める!
        self.player_y = 56 #プレイヤーの最初の縦の位置を決める!
        
        self.star_x = pyxel.rndi(0,160) #星の最初の横の位置を0~160の場所からランダムで決める!
        self.star_y = pyxel.rndi(0,120) #星の最初の縦の位置を0~120の場所からランダムで決める!
        
        self.score = 0 #最初のスコアはもちろん0!
        
        pyxel.run(self.update,self.draw) #self.updateとself.drawに動けー!って言う宣言!

第2回はこの続きからです。

・・・・・・・
さて、初期設定は分かりました。次に↑のコードの最後に宣言したself.updateの部分を作っていきます。

ChatGPT君が出してくれたコードがこちらです。

    def update(self):
    #playerの移動  
        if pyxel.btn(pyxel.KEY_UP):
            self.player_y = max(self.player_y - 2,0)
        if pyxel.btn(pyxel.KEY_DOWN):
            self.player_y = min(self.player_y + 2,112)
        if pyxel.btn(pyxel.KEY_LEFT):
            self.player_x = max(self.player_x - 2,0)
        if pyxel.btn(pyxel.KEY_RIGHT):
            self.player_x =min(self.player_x + 2,152)

"self.update"については第1回の時にChatGPT君に質問した時に少し教えてもらいました。

Pyxel に update メソッド(ゲームロジックの更新)と draw メソッド(画面の描画)を渡してゲームを開始します。

うーん、何となく言いたいことは分かりますが、何だかモヤモヤします・・・

なので、改めて聞いてみました!

すみません。self.updateについてもう少し詳しく知りたいです。初心者にも分かるように丁寧に教えてください。

すると、

もちろんです。self.updateについて詳しく説明します。

self.update の役割

self.update は、クラス内の update メソッドを指しています。self は、クラスから作られたオブジェクト自身を表す特殊な変数です。

メソッドの呼び出し

クラス内でメソッドを定義すると、そのメソッドをオブジェクトから呼び出すことができます。例えば、以下のようにして呼び出します。

class Simplegame:
    def __init__(self):
        self.score = 0  # スコアの初期化
        
    def update(self):
        self.score += 1  # スコアを1増やす

ここで、update メソッドはスコアを1増やす機能を持っています。

self について

self は、クラスのインスタンス(オブジェクト)自身を指すキーワードです。例えば、Simplegame クラスから作られたオブジェクトが game という名前だとすると、self はその game オブジェクトを指します。

メソッドの使い方

実際に Simplegame クラスのオブジェクトを作成し、update メソッドを呼び出してみましょう。

game = Simplegame()
game.update()  # スコアが1増える
print(game.score)  # 1が表示される

Pyxel の文脈での self.update

Pyxel では、pyxel.run(self.update, self.draw) を使って、ゲームループを開始します。pyxel.run 関数は、指定された update と draw メソッドを繰り返し呼び出します。

self.update: ゲームのロジック(プレイヤーの移動、衝突判定など)を更新するメソッド。
self.draw: ゲームの画面を描画するメソッド。

まとめ

self.update は、クラスのインスタンス(オブジェクト)内で定義された update メソッドを指し、ゲームのロジックを更新するために使われます。Pyxel では、この update メソッドが pyxel.run に渡され、ゲームループの一部として繰り返し呼び出されます。self は、メソッド内でそのクラスの他のプロパティやメソッドにアクセスするために使われます。

これで、self.update の意味と役割が理解できたと思います。もし他にも質問があれば教えてくださいね。

ふーん!まぁまぁ理解できました。少しくどいぐらいですね笑

要は、self.updateが無いとゲームにおける「動き」の部分が設定できないということを理解しました。こんなざっくりだけど、いいのかな?

・・・・・・・・
何はともあれ、self.updateの重要性も理解したので、お楽しみの「プレイヤーの動き」の設定に入ります・・・!

        if pyxel.btn(pyxel.KEY_UP):
            self.player_y = max(self.player_y - 2,0)

コードの中身を見ると、↑の似たようなコードが4つ並んでいることが分かります。これは多分、KEY_UPとかKEY_RIGHTとか書いてあるので、↑キーを押したら上に行く、→キーを押したら右に行く、みたいな感じでしょう。

さぁ、ここでも分からない部分が出てきました。
pyxel.btnって何だ・・・?

if pyxel.btn(pyxel.KEY_UP):とはどういう意味ですか?? 丁寧に教えてください。

if pyxel.btn(pyxel.KEY_UP): は、特定のキーが押されているかどうかをチェックする条件文です。これについて詳しく説明します。

Pyxelの pyxel.btn 関数

pyxel.btn は Pyxel ライブラリに用意されている関数で、特定のキーが押されているかを確認します。この関数は、押されているキーに対応するコードを引数として受け取ります。

pyxel.KEY_UP

pyxel.KEY_UP は、キーボードの「上矢印キー」に対応する定数です。Pyxel には他にも多くのキー定数があり、例えば pyxel.KEY_DOWN(下矢印キー)、pyxel.KEY_LEFT(左矢印キー)、pyxel.KEY_RIGHT(右矢印キー)などがあります。

条件文 if

if は、条件が真(True)である場合に、後続のブロック(インデントされた部分)を実行するための文です。

・・・

もしかして、pyxel.btnってpyxel.ボタン・・・ってコト!?

もしかして、pyxel.btnってpyxel.ボタン・・・ってコト!?

はい、その通りです!pyxel.btn の btn は「ボタン」の略です。Pyxel では、pyxel.btn 関数を使ってキーボードのボタン(キー)が押されているかどうかをチェックします。したがって、pyxel.btn は「Pyxelのボタンを確認する関数」という意味になります。

安直すぎてなぜか笑ってしまった私

・・・・・・・
if pyxel.btn(pyxel.KEY_UP): というのは、「もし、↑キーを押したなら~する!」という意味だというのは分かりました。pyxel.KEY_UPだけではなく、pyxel.btnという関数を用いて「ボタンを押します!」という宣言も必ず必要みたいですね。

さて、「もし、↑キーを押したなら・・・」は分かったので、その後の「~する!」の部分も理解していきましょう。

self.player_y = max(self.player_y - 2,0)

ここはどういう意味なんだろう・・・と考えていると、どこか見たことがある単語が並んでいます。self.player_yです。これは初期設定で決めた
プレイヤーの縦の位置を決めるself.player_y = 56で確認しました。

↑キーを押したなら動く、という動きのはずなので、↑キーを押すとプレイヤーのy座標が変わってプレイヤーが動く!というコード・・・のはず。

ChatGPT君に確認してみます。

self.player_y = max(self.player_y - 2,0) このコードは「↑キーを押すとプレイヤーのy座標が変わってプレイヤーが動く」という意味ですか??

すると、

はい、その通りです。このコードは、上矢印キー(↑ キー)を押すとプレイヤーの y 座標が変わり、プレイヤーが上に動くことを意味します。具体的には、self.player_y が 2 減少します。以下で詳しく説明します。

やっぱり合ってました!詳しい説明を見てみましょう。

self.player_y - 2
self.player_y はプレイヤーの現在の y 座標です。
self.player_y - 2 は現在の y 座標から 2 ピクセル引いた値を計算します。つまり、プレイヤーを上に 2 ピクセル移動させることを意味します。
max(self.player_y - 2, 0)
max 関数は、2 つの値のうち大きい方を返します。
ここでは self.player_y - 2 と 0 を比較し、その大きい方を返します。
これにより、プレイヤーが画面の上端(y 座標が 0)を超えて上に移動することを防ぎます。例えば、プレイヤーの y 座標が 1 である場合、self.player_y - 2 は -1 になりますが、max 関数によって y 座標は 0 に制限されます。

うんうん、分かる分かる!

・・・と、ここで、大事なことを学びます。pyxelにおいては画面の上端がy=0ということ。これを理解しないと、max(self.player_x - 2,0)の意味が分からないですよね。

要は、プレイヤーのy座標が0より小さいと画面外に出て行ってしまうので、どんなに↑キーを押してもプレイヤーのy座標が0以下にならないようにするよ!
という意味ですね。

このコードも理解したので、次のコードに行きます。

if pyxel.btn(pyxel.KEY_DOWN):
   self.player_y = min(self.player_y + 2,112)

こっちはKEY_DOWNと書いてあるから下に行くためのコードや!
ただ、さっきのと違うのは、maxがminになっていること0の部分が112という謎の数字となっていること。うーん・・・さっきの逆だからminはself.player_y + 2と112を比べて小さい数字を返して、下の画面外に行くのを防ぐためなのは分かるんだけど、112って何?

GPT君に聞いてみます。

self.player_y = min(self.player_y + 2,112) このコードの112という数字は何の数字ですか?

すると、

この 112 という数字は、プレイヤーが画面の下端を超えて移動しないようにするための制限値です。具体的には、Pyxel の画面高さが 120 ピクセルである場合、プレイヤーの高さを考慮して、プレイヤーが画面の下端(下から8ピクセルの位置)に到達したときにそれ以上下に移動しないようにしています。
(省略)
画面サイズとの関係

Pyxel の画面サイズは (160, 120) で、高さが 120 ピクセルです。プレイヤーのキャラクターが 8 ピクセルの大きさである場合、画面の下端に位置するためにはプレイヤーの y 座標が 112 を超えないようにする必要があります(120 - 8 = 112)。

あぁーそういうことね。おそらく、最初に出したコードでは、プレイヤーの大きさを8ピクセルに設定しているから、120-8=112という数字が出されたのね。あとは、さっきのmaxのコードの時と理論は一緒だね。


・・・・・・・
yの部分を理解したので、xの部分も自ずと理解できました!

def update(self):
    #playerの移動

        if pyxel.btn(pyxel.KEY_UP):
            self.player_y = max(self.player_y - 2,0)
        if pyxel.btn(pyxel.KEY_DOWN):
            self.player_y = min(self.player_y + 2,112)
        if pyxel.btn(pyxel.KEY_LEFT):
            self.player_x = max(self.player_x - 2,0)
        if pyxel.btn(pyxel.KEY_RIGHT):
            self.player_x =min(self.player_x + 2,152)

これだけだと、訳の分からない英語がグチャァ…と並んでいるように見えましたが、1個1個分解してみると何てことない動きの設定だということが分かりました。あと、pyxelは、

↑がy = 0! ←がx = 0! だから、左上が(x,y) = (0,0)!

今回の学習の中では何気に一番重要な所なんじゃないかな?

今回はここまで。次回は、プレイヤーと星の当たり判定を設定します。


いいなと思ったら応援しよう!

この記事が参加している募集