玉を打ち返す
まずは玉を打ち返せるようにします。
キー入力でバーを移動させることやバーと玉の当たり判定が必要になります。
キー入力でバーを移動させるには、def keyPressEventで入力を取得します。筆者のMacの構築環境だと矢印キーの入力が得られなかったので、h(左)とl(右)でvi風の入力にしました。あと玉の発出もenterキーでするようにしたが、macだとQt.Key_Enter の値と違うようなので、直接数値を指定しました(16777220はEnterキー)。
qtのkeyイベントの入力についてリンク参照。
上記のキー入力によって、def bar_moveを呼び出してバーを移動させます。
バーと玉の判定は若干自信がないのですが、四角の判定と上の2つの角の判定を行っています。
本当はリンク先のようにやったほうがいいけど、自力で作ったらコードのようになった。
バーの場合は、下と横は考えなくもいいと思うのでそのままにしています。
次のブロックを破壊する判定は、ちゃんと2領域プラス角4つにします。
判定もそうだけど加速度も考えなければいけないな。
横に当たった場合も跳ね返るなど(当たり前)
#!/usr/bin/env python
from PyQt5.QtWidgets import (QApplication, QWidget, QComboBox, QDialog,
QDialogButtonBox, QFormLayout, QGridLayout, QGroupBox, QHBoxLayout,
QLabel, QLineEdit, QMenu, QMenuBar, QPushButton, QSpinBox, QTextEdit,
QVBoxLayout, QGraphicsView, QGraphicsScene, QGraphicsItem, QGraphicsPixmapItem)
from PyQt5.QtGui import (QIcon, QPixmap, QBrush, QPen, QColor)
from PyQt5 import (QtCore , QtGui)
from PyQt5.QtCore import (QLineF, QPointF, QRectF, Qt, QTimer)
from PIL import Image, ImageDraw
from glob import glob
import sys
import os
import re
import cv2
class Test_graphics(QGraphicsItem):
def __init__(self):
super(Test_graphics, self).__init__()
self.ball_start = 0
self.x = 195
self.y = 368
self.a = 1
self.b = -1
self.bar_x = 175
def paint(self, painter, option, widget):
painter.setPen(Qt.black)
painter.drawEllipse(self.x, self.y, 10, 10)
painter.setPen(Qt.red)
painter.drawRect(self.bar_x, 379, 50, 10)
def boundingRect(self):
return QRectF(0,0,400,400)
def redraw(self):
if self.ball_start == 0:
pass
elif self.ball_start == 1:
self.x = self.x + 10*self.a
self.y = self.y + 10*self.b
if self.x <= 0:
self.a = 1
elif self.x >= 390:
self.a = -1
else:
pass
if self.y <= 0:
self.b = 1
elif self.y >= 390:
self.b = -1
else:
pass
self.collision_ball()
self.update()
elif self.ball_start == 2:
pass
def bar_move(self,input_x):
if self.bar_x + input_x < -5:
pass
elif self.bar_x + input_x > 355:
pass
else:
self.bar_x = self.bar_x + input_x
if self.ball_start == 0:
self.x = self.x + input_x
self.update()
def ball_move(self):
if self.ball_start == 0:
self.ball_start = 1
elif self.ball_start == 1:
self.ball_start = 2
elif self.ball_start == 2:
self.ball_start = 1
self.update()
def collision_ball(self):
r1 = (self.x - self.bar_x)**2 + (self.y - 359)**2
r2 = (self.x - (self.bar_x+50))**2 + (self.y - 359)**2
if ((self.y >= 359 and self.y <=385) and (self.bar_x <= self.x and self.bar_x +50 >= self.x)):
self.b = -1
elif (self.y >= 359 and self.y <=375) and (100 >= r1 or 100 >= r2):
self.b = -1
class MainWindow(QWidget):
def __init__(self,parent=None):
super(MainWindow, self).__init__(parent)
path = os.path.join(os.path.dirname(sys.modules[__name__].__file__), 'ico.png')
self.view = QGraphicsView()
scene = QGraphicsScene()
self.item = Test_graphics()
self.view.setSceneRect(0, 0, 400, 400);
item = QGraphicsPixmapItem(QPixmap(path))
item.setOffset (110, 110)
scene.addItem(item)
scene.addItem(self.item)
self.view.setScene(scene)
mainLayout = QVBoxLayout()
mainLayout.addWidget(self.view)
self.setLayout(mainLayout)
#windowのタイトル変更
self.setWindowTitle("Test App8")
self.plot_times = 0
self.timer = QTimer(self)
self.timer.timeout.connect(self.time_Event)
self.timer.start(100)
def time_Event(self):
self.item.redraw()
def keyPressEvent(self, e):
pressed = e.key()
if e.key() == Qt.Key_H: # 左
self.item.bar_move(-10)
elif e.key() == Qt.Key_L: # 右
self.item.bar_move(10)
elif e.key() == 16777220:
self.item.ball_move()
if __name__ == '__main__':
app = QApplication(sys.argv)
path = os.path.join(os.path.dirname(sys.modules[__name__].__file__), 'ico.png')
app.setWindowIcon(QIcon(path))
P = MainWindow()
P.show()
sys.exit(app.exec_())
ブロックの配置やブロックの当たり判定、衝突時の跳ね返り
ブロックの配置やブロックの当たり判定、衝突時の跳ね返りを行いました。
ブロックの当たり判定は4角の判定を行うと感度が良すぎるので、玉の中心と四角形の辺で行いました。
以外にブロックの色を列ごとに変化させるのが苦労しました。
#!/usr/bin/env python
from PyQt5.QtWidgets import (QApplication, QWidget, QComboBox, QDialog,
QDialogButtonBox, QFormLayout, QGridLayout, QGroupBox, QHBoxLayout,
QLabel, QLineEdit, QMenu, QMenuBar, QPushButton, QSpinBox, QTextEdit,
QVBoxLayout, QGraphicsView, QGraphicsScene, QGraphicsItem, QGraphicsPixmapItem)
from PyQt5.QtGui import (QIcon, QPixmap, QBrush, QPen, QColor)
from PyQt5 import (QtCore , QtGui)
from PyQt5.QtCore import (QLineF, QPointF, QRectF, Qt, QTimer)
from PIL import Image, ImageDraw
from glob import glob
import sys
import os
import re
import cv2
class Test_graphics(QGraphicsItem):
def __init__(self):
super(Test_graphics, self).__init__()
self.ball_start = 0
self.x = 195
self.y = 368
self.a = 1
self.b = -1
self.bar_x = 175
self.block = [[1 for i in range(8)] for j in range(4)]
def paint(self, painter, option, widget):
#draw ball
painter.setPen(Qt.black)
painter.setBrush(Qt.NoBrush)
painter.drawEllipse(self.x, self.y, 10, 10)
#draw block
painter.setPen(Qt.white)
pen = [[255,0,0,255],[255,255,0,255],[0,255,0,255],[0,0,255,255]]
for i in range(0,4,1):
for j in range(0,8,1):
if self.block[i][j] == 1:
r = pen[i][0]
g = pen[i][1]
b = pen[i][2]
a = pen[i][3]
painter.setBrush(QColor(r,g,b,a))
painter.drawRect(50*j,20*i, 50, 20)
#draw bar
painter.setPen(Qt.red)
painter.setBrush(Qt.white)
painter.drawRect(self.bar_x, 379, 50, 10)
def boundingRect(self):
return QRectF(0,0,400,400)
def redraw(self):
if self.ball_start == 0:
pass
elif self.ball_start == 1:
self.x = self.x + 10*self.a
self.y = self.y + 10*self.b
if self.x <= 0:
self.a = 1
elif self.x >= 390:
self.a = -1
else:
pass
if self.y <= 0:
self.b = 1
elif self.y >= 390:
self.b = -1
else:
pass
self.collision_bar()
self.collision_block()
self.update()
elif self.ball_start == 2:
pass
def bar_move(self,input_x):
if self.bar_x + input_x < -5:
pass
elif self.bar_x + input_x > 355:
pass
else:
self.bar_x = self.bar_x + input_x
if self.ball_start == 0:
self.x = self.x + input_x
self.update()
def ball_move(self):
if self.ball_start == 0:
self.ball_start = 1
elif self.ball_start == 1:
self.ball_start = 2
elif self.ball_start == 2:
self.ball_start = 1
self.update()
def collision_bar(self):
r1 = (self.x - self.bar_x)**2 + (self.y - 359)**2
r2 = (self.x - (self.bar_x+50))**2 + (self.y - 359)**2
if ((self.y >= 359 and self.y <=385) and (self.bar_x <= self.x and self.bar_x +50 >= self.x)):
self.b = -1
elif (self.y >= 359 and self.y <=375) and (100 >= r1 or 100 >= r2):
self.b = -1
def collision_block(self):
for i in range(0,4,1):
for j in range(0,8,1):
if self.block[i][j]== 0:
pass
elif self.x > 50*j and self.x < 50*(j+1) and self.y > 20*i and self.y < 20*(i+1) :
self.block[i][j]= 0
if self.x > 50*j and self.x < 50*(j+1):
if self.b == 1:
self.b = -1
elif self.b == -1:
self.b = 1
elif self.y > 20*i and self.y < 20*(i+1):
if self.a == 1:
self.a = -1
elif self.a == -1:
self.a = 1
class MainWindow(QWidget):
def __init__(self,parent=None):
super(MainWindow, self).__init__(parent)
path = os.path.join(os.path.dirname(sys.modules[__name__].__file__), 'ico.png')
self.view = QGraphicsView()
scene = QGraphicsScene()
self.item = Test_graphics()
self.view.setSceneRect(0, 0, 400, 400);
item = QGraphicsPixmapItem(QPixmap(path))
item.setOffset (110, 110)
scene.addItem(item)
scene.addItem(self.item)
self.view.setScene(scene)
mainLayout = QVBoxLayout()
mainLayout.addWidget(self.view)
self.setLayout(mainLayout)
#windowのタイトル変更
self.setWindowTitle("Test App9")
self.plot_times = 0
self.timer = QTimer(self)
self.timer.timeout.connect(self.time_Event)
self.timer.start(100)
def time_Event(self):
self.item.redraw()
def keyPressEvent(self, e):
pressed = e.key()
if e.key() == Qt.Key_H: # 左
self.item.bar_move(-10)
elif e.key() == Qt.Key_L: # 右
self.item.bar_move(10)
elif e.key() == 16777220:
self.item.ball_move()
if __name__ == '__main__':
app = QApplication(sys.argv)
path = os.path.join(os.path.dirname(sys.modules[__name__].__file__), 'ico.png')
app.setWindowIcon(QIcon(path))
P = MainWindow()
P.show()
sys.exit(app.exec_())
アプリ画面です。
音と点数のカウント(文字の表示)を追加
pyqtでの音の出し方がわからなかったので、pyaudioとsubprocessで実行しています。
#!/usr/bin/env python
from PyQt5.QtWidgets import (QApplication, QWidget, QComboBox, QDialog,
QDialogButtonBox, QFormLayout, QGridLayout, QGroupBox, QHBoxLayout,
QLabel, QLineEdit, QMenu, QMenuBar, QPushButton, QSpinBox, QTextEdit,
QVBoxLayout, QGraphicsView, QGraphicsScene, QGraphicsItem, QGraphicsPixmapItem, QGraphicsTextItem)
from PyQt5.QtGui import (QIcon, QPixmap, QBrush, QPen, QColor)
from PyQt5 import (QtCore , QtGui)
from PyQt5.QtCore import (QLineF, QPointF, QRectF, Qt, QTimer)
from PIL import Image, ImageDraw
from glob import glob
import sys
import os
import re
import cv2
import subprocess
class Test_graphics(QGraphicsItem):
def __init__(self):
super(Test_graphics, self).__init__()
self.ball_start = 0
self.x = 195
self.y = 368
self.a = 1
self.b = -1
self.bar_x = 175
self.block = [[1 for i in range(8)] for j in range(4)]
self.point = 0
self.game_over = 0
self.sound = os.path.join(os.path.dirname(sys.modules[__name__].__file__), "cannon_sound.py")
def paint(self, painter, option, widget):
#draw ball
painter.setPen(Qt.black)
painter.setBrush(Qt.white)
painter.drawEllipse(self.x, self.y, 10, 10)
#draw block
painter.setPen(Qt.white)
pen = [[255,0,0,255],[255,255,0,255],[0,255,0,255],[0,0,255,255]]
for i in range(0,4,1):
for j in range(0,8,1):
if self.block[i][j] == 1:
r = pen[i][0]
g = pen[i][1]
b = pen[i][2]
a = pen[i][3]
painter.setPen(Qt.white)
painter.setBrush(QColor(r,g,b,a))
painter.drawRect(50*j,20*i, 50, 20)
painter.setPen(Qt.white)
painter.setFont(QtGui.QFont("System" , 12, QtGui.QFont.Normal, False))
painter.drawText(QtCore.QRect(50*j,20*i, 50, 20) ,Qt.AlignCenter ,"10")
#draw bar
painter.setPen(Qt.red)
painter.setBrush(Qt.white)
painter.drawRect(self.bar_x, 379, 50, 10)
if self.game_over == 1:
painter.setPen(Qt.red)
painter.setFont(QtGui.QFont("System" , 60, QtGui.QFont.Bold, False))
painter.drawText(QtCore.QRect(0,0,400,400) ,Qt.AlignCenter ,"GAME OVER")
def boundingRect(self):
return QRectF(0,0,400,400)
def redraw(self):
if self.ball_start == 0:
pass
elif self.ball_start == 1:
self.x = self.x + 10*self.a
self.y = self.y + 10*self.b
if self.x <= 0:
self.a = 1
elif self.x >= 390:
self.a = -1
else:
pass
if self.y <= 0:
self.b = 1
elif self.y >= 390:
#self.b = -1
self.game_over = 1
self.ball_start == 0
else:
pass
self.collision_bar()
self.collision_block()
self.update()
elif self.ball_start == 2:
pass
return self.point
def bar_move(self,input_x):
if self.bar_x + input_x < -5:
pass
elif self.bar_x + input_x > 355:
pass
else:
self.bar_x = self.bar_x + input_x
if self.ball_start == 0:
self.x = self.x + input_x
self.update()
def ball_move(self):
if self.ball_start == 0:
self.ball_start = 1
elif self.ball_start == 1:
self.ball_start = 2
elif self.ball_start == 2:
self.ball_start = 1
self.update()
def collision_bar(self):
r1 = (self.x - self.bar_x)**2 + (self.y - 359)**2
r2 = (self.x - (self.bar_x+50))**2 + (self.y - 359)**2
if ((self.y >= 359 and self.y <=385) and (self.bar_x <= self.x and self.bar_x +50 >= self.x)):
self.b = -1
elif (self.y >= 359 and self.y <=375) and (100 >= r1 or 100 >= r2):
self.b = -1
def collision_block(self):
for i in range(0,4,1):
for j in range(0,8,1):
if self.block[i][j]== 0:
pass
elif self.x > 50*j and self.x < 50*(j+1) and self.y > 20*i and self.y < 20*(i+1) :
self.block[i][j]= 0
subprocess.Popen(self.sound )
self.point = self.point + 10
if self.x > 50*j and self.x < 50*(j+1):
if self.b == 1:
self.b = -1
elif self.b == -1:
self.b = 1
elif self.y > 20*i and self.y < 20*(i+1):
if self.a == 1:
self.a = -1
elif self.a == -1:
self.a = 1
class MainWindow(QWidget):
def __init__(self,parent=None):
super(MainWindow, self).__init__(parent)
path = os.path.join(os.path.dirname(sys.modules[__name__].__file__), 'ico.png')
self.view = QGraphicsView()
scene = QGraphicsScene()
self.item = Test_graphics()
self.view.setSceneRect(0, 0, 400, 400);
item = QGraphicsPixmapItem(QPixmap(path))
item.setOffset (110, 110)
self.text = QGraphicsTextItem("")
self.text.setFont( QtGui.QFont( 'System Black', 30 ) )
self.text.setTransform( QtGui.QTransform().translate( 250, 330))
scene.addItem(item)
scene.addItem(self.text)
scene.addItem(self.item)
self.view.setScene(scene)
mainLayout = QVBoxLayout()
mainLayout.addWidget(self.view)
self.setLayout(mainLayout)
self.setWindowTitle("Test App10")
self.plot_times = 0
self.timer = QTimer(self)
self.timer.timeout.connect(self.time_Event)
self.timer.start(100)
if os.path.isdir("./png") == False :
os.mkdir("./png")
else:
pass
def time_Event(self):
point = self.item.redraw()
if point >= 100 :
point = str(point) + "Point"
elif point >= 10 :
point = "0" + str(point) + "Point"
else :
point = "00" + str(point) + "Point"
self.text.setPlainText(str(point))
def keyPressEvent(self, e):
pressed = e.key()
if e.key() == Qt.Key_H: # 左
self.item.bar_move(-10)
elif e.key() == Qt.Key_L: # 右
self.item.bar_move(10)
elif e.key() == 16777220:
self.item.ball_move()
if __name__ == '__main__':
app = QApplication(sys.argv)
path = os.path.join(os.path.dirname(sys.modules[__name__].__file__), 'ico.png')
app.setWindowIcon(QIcon(path))
P = MainWindow()
P.show()
sys.exit(app.exec_())
#!/usr/bin/env python
import wave
import pyaudio
import sys
import os
import re
CHUNK = 1024
filename = os.path.join(os.path.dirname(sys.modules[__name__].__file__), 'cannon1.wav')
wf = wave.open(filename, "r")
p = pyaudio.PyAudio()
stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
channels=wf.getnchannels(),
rate=wf.getframerate(),
output=True)
data = wf.readframes(CHUNK)
while len(data) > 0:
stream.write(data)
data = wf.readframes(CHUNK)
stream.stop_stream()
stream.close()
p.terminate()