俺「作りましょう!」(と心の中で決意)
【概要】
- 「Push Start!」ボタンを押すとルーレットが回り始める
- 「Running...」中はルーレットが減速しながら回り続ける
- 一定速度以下になると停止し、「Once More!」ボタンが現れる
4つのファイルを使ってます。
- main.py(実行)
- roulette.kv(設定)
- make_figures.py(ルーレット図の作成)←要numpy,matplotlib
- 実行すると、figuresディレクトリ内にfig_x_of_n.pngを作成する
- nはルーレットの目の数で、xはその図の中でどの数字がハイライトされているか
- main.pyの中で「filename_first + str(i) + filename_last」となっているのは読み込まれるファイルを指定している
- make_sound.py(ルーレット音の作成)
- 実行すると、ディレクトリ内にsound.wavを作成する
- 録画では鳴ってないけどルーレットが回転するごとに800Hzの音が100ms流れてます
make_系は予め走らせておいて必要な図を作っておきます
<main.py>
# -*- coding: utf-8 -*-
import kivy
kivy.require('1.9.0')
from kivy.app import App
from kivy.clock import Clock
from kivy.core.window import Window
from kivy.core.audio import SoundLoader
from kivy.properties import StringProperty, ObjectProperty
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
from kivy.uix.widget import Widget
from kivy.uix.button import Button
import sys
import os
import random
number_of_player = 5
sound = SoundLoader.load('sound.wav')
filename_first = 'figures/fig_'
filename_last = '_of_' + str(number_of_player) + '.png'
class StartButton(Button):
state = StringProperty('Push Start!')
class RouletteImage(Widget):
filename = StringProperty(filename_first + 'none' + filename_last)
def filename_update(self, counter):
value = counter % number_of_player + 1
self.filename = filename_first + str(value) + filename_last
class Root(FloatLayout):
sb = ObjectProperty(None)
ri = ObjectProperty(None)
val = 0; c_val = 0.02
n_move = 0
timer = 0
update_fps = 1 / 60
def update(self, dt):
if self.sb.state == 'Push Start!':
pass
elif self.sb.state == 'Running...':
self.when_running()
elif self.sb.state == 'Once More!':
self.when_once_more()
def when_running(self):
if self.val == 0:
self.counter = random.randint(0,number_of_player - 1)
self.update_val()
if self.val >= self.c_val or self.timer >= 60:
self.val -= self.c_val
self.update_img()
def update_val(self):
self.val += self.update_fps / (self.n_move + 1) ** 1.1
self.timer += self.update_fps
def update_img(self):
self.counter += 1
self.ri.filename_update(self.counter)
self.n_move += 1
self.timer = self.timer % 60
sound.play()
if self.update_fps / (self.n_move + 1) < 0.001:
if random.randint(0,5) == 0:
self.sb.state = 'Once More!'
def when_once_more(self):
if self.val != 0:
self.val = 0
self.n_move = 0
self.timer = 0
class rouletteApp(App):
def build(self):
root = Root()
Clock.schedule_interval(root.update, root.update_fps)
return root
if __name__ == '__main__':
rouletteApp().run()
<roulette.kv>
#: kivy 1.9.0
<StartButton>:
text: self.state
on_press: self.state = 'Running...'
on_release: self.state = 'Running...'
<RouletteImage>:
Image:
size: 300, 300
center: self.parent.center
source: self.parent.filename
<Root>:
sb: sbval
ri: rival
canvas:
Color:
rgb: (0, 0.3, 0)
Rectangle:
size: self.size
StartButton:
id: sbval
size_hint: 0.2, 0.1
RouletteImage:
id: rival
<make_figures.py>
# -*- coding: utf-8 -*-
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
class Settings:
fig_size = 500
class MakePolygon:
def __init__(self, n):
settings = Settings()
def make_info_table(n, settings):
dat = pd.DataFrame({'number_of_angles':[n],
'fig_size':[settings.fig_size]})
dat.index = ['value']
return dat.T
self.info = make_info_table(n, settings)
def make_vertex_table(self):
n = self.info.ix['number_of_angles','value']
vertex_angle = np.array([])
for i in np.arange(n + 1):
vertex_angle = np.r_[vertex_angle, np.pi * 2 * i / n]
vertex_x = np.cos(vertex_angle)
vertex_y = np.sin(vertex_angle)
return np.c_[vertex_x, vertex_y]
def make_figure(self, fill):
size = self.info.ix['fig_size','value'] / 100
vertex_table = self.make_vertex_table()
plt.rc('axes', edgecolor="none")
fig = plt.figure(figsize=(size, size))
ax = fig.add_subplot(111, xlim = (-1.1, 1.1),
ylim = (-1.1, 1.1), xticks = [], yticks = [])
for i in np.arange(vertex_table.shape[0] - 1):
ax.plot([vertex_table[i, 0], vertex_table[i + 1, 0]],
[vertex_table[i, 1], vertex_table[i + 1, 1]],
color = 'white')
ax.plot([0, vertex_table[i, 0]],
[0, vertex_table[i, 1]],
color = 'white')
def make_triangle_table(n):
triangle_table = pd.DataFrame({'x': [0,
vertex_table[n, 0], vertex_table[n + 1, 0]],
'y1': [0, vertex_table[n, 1], vertex_table[n + 1, 1]],
'y2': [0, vertex_table[n, 1], vertex_table[n + 1, 1]]})
triangle_table = triangle_table.sort('y1')
triangle_table = triangle_table.sort('x')
triangle_table.index = np.sort(np.array(triangle_table.index))
m_val = np.abs(triangle_table.x[0]-triangle_table.x[1])
n_val = np.abs(triangle_table.x[2]-triangle_table.x[1])
y1_1 = (n_val * triangle_table.y1[0] + \
m_val * triangle_table.y1[2]) / (m_val + n_val)
triangle_table.y1[1] = y1_1
return triangle_table
for i in np.arange(self.info.ix['number_of_angles', 'value']):
triangle_table = make_triangle_table(i)
ax.fill_between(np.array(triangle_table.x),
np.array(triangle_table.y1),
np.array(triangle_table.y2),
color = 'white', alpha = 0.8)
ax.text(np.mean(triangle_table.x),
np.mean(triangle_table.y2),
i + 1, horizontalalignment = 'center',
verticalalignment = 'center', fontsize = 20)
if fill == 'none':
filename = 'figures/fig_none_of_' + \
str(self.info.ix['number_of_angles', 'value']) + '.png'
else:
triangle_table = make_triangle_table(fill)
ax.fill_between(np.array(triangle_table.x),
np.array(triangle_table.y1),
np.array(triangle_table.y2),
color = 'yellow', alpha = 0.8)
filename = 'figures/fig_' + str(fill + 1) + '_of_' + \
str(self.info.ix['number_of_angles', 'value']) + '.png'
fig.savefig(filename, transparent = True)
def make_figure_all(self):
self.make_figure('none')
for i in np.arange(self.info.ix['number_of_angles', 'value']):
self.make_figure(i)
if __name__ == '__main__':
for i in np.arange(3,7): #この設定では、目の数3~6の時に使う図を作成
MakePolygon(i).make_figure_all()
<make_sound.py>
# -*- coding: utf-8 -*-
import wave
import numpy as np
sec = 0.05
freq = 44100
t = np.linspace(0.0, sec, freq * sec)
amp = 15000
hz = 800
w = amp * np.sin(hz * 2 * np.pi * t) / 2
data = w.astype(np.int16)
with wave.open('sound.wav', 'w') as out:
out.setnchannels(1)
out.setsampwidth(2)
out.setframerate(freq)
out.writeframes(data.tostring())
もちろんだけど、make_soundやmake_figuresは、カレントディレクトリをrouletteに移動してから実行しないとエラーが出る。
ファイル置き場はこちら。
0 件のコメント:
コメントを投稿