タイトル画像
琴葉茜

次はコンピューター(CPU)側のバーの動きを作っていくけど、まずはプレイヤー側とは反対側にバーを設置しようか!

琴葉葵

おっけー!今回はちょっと自分で考えてみる!!

琴葉葵

まず、y座標はプレイヤーのバーと同じ位置で良いよね

琴葉茜

そうだね!

琴葉葵

x座標は、プレイヤーのバーの座標が「10」だったから、CPUは「ウィンドウの幅 - 10」か!

琴葉葵

...だけど、バーの座標の基準は左上だから、バーの幅の分も考えないといけないね!

琴葉茜

お!よく気付いたね!!
...ということはー?

琴葉葵

「ウィンドウの幅 - 10 - バーの幅」だね!
プログラムにすると「pyxel.width - 10 - self.bar_width」だ!

琴葉茜

おー!正解!!

琴葉茜

そしたら、今の内容をCPUのx座標を「self.cpu_x」、y座標を「self.cpu_y」として関数「__init__」に追加しよう!

# 関数「__init__」の「pyxel.run()」の上の行に追加
self.cpu_x = pyxel.width - 10 - self.bar_width
self.cpu_y = (pyxel.height - self.bar_height) // 2
琴葉葵

あとは、関数「draw」の方にCPU用の「pyxel.rect()」を追加だね!

# 関数「draw」の最後に追加
pyxel.rect(self.cpu_x, self.cpu_y, self.bar_width, self.bar_height, 14)
琴葉茜

もうここまでの流れはバッチリだね!早速、どうなったか確認してみよう!

解説画像1
琴葉葵

うん、良い感じ!!

琴葉茜

そしたら次は、ホッケーとCPUのバーとの衝突判定を作ろうか!

琴葉茜

...とは言っても、条件式は前回の方法と同じで、「self.bar_x」と「self.bar_y」が「self.cpu_x」と「self.cpu_y」に変わったバージョンを追加して、衝突したときに左に行くように変えれば良いだけだよ

# 関数「update」の最後に追加
if (
    self.x - self.r <= self.cpu_x + self.bar_width and
    self.x + self.r >= self.cpu_x and
    self.y + self.r >= self.cpu_y and
    self.y - self.r <= self.cpu_y + self.bar_height
):
    self.vx = -abs(self.vx)  # 絶対値にマイナスをつける
琴葉葵

前回と一緒だから簡単だね!

琴葉茜

さて、ここからが本番!CPUの動きを作るけど、葵はどうやって作るのが良いと思う?

琴葉葵

そうだねー
まずはホッケーのy座標に合わせて動いてみるとか??

琴葉茜

オッケー!そしたら、単純にその仕組みで動かしてみようか!

# 関数「update」のプレイヤーバーの操作の下に追加
# プレイヤーバーの操作(上下キー)
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))

# CPUバーの自動追尾(この2行を追加)
self.cpu_y = self.y - self.bar_height // 2
self.cpu_y = max(0, min(pyxel.height - self.bar_height, self.cpu_y))
琴葉葵

絶対にバーの真ん中でホッケーを捉えてるの強すぎる(笑)

琴葉茜

常にホッケーと上下の方向は同じだしね
そしたら、もう少しだけ動きを変えてみようか

琴葉茜

例えば、ランダムを使ってたまに動かない場合を作るならこんな感じだよ
さっきのCPUの動き部分のプログラムを下のプログラムに変えてみよう!

import random # 追加を忘れずに!!

# 途中省略

        # CPUバーの自動追尾
        if random.random() > 0.2:  # 80%の確率で追尾
            if self.y > self.cpu_y + self.bar_height // 2:
                self.cpu_y += 1.2
            elif self.y < self.cpu_y + self.bar_height // 2:
                self.cpu_y -= 1.2
        self.cpu_y = max(0, min(pyxel.height - self.bar_height, self.cpu_y))
琴葉葵

あ!ちょっとぎこちない動きになって、ホッケーに追いつかない時が出てくるようになった!

琴葉茜

他にも、「反応するのはホッケーが一定距離まで近づいてきてから」や「5フレームに1回しか動かない」って感じで動きを作ってあげると面白いかもね!

琴葉葵

自分でもちょっと考えてみる!

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

import pyxel
import random

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_width = 5 # バーの幅
        self.bar_x = 10 # プレイヤーのx座標
        self.bar_y = (pyxel.height - self.bar_height) // 2 # プレイヤーのy座標

        # CPU(右側)のバー
        self.cpu_x = pyxel.width - 10 - self.bar_width # CPUのx座標
        self.cpu_y = (pyxel.height - self.bar_height) // 2 # CPUの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))

        # CPUバーの自動追尾
        if random.random() > 0.2:  # 80%の確率で追尾
            if self.y > self.cpu_y + self.bar_height // 2:
                self.cpu_y += 1.2
            elif self.y < self.cpu_y + self.bar_height // 2:
                self.cpu_y -= 1.2
        self.cpu_y = max(0, min(pyxel.height - self.bar_height, self.cpu_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

        # プレイヤーバーの衝突判定
        if (
            self.x + self.r >= self.bar_x and
            self.x - self.r <= self.bar_x + self.bar_width and
            self.y + self.r >= self.bar_y and
            self.y - self.r <= self.bar_y + self.bar_height
        ):
            self.vx = abs(self.vx)

        # CPUの衝突判定
        if (
            self.x - self.r <= self.cpu_x + self.bar_width and
            self.x + self.r >= self.cpu_x and
            self.y + self.r >= self.cpu_y and
            self.y - self.r <= self.cpu_y + self.bar_height
        ):
            self.vx = -abs(self.vx) 

    def draw(self):
        pyxel.cls(0)
        pyxel.circ(self.x, self.y, self.r, 8)
        pyxel.rect(self.bar_x, self.bar_y, self.bar_width, self.bar_height, 11)
        pyxel.rect(self.cpu_x, self.cpu_y, self.bar_width, self.bar_height, 14)

App()