KUNISAN.JPトップ

KUNISAN.JPブログ - 3 / 1374 ページ

新規書き込み


ページ:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ... 1374

Python - リスト内包表記とPygameのスプライト機能

名前: 小川 邦久 リンク: http://kunisan.jp/ 日付: 2017年12月2日



Python - リスト内包表記とPygameのスプライト機能先日のPythonミニゲーム(DOG & BURGERS)の後、Webサーバー上で動くプログラムを作成しようと思っていました。しかし、その前にやっておきたいことが2点あったので、今回はそれを試す目的でサンプルプログラムを作成してみました。

以下、ソースコードです。

-------------------------
""" list_comprehension_sprite.py """

import math
import pygame
from pygame.locals import *
import sys

pygame.init()
SCR_RECT = Rect(0,0,400,300)
SURFACE = pygame.display.set_mode(SCR_RECT.size)
FPSCLOCK = pygame.time.Clock()

pygame.display.set_caption("Sunflowers")

class MySprite(pygame.sprite.Sprite):
""" スプライト定義 """
def __init__(self, filename, x=0, y=0):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(filename)
self.width = self.image.get_width()
self.height = self.image.get_height()
self.x = x
self.y = y
self.rect = Rect(self.x, self.y, self.width, self.height)
#スプライト表示
def locate(self, x = 9999, y = 9999):
if x < 9999:
self.x = x
if y < 9999:
self.y = y
self.rect = Rect(self.x, self.y, self.width, self.height)

def main():
""" メインルーチン """

#三角関数結果をリスト化(内包表記)
circle_x = [math.cos(math.pi/180*i) for i in range(360)]
circle_y = [math.sin(math.pi/180*i) for i in range(360)]

#スプライトグループ作成
sprites = pygame.sprite.Group()

#ひまわりスプライト定義(リスト)
sunflowers = []
for i in range(10):
sunflowers.append(0)
sunflowers[i] = MySprite("sunflowers.gif", circle_x[i*36]*100+200, circle_y[i*36]*100+200)
sprites.add(sunflowers[i])

#変数初期設定
circle_counter = 0
a = 0

while True:

#ウインドウ閉じるボタン
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()

#画面塗りつぶし
SURFACE.fill((0,0,0))

#角度カウンター
circle_counter += 1
if circle_counter >= 360:
circle_counter = 0

#ひまわり座標計算
for i in range(10):
a = circle_counter + i * 36
if a >= 360:
a -= 360
sunflowers[i].locate(circle_x[a]*100+175, circle_y[a]*110+125)

#スプライトグループ表示
sprites.draw(SURFACE)

#画面アップデート
pygame.display.update()
FPSCLOCK.tick(100)

if __name__ == '__main__':
main()
-------------------------


ファイル一式はこちらからダウンロードできます
※本プログラムやファイルの二次配布や二次掲載はご遠慮ください。個人的なプログラム改造はご自由にどうぞ。ただし、本プログラムに関するご質問等はお受けしません。

まずはリスト内包表記(List Comprehension)です。

今から30年近く前(高校2年でした)、X68000であるゲームを作っている時に、円運動するキャラクターを設置しようと思いつきました。シンプルに三角関数(サイン/sin、コサイン/cos)で座標を決めればいいと思っていたのですが、当時のパソコンは今のものに比べて処理速度が貧弱ということもあり、キャラクターを複数設置すると三角関数の繰り返しの計算の影響で、動作に遅延が起きるようになってしまいました。そこで考えついたのが、「三角関数の計算で得られた数値を予め配列変数に格納しておき、キャラクターの座標はその配列変数から順番に取り出していく」という方式です。これにより繰り返しの処理が変数から数値を取り出すだけになったことから、動作の遅延は解消されました。

Pythonでは配列変数とは言わず、「リスト」と呼びますが、今回のソースコードでは、以下の部分が三角関数(コサイン)の計算とリストへの格納になります。
circle_x = [math.cos(math.pi/180*i) for i in range(360)]


他の言語に慣れている人なら、恐らくこんな感じの方が馴染み深いと思います。
for i in range(360):
circle_x[i] = math.cos(math.pi/180*i)


これが一行でまとまる上に見た目も分かりやすいので、 これからも内包表記を多用していこうと思います。

ちなみに、比較的「低速」と言われるPythonですが、当時のX68000のX-BASIC+Cコンパイラーで作成したプログラムよりも断然早く、この程度の円運動なら繰り返し三角関数を計算させる方法でも全く問題ありませんでした(10倍速でも問題無いです)。しかし、今後大きなプログラムを作る時など、端末側に負担をかけない意味で、このやり方は慣れておいた方が良いかなと思っています。

次にスプライト(Sprite)機能です。

また昔話になりますが、上述のX68000のX-BASICや、その数年前のファミコンのプログラミングソフト「ファミリーBASIC」でもスプライト機能に対応していました。スプライト機能を使うとキャラクターを動かしつつ特別な処理をしなくても、背景画像が崩れることはありません。逆にスプライト機能が無いパソコンでは、キャラクターが動作した後に残像が残ってしまうため、その部分のみを都度描き直したり、もしくは画面全体を毎回リフレッシュして描画するなどの手法が必要でした。

ちなみに、昨年作成したHTML+JavaScriptのミニゲームでは、div要素をブロックにして座標を設定する形で、ほぼスプライト機能と同じことができました。

Pygameのスプライトについても、同じような機能を期待していたのですが、残念ながら何らかの処理をしない限り、キャラクターを動かした後に残像が残ってしまいます。そのため、今回作成したサンプルプログラムでは、動作毎に画面をリフレッシュする方式を取っています。

ただ、Pygameのスプライトは衝突(collision)判定が充実していて、グループ化の機能と合わせて使用すれば効率よくプログラムが書けるかも知れません。今回のサンプルプログラムにはその辺りの関数は含めていませんが、また近いうちにスプライト+衝突判定を利用したミニゲームを作ってみようと思います。





Python関連記事(リンク一覧): Python - リスト内包表記とPygameのスプライト機能 / Pythonの学習とPygameを使ったミニアクションゲーム作成 / ...(記事連続表示)

Pythonゲームプログラミング 知っておきたい数学と物理の基本 (Future Coders(NextPublishing)) eBook
Pythonゲームプログラミング 知っておきたい数学と物理の基本 (Future Coders(NextPublishing)) eBookをAmazon.co.jpでチェック


ページ:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ... 1374