bouncegameの改造 コードのエラーを特定してほしい
たのしいプログラミング Pythonではじめよう!の第II部 Bounce!ゲーム(第13章、第14章)を変更しましたが、実行した際にpaddleに当たった時のボールの挙動がおかしいという現象が起きています。
バーではなく、ボールがバーに当たった時に上に移動せずに、斜め下に移動してしまうので、ボールがpaddleに反射して上に動くようにしたいと考えていますが、意図したとおりに動作しません。
from tkinter import *
import random
import time
from sys import exit
#必要なモジュールをインポート
tk = Tk()
tk.title('Game')#ウインドウのタイトル
tk.resizable(0, 0)#ウインドウのサイズ変更を不可能に
tk.wm_attributes('-topmost', 1)#ウインドウを一番上に表示
canvas = Canvas(tk, width=1000, height=800, bd=0, highlightthickness=0)#キャンバスを配置
canvas.pack()#キャンバスの表示
#my_image = PhotoImage(file='bg_yozora_night_sky.gif')
canvas.create_image(0, 0, anchor=NW)#image=my_image
tk.update()#アニメーションのためにtkinterを初期化
count = 0
global colors
colors=['red','blue','black','yellow','green','purple','magenta']
random.shuffle(colors)
color=colors[0]
color2=colors[2]
color3=colors[3]
color4=colors[4]
lost = False
scores = canvas.create_text(800, 10, text="Score: " + str(count), fill = "red",font=('Blackoak Std',10))
###ボール###
class Ball:
#クラスをボールに設定
def __init__(self, canvas, paddle, board, board2, color):
#canvas,color,paddle,score引数を受け取る__init__関数を作成
self.canvas = canvas
self.paddle = paddle
self.board = board
self.board2 = board2
self.id = canvas.create_oval(10, 10, 25, 25, fill=color)
#create_oval関数を呼び出し、引数[左上角の座標(10,10)、右下角の座標(25,25)、円の色}]をセット
self.canvas.move(self.id, 470, 200)
#円の識別番号(オブジェクトの変数id)を用いてキャンバスのほぼ中央(235,100)に円を移動
starts = [-3, -2, -1, 1, 2, 3]#数字のリストをセットしたstarts関数をセット
random.shuffle(starts)#starts関数の値の順序をシャッフル
self.x = starts[0]#リストの先頭をxにセット
self.y = -3
self.canvas_height = self.canvas.winfo_height()
#キャンバスのwinfo_height関数が返す値をオブジェクトの変数canvas_heightにセット
self.canvas_width = self.canvas.winfo_width()
#キャンバスのwinfo_width関数が返す値をオブジェクトの関数canvas_widthにセット
self.hit_bottom = False
def hit_paddle(self, pos):
paddle_pos = self.canvas.coords(self.paddle.id)
if pos[2]>= paddle_pos[0] and pos[0] <= paddle_pos[2]:
if pos[3] >= paddle_pos[1] and pos[3] <= paddle_pos[3]:
self.x += self.paddle.x
global count
count +=1
score()
if pos[3] <= self.canvas_height:
self.canvas.after(5, self.draw)
else:
self.canvas.move(self.id, 245, 200) #added this line
game_over()
global lost
lost = True
def hit_bottom(self, pos):
paddle2_pos = self.canvas.coords(self.paddle2.id)
if pos[2] >= paddle2_pos[0] and pos[0] <= paddle2_pos[2]:
if pos[1] >= paddle2_pos[1] and pos[1] <= paddle2_pos[3]:
return True
return False
def hit_board(self, pos):#障害物の判定
board_pos = self.canvas.coords(self.board.id)
if pos[2]>= board_pos[0] and pos[0] <= board_pos[2]:
if pos[3] >= board_pos[1] and pos[3] <= board_pos[3]:
return True
return False
def hit_board2(self, pos):
board2_pos = self.canvas.coords(self.board2.id)
if pos[2]>= board2_pos[0] and pos[0] <= board2_pos[2]:
if pos[3] >= board2_pos[1] and pos[3] <= board2_pos[3]:
return True
return False
def hit_board_bottom(self, pos):
board_pos = self.canvas.coords(self.board.id)
if pos[2]>= board_pos[0] and pos[0] <= board_pos[2]:
if pos[1] <= board_pos[3] and pos[1] >= board_pos[1]:
return True
return False
def hit_board2_bottom(self, pos):#board2の下側の当たり判定
board2_pos = self.canvas.coords(self.board2.id)
if pos[2]>= board2_pos[0] and pos[0] <= board2_pos[2]:
if pos[1] <= board2_pos[3] and pos[1] >= board2_pos[1]:
return True
return False
def draw(self):
self.canvas.move(self.id, self.x, self.y)
pos = self.canvas.coords(self.id)
speed=[1,2,3,4,5]
speed2=[-1,-2,-3,-4,-5]
random.shuffle(speed)
random.shuffle(speed2)
colors=['red','blue','black','yellow','green','purple','magenta']
random.shuffle(colors)
if pos[1] <= 0:
self.y = speed[0]
canvas.itemconfig(self.id,fill=colors[0])
if self.hit_board(pos)==True:
self.y=-6
if self.hit_board_bottom(pos)==True:
self.y=6
if self.hit_board2(pos)==True:
self.y=-6
if self.hit_board2_bottom(pos)==True:
self.y=6
if self.hit_paddle(pos) == True:
self.y = -6
## global count
## count +=1
## score()
##
## if count == 0:
## canvas.create_text(250, 200, text='YOU WIN!')
## tk.update_idletasks()
## tk.update()
## while 1:
## if ball.hit_bottom ==True:
## ball.draw()
## paddle.draw()
## paddle2.draw()
## paddle3.draw()
if pos[3] >= self.canvas_height:
self.hit_bottom = True
canvas.itemconfig(self.id,fill=colors[0])
if pos[0] <= 0:
self.x = speed[1]
canvas.itemconfig(self.id,fill=colors[0])
if pos[2] >= self.canvas_width:
self.x = speed2[1]
canvas.itemconfig(self.id,fill=colors[0])
zahyou=self.canvas.coords(self.id)##←壁に当たったらワープ←座標取り出し
a=[-500,-450,-400,-350]##←壁に当たったらワープ
random.shuffle(a)##←壁に当たったらワープ
self.canvas.move(self.id,a[0],-(zahyou[1]))##←壁に当
###障害物1###
class Board:
def __init__(self, canvas, color):
self.canvas = canvas
self.id = canvas.create_rectangle(150, -200, 250, -210, fill=color)
self.canvas.move(self.id, 200, 300)
self.x = 0
self.canvas_width = self.canvas.winfo_width()
self.started = False
def draw(self):#ボードの描画
self.canvas.move(self.id, self.x, 0)
pos =self.canvas.coords(self.id)
if pos[0] <= 0:
self.x =0
elif pos[2] >= self.canvas_width:
self.x = 0
###障害物2###
class Board2:
def __init__(self, canvas, color):
self.canvas = canvas
self.id = canvas.create_rectangle(-100, -150, 0, -160, fill=color)
self.canvas.move(self.id, 200, 300)
self.x = 0
self.canvas_width = self.canvas.winfo_width()
def draw(self):#ボードの描画
self.canvas.move(self.id, self.x, 0)
pos =self.canvas.coords(self.id)
if pos[0] <= 0:
self.x =0
elif pos[2] >= self.canvas_width:
self.x = 0
class Paddle:
def __init__(self, canvas, color):
self.canvas = canvas
self.id = canvas.create_rectangle(0, 0, 150, 10, fill=color)
self.canvas.move(self.id, 400, 700)
self.x = 0
self.y = 0
self.canvas_width = self.canvas.winfo_width()
self.started = False
self.canvas.bind_all('<Up>', self.turn_up)
self.canvas.bind_all('<Down>', self.turn_down)
self.canvas.bind_all('<Left>', self.turn_left)
self.canvas.bind_all('<Right>', self.turn_right)
self.canvas.bind_all('<s>', self.start_game)#クリックしたときにスタート
def draw(self):#ラケットの描画
self.canvas.move(self.id, self.x, self.y)
pos =self.canvas.coords(self.id)
if pos[0] <= 0:##←パドルが壁を貫通しないようにする
self.x =0
elif pos[2] >= self.canvas_width:##←パドルが壁を貫通しないようにする
self.x = 0
#こうすべきかな。
pos =self.canvas.coords(self.id)
elif pos[1] <= 0:##←パドルが壁を貫通しないようにする
self.y =0
elif pos[3]>= 800:##←パドルが壁を貫通しないようにする
self.y = 0
global lost
if lost == False:
self.canvas.after(10, self.draw)
def turn_up(self, evt):
self.canvas.move(self.id, self.x, self.y)##←動く範囲指定
pos = self.canvas.coords(self.id)##←動く範囲指定
if pos[1] >0:##←動く範囲指定
self.y = -6
elif pos[1] <=0:##←動く範囲指定
self.y =0##←動く範囲指定
def turn_down(self, evt):
self.canvas.move(self.id, self.x, self.y)##←動く範囲指定
pos = self.canvas.coords(self.id)##←動く範囲指定
if pos[3]<800:##←動く範囲指定
self.y = 6
elif pos[3]>=800:##←動く範囲指定
self.y=0##←動く範囲指定
def turn_left(self, evt):
self.canvas.move(self.id, self.x, self.y)##←動く範囲指定
pos = self.canvas.coords(self.id)##←動く範囲指定
if pos[0]>0:
self.x = -6
elif pos[0]<=0:##←動く範囲指定
self.x=0##←動く範囲指定
def turn_right(self, evt):
self.canvas.move(self.id, self.x, self.y)##←動く範囲指定
pos = self.canvas.coords(self.id)##←動く範囲指定
if pos[2]< self.canvas_width:##←動く範囲指定
self.x = 6
elif pos[2]>= self.canvas_width:##←動く範囲指定
self.x=0##←動く範囲指定
def start_game(self, evt):#スタートする関数
self.started = True
self.onemore(evt)
def end(self, evt):
tk.destroy()
def onemore(self, evt):
while True:#常にループ実行
if ball.hit_bottom == False and paddle.started == True:#ゲームを続ける条件
ball.draw()#ballオブジェクトのdraw関数の呼び出し
paddle.draw()#paddleオブジェクトのdraw関数の呼び出し
board.draw()
board2.draw()
if ball.hit_bottom == True:
time.sleep(1)
canvas.itemconfig(game_over, state = 'normal')
canvas.itemconfig(retry1, state = 'normal')#テキストを表示する条件
canvas.itemconfig(retry2, state = 'normal')
self.canvas.bind_all('<n>', self.end)
self.canvas.bind_all('<y>', self.restart)
tk.update_idletasks()
tk.update()
time.sleep(0.01)
def restart(self,evt):
ball.hit_bottom == False
paddle.started == True
def game_over():
game_over =canvas.create_text(150, 150, text ='GAME OVER!', font =('Courier', 30), fill='yellow', state ='hidden')
#ゲームオーバーのテキスト表示,hiddenで隠しておく
retry1 = canvas.create_text(200, 250, text ='もう一度、ゲームを行いますか', font =('Courier', 20),fill='yellow', state ='hidden')
retry2 = canvas.create_text(300, 300, text ='(Yes/No)', font =('Courier', 20),fill='yellow', state ='hidden')
def start_game_menu():
global lost, count, ball
if lost == True:
ball = Ball(canvas, paddle, paddle2,paddle3,"red")
lost = False
board.draw()
board2.draw()
paddle.draw()
ball.draw()
count = 0
score()
canvas.itemconfig(game, text=" ")
time.sleep(1)
def score():
canvas.itemconfig(scores, text="Score:"+ str(count))
def start_game(event):
global lost, count, ball ,paddle
if lost == True:
ball = Ball(canvas, paddle, board2, board,color2)
canvas.move(paddle, 400, 600)
lost = False
board.draw()
board2.draw()
paddle.draw()
ball.draw()
count = 0
score()
canvas.itemconfig(game, text=" ")
time.sleep(1)
def out():
tk.destroy()
def out_keypress(event):
tk.destroy()
####
menu=Menu(tk)
tk.config(menu=menu)
filemenu=Menu(menu)
menu.add_cascade(label="Menu", menu=filemenu)
filemenu.add_cascade(label="Exit",command=out)
filemenu.add_cascade(label="Restart",command=start_game_menu)
###各種設定###
paddle = Paddle(canvas, color2)
board = Board(canvas, color3)
board2 = Board2(canvas, color4)
#ラケットの色を青色に設定
ball = Ball(canvas, paddle, board, board2, color)
#ボールの色を赤に設定
game = canvas.create_text(500, 300, text=" ", fill="red", font=("Arial", 20))
canvas.bind_all("<s>", start_game)
canvas.bind_all("<y>", start_game)
canvas.bind_all("<n>", out_keypress)
tk.mainloop()
※原著のページに元となったソースコードのダウンロードリンクがあります