タイトル画像
琴葉茜

次はプレイヤーが操作するための「バー」を作っていくよ!

琴葉葵

バーってことは長方形を作る感じ??

琴葉茜

その通り!
「長方形」を配置する場合は「pyxel.rect(x座標, y座標, 幅, 高さ, 色)」で出来るよ

琴葉茜

この時の「x座標」「y座標」は長方形の左上が基準になる点に気を付けてね

def draw(self):
    pyxel.cls(0)
    pyxel.circ(pyxel.width // 2, pyxel.height // 2, 4, 8)
    pyxel.rect(10, 50, 5, 20, 11) # これを追加
琴葉葵

座標の基準が円の時と違うのは気を付けないとだね

琴葉茜

ちなみにy軸座標の「50」って値は、初期状態でバーがウィンドウの中央ラインに来るように「ウィンドウの高さの半分 - バーの高さの半分」という計算で求めているよ

解説画像1
琴葉葵

おお!なるほど!適当じゃないんだね

琴葉茜

次はバーのy座標を管理する「self.bar_y」を用意するよ!
ついでに、ウィンドウの端を判定するために、バーの高さを管理する「self.bar_height」も追加しておくよ

class App:
    def __init__(self):
        pyxel.init(160, 120, title="ホッケーゲーム")
        self.x = pyxel.width // 2
        self.y = pyxel.height // 2
        self.vx = 1
        self.vy = 1
        self.r = 4 

        self.bar_height = 20 # バーの高さ
        self.bar_y = (pyxel.height - self.bar_height) // 2 # バーのy座標

        pyxel.run(self.update, self.draw)

    # 一部省略

    def draw(self):
        pyxel.cls(0)
        pyxel.circ(self.x, self.y, self.r, 8)
        pyxel.rect(10, self.bar_y, 5, self.bar_height, 11) # y座標と高さをインスタンス変数に変更
琴葉葵

ちゃんと計算式で座標を設定してるの、ちょっとカッコいい...
起動してみたけど問題なさそうだね

琴葉茜

ばっちりだね!
そしたら、今の変数を利用して関数「update」の中で「バーを操作するプログラム」を追加しよう

琴葉茜

今回はキーボード入力で操作するために「pyxel.btn(ボタンの種類)」を使うよ!

琴葉葵

ボタンの種類はどうやって指定するの?そのまま文字列で「"A"」って感じ??

琴葉茜

ボタンの種類を指定する場合は「pyxel.A」って感じで、「pixel.大文字」で指定にするよ!
今回は上下の矢印キーを使いたいから「pyxel.UP」「pixel.DOWN」だね

琴葉葵

アルファベット以外はキーの名前を全部大文字で指定するんだね!

琴葉茜

あとはif文で、上下キーが入力された時に「self.bar_y」が増減するようにすればOK

def update(self):
    self.x += self.vx
    self.y += self.vy
    
    # 矢印の上キーが押されたら上へ移動
    if pyxel.btn(pyxel.KEY_UP):
        self.bar_y -= 2
    # 矢印の下キーが押されたら下へ移動
    if pyxel.btn(pyxel.KEY_DOWN):
        self.bar_y += 2
    
    # 以下省略
琴葉葵

おおー!ちゃんと上下に動いた!!

琴葉茜

上手くいったみたいだね!今回は1フレーム当たりに動く量を「2」にしてるけど、自分なりにちょうど良い量に調整してみたら良いからね

琴葉葵

分かった!ところで、ずっと下か上を押しっぱなしにしてるとウィンドウの外に行っちゃうけど、もし外に出ないようにしたい場合はホッケーの時みたいにif文で設定したら良いの??

琴葉茜

その方法でも良いんだけど、今回は跳ね返るわけじゃなくて「それ以上先に行かないようにする」から、もう少し簡単な方法で管理してみるよ

琴葉葵

簡単な方法?つまり、if文を使わないってこと??

琴葉茜

そういうことだね
バーの基準点はバーの左上になるから、y座標の移動範囲は最小が「0」、最大が「ウィンドウの高さ - バーの高さ」になるよね

解説画像2
琴葉葵

その説明をするってことは、「最小」と「最大」を出してくれる関数があるんだねっ!!

琴葉茜

その通り!「最小」と「最大」はそれぞれ、「min()」と「max()」を使うことで簡単に出してくれるようになるんだ

解説画像3
琴葉葵

じゃあ、現在のバーの位置「self.bar_y」と比較する形になるんだね

琴葉茜

ここでちょっとした問題!
「バーの位置が0よりも小さい場合、バーの位置を0にする」時は、「min()」と「max()」のどっちを使ったら良いと思う?

琴葉葵

え?そんなの「0よりも小さい場合」だから、「min()」を使えば...

琴葉葵

あれ?そうするとバーの位置の値が選ばれちゃってダメだから「max()」を使わないといけない??

琴葉茜

そうだね!「max()」を使うのが正解だよ!!ちょっと混乱しちゃうでしょ

琴葉葵

小さい値を気にしないといけないのに「max()」を使うってちょっと変な感じだね

琴葉茜

「最終的にどうしたいか?」が大事だから、このあたりのイメージはしっかり持てるようになっておこうね

琴葉茜

ということで、バーがウィンドウの外に出ないようにするプログラムを、さっきのif文の下に追加してみよう!

# 矢印の上キーが押されたら上へ移動
if pyxel.btn(pyxel.KEY_UP):
    self.bar_y -= 2
# 矢印の下キーが押されたら下へ移動
if pyxel.btn(pyxel.KEY_DOWN):
    self.bar_y += 2

# 画面外に出ないように制限
self.bar_y = max(0, min(pyxel.height - self.bar_height, self.bar_y))
琴葉葵

お、ちゃんとウィンドウの外に出なくなった!

琴葉茜

もちろんif文で作っても良いけど、今回みたいに「シンプルに作れないか」「便利な関数はないか」とかを意識できるようになろうね

琴葉葵

そうだね、ちょっと意識してみるよ!

この時点での全体のプログラム

import pyxel

class App:
    def __init__(self):
        pyxel.init(160, 120, title="ホッケーゲーム")
        self.x = pyxel.width // 2
        self.y = pyxel.height // 2
        self.vx = 1  # 速度(x方向)
        self.vy = 1  # 速度(y方向)
        self.r = 4   # 半径

        self.bar_height = 20 # バーの高さ
        self.bar_y = (pyxel.height - self.bar_height) // 2 # バーのy座標

        pyxel.run(self.update, self.draw)

    def update(self):
        self.x += self.vx
        self.y += self.vy
        
        # 矢印の上キーが押されたら上へ移動
        if pyxel.btn(pyxel.KEY_UP):
            self.bar_y -= 2
        # 矢印の下キーが押されたら下へ移動
        if pyxel.btn(pyxel.KEY_DOWN):
            self.bar_y += 2

        # 画面外に出ないように制限
        self.bar_y = max(0, min(pyxel.height - self.bar_height, self.bar_y))

        # ウィンドウの端に当たったら反射(跳ね返る)
        if self.x <= self.r or self.x >= pyxel.width - self.r:
            self.vx *= -1
        if self.y <= self.r or self.y >= pyxel.height - self.r:
            self.vy *= -1

    def draw(self):
        pyxel.cls(0)
        pyxel.circ(self.x, self.y, self.r, 8)
        pyxel.rect(10, self.bar_y, 5, self.bar_height, 11) # y座標と高さをインスタンス変数に変更 
App()