ブロック崩しゲームを作成してます。パドルとボールを使ってブロックを崩すという動作を作ることはできました。でも、ボールをパドルで跳ね返すときに、反射角が常に一定になってしまいます。パドルのあたる位置によってボールの反射角を変更したいです。またボールが動作中にたまにかけてしまうことがあります。この不具合を解消したいです。
from tkinter import * from dataclasses import dataclass import time import random #初期状態の設定 DURATION = 0.01 #描画間隔 PADDLE_X0 = 200 #パドルの初期位置x PADDLE_Y0 = 550 #パドルの初期位置y BALL_Y0 = 300 # ボールの初期位置y PAD_VX = 10 #パドルの速度 BALL_VX = 5 #ボールの速度 BALL_VY = 5 #ボールの速度 BLOCK_X = 100 #ブロックの位置x BLOCK_Y = 100 #ブロックの位置y BLOCK_W = 100 #ブロックの幅 BLOCK_H = 20 #ブロックの高さ NUM_BLOCKS = 7 #ブロックの位置 #変える色を用意する COLORS = ["blue", "red", "black", "white", "green", "pink", "orange"] @dataclass class Paddle: id: int x : int y : int w : int h : int v : int c : str @dataclass class Ball: id: int x : int y : int d : int vx: int vy: int c : str @dataclass class Block: id: int x : int y : int w : int h : int c : str @dataclass class Game: start: int #--------------------------------- #ball #ボールの描画・登録 def make_ball(x, y, d, vx, vy, c="black"): id = canvas.create_oval(x, y, x + d, y + d, fill=c, outline=c) return Ball(id, x, y, d, vx, vy, c) #ボールの移動(左右) def move_ball(ball): ball.x += ball.vx ball.y += ball.vy #ボールの再描画 def redraw_ball(ball): canvas.coords(ball.id, ball.x, ball.y, ball.x + ball.d, ball.y + ball.d) #paddle #パドルの描画・登録 def make_paddle(x, y, w , v, h, c="blue"): id = canvas.create_rectangle(x, y, x + w, y + h, fill=c, outline=c) return Paddle(id, x, y, w, h, v, c) #パドルの移動(左右) def move_paddle(pad): pad.x += pad.v #パドルの再描画 def redraw_paddle(pad): canvas.coords(pad.id, pad.x, pad.y, pad.x + pad.w, pad.y + pad.h) #block #ブロックの描画・登録 def make_block(x, y, m=40, n=300, c="green"): id = canvas.create_rectangle(x, y, x + m, y + n, fill=c, outline=c) return Block(id, x, y, m, n, c) #複数のブロックを生成する def make_blocks(n_rows, x0, y0, w, h, pad=10): blocks = [] for x in range(n_rows): blocks.append(make_block(x0, y0, w, h)) x0 = x0 + w + pad return blocks #ブロックを消す def delete_block(block): canvas.delete(block.id) def game_start(event): game.start = True #------------------------------------------------- #wall #壁の作成 def make_walls(ox, oy, width, height): canvas.create_rectangle(ox, oy, ox + width, oy + height) #--------------------------------------------------------- #パドル操作のイベントハンドラ def left_paddle(event): #速度を左向きに設定 paddle.v = -PAD_VX def right_paddle(event): #速度を右向きに設定 paddle.v = PAD_VX def stop_paddle(event): #速度を0に設定 paddle.v = 0 def change_paddle_color(pad, c="red"): canvas.itemconfigure(pad.id, fill=c) canvas.itemconfigure(pad.id, outline=c) redraw_paddle(pad) tk = Tk() canvas = Canvas(tk, width=1000, height=800, bd=0) canvas.pack() tk.update() paddle = make_paddle(PADDLE_X0, PADDLE_Y0, 100, PAD_VX, 10) ball = make_ball(200, BALL_Y0, 10, BALL_VX, BALL_VX) make_walls(100, 100, 800, 600) blocks = make_blocks(NUM_BLOCKS, BLOCK_X, BLOCK_Y, BLOCK_W, BLOCK_H) game = Game(False) #イベントと、イベントハンドラを連結する canvas.bind_all('<KeyPress-Left>', left_paddle) canvas.bind_all('<KeyPress-Right>', right_paddle) canvas.bind_all('<KeyRelease-Left>', stop_paddle) canvas.bind_all('<KeyRelease-Right>', stop_paddle) canvas.bind_all('<KeyPress-space>', game_start) #spaceが押された #---------------------------------------------------------------- #SPACEの入力待ち id_text = canvas.create_text(400, 200, text = "Press 'SPACE' to start", font = ('FixedSys', 16)) tk.update() while not game.start: #ひたすらSPACEを待つ tk.update() time.sleep(DURATION) canvas.delete(id_text) #SPACE入力のメッセージを削除 tk.update() #プログラムのメインループ while True: move_paddle(paddle) # move_ball(ball) if ball.y + ball.vy <= 100: #ボールが上端についた ball.vy = -ball.vy if ball.y + ball.d >= 600: #ボールが下端についた break if (ball.x + ball.vx < 100 \ or ball.x + ball.d >= 900): ball.vx = -ball.vx for block in blocks: #ボールのX位置がブロックに届き、Y位置もっブロックの範囲内 if ( block.x <= ball.x <=block.x + block.w \ and block.y <= ball.y <= block.y + block.h): ball.vx = -ball.vx #ボールを跳ね返す delete_block(block) #ブロックを消す blocks.remove(block) #ブロックのリストからこのブロックを削除 break if blocks == []:break #blocksリストが空になったら終了 #ボールがパドルの上端に届き、ボールの幅がパドルの幅に収まっている if (ball.y + ball.d >= paddle.y \ and paddle.x <= ball.x <= paddle.x + paddle.w): ball.vy = -ball.vy redraw_paddle(paddle) #パドルの再描画 redraw_ball(ball) #ボールの再描画 tk.update() #描画が画面に反映される time.sleep(DURATION) #次に描画するまで、sleepする
> パドルのあたる位置によってボールの反射角を変更したいです
質問はなんでしょう?
例)
「こういうふうに書いてみたけどエラーが出る」
「コードを書く以前の段階で、自分の思い描いた状況を具体的に言語化出来ない」
「いい感じのアルゴリズム考えてそれを実装したコードください」(丸投げ)
言葉たらずですみません。
パドルにボールが当たる位置によって角度が変わるようにしたいのですが、どのような関数?を使えばいいのか見当がつきません。言語化するにあたって考え方のヒントのようなものをいただけたら嬉しいです。
パドルの中央位置を0としたパドルとボールの接触点のx軸方向の位置
ボールの入射角度
ボールの反射角度
の関係を具体的に決めてください
a = math.atan(ball.vy/ (abs(paddle.x + paddle.w/2 - ball.x))) という関数?を作り
下の条件文
#ボールがパドルの上端に届き、ボールの幅がパドルの幅に収まっている
if (ball.y + ball.d >= paddle.y \
and paddle.x <= ball.x <= paddle.x + paddle.w):
ball.vy = -ball.vy
a = math.atan(ball.vy/ball.vx)
のところの末尾にこのように入れて実行してみたのですが変化がありませんでした。
|paddle.x + paddle.w/2 - ball.x|はパドルの中心からボールの接触した点の距離を表しています。
どこが間違っているのでしょうか。
いろいろ考え直して実行することができました!
回答1件
あなたの回答
tips
プレビュー