たくさんの円を動かそう!ディクショナリ機能で大量の変数を管理するよ

たくさんの円を動かそう!ディクショナリ機能で大量の変数を管理するよ

動く円をどんどん増やしてみよう!

前回の記事で、「ウィンドウの中を反射する円」が作れたね。今回は円をもっと増やしてたくさんの円がウィンドウの中を動き回るようにするよ!

大量の変数を管理する方法を覚えるよー!

ディクショナリ機能の使い方を覚えよう!

前回は1個の円を動かすのに、x,y,dx,dyという4つの変数をつかったね。このまま円を増やしていくと、x1,y1,dx1,dy1,x2,y2,dx2,dy2,x3…って感じで変数がどんどん増えて管理が大変だ。

そこで便利なのがPythonの「ディクショナリ(Dictionary)」という機能なんだ。これは「キーと値のペア」をセットにしてまとめる仕組みだ。言葉じゃわかりにくいと思うから実際に書きかたをみてみよう。

ball = {"x":400, "y":300, "dx":1, "dy":1}

ballというのは変数だから自分の好きな名前をつけてOKだ。ballの中にx,y,dx,dyの4つの値がセットで入ってるんだね。値を取り出したいときはこんなふうに書く。これで変数xの中身「400」が取り出せるんだ。

ball["x"]

リストとディクショナリを組み合わせよう!

さて、ここまでのやり方で3つの円の変数を書こうと思ったらこんな感じだ。

ball_1 = {"x":400, "y":300, "dx":1, "dy":1}
ball_2 = {"x":200, "y":100, "dx":-1, "dy":1}
ball_3 = {"x":100, "y":200, "dx":1, "dy":-1}

x,y,dx,dyの変数はまとめてスッキリしたけど、ballの変数が3つあるからそれぞれに円を描画するプログラムを書かないといけないからまだ大変だ。これをさらにまとめるには、前にもやった「リスト」が使える。実際に書いてみるとこんな感じ。

balls = [
    {"x":400, "y":300, "dx":1, "dy":1},
    {"x":200, "y":100, "dx":-1, "dy":1},
    {"x":100, "y":200, "dx":1, "dy":-1}
]

ここから値をとるときは、たとえば1つ目の円のx座標なら下のように書けばOKだ。

balls[0]["x"]

これで変数は「balls」の1つだけなのに、12個もの値を持つことができたね!この書き方ならもっとどんどん増えても大丈夫だ。

実はここで一番大事なのは、単純にコードを短くかけるってことだけじゃないんだ。試しに3つの円のx座標を順番に書いてみる。

balls[0][“x”]
balls[1][“x”]
balls[2][“x”]

3つの値で違うのは[0]の部分だけ。つまりforやwhileでまとめて命令を出すことができるんだね!たくさんの値をまとめて書くと、こういうメリットがあるってことを覚えておこう。

たくさんの円をループで動かそう!

それじゃあ実際に3つの円を動かしてみよう。先にコードをまとめて書いちゃうね。

# codeing=utf-8
import tkinter as tk

#円をリストで用意
balls = [
    {"x":400, "y":300, "dx":1, "dy":1, "color":"red"},
    {"x":200, "y":100, "dx":-1, "dy":1, "color":"green"},
    {"x":100, "y":200, "dx":1, "dy":-1, "color":"blue"}
]

def move():
    global balls
    for b in balls:
        #前の円を隠す
        canvas.create_oval(b["x"]-22, b["y"]-22, b["x"]+22, b["y"]+22, fill="white", width=0)
        #円を次の位置に
        b["x"] = b["x"]+b["dx"]
        b["y"] = b["y"]+b["dy"]
        canvas.create_oval(b["x"]-20, b["y"]-20, b["x"]+20, b["y"]+20, fill=b["color"], width=0)
        #画面端で移動量をかえる
        if b["x"] >= canvas.winfo_width():
            b["dx"] = -1
        if b["x"] <= 0:
            b["dx"] = 1
        if b["y"] >= canvas.winfo_height():
            b["dy"] = -1
        if b["y"] <= 0:
            b["dy"] = 1
    #タイマーをつくる
    root.after(10, move)


#ウィンドウを作る
root = tk.Tk()
root.geometry("600x400")
 
#Canvasを作る
canvas = tk.Canvas(root, width=600, height=400, bg="white")
canvas.place(x=0, y=0)

#タイマーをつくる
root.after(10, move)


root.mainloop()

解説

まず最初に注目なのは、4〜9行目。リストとディクショナリを組み合わせた書きかたをしてるね。最後の「color」は円の色を決めるために追加したよ。

#円をリストで用意
balls = [
    {"x":400, "y":300, "dx":1, "dy":1, "color":"red"},
    {"x":200, "y":100, "dx":-1, "dy":1, "color":"green"},
    {"x":100, "y":200, "dx":1, "dy":-1, "color":"blue"}
]

今回のポイントになるのは11〜30行目のmove()の中身。

def move():
    global balls
    for b in balls:
        #前の円を隠す
        canvas.create_oval(b["x"]-22, b["y"]-22, b["x"]+22, b["y"]+22, fill="white", width=0)
        #円を次の位置に
        b["x"] = b["x"]+b["dx"]
        b["y"] = b["y"]+b["dy"]
        canvas.create_oval(b["x"]-20, b["y"]-20, b["x"]+20, b["y"]+20, fill=b["color"], width=0)
        #画面端で移動量をかえる
        if b["x"] >= canvas.winfo_width():
            b["dx"] = -1
        if b["x"] <= 0:
            b["dx"] = 1
        if b["y"] >= canvas.winfo_height():
            b["dy"] = -1
        if b["y"] <= 0:
            b["dy"] = 1
    #タイマーをつくる
    root.after(10, move)

まず12行目でballsをグローバル宣言してるね。円に関する値はぜんぶこの中に入ってるから、宣言もこれだけでOKなんだね。

global balls

そして肝心なforループでまとめて書いてるのが13行目から。

    for b in balls:
        #前の円を隠す
        canvas.create_oval(b["x"]-22, b["y"]-22, b["x"]+22, b["y"]+22, fill="white", width=0)

「for b in balls:」と、繰り返すときに使う変数を「b」とおいてる。これは変数ballsの頭文字をつかってわかりやすくしてみた。そして「in balls」という書き方は配列の中身を順番に処理していくって意味だったね。

それぞれの円を描く処理は「b[“x”]-22」みたいにbと”x”を使って、ディクショナリ機能で値をとりだしながら指定してるんだね。

円を増やすのもとっても簡単!

ここで仮に「やっぱり円を5個にしたバーションを作り直したい」と思ったとしよう。そんなとき、今回の書きかたならとっても簡単なんだ。なぜなら円についての情報は全部「balls」にまとめてたよね。だからそこに追加するだけ。実際に書いてみるとこんな感じ。

↓こうだったのを

#円をリストで用意
balls = [
    {"x":400, "y":300, "dx":1, "dy":1, "color":"red"},
    {"x":200, "y":100, "dx":-1, "dy":1, "color":"green"},
    {"x":100, "y":200, "dx":1, "dy":-1, "color":"blue"}
]

↓こうしてみよう!

#円をリストで用意
balls = [
    {"x":400, "y":300, "dx":1, "dy":1, "color":"red"},
    {"x":200, "y":100, "dx":-1, "dy":1, "color":"green"},
    {"x":100, "y":200, "dx":1, "dy":-1, "color":"blue"},
    {"x":150, "y":150, "dx":-1, "dy":1, "color":"purple"},
    {"x":300, "y":250, "dx":1, "dy":-1, "color":"yellow"}
]

これだけで、いくらでも円を増やせちゃうんだ。こんな風に「ここは円の情報」、「ここは動きの処理」みたいにハッキリと分けてプログラムを書くと、後から直す時にそこだけしか見なくても直せちゃうから便利。この考え方はとっても重要だから覚えておこう!

今日のまとめ

  • 「ディクショナリ機能」の使い方を覚えよう!
  • リストとディクショナリを組み合わせよう!
  • ディクショナリとループを使って大量の変数をまとめて動かそう!