クラスとオブジェクトの使い方をマスターするよ!

クラスとオブジェクトの使い方をマスターするよ!

クラスとオブジェクトを使ってみよう!

前回の記事では、リストとディクショナリを使ってたくさんの円を動かしたよね。今回はそれをちょっと違った書きかたで作ってみるよ。使うのは「クラス」「オブジェクト」だ。

クラスとオブジェクトの考え方

前回の書き方は、「①円の情報をたくさん用意する、②円を描いたり動かす関数を作る、③1と2を組み合わせて円を動かす」って感じだった。①と②はあくまで別々なのがポイントだ。

それに対してクラスとオブジェクトの考え方は、「①情報や関数などすべての情報を持った円を作る、②円それぞれに関数を実行させる」ってふうに作っていく。①で円がすべての情報を持っているのがポイントなんだ。

こうしておくと円は自分のことは何でもわかるって状態になる。だから「動け」の一言で正しい位置で正しい動きかたをしてくれるんだね。

ちなみに、いまの例の円みたいに自分のことは何でもわかる状態のもののことを「オブジェクト」っていうから覚えておこう。

クラスとオブジェクトで書き換えていこう

書き方のルール

オブジェクトを作るために書くプログラムが「クラス(class)」だ。クラスが1つあれば、それを元にしたオブジェクトがいくつも作れる。それじゃあ早速クラスを作ってみよう。話をカンタンにするために、円を動かすことは一旦忘れてx座標やy座標などの情報を持つだけのものを作ってみるよ。

クラスをつくるにはこんな書きかたをするんだ。

class クラス名:
    クラスの内容

前回の記事と同じように円を作るならこんな感じで書く。

class Ball:
    def __init__(self, x, y, dx, dy, color)
        self.x = x
        self.y = y
        self.dx = dx
        self.dy = dy
        self.color = color

ここで書いた「__init__」は、オブジェクトを最初につくるときに呼び出される特殊な関数なんだ。「コンストラクタ(constructor)」って呼ぶから覚えておこう。これはオブジェクトを最初の状態にするときの処理につかうよ。

最初の引数「self」というのは自分自身って意味になる。これを使って受け取った値を自分自身に代入できるから覚えておこう。

クラスはオブジェクトをつくるためのものと言ったよね。じゃあ実際にクラスからオブジェクトを作ってみよう。

b = Ball(400, 300, 1, 1, "red")

これで変数bに「class Ball」でつくったオブジェクトが代入されるんだ。bというのは自分でつけた変数だから好きな名前でOKだよ。そしてポイントはこのオブジェクトを作った段階で「__init__」が実行されること。つまりbに「x=400」「y=300」…という処理が自動でされるんだ。

実際に動きを書いていこう!

次はこのクラスに動きの命令をするための関数をつくっていくよ。これを「メソッド(method)」というから覚えておこう。実際にメソッドを書いてみるとこんな感じ。

class Ball:
    def __init__(self, x, y, dx, dy, color)
        self.x = x
        self.y = y
        self.dx = dx
        self.dy = dy
        self.color = color
    def move(self, canvas)
        #ここに処理を書いていく

前回の記事と同じで「move()」という名前で関数をつくったんだね。ポイントは最初の引数に「self」を入れてること。__init__のときと同じルールだから覚えておこう。このおかげで自分自身の値を取得できるんだ。たとえば自分の「x」を取得するなら「self.x」でできるんだね。2つめの引数「canvas」はキャンバスの値を入れられるように用意した。

それじゃあ円を動かすプログラムを書いていこう。まずはBallオブジェクトをつくる。

#円をひとつつくる
b = Ball(400,300,1,1,"red")

そして、bを連続して動かすために「loop」という関数を作って見た。

def loop():
    #動かして繰り返す
    b.move(canvas)
    root.after(10,loop)

「b.move(canvas)」は、さっきつくったballオブジェクトにmove()を実行しろって意味だ。4行目でloop()の中にさらに「root.after(10,loop)」があるから、この関数はなんども繰り返されるよ。

ここまでで、オブジェクトを作ってbに入れて、bにmove()を繰り返し実行させるってところまで準備ができた。次は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)

それをこんな風に書き換える。

class Ball:
    def __init__(self, x, y, dx, dy, color):
        self.x = x
        self.y = y
        self.dx = dx
        self.dy = dy
        self.color = color
    def move(self, canvas):
        #前の円を隠す
        canvas.create_oval(self.x-22, self.y-22, self.x+22, self.y+22, fill="white", width=0)

変更点は、まだ円を1つ書くだけだから「forループ」の記述を消したところ。それと変数を「b[“x”]-22〜」から「self.x-22〜」に書き換えたところだけだね。他の円の動きに関する記述も前回の記事をみながら全部変数を置き換えていこう!

ここまでの内容を全部ふまえて、完成したプログラムはこんな感じ!

# codeing=utf-8
import tkinter as tk

class Ball:
    def __init__(self, x, y, dx, dy, color):
        self.x = x
        self.y = y
        self.dx = dx
        self.dy = dy
        self.color = color
    def move(self, canvas):
        #前の円を隠す
        canvas.create_oval(self.x-22, self.y-22, self.x+22, self.y+22, fill="white", width=0)
        #円を次の位置に
        self.x = self.x + self.dx
        self.y = self.y + self.dy
        canvas.create_oval(self.x-20, self.y-20, self.x+20, self.y+20, fill=self.color, width=0)
        #画面端で移動量をかえる
        if self.x >= canvas.winfo_width():
            self.dx = -1
        if self.x <= 0:
            self.dx = 1
        if self.y >= canvas.winfo_height():
            self.dy = -1
        if self.y <= 0:
            self.dy = 1

#円をひとつつくる
b = Ball(400,300,1,1,"red")

def loop():
    #動かして繰り返す
    b.move(canvas)
    root.after(10,loop)

#ウィンドウを作る
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, loop)
 
 
root.mainloop()

実行してみると、円が動くから試してみよう!

円を増やす

さて、ここまで円を1つでやってたから、今回も円を増やしてみよう。まず円を1つ作っていたところを3つにする。

▽ 変更前

#円をひとつつくる
b = Ball(400,300,1,1,"red")

▽ 変更後

#円をたくさん作る
balls = [
    Ball(400,300,1,1,"red"),
    Ball(200,100,-1,1,"green"),
    Ball(100,200,1,-1,"blue"),
    Ball(150,150,-1,1,"purple"),
    Ball(300,250,-1,-1,"yellow")
]

次にloop()の中身をforですべての円にmove()させるようにする。

▽ 変更前

def loop():
    #動かして繰り返す
    b.move(canvas)
    root.after(10,loop)

▽ 変更後

def loop():
    #動かして繰り返す
    for b in balls:
        b.move(canvas)
    root.after(10,loop)

これでOKだ!

今日のまとめ

  • クラスとオブジェクトの考え方を理解しよう!
  • クラスの書きかたを覚えよう!
  • オブジェクトの作り方を覚えよう!