#!/usr/bin/env python
# -*- coding: utf-8 -*-
# -*- mode: python;Encoding: utf8n -*-
 
"""
Pygletサンプル
 
BG表示、スプライト表示、oggのループ再生を行う
 
- 座標は、左下が(0,0)になってることに注意
- ジョイスティックにも対応。pyglet 1.2 alpha 1 以上が必要。
 
- use pyglet 1.2 alpha 1
- use joystick
"""
 
import os
import sys
sys.path.insert(0, '.')
import PIL.Image
sys.modules['Image'] = PIL.Image
import math
import time
import pyglet
# pyglet.options['debug_gl'] = False
import pyglet.window
import pyglet.window.key
import pyglet.window.mouse
import pyglet.gl
import pyglet.resource
import pyglet.media
import pyglet.sprite
import pyglet.font
from pyglet.window import key
from pyglet.window import mouse
 
class Window(pyglet.window.Window):
    """ウインドウ用クラス"""
 
    def __init__(self, *args, **kwargs):
        super(Window, self).__init__(*args, **kwargs)
        self.step = 0
        self.set_vsync(False)
 
        self.running = True
        self.frame = 0  # フレームカウンタ
        self.count = 0
 
        self.fps_count = 0  # FPS算出用
        self.lasttime = time.time()
 
        self.updating = False  # 更新処理中かどうかのフラグ
        self.keys_held = []  # 入力されたキーの記録用
        self.batch_enable = False  # バッチを使って描画するか否か
 
        self.scr_w = self.width
        self.scr_h = self.height
        self.resize_fg = False
 
        self.bgm_file = ""
        self.bgm_src = None
 
        self.spr_batch = None
        self.bg_batch = None
        self.txt_batch = None
 
        self.image = None
        self.bgimg = []
 
        self.bgspr = []
        self.sprs = []
        self.label = []
        self.sprite = None
 
        self.sprdraw = True
        self.bgx = [0, 0]
        self.bgy = [0, 0]
 
        self.fntname = "Arial"
        self.font_bold = False
 
        # ジョイスティック用の初期化処理
        self.joystick_enable = False
        joysticks = pyglet.input.get_joysticks()
        if joysticks:
            self.joystick_enable = True
            self.joystick = joysticks[0]
            self.joystick.open()
 
        fpsrate = 60
 
        # FPS制限
        # ※ pyglet 1.1以降、schedule_interval() を使うなら不要らしい
        # pyglet.clock.set_fps_limit(fpsrate)
 
        # 更新処理を一定時間間隔で呼ぶように設定
        pyglet.clock.schedule_interval(self.update, 1.0 / float(fpsrate))
 
    def on_key_press(self, symbol, modifiers):
        """キーを押した瞬間のイベント"""
        if self.step == 0:
            return
 
        self.keys_held.append(symbol)  # キーをリストに記録
 
        if symbol == key.F2:
            # フルスクリーン/ウインドウ表示切り替え
            if not self.fullscreen:
                # フルスクリーン表示に設定
                self.set_fullscreen(fullscreen=True,
                                    width=self.width,
                                    height=self.height)
            else:
                # ウインドウ表示に設定
                self.set_fullscreen(fullscreen=False)
 
        if symbol == key.F3:
            # スプライト表示切り替え
            self.sprdraw = not self.sprdraw
 
        if symbol == key.F4:
            # FPS表示切り替え
            self.fps_disp_enable = not self.fps_disp_enable
 
        if symbol == key.F5:
            # バッチ描画切り替え
            self.batch_enable = not self.batch_enable
            self.label[8].text = "F5: BATCH %s" % \
            ("ON" if self.batch_enable else "OFF")
 
        if symbol == key.F6:
            # Vsync切り替え
            self.set_vsync(not self.vsync)
            self.label[9].text = "F6: VSYNC %s" % \
            ("ON" if self.vsync else "OFF")
 
        if symbol == key.Q or symbol == key.ESCAPE:  # アプリ終了を指示
            self.running = False
 
    def on_key_release(self, symbol, modifiers):
        """キーを離した際のイベント"""
        if symbol in self.keys_held:
            self.keys_held.pop(self.keys_held.index(symbol))  # キーを除外
 
    def on_mouse_press(self, x, y, button, modifiers):
        """マウスボタン押し下げイベント"""
        if self.step > 0:
            if button == mouse.LEFT:
                self.sprite.x = x
                self.sprite.y = y
 
    def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
        """マウスドラッグイベント"""
        if self.step > 0:
            if button == mouse.LEFT:
                self.sprite.x = x
                self.sprite.y = y
 
#     def on_resize(self, width, height):
#         """ウインドウリサイズイベント"""
#         super(Window, self).on_resize(width, height)
#         # print "on_resize(width=%d, height=%d)" % (width, height)
#         self.scr_w = width
#         self.scr_h = height
#         self.resize_fg = True
 
    def init_resource(self):
        """画像リソースその他を読み込み"""
 
        # リソースの場所を設定
        pyglet.resource.path = ['res']
        pyglet.resource.reindex()
 
        # フォント読み込み
        if False:
            pyglet.resource.add_font('VeraMoBd.ttf')
            pyglet.font.load("Bitstream Vera Sans Mono", bold=True)
            self.fntname = "Bitstream Vera Sans Mono"
            self.font_bold = True
        else:
            self.fntname = "Arial"
            self.font_bold = False
 
        # バッチ描画用の初期化
        self.bg_batch = pyglet.graphics.Batch()  # BG表示用
        self.spr_batch = pyglet.graphics.Batch()  # スプライト表示用
        self.txt_batch = pyglet.graphics.Batch()  # テキスト表示用
 
        # 画像読み込み
 
        # スプライト表示用の画像を読み込む
        self.image = pyglet.resource.image('ufo.png')
 
        # 基準座標を画像の中心にする
        self.image.anchor_x = self.image.width // 2
        self.image.anchor_y = self.image.height // 2
 
        # BG表示用の画像を読み込む
        self.bgimg = []
        self.bgimg.append(pyglet.resource.image('bg1.png'))
        self.bgimg.append(pyglet.resource.image('bg2.png'))
 
        # ogg読み込み
        self.bgm_file = "bgm32.ogg"
        if os.path.exists("./res/bgm32.wav"):
            self.bgm_file = "bgm32.wav"
 
        self.bgm_src = pyglet.resource.media(self.bgm_file, streaming=False)
 
    def init_bg(self):
        """BG初期化.
 
        512x512ドットのスプライトを4枚並べてBG1つ分、それを2枚作る
        """
        self.bgx = [0.0, 0.0]
        self.bgy = [0.0, 0.0]
        self.bgspr = []
        for i in range(2):
            for o in [[0, 0], [512, 0], [0, 512], [512, 512]]:
                bg = pyglet.sprite.Sprite(img=self.bgimg[i],
                                          x=o[0], y=o[1],
                                        batch=self.bg_batch
                                          )
                bg.scale = 1.0
                self.bgspr.append(bg)
 
    def init_sprite(self):
        """スプライト群を初期化"""
 
        # 画面内を跳ね回る(?)スプライトを発生
        ufo_num = 512
        self.sprs = []
        self.sprdraw = True
        sx = self.width / 2
        sy = self.height / 2
        r = 3.0
        for i in range(ufo_num):
            ang = i * 360.0 / ufo_num
            ufo = pyglet.sprite.Sprite(img=self.image, x=sx, y=sy,
                                        batch=self.spr_batch
                                       )
            rad = math.radians(ang)
            ufo.dx = r * math.cos(rad)
            ufo.dy = r * math.sin(rad)
            ufo.fpx = float(sx)
            ufo.fpy = float(sy)
            ufo.scale = 1.0
            self.sprs.append(ufo)
 
        # 入力機器の動作確認用スプライトを発生
        self.sprite = pyglet.sprite.Sprite(img=self.image, x=sx, y=sy,
                                            batch=self.spr_batch
                                           )
        self.sprite.scale = 1.0
 
        # self.sprite.scale = 1.5
 
    def init_text(self):
        """テキスト描画関係を初期化"""
 
        # 表示するテキスト群
        mesdt = ["FPS",  # 0
                 "Joystick None",  # 1
                 "BGM",  # 2
                 "avbin Ver.",  # 3
                 "", # 4
                 "F2: Full/Wdw", # 5
                 "F3: SPR", # 6
                 "F4: L-FPS", # 7
                 "F5: BATCH OFF", # 8
                 "F6: VSYNC OFF", # 9
                 "Mouse Click: ?",
                 "Cursor Key: ?",
                 "ESC,Q: EXIT"]
        tx = 10
        ty = 450
        fsize = 10
        self.label = []
        for s in mesdt:
            lbl = pyglet.text.Label(text=s, font_name=self.fntname,
                                    font_size=fsize, bold=self.font_bold,
                                    x=tx, y=ty,
                                    batch=self.txt_batch
                                    )
            self.label.append(lbl)
            ty -= (fsize + 6)
 
        # FPS表示のための初期化
        self.fps_disp_enable = True
        self.fps_disp = pyglet.clock.ClockDisplay(format='%(fps).2f FPS',
                                                  color=(1, 1, 1, 0.75))
 
        # ジョイスティックが繋がっているなら、そのことも表示
        if self.joystick_enable:
            self.label[1].text = "Joystick"
 
        self.label[2].text = "play %s" % (self.bgm_file)
 
    def init_sound(self):
        """ogg再生開始"""
        if pyglet.media.have_avbin:
            self.label[3].text = \
            "avbin ver = %d" % (pyglet.media.avbin.get_version())
        else:
            self.label[3].text = "not have avbin"
 
        # self.sndplayer = pyglet.media.Player()
        self.sndplayer = pyglet.media.ManagedSoundPlayer()
        self.sndplayer.queue(self.bgm_src)  # キューに入れる
        self.sndplayer.eos_action = self.sndplayer.EOS_LOOP  # ループ再生を指定
        self.sndplayer.play()  # 再生開始
 
    def update(self, dt):
        """座標更新処理"""
 
        if self.updating:
            # 前回の更新処理が終わって無ければ、何もせずに戻る
            return
 
        self.updating = True  # 処理中フラグを設定
 
        if self.step == 0:
            # 初期化処理
            self.init_resource()
            self.init_bg()
            self.init_sprite()
            self.init_text()
            self.init_sound()
            self.step = 1
        elif self.step == 1:
            # BGスクロール
            ofsx = math.cos(math.radians(self.frame))
            self.bgx[0] = -64.0 + (64.0 * ofsx)
            self.bgx[1] = -128.0 + (128.0 * ofsx)
            self.bgy[0] = (self.bgy[0] + 2.0) % 512.0
            self.bgy[1] = (self.bgy[1] + 6.0) % 512.0
 
            bgid = 0
            for i in range(2):
                for o in [[0, 0], [512, 0], [0, 512], [512, 512]]:
                    bg = self.bgspr[bgid]
                    bg.set_position(int(self.bgx[i] + o[0]),
                                    int(-self.bgy[i] + o[1]))
                    bgid += 1
 
            # スプライト群の移動
            x_min = 32.0
            y_min = 32.0
            x_max = float(self.width - 32.0)
            y_max = float(self.height - 32.0)
            for ufo in self.sprs:
                ufo.fpx += ufo.dx
                ufo.fpy += ufo.dy
                if ufo.fpx < x_min or ufo.fpx > x_max:
                    ufo.dx *= -1.0
                if ufo.fpy < y_min or ufo.fpy > y_max:
                    ufo.dy *= -1.0
                ufo.set_position(ufo.fpx, ufo.fpy)
 
            self.sprite.rotation += 4
 
            # 押されたキーによってスプライトを移動
            spd = 6.0
            if key.LEFT in self.keys_held:
                self.sprite.x -= spd
            if key.RIGHT in self.keys_held:
                self.sprite.x += spd
            if key.UP in self.keys_held:
                self.sprite.y += spd
            if key.DOWN in self.keys_held:
                self.sprite.y -= spd
 
            # ジョイスティックの入力値でスプライトを移動
            if self.joystick_enable:
                # デジタルバッドの場合、x,y は -1,0,1 の値が得られる
                jx = self.joystick.x
                jy = self.joystick.y
                self.sprite.x += (jx * spd)
                self.sprite.y += (-jy * spd)
                self.label[1].text = "Joystick (%.2f,%.2f)" % (jx, jy)
 
                self.sprite.scale = 0.5
                self.sprite.opacity = 255
                self.sprite.color = (255, 255, 255)
 
                # ボタン情報は True/False が入っている
                if self.joystick.buttons[0]:
                    self.sprite.scale = 2.0
                if self.joystick.buttons[1]:
                    self.sprite.opacity = 128
                if self.joystick.buttons[2]:
                    self.sprite.color = (255, 255, 0)
 
            if not self.running:
                self.step = 2
 
        elif self.step == 2:
            # BGMフェードアウト開始
            self.count = 1.0
            self.step = 3
 
        elif self.step == 3:
            # BGMフェードアウト中
            self.sndplayer.volume = self.count
            self.count -= 0.05
            if self.count <= 0.0:
                self.sndplayer.pause()
                self.step = 4
 
        elif self.step == 4:
            pyglet.app.exit()  # アプリ終了
 
        self.frame += 1  # フレームカウンタをインクリメント
 
        self.updating = False  # 処理中フラグをクリア
 
    def calc_fps(self):
        """FPS算出"""
        if time.time() - self.lasttime >= 1:
            # 1秒以上時間が経っていたら、FPS表示値を更新
            self.label[0].text = "FPS: %d" % (self.fps_count)
            self.fps_count = 0
            self.lasttime = time.time()
        else:
            self.fps_count += 1
 
    def on_draw(self):
        """描画処理"""
        if self.step <= 0:
            return  # 初期化がまだなら、何もせず戻る
 
        # pyglet.clock.tick()  # 時間待ち、らしい
        self.clear()  # 画面クリア
 
        if self.batch_enable:
            # バッチ描画する場合
            self.bg_batch.draw()  # BG描画
 
            if self.sprdraw:
                self.spr_batch.draw()  # スプライト描画
 
            self.calc_fps()
            self.txt_batch.draw()  # テキスト描画
 
        else:
            # バッチ描画をしない場合
            for bg in self.bgspr:
                bg.draw()
 
            if self.sprdraw:
                for spr in self.sprs:
                    spr.draw()
 
                self.sprite.draw()
 
            self.calc_fps()
            for lbl in self.label:
                lbl.draw()
 
        if self.fps_disp_enable:
            self.fps_disp.draw()  # FPS表示(大)
 
        # self.flip()
 
def main():
    # ウインドウ生成
    window = Window(width=640,
                    height=480,
                    caption='Pyglet Sample',
                    # resizable=True,
                    # vsync=True
                    )
 
    pyglet.app.run()  # イベントループ開始
 
if __name__ == '__main__':
    main()
 
最終更新:2013年05月13日 20:28