質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

3157閲覧

ブロック崩しゲームを作成しています。パドルにボールが跳ね返るときに角度をあたる位置によって変えたいのですが変えることができません。また、動作中にボールが欠けることがあります。この不具合を解消したいです

Simonde

総合スコア7

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2020/10/12 05:26

ブロック崩しゲームを作成してます。パドルとボールを使ってブロックを崩すという動作を作ることはできました。でも、ボールをパドルで跳ね返すときに、反射角が常に一定になってしまいます。パドルのあたる位置によってボールの反射角を変更したいです。またボールが動作中にたまにかけてしまうことがあります。この不具合を解消したいです。

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する

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ozwk

2020/10/12 05:48

> パドルのあたる位置によってボールの反射角を変更したいです 質問はなんでしょう? 例) 「こういうふうに書いてみたけどエラーが出る」 「コードを書く以前の段階で、自分の思い描いた状況を具体的に言語化出来ない」 「いい感じのアルゴリズム考えてそれを実装したコードください」(丸投げ)
Simonde

2020/10/12 06:19

言葉たらずですみません。 パドルにボールが当たる位置によって角度が変わるようにしたいのですが、どのような関数?を使えばいいのか見当がつきません。言語化するにあたって考え方のヒントのようなものをいただけたら嬉しいです。
ozwk

2020/10/12 06:33

パドルの中央位置を0としたパドルとボールの接触点のx軸方向の位置 ボールの入射角度 ボールの反射角度 の関係を具体的に決めてください
Simonde

2020/10/12 09:55

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|はパドルの中心からボールの接触した点の距離を表しています。 どこが間違っているのでしょうか。
Simonde

2020/10/12 10:48

いろいろ考え直して実行することができました!
guest

回答1

0

ベストアンサー

ボールの跳ね返り方を変えるのであれば、以下の場所

python

1 #ボールがパドルの上端に届き、ボールの幅がパドルの幅に収まっている 2 if (ball.y + ball.d >= paddle.y \ 3 and paddle.x <= ball.x <= paddle.x + paddle.w): 4 ball.vy = -ball.vy

で、ポールがパドルにあたった位置が計算できると思うので、その値に応じてball.vxやball.vyの値を書き換える処理を追加すればいいでしょう。

例えば、(paddle.x と ball.xの差分とpaddle.wの比)と(vx,vy)の値を取って新たなvx, vyを返すような関数を作って値を計算するなどですかね。

投稿2020/10/12 06:23

TakaiY

総合スコア12765

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Simonde

2020/10/12 09:55

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|はパドルの中心からボールの接触した点の距離を表しています。 どこが間違っているのでしょうか。
Simonde

2020/10/12 10:48

いろいろ考え直して実行することができました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問