木曜日, 1月 21, 2010

ClutterのチュートリアルをPyClutterに翻訳 その2

ClutterのチュートリアルをPyClutterに翻訳するその2

Scoreを使って複数のタイムラインを流すところの前半まで。後半のところはPyClutterの問題なのか、うまく出来ないので、原因を調査中。
追記:原因解明。何が問題だったのかは後で書く。

複数タイムラインの次は画像の読み込みのチュートリアルだけど、画像を用意するのが面倒なのでやらない。

大きさの変更やオブジェクトの選択


まわして、かくだい
#!/usr/bin/python
# -*- coding: utf-8 -*-

import clutter
import mathhacks

global rotation
global scale
rotation = 0
scale = 0


def on_timeline_new_frame(timeline, frame_num, rect_list):
global rotation
global scale

rotation += 0.3
rect_list[0].set_rotation(clutter.Z_AXIS, rotation * 5, 0, 0, 0)
rect_list[1].set_rotation(clutter.Z_AXIS, rotation * 4, 0, 0, 0)
rect_list[2].set_rotation(clutter.Z_AXIS, rotation * 3, 0, 0, 0)
rect_list[3].set_rotation(clutter.Z_AXIS, rotation * 2, 0, 0, 0)
rect_list[4].set_rotation(clutter.Z_AXIS, rotation * 1, 0, 0, 0)
rect_list[5].set_rotation(clutter.Z_AXIS, rotation * 0.5, 0, 0, 0)

scale += 0.01
if scale > 1.0:
scale = 0

scale_amount = mathhacks.smooth_step2(1.0, 2.0, scale)
for rect in rect_list:
rect.set_scale(scale_amount, scale_amount)


def quit(actor, *args):
clutter.main_quit()


def create_rect(color):
rect = clutter.Rectangle(color)
rect.set_size(256, 128)
rect.set_position(128, 128)
rect.set_anchor_point(128, 64)

return rect


clutter.init()
stage_color = clutter.Color(0, 0, 0, 255)
stage = clutter.Stage()
stage.set_size(512, 512)
stage.set_color(stage_color)

red = clutter.Color(255, 0, 0, 128)
green = clutter.Color(0, 255, 0, 128)
blue = clutter.Color(0, 0, 255, 128)
yellow = clutter.Color(255, 255, 0, 128)
cyan = clutter.Color(0, 255, 255, 128)
purple = clutter.Color(255, 0, 255, 128)

rect_list = []
rect_list.append(create_rect(red))
rect_list.append(create_rect(green))
rect_list.append(create_rect(blue))
rect_list.append(create_rect(yellow))
rect_list.append(create_rect(cyan))
rect_list.append(create_rect(purple))

stage.connect('hide', quit)
stage.show()

for r in rect_list:
stage.add(r)

timeline = clutter.Timeline(60)
timeline.connect('new-frame', on_timeline_new_frame, rect_list)
timeline.set_loop(True)
timeline.start()

clutter.main()


まわして、かくだいして、おしたらきえる
#!/usr/bin/python
# -*- coding: utf-8 -*-

import clutter
import mathhacks

global rotation
global scale
rotation = 0
scale = 0


def on_timeline_rotation_new_frame(timeline, frame_num, rect_list):
global rotation

rotation += 0.3
rect_list[0].set_rotation(clutter.Z_AXIS, rotation * 5, 0, 0, 0)
rect_list[1].set_rotation(clutter.Z_AXIS, rotation * 4, 0, 0, 0)
rect_list[2].set_rotation(clutter.Z_AXIS, rotation * 3, 0, 0, 0)
rect_list[3].set_rotation(clutter.Z_AXIS, rotation * 2, 0, 0, 0)
rect_list[4].set_rotation(clutter.Z_AXIS, rotation * 1, 0, 0, 0)
rect_list[5].set_rotation(clutter.Z_AXIS, rotation * 0.5, 0, 0, 0)

def on_timeline_scale_new_frame(timeline, frame_num, rect_list):
global scale
scale += 0.01
if scale > 1.0:
scale = 0

scale_amount = mathhacks.smooth_step2(1.0, 2.0, scale)
for rect in rect_list:
rect.set_scale(scale_amount, scale_amount)

def on_stage_button_press(stage, event, *arg):
x = 0
y = 0
x, y = event.x, event.y
clicked = stage.get_actor_at_pos(clutter.PICK_ALL, x, y)
if clicked == stage:
return
clicked.hide()

def quit(actor, *args):
clutter.main_quit()


def create_rect(color):
rect = clutter.Rectangle(color)
rect.set_size(256, 128)
rect.set_position(128, 128)
rect.set_anchor_point(128, 64)

return rect


clutter.init()
stage_color = clutter.Color(0, 0, 0, 255)
stage = clutter.Stage()
stage.set_size(512, 512)
stage.set_color(stage_color)

red = clutter.Color(255, 0, 0, 128)
green = clutter.Color(0, 255, 0, 128)
blue = clutter.Color(0, 0, 255, 128)
yellow = clutter.Color(255, 255, 0, 128)
cyan = clutter.Color(0, 255, 255, 128)
purple = clutter.Color(255, 0, 255, 128)

rect_list = []
rect_list.append(create_rect(red))
rect_list.append(create_rect(green))
rect_list.append(create_rect(blue))
rect_list.append(create_rect(yellow))
rect_list.append(create_rect(cyan))
rect_list.append(create_rect(purple))

stage.connect("button-press-event", on_stage_button_press)
stage.connect('hide', quit)
stage.show()

for r in rect_list:
stage.add(r)

timeline = clutter.Timeline(60)
timeline.connect('new-frame', on_timeline_new_frame, rect_list)
timeline.set_loop(True)
timeline.start()

clutter.main()

スコアを記録する


#!/usr/bin/python
# -*- coding: utf-8 -*-

import clutter
import mathhacks

global rotation
global scale
rotation = 0
scale = 0


def on_timeline_rotation_new_frame(timeline, frame_num, rect_list):
global rotation

rotation += 0.3
rect_list[0].set_rotation(clutter.Z_AXIS, rotation * 5, 0, 0, 0)
rect_list[1].set_rotation(clutter.Z_AXIS, rotation * 4, 0, 0, 0)
rect_list[2].set_rotation(clutter.Z_AXIS, rotation * 3, 0, 0, 0)
rect_list[3].set_rotation(clutter.Z_AXIS, rotation * 2, 0, 0, 0)
rect_list[4].set_rotation(clutter.Z_AXIS, rotation * 1, 0, 0, 0)
rect_list[5].set_rotation(clutter.Z_AXIS, rotation * 0.5, 0, 0, 0)


def on_timeline_scale_new_frame(timeline, frame_num, rect_list):
global scale
scale += 0.01
if scale > 1.0:
scale = 0

scale_amount = mathhacks.smooth_step2(1.0, 2.0, scale)
for rect in rect_list:
rect.set_scale(scale_amount, scale_amount)


def on_stage_button_press(stage, event, *arg):
x = 0
y = 0
(x, y) = (event.x, event.y)
clicked = stage.get_actor_at_pos(clutter.PICK_ALL, x, y)
if clicked == stage:
return
clicked.hide()


def quit(actor, *args):
clutter.main_quit()


def create_rect(color):
rect = clutter.Rectangle(color)
rect.set_size(256, 128)
rect.set_position(128, 128)
rect.set_anchor_point(128, 64)

return rect


clutter.init()
stage_color = clutter.Color(0, 0, 0, 255)
stage = clutter.Stage()
stage.set_size(512, 512)
stage.set_color(stage_color)

red = clutter.Color(255, 0, 0, 128)
green = clutter.Color(0, 255, 0, 128)
blue = clutter.Color(0, 0, 255, 128)
yellow = clutter.Color(255, 255, 0, 128)
cyan = clutter.Color(0, 255, 255, 128)
purple = clutter.Color(255, 0, 255, 128)

rect_list = []
rect_list.append(create_rect(red))
rect_list.append(create_rect(green))
rect_list.append(create_rect(blue))
rect_list.append(create_rect(yellow))
rect_list.append(create_rect(cyan))
rect_list.append(create_rect(purple))

stage.connect('button-press-event', on_stage_button_press)
stage.connect('hide', quit)

for r in rect_list:
stage.add(r)

score = clutter.Score()
score.set_loop(True)

timeline_rotation = clutter.Timeline(500)
timeline_rotation.connect('new-frame', on_timeline_rotation_new_frame,
rect_list)
score.append(timeline_rotation)

timeline_scale = clutter.Timeline(500)
timeline_scale.connect('new-frame', on_timeline_scale_new_frame,
rect_list)
score.append(timeline_scale)
score.start()

stage.show()
clutter.main()


2つのTimelineを接続する


pyclutterのREADMEを読むと書いてあるが、Score#appendの引数の順番は、CのAPIと違っている。昨日はこれに気づかなかった。ちゃんとREADMEは読めという話ですね。
これはよりPythonicな書き方をするためらしい。こういうのは今後もあると思われ。
#!/usr/bin/python
# -*- coding: utf-8 -*-

import clutter
import mathhacks

# 回転情報
global rotation
global scale
rotation = 0
scale = 0


def on_timeline_rotation_new_frame(timeline, frame_num, rect_list):
global rotation

rotation += 0.3
rect_list[0].set_rotation(clutter.Z_AXIS, rotation * 5, 0, 0, 0)
rect_list[1].set_rotation(clutter.Z_AXIS, rotation * 4, 0, 0, 0)
rect_list[2].set_rotation(clutter.Z_AXIS, rotation * 3, 0, 0, 0)
rect_list[3].set_rotation(clutter.Z_AXIS, rotation * 2, 0, 0, 0)
rect_list[4].set_rotation(clutter.Z_AXIS, rotation * 1, 0, 0, 0)
rect_list[5].set_rotation(clutter.Z_AXIS, rotation * 0.5, 0, 0, 0)


def on_timeline_scale_new_frame(timeline, frame_num, rect_list):
global scale
scale += 0.01
if scale > 1.0:
scale = 0

scale_amount = mathhacks.smooth_step2(1.0, 2.0, scale)
for rect in rect_list:
rect.set_scale(scale_amount, scale_amount)


def on_stage_button_press(stage, event, *arg):
x = 0
y = 0
(x, y) = (event.x, event.y)
clicked = stage.get_actor_at_pos(clutter.PICK_ALL, x, y)
if clicked == stage:
return
clicked.hide()


def quit(actor, *args):
clutter.main_quit()


def create_rect(color):
rect = clutter.Rectangle(color)
rect.set_size(256, 128)
rect.set_position(128, 128)
rect.set_anchor_point(128, 64)

return rect


clutter.init()
stage_color = clutter.Color(0, 0, 0, 255)
stage = clutter.Stage()
stage.set_size(512, 512)
stage.set_color(stage_color)

red = clutter.Color(255, 0, 0, 128)
green = clutter.Color(0, 255, 0, 128)
blue = clutter.Color(0, 0, 255, 128)
yellow = clutter.Color(255, 255, 0, 128)
cyan = clutter.Color(0, 255, 255, 128)
purple = clutter.Color(255, 0, 255, 128)

rect_list = []
rect_list.append(create_rect(red))
rect_list.append(create_rect(green))
rect_list.append(create_rect(blue))
rect_list.append(create_rect(yellow))
rect_list.append(create_rect(cyan))
rect_list.append(create_rect(purple))

stage.connect('button-press-event', on_stage_button_press)
stage.connect('hide', quit)

for r in rect_list:
stage.add(r)

score = clutter.Score()
score.set_loop(True)

timeline_rotation = clutter.Timeline(500)
timeline_rotation.connect('new-frame', on_timeline_rotation_new_frame,
rect_list)
score.append(timeline_rotation)

timeline_scale = clutter.Timeline(500)
timeline_scale.connect('new-frame', on_timeline_scale_new_frame,
rect_list)
score.append(timeline_scale, timeline_rotation)
score.start()

stage.show()
clutter.main()

火曜日, 1月 19, 2010

ClutterのチュートリアルをPyClutterに翻訳 その1

Mikeforce::HomePageのClutterチュートリアルの和訳をPyClutterでやってみる。

覚えておいてほしいこととして、あくまでのこの記事は Clutter のドキュメントで今現在不足している箇所を補うための「臨時措置」みたいなものだということです。私たちは、もっと広い視野でみた Python を中心とする Clutter のチュートリアルを作成中ですが、それを完成するには2,3ヶ月必要であるとみています。その間は、ここで紹介するチュートリアルで我慢していただき、 Clutter を使ったプログラミングを楽しんで欲しいと考えています。

と書いてあるので、そのうち本気措置が取られる事を期待しつつ、とりあえず前半戦

初めの一歩


黒い枠が出来るだけ。
import clutter

clutter.init()
color = clutter.Color(0, 0, 0, 255)
stage = clutter.Stage()
stage.set_size(512, 512)
stage.set_color(color)
stage.show()

clutter.main()


四角を追加
import clutter

clutter.init()
stage_color = clutter.Color(0, 0, 0, 255)
stage = clutter.Stage()
stage.set_size(512, 512)
stage.set_color(stage_color)

actor_color = clutter.Color(0, 255, 0, 128)
rect = clutter.Rectangle(actor_color)
rect.set_size(100, 100)
rect.set_position(100, 100)

stage.add(rect)
stage.show()
clutter.main()


必要に応じて長方形を描画する


元ネタでは、長方形の描画とstageへの登録を同じ関数内でやっているのだけど、個人的にそれが嫌なので、四角を作るだけにした。
あと、PyClutterの場合、メインのウィンドウを閉じてもプロセスが生き続けてしまうので、それを避けるために、stageのhideシグナルに終了処理をくっつけた。
import clutter

"""ウィンドウを閉じたときに終了するためのclosure"""
def quit(actor, *args):
clutter.main_quit()

"""関数内でaddするのが嫌だったのでrectを作るだけ"
def create_rect(color):
rect = clutter.Rectangle(color)
rect.set_size(256, 128)
rect.set_position(128, 128)

return rect


stage_color = clutter.Color(0, 0, 0, 255)
stage = clutter.Stage()
stage.set_size(512, 512)
stage.set_color(stage_color)

actor_color = clutter.Color(0, 255, 0, 128)
rect = create_rect(actor_color)
stage.add(rect)
# 終了関数を設定
stage.connect('hide', quit)
stage.show()
clutter.main()


アニメーション一歩手前


#!/usr/bin/python
# -*- coding: utf-8 -*-

import clutter


def quit(actor, *args):
clutter.main_quit()


def create_rect(color):
rect = clutter.Rectangle(color)
rect.set_size(256, 128)
rect.set_position(128, 128)

return rect


clutter.init()
stage_color = clutter.Color(0, 0, 0, 255)
stage = clutter.Stage()
stage.set_size(512, 512)
stage.set_color(stage_color)

red = clutter.Color(255, 0, 0, 128)
green = clutter.Color(0, 255, 0, 128)
blue = clutter.Color(0, 0, 255, 128)
yellow = clutter.Color(255, 255, 0, 128)
cyan = clutter.Color(0, 255, 255, 128)
purple = clutter.Color(255, 0, 255, 128)

rect1 = create_rect(red)
rect2 = create_rect(green)
rect3 = create_rect(blue)
rect4 = create_rect(yellow)
rect5 = create_rect(cyan)
rect6 = create_rect(purple)

stage.add(rect1)
stage.add(rect2)
stage.add(rect3)
stage.add(rect4)
stage.add(rect5)
stage.add(rect6)

stage.connect('hide', quit)
stage.show()
clutter.main()


アニメーション


処理をシンプルにするために、四角形をリストに入れて運ぶようにしている。
on_timeline_new_frameの中がかっこ悪いのが気になる。
#!/usr/bin/python
# -*- coding: utf-8 -*-

import clutter

# 回転情報
global rotation
rotation = 0


def on_timeline_new_frame(timeline, frame_num, rect_list):
global rotation
rotation += 0.3
rect_list[0].set_rotation(clutter.Z_AXIS, rotation * 5, 0, 0, 0)
rect_list[1].set_rotation(clutter.Z_AXIS, rotation * 4, 0, 0, 0)
rect_list[2].set_rotation(clutter.Z_AXIS, rotation * 3, 0, 0, 0)
rect_list[3].set_rotation(clutter.Z_AXIS, rotation * 2, 0, 0, 0)
rect_list[4].set_rotation(clutter.Z_AXIS, rotation * 1, 0, 0, 0)
rect_list[5].set_rotation(clutter.Z_AXIS, rotation * 0.5, 0, 0, 0)


def quit(actor, *args):
clutter.main_quit()


def create_rect(color):
rect = clutter.Rectangle(color)
rect.set_size(256, 128)
rect.set_position(128, 128)

return rect


clutter.init()
stage_color = clutter.Color(0, 0, 0, 255)
stage = clutter.Stage()
stage.set_size(512, 512)
stage.set_color(stage_color)

red = clutter.Color(255, 0, 0, 128)
green = clutter.Color(0, 255, 0, 128)
blue = clutter.Color(0, 0, 255, 128)
yellow = clutter.Color(255, 255, 0, 128)
cyan = clutter.Color(0, 255, 255, 128)
purple = clutter.Color(255, 0, 255, 128)

rect_list = []
rect_list.append(create_rect(red))
rect_list.append(create_rect(green))
rect_list.append(create_rect(blue))
rect_list.append(create_rect(yellow))
rect_list.append(create_rect(cyan))
rect_list.append(create_rect(purple))

stage.connect('hide', quit)
stage.show()

for r in rect_list:
stage.add(r)

timeline = clutter.Timeline(60)
timeline.connect('new-frame', on_timeline_new_frame, rect_list)
timeline.set_loop(True)
timeline.start()

clutter.main()


アニメーション アンカーポイントを変更


#!/usr/bin/python
# -*- coding: utf-8 -*-

import clutter

# 回転情報
global rotation
rotation = 0


def on_timeline_new_frame(timeline, frame_num, rect_list):
global rotation
rotation += 0.3
rect_list[0].set_rotation(clutter.Z_AXIS, rotation * 5, 0, 0, 0)
rect_list[1].set_rotation(clutter.Z_AXIS, rotation * 4, 0, 0, 0)
rect_list[2].set_rotation(clutter.Z_AXIS, rotation * 3, 0, 0, 0)
rect_list[3].set_rotation(clutter.Z_AXIS, rotation * 2, 0, 0, 0)
rect_list[4].set_rotation(clutter.Z_AXIS, rotation * 1, 0, 0, 0)
rect_list[5].set_rotation(clutter.Z_AXIS, rotation * 0.5, 0, 0, 0)


def quit(actor, *args):
clutter.main_quit()


def create_rect(color):
rect = clutter.Rectangle(color)
rect.set_size(256, 128)
rect.set_position(128, 128)
rect.set_anchor_point(128, 64)

return rect


clutter.init()
stage_color = clutter.Color(0, 0, 0, 255)
stage = clutter.Stage()
stage.set_size(512, 512)
stage.set_color(stage_color)

red = clutter.Color(255, 0, 0, 128)
green = clutter.Color(0, 255, 0, 128)
blue = clutter.Color(0, 0, 255, 128)
yellow = clutter.Color(255, 255, 0, 128)
cyan = clutter.Color(0, 255, 255, 128)
purple = clutter.Color(255, 0, 255, 128)

rect_list = []
rect_list.append(create_rect(red))
rect_list.append(create_rect(green))
rect_list.append(create_rect(blue))
rect_list.append(create_rect(yellow))
rect_list.append(create_rect(cyan))
rect_list.append(create_rect(purple))

stage.connect('hide', quit)
stage.show()

for r in rect_list:
stage.add(r)

timeline = clutter.Timeline(60)
timeline.connect('new-frame', on_timeline_new_frame, rect_list)
timeline.set_loop(True)
timeline.start()

clutter.main()


続きはまた今度。

日曜日, 1月 17, 2010

PyClutter 33行のHello, World的なコード

PyClutterはClutterのPythonバインド。
基本的な使い方はベースとなっているGtkとあまり変わらない。
import clutter

def main():
stage = clutter.Stage()
stage.set_color(clutter.Color(0xaa, 0xbb, 0xcc, 0xff))
stage.set_size(200, 200)

label = clutter.Text()
label.set_text('clutter')

button = clutter.Rectangle()
button.set_color(clutter.Color(0xcc, 0xbb, 0xaa, 0xff))
button.set_width(100)
button.set_height(100)
button.set_x(50)
button.set_y(50)
button.set_reactive(True)

stage.add(label)
stage.add(button)
stage.connect('button-press-event', change, label)
stage.connect('hide', quit)
stage.show_all()

def change(actor, event, label):
label.set_text('press button')

def quit(actor):
clutter.main_quit()

if __name__ == '__main__':
main()
clutter.main()

日曜日, 1月 03, 2010

スクリプト書き初め2010

「年末年始はスクリプト書く!」という人に触発されて、スクリプト書き初めをやってみました。
実行結果はこのようになります。



以下コード。
pygameでも出来ただろうけど、あえてPyClutterを使っています。
下敷きにしたのは、PyClutterサンプルのflower.py。
先に言い訳を書いておくと、コメントとか一切無いのは書き初めなので一気に書いたから、改行に見苦しい点があるのはpythontidyのせいです。

#!/usr/bin/python
# -*- coding: utf-8 -*-

import clutter
from clutter import CairoTexture
import cairo
import gobject

import sys
import random

BACKGROUND_COLOR = (0xee, 0xee, 0xee, 0xff)


class Snow(CairoTexture):

colors = (
(0.6, 0.7, 0.9, 0.5),
(0.6, 0.7, 1.0, 0.5),
(0.7, 0.9, 0.9, 0.5),
(0.7, 0.7, 1.0, 0.5),
(0.8, 0.7, 0.9, 0.5),
(0.8, 0.9, 1.0, 0.5),
)

def __init__(
self,
x,
y,
translation_velocity,
rotation_velocity,
ground,
):

self.x = x
self.y = y
self.rot = 0
self.v = translation_velocity
self.rv = rotation_velocity
self.ground = ground

CairoTexture.__init__(self, 20, 20)
cr = self.cairo_create()
cr.move_to(0, 0)
cr.rectangle(2, 2, 16, 16)
random_color = Snow.colors[random.randint(0, 5)]
cr.set_source_rgba(*random_color)
cr.paint()

def tick(self, max_width, max_height):
if self.ground - 10 < self.get_y():
return
self.y += self.v
self.rot += self.rv

if self.y > max_height:
self.y = -self.get_height()

self.set_position(self.x, self.y)
self.set_rotation(clutter.Z_AXIS, self.rot, self.get_width()
/ 2, self.get_height() / 2, 0)


class Kakizome(CairoTexture):

def __init__(self):
self.stage = clutter.Stage()
self.stage.set_color(clutter.Color(*BACKGROUND_COLOR))
self.stage.set_size(640, 480)
self.stage.set_title('Kakizome 2010')
self.started = False
self.ground = self.stage.get_height()

self.label = self.create_label('Hello, New Year.')
self.label.set_depth(1.0)
self.stage.add(self.label)

self.snows = list()

self.timeline = clutter.Timeline(500)
self.timeline.set_loop(True)
self.stage.connect('key-press-event', self.on_key_press)

gobject.timeout_add(50, self.tick, self.snows,
self.get_width(), self.stage.get_height())

def create_label(self, message):
label_color = clutter.Color(*BACKGROUND_COLOR)
label = clutter.Text()
label.set_text(message)
label.set_font_name('Mono 32')
label.set_color(label_color)
label_x = (self.stage.get_width() - label.get_width()) - 50
label.set_position(label_x, (self.stage.get_height() / 3) * 2)
return label

def tick(self, snows, height, width):
for snow in snows:
snow.tick(height, width)
if self.ground < 0:
return True

if random.randint(0, 1000) % 125 == 0:
self.ground -= 5

self.fall_snow()

return True

def fall_snow(self):
snow = Snow(random.randint(-10, self.stage.get_width()), -20,
random.randint(1, 5), random.randint(3, 5),
self.ground)
self.stage.add(snow)
snow.set_position(snow.x, snow.y)
self.snows.append(snow)

def run(self):
self.stage.show_all()
self.timeline.start()
clutter.main()

def on_key_press(self, actor, event):
key = event.get_key_symbol()
if key == clutter.keysyms.q:
clutter.main_quit()


if __name__ == '__main__':
app = Kakizome()
app.run()
sys.exit(0)