第1回 インベーダーゲームもどきを作る
こんな画面をベースにゲームを作っていきます。

たまたま自作のUFO画像があったのでインベーダーゲームを作ることにしました。 見ての通りUFOがたくさんいます。動作はUFOが右に移動して右端にいったら左に進む。UFOが左端にいったら右に進む。これをを繰り返します。
これをどのように処理するか?

クラスを使う!

クラスの解説記事あちらこちらにあります。しかし、単なる使い方だけでどんなメリットがあるか?言及している記事はなかったような気がします。(多くの記事を見たわけではありませんが...)
UFOをプロパティーは、
①画像はみな同じ
②表示位置は異なる
③動作はみな同じ
となります。クラスの定義です。

class ufo(pygame.sprite.Sprite):
    def __init__(self, x,y, vx, vy, angle=0):
        pygame.sprite.Sprite.__init__(self)
        self.vx = vx
        self.vy = vy
        self.angle = angle
        self.image = pygame.image.load('ufo.png').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 = pygame.Rect(x, y, w, h)
        self.attacked = False

    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)
クラスufoはpygame.sprite.Sprite(特定の画像をゲーム画面に表示するためのシンプルな基底クラス)を継承して作成します。
インスタンス作成時の引数は、
x  画像のx座標
y  画像のy座標
vx 画像のx方向移動量
vy 画像のy方向移動量
angle 画像の回転量

self.rect = pygame.Rect(x, y, w, h)
このrectにはufoの位置情報が格納されます。

def update(self):
でUFOの動きを定義します。
self.rect.move_ip(self.vx, self.vy)
vx,vyの移動量によりufoを移動します。

次にufoの操作方法
#スプライトグループの作成
group = pygame.sprite.RenderUpdates()
groupにufoを追加する
# スプライトを描画
group.draw(screen)
これは複数のufoの update():を呼び出します。

滑らかに画像を移動する
ネットで紹介されているサンプルで画像がチカチカして動きが汚い(言いすぎか)ものがあります。滑らかに動かすことはできないのでしょうか!できます。
①画像の移動量を小さくする
②フレームレートを大きくする
ことで滑らかになります。
clock.tick(30)
この部分です。

全ソースです。

	import pygame
import pygame.sprite
import sys

SCREEN = pygame.Rect(0, 0, 640, 480) 

class ufo(pygame.sprite.Sprite):
    def __init__(self, x,y, vx, vy, angle=0):
        pygame.sprite.Sprite.__init__(self)
        self.vx = vx
        self.vy = vy
        self.angle = angle
        self.image = pygame.image.load('ufo.png').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 = pygame.Rect(x, y, w, h)
        self.attacked = False

    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)
        pass

  

def main():
    pygame.init()
    pygame.display.set_caption("Pygame スプライトでUFO")
    screen = pygame.display.set_mode(SCREEN.size)
    clock = pygame.time.Clock()
   #スプライトグループの作成
    group = pygame.sprite.RenderUpdates()
    # スプライトの追加
    #横8列、縦4行
    x = 16
    y = 16
    ufos = []
    for i in range(4):
        for j in range(8):
            ufo1= ufo(x,y, 3, 0, 0)
            group.add(ufo1) 
            x += 64
            ufos.append(ufo1)
        y +=50
        x = 16
    # ufos[0].remove(group) #この方法で削除できる
    ufos[0]
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                # 終了ボタンで終了
                pygame.quit()
                sys.exit()

        screen.fill((0, 64, 0)) # 画面の背景色
        # スプライトグループを更新
        # size = len(group)
        dir = 0
        for u  in group:
            if u.vx  + u.rect.right >= SCREEN.width:
                dir = 1
                break
            elif u.rect.left + u.vx < SCREEN.left:
                dir = -1
                break
        for u  in group:
            if dir == 1:
                u.vx = -abs(u.vx)
            elif  dir == -1:
                u.vx = abs(u.vx)

        group.update()
        # スプライトを描画
        group.draw(screen)
        pygame.display.update()
        clock.tick(30)

if __name__ == '__main__':
    main()