さて、一応CPUの動きも出来たことだし、次はスコアの管理と表示をしていこうか!
スコアの管理も変数を使えば良いんだね!
ちなみに、ホッケーゲームの点数はどういう時に得点になるかな??
んー今回の場合だと、左端に当たった場合は「CPU」の得点で、右端に当たった場合は「プレイヤー」の得点だよね
そうだね!ということで、プレイヤーの得点を「self.score_player」、CPUの得点を「self.score_cpu」として得点の管理をしていこうか!
# 関数「__init__」の「pyxel.run()」の上の行に追加
# スコア初期化
self.score_player = 0
self.score_cpu = 0
おっけー!それぞれの得点用の変数は準備できたよ!
次は、得点を表示するための「self.text()」を関数「draw」に追加しよう!
# 関数「draw」の最後に追加
pyxel.text(20, 4, f"YOU: {self.score_player:04}", 11)
pyxel.text(100, 4, f"CPU: {self.score_cpu:04}", 14)
良い感じ!!ところでちょっと気になったんだけど、Pyxelでは日本語表示はできないの?
残念ながら非対応なんだよね
だけど、「PyxelUniversalFont」っていう拡張用の外部ライブラリを使えば対応するみたいだから、興味があれば調べてみてね!
了解!
そしたら、ここからは得点が増える仕組みを考えよう!まずは、関数「update」の「左右の端にぶつかったときに跳ね返す」プログラムの部分に注目してね
# 関数「update」内
# ウィンドウの端に当たったら反射(跳ね返る)
if self.x <= self.r or self.x >= pyxel.width - self.r: # ここの2行に注目!
self.vx *= -1
if self.y <= self.r or self.y >= pyxel.height - self.r:
self.vy *= -1
...(じーーーーーー)
前回までは、左右の端にぶつかったら跳ね返すようにしてたから左右の区別なしでif文を作ってたよね
あ!だけど、今回は左と右で「得点が入る対象」が違うから条件を分けないといけないのか!
そういうこと!つまり、こんな感じの変更になるよ
# ウィンドウの端に当たったら反射(跳ね返る)
if self.x <= self.r: # 左側が当たった場合はCPUの得点
self.score_cpu += 1
self.vx *= -1
elif self.x >= pyxel.width - self.r:
self.score_player += 1 # 右側が当たった場合はプレイヤーの得点
self.vx *= -1
if self.y <= self.r or self.y >= pyxel.height - self.r:
self.vy *= -1
まぁそんな感じだよね!イメージ通り!
これで一応得点の管理は完了だけど、せっかくだからもう少しホッケーゲームを改良してみよう!
まずは得点が入った時にホッケーが真ん中にリセットされるようにしようか
そうだね!ついでに、リセットのたびに飛んでいく方向が変わると面白いかも!
オッケー!せっかくだし、リセットの部分を関数にして、プログラムを起動した時の初期化にも対応させよう
まず、ホッケーをリセットするための関数「reset_hockey」を関数「update」より上の辺りに用意しよう
# ホッケーの初期化
def reset_hockey(self):
self.x = pyxel.width // 2
self.y = pyxel.height // 2
self.vx = random.choice([-1, 1])
self.vy = random.choice([-1, 1])
self.r = 4
ホッケーの速度「self.vx」「self.vy」は飛んでいく方向をランダムにしたんだね!
次に、関数「reset_hockey」を適切な箇所に使っていこうか
関数「__init__」の最初の方のホッケーを初期化している場所と...
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
↓↓ 変更後 ↓↓
def __init__(self):
pyxel.init(160, 120, title="ホッケーゲーム")
# ホッケーの初期化
self.reset_hockey()
関数「update」の中の前回作った左右の端に来たら跳ね返す場所だね!
# ウィンドウの端に当たったら反射(跳ね返る)
if self.x <= self.r: # 左側が当たった場合はCPUの得点
self.score_cpu += 1
self.vx *= -1
elif self.x >= pyxel.width - self.r:
self.score_player += 1 # 右側が当たった場合はプレイヤーの得点
self.vx *= -1
if self.y <= self.r or self.y >= pyxel.height - self.r:
self.vy *= -1
↓↓ 変更後 ↓↓
# ウィンドウの端に当たったら反射(跳ね返る)
if self.x <= self.r: # 左側が当たった場合はCPUの得点
self.score_cpu += 1
self.reset_hockey()
elif self.x >= pyxel.width - self.r:
self.score_player += 1 # 右側が当たった場合はプレイヤーの得点
self.reset_hockey()
if self.y <= self.r or self.y >= pyxel.height - self.r:
self.vy *= -1
バッチリ!早速動かしてみようか!
うん、ちゃんと左右の端に当たった時にホッケーが真ん中に戻ってるし、最初の動きもランダムになってるね!
ところでおねーちゃん!リセットを作る時に思いついたんだけど、ゲームをもう少し面白くするために、「ホッケーをバーで跳ね返す度に速くしていく」ってどうかな??
お!確かに、試合が長引くと難しくなっていく仕組みは緊張感が出てくるし面白そうだね!
ふふん!じゃあ早速自分で変更してみる!!
関数「update」の衝突判定をするif文の中の「abs(self.vx)」が「1」増えるようにすれば良いから、こうかな??
# 関数「update」の中
# プレイヤーバーの衝突判定
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) + 1 # ←ココを変更
# 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) + 1) # ←ココを変更
「1」はさすがに速すぎたかも...!!
増やす量は丁度良い感じに修正すれば良いとして、バッチリだね!!
そんな感じで、自分なりにどうしたら面白くなるか考えて試してみることが大事だから、どんどんチャレンジしてみようね!!
この時点での全体のプログラム
import pyxel
import random
class App:
def __init__(self):
pyxel.init(160, 120, title="ホッケーゲーム")
# ホッケーの初期化
self.reset_hockey()
# プレイヤー(左側)のバー
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座標
# スコア用
self.score_player = 0
self.score_cpu = 0
pyxel.run(self.update, self.draw)
# ホッケーの初期化
def reset_hockey(self):
self.x = pyxel.width // 2
self.y = pyxel.height // 2
self.vx = random.choice([-1, 1])
self.vy = random.choice([-1, 1])
self.r = 4
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: # 左側が当たった場合はCPUの得点
self.score_cpu += 1
self.reset_hockey()
elif self.x >= pyxel.width - self.r:
self.score_player += 1 # 右側が当たった場合はプレイヤーの得点
self.reset_hockey()
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) + 1
# 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) + 1)
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)
pyxel.text(20, 4, f"YOU: {self.score_player:04}", 11)
pyxel.text(100, 4, f"CPU: {self.score_cpu:04}", 14)
App()
