コンテンツにスキップ

Pythonアプリ(9):お金キャッチゲームを作ろう

1.まず、1個のボタンを落下させよう

ボタンが上から下へ落下するプログラムを作りましょう。下まで行ったら上から落下し直すのを繰り返します。placeメソッドを使っています。

from tentoapp import *
import random
def move():
global b
b.y += 1
b.place(b.x,b.y,b.w,b.h)
if b.y > 400:
b.x = random.randrange(0, 500) # 600だと、右端に隠れてしまう
b.y = 0
app.after(10,move)
app = App()
app.size(600,400)
b = Button(app)
b.x = random.randrange(0, 500) # (0,600)では右端に隠れてしまう
b.y = 0
b.w = 100
b.h = 30
app.after(1000,move)
app.start()

関数 move() の中で app.after(10,move) を呼び出すことで、ループを作っています。その中で、 b.y += 1 をすることによって、ボタンを落下させています。

ボタンが下( b.y > 400 )まで落下すると、上( b.y = 0 )から落下し直します。

2.落下してきたボタンをキャッチできるようにしよう

落下中のボタンをマウスでクリック(キャッチ)したら、上から落下し直すようにしましょう。

from tentoapp import *
import random
def init():
global b
b = Button(app)
b_set()
def b_set():
global b
b.x = random.randrange(0, 500)
b.y = 0
b.w = 100
b.h = 30
b.onclick = clicked
def move():
global b
b.y += 1
b.place(b.x,b.y,b.w,b.h)
if b.y > 400:
b_set(b)
app.after(10,move)
def clicked():
b_set()
app = App()
app.size(600,400)
init()
app.after(1000,move)
app.start()

これまでメインルーチンの所にあったボタンのインスタンス化や初期設定( b = Button(app)b.h = 30 )は、関数 init()b_set() にまとめました。

ボタンをクリックすると関数 clicked() が呼び出され、ボタンは上から落下し直します。

3.複数のボタンを落下させよう

ボタンを複数にします。ボタンが複数の場合、インスタンス化や初期設定もそれぞれ行わなければなりません。これは init() 関数の中で、for文を使って行います。ここで生成されたButtonオブジェクト b は関数 b_set() で初期設定された後、リスト bList に次々に追加されます。

なお、 bList.append(b) でbListに追加されるのは b という変数ではなく、forループの中で次々に生成されるButtonオブジェクト b のアドレス(のようなもの)が追加されます。

また、ボタンが複数になると、どのButtonオブジェクトを処理(上から落ち始めるように設定)するのかを指定しなければなりません。そのため、関数 b_set() では引数を指定するようにします。

このため、関数init()b_set() は下記のようになります。

def init():
global bList
for i in range(n):
b = Button(app)
b_set(b)
bList.append(b)
def b_set(b):
global bList
b.x = random.randrange(0, 500)
b.y = random.randrange(-400, 0) #(注)
b.w = 100
b.h = 30
b.onclick = clicked

(注)これまでのようにb.y = 0とすると、複数のボタンが横一列で落下します。これを避けるために、 b.y = random.randrange(-400, 0) としています。

リストに格納された複数のオブジェクトを順次処理したい場合は、

for 変数 in リスト:

という構文が使えます。添字(数字)を使う配列でもできますが、Pythonではこのような in リスト の形がよく使われます。

これにより、関数 move() は次のようになります。

def move():
global bList
for b in bList:
b.y += 1
b.place(b.x,b.y,b.w,b.h)
if b.y > 400:
b_set(b)
app.after(10,move)

複数のウェジット(ここではButtonオブジェクト)があって、どのウェジットがクリックされたかを判別したいときは、下記のように 引数.widget で判別します。

def clicked(e):
eb = e.widget
b_set(eb)

メインルーチンの部分も、下記のようになります。

n = 10
bList = []
app = App()
app.size(600,400)
init()
app.after(1000,move)
app.start()

4.各ボタンに金額を付けよう

各ボタンにランダムで金額を付け、表示させましょう。プラスの金額だけでなく、マイナスの金額も付けるとゲームとして面白くなるでしょう。

下記は、ボタンの数(n)によって出現する金額が変わるようにした例です。

def b_set(b):
global bList
b.x = random.randrange(0, 500)
b.y = random.randrange(-400, 0)
b.yen = 10 * random.randint(-n,n)
b.text = str(b.yen)+""
b.fontsize = 20
b.w = 100
b.h = 30
b.onclick = clicked

5.キャッチした合計金額を表示しよう

キャッチした合計金額を表示するようにしましょう。

プログラム全体はこのようになります。

from tentoapp import *
import random
def init():
global bList
for i in range(n):
b = Button(app)
b_set(b)
bList.append(b)
def b_set(b):
global bList
b.x = random.randrange(0, 500)
b.y = random.randrange(-400, 0)
b.yen = 10 * random.randint(-n,n)
b.text = str(b.yen)+""
b.fontsize = 20
b.w = 100
b.h = 30
b.onclick = clicked
def move():
global bList
for b in bList:
b.y += 1
b.place(b.x,b.y,b.w,b.h)
if b.y > 400:
b_set(b)
app.after(10,move)
def clicked(e):
global money, get
eb = e.widget
money += eb.yen
get.text = str(money) + ""
get.place(150,100)
b_set(eb)
n = 10
money = 0
bList = []
app = App()
app.size(600,400)
get = Label(app)
get.text = "0円"
get.fontsize = 100
get.place(150,100)
init()
app.after(1000,move)
app.start()

やってみよう

1. 見逃し金額も表示しよう。☆

見逃したボタン全部を合計するのではなく、プラスの金額だけを合計すると悔しくなって面白いよ。

2. キャッチした時に音が鳴るようにしよう。☆☆

金額がプラスの場合とマイナスの場合では違う音にしてみよう。

3. 金額によってボタンの大きさや落下速度を変えよう。☆☆☆

4. 改造してみよう

その他、タイマーを設けたり、ボタンをお札の画像にしたり、キャッチした時に爆発したりしてみよう。

サンプルコード

20230604 okanechatch.zip