Pyxelを触ってみよう2

こんにちは。元TENTO生で現在スタッフをしているSです。
少し時間は経ってしまいましたが、前回の続きに取り組みたいと思います。今日は、ミニゲームを完成させるところまで取り組みたいと思います。
前回のブログについてはこちらから↓
https://www.tento-net.com/blog/pyxel1
水色のキャラクターを動かそう
前回、白いキャラクターは動かせるようにしました。
水色のキャラクターも同じように矢印キーで動かすと、白いキャラクターとくっついて動いてしまうため、別の方法で動かしていきたいと思います。
今回は水色のキャラクターは、上から下に自動的に落ちていくようにします。水色のキャラクターのための変数を作成し、コードが走っている間に1ずつ値が増えるようにしました。
今回変更したコード部分↓blueY = 0  # 水色キャラクターのY座標のための変数
blueY += 1
blt(20,blueY, 1, 0, 0, 8, 8, 0) # 水色のキャラクター
しかし、このままだと水色キャラクターが枠外に出てしまうと、もう一度再実行をしないと水色のキャラクターが戻ってきません。そこで次は、水色のキャラクターが枠外に行ってしまったら、上に戻してもう一度落ちていくようにします。ついでに、水色キャラクターのx座標についてもランダムに出現させるようにします。
今回変更したコード部分↓blueX = 4 # 水色キャラクターのX座標のための変数を作成
if blueY > 92: # 水色キャラクターのyが92を超えたら0にしてもう一度上に戻らせる
blueX = random.randint(8, 89)
blueY = 0
水色のキャラクターを捕まえたらコスチュームを変える
では次に、水色のキャラクターを敵に見立てて、白いキャラクターが捕まえたら、敵が死ぬ仕組みを作ります。
まず、死んだキャラクターのコスチュームを作ります。今回はピンクのキャラクターを作ってみました。

キャラクターが作れたら、次に当たり判定に取り掛かります。
当たり判定では、
1,敵キャラクターに白いキャラクターが触れたかどうかを確かめる
2,もし触れていたら、敵のコスチュームを先ほど新しく作ったコスチュームに変更させる
ということを行います。
今回変更したコード部分↓blueImg = 1 # 水色キャラクターのコスチュームのための変数(1が通常、2が死んだ状態)
# 敵を動かしている部分
blueY += 1
if blueY > 92: # 水色キャラクターのyが92を超えたら0にしてもう一度上に戻らせる
    blueX = random.randint(8, 89)
    blueY = 0
    blueImg = 1 #  上に戻ってきたら通常の見た目に戻す
# 敵の当たり判定部分
    if (whiteX < blueX + 8 and
        whiteX + 8 > blueX and
        whiteY < blueY + 8 and
        whiteY + 8 > blueY):
        blueImg = 2  # 当たったら2番の見た目に変える
blt(blueX,blueY, blueImg, 0, 0, 8, 8, 0) # 水色のキャラクターに見た目のための変数を追加
ひとまず、基本のミニゲームは完成しました。こんな感じで、敵を捕らえたら敵が赤くなります。


完成版コード
基本のコードはこちら↓from pyxel import *
import random
init(100, 100) # 画面の大きさ
load("my_resource.pyxres") # キャラクターのインポート
whiteX = 10 # 白キャラクターのX座標のための変数
whiteY = 50 # 白キャラクターのY座標のための変数
blueX = 4 # 水色キャラクターのX座標のための変数
blueY = 0 # 水色キャラクターのY座標のための変数
blueImg = 1 # 水色キャラクターのコスチュームのための変数(1が通常、2が死んだ状態)
while True:
if btn(KEY_RIGHT) and whiteX < 88: # 右矢印が押されたら whiteX += 2 if btn(KEY_LEFT) and whiteX > 4: # 左矢印が押されたら
whiteX -= 2
if btn(KEY_UP) and whiteY > 4: # 上矢印が押されたら
whiteY -= 2
if btn(KEY_DOWN) and whiteY < 88: # 下矢印が押されたら
whiteY += 2
# 敵を動かしている部分
blueY += 1
if blueY > 92: # 水色キャラクターのyが92を超えたら0にしてもう一度上に戻らせる
    blueX = random.randint(8, 89)
    blueY = 0
    blueImg = 1 #  上に戻ってきたら通常の見た目に戻す
#  敵の当たり判定部分
if (whiteX < blueX + 8 and
    whiteX + 8 > blueX and
    whiteY < blueY + 8 and
    whiteY + 8 > blueY):
    blueImg = 2  # 当たったら2番の見た目に変える
cls(3) # 背景
rect(2, 2, 96, 96, 13) # 枠のための灰色の四角
rect(3, 3, 94, 94, 3) #  枠のための緑色の四角
blt(whiteX,whiteY, 0, 0, 0, 8, 8, 0)  # 白いキャラクター
blt(blueX,blueY, blueImg, 0, 0, 8, 8, 0) # 水色のキャラクター
flip()
番外編
ここからは、色々と遊び心を加えていきます。
1,敵を再利用せず、敵が下まで行ったらもう一体表示させる
2,敵を消さず、ずっと表示させる
3,効果音を付け加える
4,10体敵が出現したところで終わりにする
5,ゲームが終了した時に、倒した敵の数によって異なるメッセージを表示させる
これらの機能を追加したコードはこちら↓
from pyxel import *
import random
init(100, 100)
load("my_resource.pyxres")
whiteX = 10
whiteY = 50
finish = False
#敵の状態をまとめた配列(x座標, y座標, スプライト番号, 停止フラグ)
enemyX = [random.randint(8, 89)]
enemyY = [0]
enemyImg = [1]
enemyStopped = [False]
while True:
# --- 白キャラ操作 ---
if btn(KEY_RIGHT) and whiteX < 88: whiteX += 2 if btn(KEY_LEFT) and whiteX > 4:
whiteX -= 2
if btn(KEY_UP) and whiteY > 4:
whiteY -= 2
if btn(KEY_DOWN) and whiteY < 88:
whiteY += 2
new_enemy_needed = False
# --- 敵の更新 ---
for i in range(len(enemyX)):
    if not enemyStopped[i]:
        enemyY[i] += 2
        # 衝突判定
        if abs(enemyX[i] - whiteX) < 8 and abs(enemyY[i] - whiteY) < 8:
            enemyImg[i] = 2
            enemyStopped[i] = True
            new_enemy_needed = True
            play(0, 0)
        # 底まで落ちたら停止
        elif enemyY[i] >= 89:
            enemyY[i] = 89
            enemyStopped[i] = True
            new_enemy_needed = True
            play(0, 1)
# 新しい敵を追加
if new_enemy_needed:
    if len(enemyX) < 10:
        enemyX.append(random.randint(8, 89))
        enemyY.append(0)
        enemyImg.append(1)
        enemyStopped.append(False)
    else:
        finish = True
# --- 描画 ---
cls(3)
rect(2, 2, 96, 96, 13)
rect(3, 3, 94, 94, 3)
# 白キャラ
blt(whiteX, whiteY, 0, 0, 0, 8, 8, 0)
# 敵
for i in range(len(enemyX)):
    blt(enemyX[i], int(enemyY[i]), enemyImg[i], 0, 0, 8, 8, 0)
# ゲーム終了メッセージ
if finish:
    caught_count = sum(1 for img in enemyImg if img == 2)
    if caught_count > 5:
        rect(30, 43, 47, 10, 8)
        text(34, 46, "FANTASTIC!", 7)
    else:
        rect(30, 43, 47, 10, 13)
        text(34, 46, "TRY AGAIN!", 3)
flip()
ちなみに操作画面はこんな感じです。




