キャラクターアニメーション
キャラクターアニメーションの作り方を紹介します。画像の移動と跳ね返り処理(2008/5/9)で紹介したような位置が変わるアニメーションではなく、こういうやつ
です。他にもシューティングの爆発なども同じ方法でできます。画像はDotWorldさん(リンク切れ)からお借りしました。RPGでもぜひ使わせてもらおうと思ってます。
サンプルスクリプト
#!/usr/bin/env python # -*- coding: utf-8 -*- import pygame from pygame.locals import * import sys SCR_RECT = Rect(0, 0, 640, 480) def load_image(filename, colorkey=None): try: image = pygame.image.load(filename) except pygame.error, message: print "Cannot load image:", filename raise SystemExit, message image = image.convert() if colorkey is not None: if colorkey is -1: colorkey = image.get_at((0,0)) image.set_colorkey(colorkey, RLEACCEL) return image def split_image(image): """32x128のキャラクターイメージを32x32の4枚のイメージに分割 分割したイメージを格納したリストを返す""" imageList = [] for i in range(0, 128, 32): surface = pygame.Surface((32,32)) surface.blit(image, (0,0), (i,0,32,32)) surface.set_colorkey(surface.get_at((0,0)), RLEACCEL) surface.convert() imageList.append(surface) return imageList class Character(pygame.sprite.Sprite): animcycle = 12 # アニメーション速度 frame = 0 def __init__(self, filename, x, y): pygame.sprite.Sprite.__init__(self, self.containers) self.images = split_image(load_image(filename)) self.image = self.images[0] self.rect = self.image.get_rect(topleft=(x,y)) def update(self): # キャラクターアニメーション self.frame += 1 self.image = self.images[self.frame/self.animcycle%4] def main(): pygame.init() screen = pygame.display.set_mode(SCR_RECT.size) pygame.display.set_caption(u"キャラクターアニメーション") all = pygame.sprite.RenderUpdates() Character.containers = all player = Character("player4.png", 0, 0) king = Character("king4.png", 32, 0) soldier = Character("soldier4.png", 64, 0) clock = pygame.time.Clock() while True: clock.tick(60) screen.fill((0,0,255)) all.update() all.draw(screen) pygame.display.update() for event in pygame.event.get(): if event.type == QUIT: sys.exit() if __name__ == "__main__": main()
イメージの分割
画像の移動と跳ね返り処理(2008/5/9)でも解説しましたが、アニメーションはちょっとずつ違った画像を連続して表示することで動いているように見せかけてます。たとえば、
も下の4つのキャラクターを連続して表示することで作っています。
まず上のように複数の画像が描かれた一枚絵をばらして4つのSurfaceを作る関数から作ります。下のは 32x128ピクセルのイメージを読み込み、32x32の4枚のイメージに分割し、分割したイメージを格納したリストを返す関数です。32x32の空の Surfaceを作成してそこに一枚絵の一部を描画して作っています。
def split_image(image): """32x128のキャラクターイメージを32x32の4枚のイメージに分割 分割したイメージを格納したリストを返す""" imageList = [] for i in range(0, 128, 32): surface = pygame.Surface((32,32)) surface.blit(image, (0,0), (i,0,32,32)) surface.set_colorkey(surface.get_at((0,0)), RLEACCEL) surface.convert() imageList.append(surface) return imageList
この関数は下のように使います。
# 分割したイメージをロード
self.images = split_image(load_image(filename))
load_image()はイメージを描画する(2008/5/5)で作成した関数です。load_image()で読み込んだ Surfaceをsplit_image()に渡して4つのSurfaceに分割するわけです。
キャラクターアニメーション
animcycle = 12 # アニメーション速度 frame = 0 def update(self): # キャラクターアニメーション self.frame += 1 self.image = self.images[self.frame/self.animcycle%4]
キャラクターアニメーションは、読み込んだ4つの画像をフレームごとに次々に切り替えて表示することで実現できます。まずanimcycleでアニメーション速度を定義します。これは、1つの画像を何フレーム表示するかを表しています。たとえば、下の例では12なので12フレームは同じ画像が表示され、12フレーム経過すると次の画像に切り替わります。当然、値が小さいほど速いアニメーションになります。何フレームたったか知るためにframeという変数を用意し、update()で更新しています。このframeの値を用いて表示する画像を選択するわけです。今回、一番重要なのは
self.image = self.images[self.frame/self.animcycle%4]
です。これは、分割した画像のリストから表示する画像を選択しています。Spriteはself.imageにセットした画像が描画されるのを思い出してください。スプライトの使い方(2008/5/17)。ここでは、self.frameの値によって描画する画像を変えているのがわかりますね。問題は、
self.frame/self.animcycle%4
が何を意味しているかですが、実際に下のように計算してみると案外簡単にわかります。ヒントを言うと%4の4はアニメーションに使う画像がいくつあるかを表しています。
# 0〜11フレームの12フレーム間は0番目の画像を描画 frame=0 → 0/12=0 → 0%4=0 frame=1 → 1/12=0 → 0%4=0 ... frame=11 → 11/12=0 → 0%4=0 # 12〜23フレームの12フレーム間は1番目の画像を描画 frame=12 → 12/12=1 → 1%4=1 frame=13 → 13/12=1 → 1%4=1 .. frame=23 → 23/12=1 → 1%4=1 # 24〜35フレームの12フレーム間は2番目の画像を描画 frame=24 → 24/12=2 → 2%4=2 ... frame=35 → 35/12=2 → 2%4=2 # 36〜47フレームの12フレーム間は3番目の画像を描画 frame=36 → 36/12=3 → 3%4=3 ... frame=47 → 47/12=3 → 3%4=3 # 48〜59フレームの12フレーム間は最初に戻って0番目の画像を描画 frame=48 → 48/12=4 → 4%4=0 ... frame=59 → 59/12=4 → 4%4=0