■ ゲームプログラミング ■ § スプライト § ■ スプライト Pygame では pygame.sprite を用いる事でスプライトの管理、描画、衝突判定等を簡単に行う事が出来 る。此れを利用してキャラクター操作に関する各種機能をスプライトクラスとして 1 個に纏め、複数の キャラクターを扱い易くしたコードを、下記に示す。 PYTHON3 import pygame
from pygame.locals import * import sys
SCREEN = Rect(0, 0, 400, 400) # スプライトのクラス
class Sprite(pygame.sprite.Sprite):
# スプライトを作成(画像ファイル名, 位置(x, y), 速さ(vx, vy), 回転 angle) def __init__(self, filename, x, y, vx, vy, angle=0):
pygame.sprite.Sprite.__init__(self)
self.img = pygame.image.load(filename).convert_alpha()
if angle != 0: self.img = pygame.transform.rotate(self.img, angle) w = self.img.get_width() h = self.img.get_height() self.rect = Rect(x, y, w, h) self.vx = vx self.vy = vy self.angle = angle def update(self): self.rect.move_ip(self.vx, self.vy) # 壁と衝突時の処理(跳ね返り)
if self.rect.left < 0 or self.rect.right > SCREEN.width: self.vx = -self.vx
if self.rect.top < 0 or self.rect.bottom > SCREEN.height: self.vy = -self.vy
# 壁と衝突時の処理(壁を超えない様に) self.rect = self.rect.clamp(SCREEN) def draw(self, screen):
screen.blit(self.img, self.rect) # メイン def main(): pygame.init() screen = pygame.display.set_mode(SCREEN.sice)
P
PY
YT
TH
HO
ON
N
入門
入
門
# スプライトを作成(画像ファイル名, 位置(x, y), 速さ(vx, vy), 回転 angle) player = Sprite("player1.png", 200, 200, 2, 0, 0) enemy1 = Sprite("enemy1.png", 200, 200, 0, 2, 0) enemy2 = Sprite("enemy2.png", 200, 200, 2, 2, 10) clock = pygame.time.Clock() while (1): clock.tick(30) # フレームレート(30fps) screen.fill((0, 20, 0, 0)) # 画面の背景色 # スプライトを更新 player.update() enemy1.update() enemy2.update() # スプライトを描画 player.draw(screen) enemy1.draw(screen) enemy2.draw(screen) # 画面更新 pygame.display.update() # イベント処理
for event in pygame.event.get(): # 終了用のイベント処理
if event.type == QUIT: # 閉じるボタンが押された時 pygame.quit()
sys.exit()
if event.type == KEYDOEN: # キーを押した時 if event.key == K_ESCAPE: # Esc キーが押された時 pygame.quit() sys.exit() if __name__ == "__main__": main() プログラムの処理の流れは下記の通りで有る。 処理 コード
① ゲームライブラリ pygame をインポートする。 import pygame
② 画面のサイズを設定する。 SCREEN=Rect(0, 0, 400, 400) ③ スプライトのクラスを定義する。 class Sprite ④ Pygame を初期化する。 pygame.init ⑤ 大きさ SCREEN.sice の画面(ウィンドウ)を生成する。 pygame.display.set_mode ⑥ スプライトを作成する。 player、enemy1、enemy2 ⑦ 指定したミリ秒の間プログラムを停止する。 clock.tick(30) ⑧ 画面を濃緑色(R=0, G=20, B=0, A=0)に塗り潰す。 screen.fill ⑨ スプライトを更新する。 player.update 等 ⑩ スプライトを描画する。 player.draw 等 ⑪ 画面を更新する。 pygame.display.update ⑫ 閉じるボタンが押されたら画面を閉じて終了する。 pygame.quit、sys.exit ⑬ Esc キーが押されたら画面を閉じて終了する。 pygame.quit、sys.exit
■ スプライトグループ スプライトグループを使用すると、スプライトの更新や描画が簡単に成り、複数のスプライトを効率良 く管理する事が出来る。大量のスプライトを使用する弾幕ゲーム等では便利な機能で有る。 Pygame ではスプライトグループを使う方法がいくつかあります。 亦、Pygame では pygame.sprite.RenderUpdates を用いる事でスプライトグループを作成する事が出 来る。此れを利用して前述のサンプルの 3 体を一括して更新し描画するコードを、下記に示す。 PYTHON3 import pygame
from pygame.locals import * import sys
SCREEN = Rect(0, 0, 400, 400) # スプライトのクラス
class Sprite(pygame.sprite.Sprite):
# スプライトを作成(画像ファイル名, 位置(x, y), 速さ(vx, vy), 回転 angle) def __init__(self, filename, x, y, vx, vy, angle=0):
pygame.sprite.Sprite.__init__(self)
self.img = pygame.image.load(filename).convert_alpha()
if angle != 0: self.img = pygame.transform.rotate(self.img, angle) w = self.img.get_width() h = self.img.get_height() self.rect = Rect(x, y, w, h) self.vx = vx self.vy = vy self.angle = angle def update(self): self.rect.move_ip(self.vx, self.vy) # 壁と衝突時の処理(跳ね返り)
if self.rect.left < 0 or self.rect.right > SCREEN.width: self.vx = -self.vx
if self.rect.top < 0 or self.rect.bottom > SCREEN.height: self.vy = -self.vy
# 壁と衝突時の処理(壁を超えない様に) self.rect = self.rect.clamp(SCREEN)
def draw(self, screen):
screen.blit(self.img, self.rect) # メイン
def main(): pygame.init()
screen = pygame.display.set_mode(SCREEN.sice)
# スプライトを作成(画像ファイル名, 位置(x, y), 速さ(vx, vy), 回転 angle) player = Sprite("player1.png", 200, 200, 2, 0, 0)
enemy1 = Sprite("enemy1.png", 200, 200, 0, 2, 0) enemy2 = Sprite("enemy2.png", 200, 200, 2, 2, 10)
# スプライトグループの作成
# スプライトの追加 group.add(player) group.add(enemy1) group.add(enemy2) clock = pygame.time.Clock() while (1): clock.tick(30) # フレームレート(30fps) screen.fill((0, 20, 0, 0)) # 画面の背景色 # スプライトグループを更新 group.update() # スプライトを描画 group.draw(screen) # 画面更新 pygame.display.update() # イベント処理
for event in pygame.event.get(): # 終了用のイベント処理
if event.type == QUIT: # 閉じるボタンが押された時 pygame.quit()
sys.exit()
if event.type == KEYDOEN: # キーを押した時 if event.key == K_ESCAPE: # Esc キーが押された時 pygame.quit() sys.exit() if __name__ == "__main__": main() 上記の様に、pygame.sprite.RenderUpdates でスプライトグループを作成し、其のグループに個々のス プライトを追加(group.add)する事で、更新や描画がグループ単位で行える様に成る。 上記以外にも、Pygame では幾つかのスプライトグループを使用する方法が有る。スプライトのクラス 定義で pygame.sprite.Sprite.init(self, self.containers) を使用すると、スプライトクラス内で予めグル ープ指定が為されるので、スプライトを作成すると自動的にグループに追加される。 PYTHON3 import pygame
from pygame.locals import * import sys
SCREEN = Rect(0, 0, 400, 400) # スプライトのクラス
class Sprite(pygame.sprite.Sprite):
# スプライトを作成(画像ファイル名, 位置(x, y), 速さ(vx, vy), 回転 angle) def __init__(self, filename, x, y, vx, vy, angle=0):
pygame.sprite.Sprite.__init__(self, self.containers)
self.image = pygame.image.load(filename).convert_alpha()
if angle != 0: self.image = pygame.transform.rotate(self.image, angle) w = self.image.get_width()
h = self.image.get_height() self.rect = Rect(x, y, w, h)
self.vx = vx self.vy = vy self.angle = angle def update(self): self.rect.move_ip(self.vx, self.vy) # 壁と衝突時の処理(跳ね返り)
if self.rect.left < 0 or self.rect.right > SCREEN.width: self.vx = -self.vx
if self.rect.top < 0 or self.rect.bottom > SCREEN.height: self.vy = -self.vy # 壁と衝突時の処理(壁を超えない様に) self.rect = self.rect.clamp(SCREEN) # メイン def main(): pygame.init() screen = pygame.display.set_mode(SCREEN.sice) # スプライトグループを作成して group = pygame.sprite.RenderUpdates() # スプライトクラスにスプライトグループを割り当てる Sprite.containers = group
# スプライトを作成(画像ファイル名, 位置(x, y), 速さ(vx, vy), 回転 angle) player = Sprite("player1.png", 200, 200, 2, 0, 0) enemy1 = Sprite("enemy1.png", 200, 200, 0, 2, 0) enemy2 = Sprite("enemy2.png", 200, 200, 2, 2, 10) clock = pygame.time.Clock() while (1): clock.tick(30) # フレームレート(30fps) screen.fill((0, 20, 0, 0)) # 画面の背景色 # スプライトグループを更新 group.update() # スプライトを描画 group.draw(screen) # 画面更新 pygame.display.update() # イベント処理
for event in pygame.event.get(): # 終了用のイベント処理
if event.type == QUIT: # 閉じるボタンが押された時 pygame.quit()
sys.exit()
if event.type == KEYDOEN: # キーを押した時 if event.key == K_ESCAPE: # Esc キーが押された時 pygame.quit() sys.exit() if __name__ == "__main__": main() クラス定義で赤字の部分を書き換えると、main 関数の赤字の部分で、グループをコンテナに登録する ので、個々のスプライトをグループに追加(group.add)する必要が無く成る。
亦、スプライトの描画を高速に行う為に dirty rect animation(汚い矩形のアニメーション)と謂う手 法が有り、此の手法では、画面を更新する時に、スプライトが更新された部分丈を再描画する。
PYTHON3 import pygame
from pygame.locals import * import sys
SCREEN = Rect(0, 0, 400, 400) # スプライトのクラス
class Sprite(pygame.sprite.Sprite):
# スプライトを作成(画像ファイル名, 位置(x, y), 速さ(vx, vy), 回転 angle) def __init__(self, filename, x, y, vx, vy, angle=0):
pygame.sprite.Sprite.__init__(self, self.containers)
self.image = pygame.image.load(filename).convert_alpha()
if angle != 0: self.image = pygame.transform.rotate(self.image, angle) w = self.image.get_width() h = self.image.get_height() self.rect = Rect(x, y, w, h) self.vx = vx self.vy = vy self.angle = angle def update(self): self.rect.move_ip(self.vx, self.vy) # 壁と衝突時の処理(跳ね返り)
if self.rect.left < 0 or self.rect.right > SCREEN.width: self.vx = -self.vx
if self.rect.top < 0 or self.rect.bottom > SCREEN.height: self.vy = -self.vy
# 壁と衝突時の処理(壁を超えない様に) self.rect = self.rect.clamp(SCREEN)
def draw(self, screen):
screen.blit(self.img, self.rect) # メイン def main(): pygame.init() screen = pygame.display.set_mode(SCREEN.sice) # スプライトグループを作成して group = pygame.sprite.RenderUpdates() # スプライトクラスにスプライトグループを割り当てる Sprite.containers = group
# スプライトを作成(画像ファイル名, 位置(x, y), 速さ(vx, vy), 回転 angle) player = Sprite("player1.png", 200, 200, 2, 0, 0) enemy1 = Sprite("enemy1.png", 200, 200, 0, 2, 0) enemy2 = Sprite("enemy2.png", 200, 200, 2, 2, 10) clock = pygame.time.Clock() # 背景の作成と描画(背景は最初に 1 回丈描画) bg = pygame.Surface(SCREEN.sice) bg.fill((0, 20, 0)) # 画面の背景色 screen.blit(bg, (0,0))
pygame.display.update() while (1): clock.tick(30) # フレームレート(30fps) group.clear(screen, bg) # スプライトグループを更新 group.update() # スプライトを更新 dirty_rects = group.draw(screen) # 画面更新(dirty rect を渡すと其の部分丈を更新する) pygame.display.update(dirty_rects) # イベント処理
for event in pygame.event.get(): # 終了用のイベント処理
if event.type == QUIT: # 閉じるボタンが押された時 pygame.quit()
sys.exit()
if event.type == KEYDOEN: # キーを押した時 if event.key == K_ESCAPE: # Esc キーが押された時 pygame.quit() sys.exit() if __name__ == "__main__": main() ■ Sprite クラスのメソッド クラス 説明 pygame.sprite.Sprite 特定の画像をゲーム画面に表示する為の単純な基底クラス pygame.sprite.DirtySprite 属性を増やして機能を追加した Sprite のサブクラス。 pygame.sprite.Group 複数の Sprite を保持するクラス pygame.sprite.RenderUpdates 描写先範囲の情報を取得する Group クラス pygame.sprite.OrderedUpdates 追加された順番に従い画面描写を行う RenderUpdates クラス pygame.sprite.LayeredUpdates レイヤーを制御し画像描写処理を行う Group クラス
pygame.sprite.LayeredDirty DirtySprites 用の Group クラス
pygame.sprite.GroupSingle Sprite オブジェクトを 1 個しか格納出来ない Group クラス Sprite クラスのメソッドには、下記の物が有る。
メソッド 説明
pygame.sprite.spritecollide Group の中から指定した Sprite と接触して居る物を探す。 pygame.sprite.collide_rect rect 属性を使って 2 個の sprite の当たり判定を行う。 pygame.sprite.collide_rect_ratio rect の大きさを変換して 2 個の sprite の当たり判定を行う。 pygame.sprite.collide_circle 円に変換した大きさで 2 個の sprite の当たり判定を行う。 pygame.sprite.collide_circle_ratio radius の大きさ変換して 2 個の sprite の当たり判定を行う。 pygame.sprite.collide_mask mask 属性を使って 2 個の sprite の当たり判定を行う。 pygame.sprite.groupcollide 2 個の Group 間で接触して居る総ての Sprite を探す。
pygame.sprite.spritecollideany 指定した Sprite が Group 内で接触して居る Sprite を調べる。 ■ pygame ドキュメント
原文:https://www.pygame.org/docs/ref/transform.html