目次
どんな人が書いてる?
環境
参考にしたサイト
pyrpg27の修正個所
画面の表示
テキスト表示
効果音を鳴らす
BGMを鳴らす
選択肢を作る
どんな人が書いてる?
ここをクリックしてください
1.おじさん
2.python初心者
環境
ここをクリックしてください
python3.11
IDLE
参考にしたサイト
ここをクリックしてください
人工知能に関する断創録
PythonとPygameで作る レトロ風RPG 全コード
Pygameド素人がRPGを作る1
Pygameド素人がRPGを作る2
PygameでRPG制作 ーーそれっぽい画面を作ってみよう
PygameでRPG制作 ーーそれっぽい画面を作ってみよう② バトル画面のメニューを作ろう
PygameでRPG制作 ーーそれっぽい画面を作ってみよう③効果音を使ってみよう
PygameでRPG制作 ーーそれっぽい画面を作ってみよう④ 各アクションのでの動作とHP機能の実装
PygameでRPG制作 ーーそれっぽい画面を作ってみよう⑤ HP表示とスライムリッキーの反撃、終了処理
人工知能に関する断創録は特に役に立ちます。ぼくのコードは、ほとんどaidiaryさんのコードをコピペしたものです。
すぐ動かせるようにpyrpg27のエラーを修正したものを書いておきます。
pyrpg27 サイトへ移動
pyrpg27の修正個所
ここをクリックしてください
Ln23(23行目) 行数はdef()の行数です。修正個所ではありません。
def load_image(dir, file, colorkey=None):
file = os.path.join(dir, file)
try:
image = pygame.image.load(file)
except (pygame.error, message):#ここ
print ("Cannot load image:"), file#ここ
raise (SystemExit, message)#ここ
image = image.convert()
if colorkey is not None:
if colorkey == -1:#ここ
colorkey = image.get_at((0,0))
image.set_colorkey(colorkey, RLEACCEL)
return image
Ln365(365行目)
def draw(self, screen, offset):
"""マップを描画する"""
offsetx, offsety = offset
# マップの描画範囲を計算
startx = int(offsetx / GS)#ここ
endx = int(startx + SCR_RECT.width/GS + 1)#ここ
starty = int(offsety / GS) - 1#ここ
endy = int(starty + SCR_RECT.height/GS) + 1 #ここ
Ln556(556行目)
def update(self, map):
"""キャラクター状態を更新する。
mapは移動可能かの判定に必要。"""
# プレイヤーの移動処理
if self.moving == True:
# ピクセル移動中ならマスにきっちり収まるまで移動を続ける
self.rect.move_ip(self.vx, self.vy)
if self.rect.left % GS == 0 and self.rect.top % GS == 0: # マスにおさまったら移動完了
self.moving = False
self.x = self.rect.left // GS#ここ
self.y = self.rect.top // GS#ここ
# キャラクターアニメーション(frameに応じて描画イメージを切り替える)
self.frame += 1
self.image = self.images[self.name][self.direction*4+self.frame//self.animcycle%4]#ここ
Ln603(行目)
def update(self, map, battle):
"""プレイヤー状態を更新する。
mapは移動可能かの判定に必要。
battleはエンカウントに必要。"""
global game_state
# プレイヤーの移動処理
if self.moving == True:
# ピクセル移動中ならマスにきっちり収まるまで移動を続ける
self.rect.move_ip(self.vx, self.vy)
if self.rect.left % GS == 0 and self.rect.top % GS == 0: # マスにおさまったら移動完了
self.moving = False
self.x = self.rect.left // GS#ここ
self.y = self.rect.top // GS#ここ
# キャラクターアニメーション(frameに応じて描画イメージを切り替える)
self.frame += 1
self.image = self.images[self.name][self.direction*4+self.frame//self.animcycle%4]#ここ
Ln764(行目)
def draw_character(self, screen, pos, ch):
"""1文字だけ描画する"""
x, y = pos
try:
rect = self.kana2rect[ch]
screen.blit(self.image, (x,y), (rect.x+self.color,rect.y,rect.width,rect.height))
except KeyError:
print ("描画できない文字があります:%s" % ch)#ここ
return
Ln843(843行目)
def set(self, message):
"""メッセージをセットしてウィンドウを画面に表示する"""
self.cur_pos = 0
self.cur_page = 0
self.next_flag = False
self.hide_flag = False
# 全角スペースで初期化
self.text = [u' '] * (self.MAX_LINES*self.MAX_CHARS_PER_LINE)
# メッセージをセット
p = 0
for i in range(len(message)):
ch = message[i]
if ch == "/": # /は改行文字
self.text[p] = "/"
p += self.MAX_CHARS_PER_LINE
p = (p//self.MAX_CHARS_PER_LINE)*self.MAX_CHARS_PER_LINE#ここ
elif ch == "%": # \fは改ページ文字
self.text[p] = "%"
p += self.MAX_CHARS_PER_PAGE
p = (p//self.MAX_CHARS_PER_PAGE)*self.MAX_CHARS_PER_PAGE#ここ
else:
self.text[p] = ch
p += 1
self.text[p] = "$" # 終端文字
self.show()
Ln868(868行目)
def update(self):
"""メッセージウィンドウを更新する
メッセージが流れるように表示する"""
if self.is_visible:
if self.next_flag == False:
self.cur_pos += 1 # 1文字流す
# テキスト全体から見た現在位置
p = self.cur_page * self.MAX_CHARS_PER_PAGE + self.cur_pos
if self.text[p] == "/": # 改行文字
self.cur_pos += self.MAX_CHARS_PER_LINE
self.cur_pos = (self.cur_pos//self.MAX_CHARS_PER_LINE) * self.MAX_CHARS_PER_LINE#ここ
elif self.text[p] == "%": # 改ページ文字
self.cur_pos += self.MAX_CHARS_PER_PAGE
self.cur_pos = (self.cur_pos//self.MAX_CHARS_PER_PAGE) * self.MAX_CHARS_PER_PAGE#ここ
elif self.text[p] == "$": # 終端文字
self.hide_flag = True
# 1ページの文字数に達したら▼を表示
if self.cur_pos % self.MAX_CHARS_PER_PAGE == 0:
self.next_flag = True
self.frame += 1
Ln888(888行目)
def draw(self, screen):
"""メッセージを描画する
メッセージウィンドウが表示されていないときは何もしない"""
Window.draw(self, screen)
if self.is_visible == False: return
# 現在表示しているページのcur_posまでの文字を描画
for i in range(self.cur_pos):
ch = self.text[self.cur_page*self.MAX_CHARS_PER_PAGE+i]
if ch == "/" or ch == "%" or ch == "$": continue # 制御文字は表示しない
dx = self.text_rect[0] + MessageEngine.FONT_WIDTH * (i % self.MAX_CHARS_PER_LINE)
dy = self.text_rect[1] + (self.LINE_HEIGHT+MessageEngine.FONT_HEIGHT) * (i // self.MAX_CHARS_PER_LINE)
self.msg_engine.draw_character(screen, (dx,dy), ch)#ここ
# 最後のページでない場合は▼を表示
if (not self.hide_flag) and self.next_flag:
if self.frame / self.animcycle % 2 == 0:
dx = self.text_rect[0] + (self.MAX_CHARS_PER_LINE/2) * MessageEngine.FONT_WIDTH - MessageEngine.FONT_WIDTH/2
dy = self.text_rect[1] + (self.LINE_HEIGHT + MessageEngine.FONT_HEIGHT) * 3
screen.blit(self.cursor, (dx,dy))
Ln919(919行目)
def draw(self, screen):
Window.draw(self, screen)
if self.is_visible == False: return
# はなす、つよさ、そうび、とびらを描画
for i in range(0, 4):
dx = self.text_rect[0] + MessageEngine.FONT_WIDTH
dy = self.text_rect[1] + (self.LINE_HEIGHT+MessageEngine.FONT_HEIGHT) * (i % 4)
self.msg_engine.draw_string(screen, (dx,dy), self.COMMAND[i])
# じゅもん、どうぐ、さくせん、しらべるを描画
for i in range(4, 8):
dx = self.text_rect[0] + MessageEngine.FONT_WIDTH * 6
dy = self.text_rect[1] + (self.LINE_HEIGHT+MessageEngine.FONT_HEIGHT) * (i % 4)
self.msg_engine.draw_string(screen, (dx,dy), self.COMMAND[i])
# 選択中のコマンドの左側に▶を描画
dx = self.text_rect[0] + MessageEngine.FONT_WIDTH * 5 * (self.command // 4)#ここ
dy = self.text_rect[1] + (self.LINE_HEIGHT+MessageEngine.FONT_HEIGHT) * (self.command % 4)
screen.blit(self.cursor, (dx,dy))
画面の表示
ここをクリックしてください
import pygame
import sys
pygame.init()
screen = pygame.display.set_mode((320, 320))
pygame.display.set_caption('screen only')
while (1):
screen.fill((0, 0, 0))
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
import pygame
ライブラリのインポート
事前にインストールしておきましょう。
コマンドで py -m pip install pygame
import sys
画面を閉じるのに必要です。
pygame.init()
初期化します。
screen = pygame.display.set_mode((320, 320))
数値は画面の大きさです。(よこ、たて)
pygame.display.set_caption('screen only')
ウィンドウの名前です。
while (1):
screen.fill((0, 0, 0))
画面の色を指定します。黒(0, 0, 0)白(255, 255, 255)灰色(128, 128, 128)
pygame.display.update()
画面の更新をします。
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
ウィンドウの閉じるボタンを押すと動かなくなります。まだ閉じません。
sys.exit()
ウィンドウを閉じます。
テキスト表示
ここをクリックしてください
import pygame
import sys
pygame.init()
screen = pygame.display.set_mode((160, 160))
pygame.display.set_caption('text only')
font = pygame.font.Font(r"date\Mplus1-Regular.ttf", 30)
while (1):
screen.fill((0, 0, 0))
message_text = font.render("こんにちは", True, (255, 255, 255))
screen.blit(message_text, (5, 65))
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
font = pygame.font.Font(r"date\Mplus1-Regular.ttf", 30)
フォントファイルをロードします。数値はフォントの大きさです。
message_text = font.render("こんにちは", True, (255, 255, 255))
Falseにすると、文字がギザギザします。数値は文字の色です。
screen.blit(message_text, (5, 65))
文字を画面に描画します。数値は座標です。(よこ、たて)
*座標は左上が(0,0)です。ヨコは右に行くほど増えます。タテは下に行くほど増えます。
.ttfファイルを探しましょう。.pngファイルだと自分でコードを書かないとダメです。
Windowsでパスをそのまま貼り付けるとエラーが出るので、""の前にrをつけましょう。(r"")
効果音を鳴らす
ここをクリックしてください
import pygame
import sys
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((160, 160))
pygame.display.set_caption('SE only')
sound = pygame.mixer.Sound("date\ボタン音45.mp3")
while (1):
screen.fill((0, 0, 0))
pygame.display.update()
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == KEYDOWN:
sound.play()
from pygame.locals import *
from pygame.locals import * は特定の定数のみをインポートし、from pygame import * はPygame全体をインポートします。
これがあると KEYDOWNやQUITの前にpygame. を書かなくてよいです。すべてのpygame.がいらなくなるわけではないです。
sound = pygame.mixer.Sound("date\ボタン音45.mp3")
効果音をロードします。
elif event.type == KEYDOWN:
何かキーが押されたときに処理を実行します。
for event in pygame.event.get():の下に書きます。
sound.play()
効果音を鳴らします。(ここではsoundは変数名です。)
BGMを鳴らす
ここをクリックしてください
import pygame
import sys
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((160,160))
pygame.display.set_caption("BGM_only")
pygame.mixer.music.load("date\MusMus-BGM-104.mp3")
pygame.mixer.music.play(-1)
while True:
pygame.display.update()
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
pygame.mixer.music.load("date\MusMus-BGM-104.mp3")
BGMをロードします。
pygame.mixer.music.play(-1)
BGMをループします。1だと1回、鳴らします。何も書かない場合でも1回、鳴らします。
start = 1.0 でスタート地点を指定できます。ただし2回目は最初から再生されます。数値は秒単位です。pygame.mixer.music.play(1,1.0)と書くこともできます。
選択肢を作る
ここをクリックしてください
import pygame
from pygame.locals import *
import sys
pygame.init()
screen = pygame.display.set_mode((160,160))
font = pygame.font.Font("date\ipaexg.ttf", 30)
cmd = 0
arrow1 = '→'
arrow2 = ' '
while (1):
screen.fill((0, 0, 0))
text1 = font.render(arrow1 + "はじめる", True, (255, 255, 255))
text2 = font.render(arrow2 + "やめる", True, (255, 255, 255))
screen.blit(text1, (10 , 50))
screen.blit(text2, (10 , 80))
pygame.display.update()
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == KEYDOWN:
if event.key == K_DOWN:
if cmd == 0:
cmd = 1
arrow1 = ' '
arrow2 = '→'
else:
arrow1 = '→'
arrow2 = ' '
cmd = 0
elif event.key == K_UP:
if cmd == 1:
arrow1 = '→'
arrow2 = ' '
cmd = 0
else:
arrow1 = ' '
arrow2 = '→'
cmd = 1
半透明
ここをクリックしてください
import pygame
import sys
from pygame.locals import *
x,y = 0,0
# Pygameの初期化
pygame.init()
# 画面サイズの設定
screen = pygame.display.set_mode((640, 480))#FULLSCREEN
font = pygame.font.Font("date\ipaexg.ttf", 20)
# 角の丸みの半径
border_radius = 5
# 半透明のSurfaceを作成
#文字の背景(小)
transparent_surface = pygame.Surface((160, 26), pygame.SRCALPHA)
transparent_surface.fill((0, 0, 0, 128)) # RGBA (黒, 透明度128)
#文字の背景(大)
transparent_surface1 = pygame.Surface((172, 98), pygame.SRCALPHA)
transparent_surface1.fill((0, 0, 0, 64)) # RGBA (黒, 透明度128)
#選択の背景(小)
transparent_surface2 = pygame.Surface((156, 22), pygame.SRCALPHA)
transparent_surface2.fill((51, 153, 255, 80)) # RGBA (黒, 透明度128)
# メインループ
running = True
while running:
screen.fill((255,255,255))
#文字の背景(小)を描画
screen.blit(transparent_surface, (240, 290))
screen.blit(transparent_surface, (240, 320))
screen.blit(transparent_surface, (240, 350))
#文字の背景(大)を描画
screen.blit(transparent_surface1, (234, 284))
# 選択の背景(小)を描画
if x >= 242 and x <= 398:
if y >=292 and y <= 314:
screen.blit(transparent_surface2, (242, 292))
elif y >=292 and y <= 344:
screen.blit(transparent_surface2, (242, 322))
elif y >=292 and y <= 374:
screen.blit(transparent_surface2, (242, 352))
#枠を描画
pygame.draw.rect(screen,(123, 123, 255),Rect(232,282,176,102), 3,border_radius=border_radius)
#テキスト表示
message_text = font.render("ニューゲーム", True, (255, 255, 255))
screen.blit(message_text, (260, 293))
message_text = font.render("コンティニュー", True, (255, 255, 255))
screen.blit(message_text, (250, 323))
message_text = font.render("フィニッシュ", True, (255, 255, 255))
screen.blit(message_text, (260, 353))
# 画面を更新
pygame.display.flip()
for event in pygame.event.get():
#マウスの位置を取得
mouse_pos = pygame.mouse.get_pos()
x = mouse_pos[0]
y = mouse_pos[1]
if event.type == QUIT:
pygame.quit()
sys.exit()
背景動画
ここをクリックしてください
import pygame
import cv2
import numpy as np
import sys
import time
# 初期化
pygame.init()
# 画面サイズの設定
screen_width, screen_height = 800, 600
screen = pygame.display.set_mode((screen_width, screen_height))
# 動画の読み込み
cap = cv2.VideoCapture("date\sakuraschool01.mp4")
# フレームレートの取得
fps = cap.get(cv2.CAP_PROP_FPS)
frame_duration = 1 / fps
# メインループ
running = True
while running:
start_time = time.time()
ret, frame = cap.read()
if not ret:
break
# OpenCVの画像をpygame用に変換
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# フレームのリサイズ
frame = cv2.resize(frame, (screen_width, screen_height))
frame = cv2.flip(frame, 1) # 水平方向に反転
frame = np.rot90(frame)
frame = pygame.surfarray.make_surface(frame)
# 画面に描画
screen.blit(frame, (0, 0))
pygame.display.update()
# イベント処理
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# フレームレートに合わせて待機
elapsed_time = time.time() - start_time
if elapsed_time < frame_duration:
time.sleep(frame_duration - elapsed_time)
# 終了処理
cap.release()
pygame.quit()
sys.exit()
Copilotに書いてもらったので説明できません。
frame = cv2.flip(frame, 1) # 水平方向に反転、ここではなぜか垂直方向に反転している
frame = np.rot90(frame)
この2つがないと、元画像から左右反転して、左に90度回転した状態。
それを、frame = cv2.flip(frame, 1)で垂直方向に反転し、
frame = np.rot90(frame)で右に90度回転して修正してあります。
本来、frame = cv2.flip(frame, 1)は水平方向に反転するようですから、python初心者のぼくには意味不明です。