複数のボールを動かそう
今回も同様に4つのSTEPで作っていきます
はじめに
完成形となるLesson7-8,7-9の内容がvscodeでなぜか実行を押しても動きませんでした。解決方法を模索しましたが未だ改善していません。ですので今回の実際に動かしてみた時の様子は、vscodeの画面ではないことをご了承ください。
追記(6月8日)
ご指摘いただいたところ無事動きました。最終行のmainloopの後の()が抜けていたようです。ミスに気付かず猛省しました。
しかしそうなると今度はなぜidleのほうでは動いたのかが謎になりました。。。。
1STEP:円を自動で動かそう
# 円の座標
x = 400
y = 300
def move():
global x, y
#いまの円を消す
canvas.create_oval(x - 20, y - 20,x + 20,y + 20,fill="white", width=0)
# x座標を動かす
x = x + 1
# 次の位置に円を描く
canvas.create_oval(x - 20,y - 20,x + 20,y + 20, fill="red", width=0)
# 再びタイマー
root.after(10, move)
これで円が右にスーっと動きます…
もっと速く動かしたい!!
⇒メモ
- x=x + 1をx + 2にすることで、x座標が2倍で進む。
- after の数字を小さくすればいい(?/1000秒の間隔で円を描いている)
2STEP:往復して円を動かそう
往復して動かすためには次の3つがカギとなります。
# 移動量
dx = 1
# x座標を動かす
x = x + dx
# 端を超えたら反対に
if x >= canvas.winfo_width():
dx = -1
if x <= 0:
dx = +1
メモ
- 円の判定は中心で、実際は半径も含めたほうがいい。(含めないほうが簡単)
- 同様にしてy方向に円を動かすことができる。
3STEP:同時にいくつか動かそう
今度は3つ同時に動かします。
先ほどと同じことをもう2つ用意すればいいんですが・・・面倒!
そこで、ディクショナリとリストを利用します。
メモ
- ディクショナリ:円に関係するデータをまとめる。
- リスト:すべての円をまとめる。
# 円をリストで管理する
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"] - 20, b["y"] - 20, b["x"] + 20, b["y"] + 20, fill="white", width=0)
# x,y座標を動かす
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)
# x座標:端を超えたら
if b["x"] >= canvas.winfo_width():
b["dx"] = -1
if b["x"] <= 0:
b["dx"] = +1
# y座標:端を超えたら
if b["y"] >= canvas.winfo_height():
b["dy"] = -1
if b["y"] <= 0:
b["dy"] = +1
4STEP:△▢も動かそう(問題有)
このステップではディクショナリとリストで円を描いたのをクラスとオブジェクトに変更します。
(変更したら動かなくなった。)
メモ
- オブジェクト:今回でいう円のこと
何が違うの???
ディクショナリとリスト | クラスとオブジェクト |
---|---|
円を作る。 それぞれにデータを与える |
データを持った円に命令(メソッド) |
ムズカシイ;;
実際のコード↓
# coding: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):
# いまの円を消す
self.erase(canvas)
# x,y座標を動かす
self.x = self.x + self.dx
self.y = self.y + self.dy
# 次の位置に円を描く
self.draw(canvas)
# x座標:端を超えたら
if (self.x >= canvas.winfo_width()):
self.dx = -1
if (self.x <= 0):
self.dx = 1
# y座標:端を超えたら
if (self.y >= canvas.winfo_height()):
self.dy = -1
if (self.y <= 0):
self.dy = 1
def erase(self, canvas):
canvas.create_oval(self.x - 20, self.y - 20, self.x + 20, self.y + 20,fill="white", width=0)
def draw(self, canvas):
canvas.create_oval(self.x - 20, self.y - 20, self.x + 20, self.y + 20,fill=self.color, width=0)
class Rectangle(Ball):
def erase(self, canvas):
canvas.create_rectangle(self.x - 20, self.y - 20, self.x + 20, self.y + 20,fill="white", width=0)
def draw(self, canvas):
canvas.create_rectangle(self.x - 20, self.y - 20, self.x + 20, self.y + 20,fill=self.color, width=0)
class Triangle(Ball):
def erase(self, canvas):
canvas.create_polygon(self.x, self.y - 20, self.x + 20, self.y + 20, self.x - 20, self.y + 20, fill="white", width=0)
def draw(self, canvas):
canvas.create_polygon(self.x, self.y - 20, self.x + 20, self.y + 20, self.x - 20, self.y + 20, fill=self.color, width=0)
# 円、三角形、四角形
balls = [Ball(400, 300, 1, 1, "red"), Rectangle(200, 100, -1, 1, "green"),Triangle(100, 200, 1, -1, "blue")]
def loop():
# 動かす
for b in balls:
b.move(canvas)
# もう一回
root.after(10,loop)
# ウィンドウを描く
root = tk.Tk()
root.geometry("800x600")
# キャンバスを置く
canvas =tk.Canvas(root, width =800,height = 600, bg="#fff")
canvas.place(x = 0, y = 0)
# タイマーをセット
root.after(10, loop)
root.mainloop
vscodeでは動かなかったので、、、
IDLEのほうで試したところ動きました。
どうしてこうなったか模索中です。(ほかのLessonで作ったものは動く。)
今回学んだ大事なこと
- クラスとオブジェクト技法(まだ理解が追い付いていない)
- リストがわかりやすく、そこそこ使いやすいことを実感
追記: