-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdippid_game.py
260 lines (221 loc) · 8.8 KB
/
dippid_game.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
# script written by joshua benker
import sys
import math
import random
from PyQt5 import QtGui, QtCore, QtWidgets
from DIPPID import SensorUDP
from enum import Enum
SENSOR_PORT = 5700
WINDOW_WIDTH = 650
WINDOW_HEIGHT = 650
BODY_WIDTH = 100
BODY_HEIGHT = 30
# state of the game
class GameState(Enum):
INTRO = 1
START = 2
LOST = 3
# main game class
# neccesssary: an android phone to get the dippid sensor output
# creates a ball-object and two body-objects from the other classes
class Game(QtWidgets.QWidget):
sensor = ()
timer = ()
body_bottom = ()
body_top = ()
ball = ()
points = 0
def __init__(self):
super().__init__()
self.screen_x_size = WINDOW_WIDTH
self.screen_y_size = WINDOW_HEIGHT
self.setFixedSize(self.screen_x_size, self.screen_y_size)
self.setFocusPolicy(QtCore.Qt.StrongFocus)
self.init_sensor()
self.init_body()
self.init_ball()
self.timer = QtCore.QTimer(self)
self.xPos_bt = self.frameGeometry().width() / 2 - BODY_WIDTH / 2
self.yPos_bt = self.frameGeometry().height() - BODY_HEIGHT
self.info = QtCore.QRect(0, self.frameGeometry().height() / 2, self.frameGeometry().width(), 100)
self.points_box = QtCore.QRect(20, 10, self.frameGeometry().width(), 40)
self.game_state = GameState.INTRO
self.init_timer_game_loop()
self.show()
# initialize the painter and calls the info depending on the game state
def paintEvent(self, event):
painter = QtGui.QPainter(self)
# draws bodies
self.draw_body(painter)
# draws ball
painter.setBrush(QtGui.QBrush(QtCore.Qt.cyan, QtCore.Qt.SolidPattern))
painter.setPen(QtGui.QPen(QtCore.Qt.cyan, QtCore.Qt.SolidPattern))
painter.drawEllipse(self.ball.x, self.ball.y, self.ball.radius, self.ball.radius)
# draws points the player achieves
painter.setPen(QtGui.QPen(QtCore.Qt.black, QtCore.Qt.SolidPattern))
points = "Points: " + str(self.points)
painter.drawText(self.points_box, QtCore.Qt.AlignLeft, points)
if self.game_state == GameState.INTRO:
self.draw_intro_message(painter)
elif self.game_state == GameState.LOST:
self.draw_gamover_message(painter)
# paints the intro message
def draw_intro_message(self, painter):
painter.setPen(QtGui.QPen(QtCore.Qt.black, QtCore.Qt.SolidPattern))
text = "Welcome.\nPress 'Button 1' to start.\nUse your phone to move " \
"the two objects by tilting it. \n You are both players."
painter.drawText(self.info, QtCore.Qt.AlignCenter, text)
# paints the game over message
def draw_gamover_message(self, painter):
text = "Oh damn. You missed the ball! \n " \
"You made " + str(self.points) + " points \nPress 'Button 1' to restart."
painter.drawText(self.info, QtCore.Qt.AlignCenter, text)
def draw_body(self, painter):
painter.setBrush(QtGui.QBrush(QtCore.Qt.blue, QtCore.Qt.SolidPattern))
painter.drawRect(self.body_bottom)
painter.drawRect(self.body_top)
# initialize the sensor on port 5700
def init_sensor(self):
BUTTON_START = 'button_1'
self.sensor = SensorUDP(SENSOR_PORT)
self.sensor.register_callback(BUTTON_START, self.button_start_pressed)
# initialize the two bodies with the class 'Body'
def init_body(self):
self.xPos_bt = self.frameGeometry().width() / 2 - BODY_WIDTH / 2
self.yPos_bt = self.frameGeometry().height() - BODY_HEIGHT
self.body_bottom = Body(self.xPos_bt, self.yPos_bt, BODY_WIDTH, BODY_HEIGHT, self, 'bottom')
self.body_top = Body(self.xPos_bt, 0, BODY_WIDTH, BODY_HEIGHT, self, 'top')
# initialize the ball with the class 'Ball'
def init_ball(self):
xPos = self.body_bottom.x() + self.body_bottom.body_width / 2
yPos = self.body_bottom.y() - 25
self.ball = Ball(xPos, yPos, 30, self)
# game loop
# found on https://doc.qt.io/qtforpython-5/PySide2/QtCore/QTimer.html
def init_timer_game_loop(self):
self.timer = QtCore.QTimer(self)
self.timer.timeout.connect(self.game_loop)
self.timer.start(30)
# gets called when the 'button 1' got pressed
# changes the game state and restarts the game if it's over
def button_start_pressed(self, data):
if data == 0:
return
if self.game_state == GameState.INTRO:
self.game_state = GameState.START
if self.game_state == GameState.LOST:
self.game_state = GameState.START
self.start_new_round()
# game loop gets called by the timer
def game_loop(self):
if self.game_state == GameState.START:
if self.sensor.has_capability('accelerometer'):
value_sensor = self.sensor.get_value('accelerometer')
else:
return
value_y = value_sensor['y']
self.body_bottom.move(value_y * 10)
self.body_top.move(value_y * 10)
self.ball.move()
self.update()
# gets called by the ball function is_gameover
# sets the game state to "lost"
def on_gameover(self):
self.game_state = GameState.LOST
self.update()
# gets called when the player starts a new round after he lost
def start_new_round(self):
self.points = 0
self.body_bottom.moveTo(self.xPos_bt, self.yPos_bt)
self.body_top.moveTo(self.xPos_bt, 0)
self.init_ball()
# class for the body
# handles moving depending on the body-type (bottom or top body)
class Body(QtCore.QRect):
def __init__(self, x, y, width, height, window, body_type):
super().__init__(x, y, width, height)
self.window = window
self.body_width = width
self.body_height = height
self.body_type = body_type
def move(self, value_y):
if self.body_type == 'bottom':
self.moveLeft(self.x() + value_y)
if self.x() < 0:
self.moveLeft(0)
elif self.x() > self.window.frameGeometry().width() - self.body_width:
self.moveLeft(self.window.frameGeometry().width() - self.body_width)
elif self.body_type == 'top':
self.moveLeft(self.x() - value_y)
if self.x() < 0:
self.moveLeft(0)
elif self.x() > self.window.frameGeometry().width() - self.body_width:
self.moveLeft(self.window.frameGeometry().width() - self.body_width)
# class for the ball
# handles moving and if it hits the window or the body
class Ball:
def __init__(self, x, y, diameter, window):
self.window = window
self.x = x
self.y = y
self.diameter = diameter
self.radius = diameter / 2
self.speed_x = 6
self.speed_y = -6
# handles ball-moving
def move(self):
self.x += self.speed_x
self.y += self.speed_y
self.hit_window()
self.hit_body()
self.is_gameover()
# checks if ball hits the body
def hit_body(self):
hit = self.touch_body(self.window.body_bottom)
if hit is False:
hit = self.touch_body(self.window.body_top)
if hit == 'out':
self.speed_x *= -1
elif hit == 'in':
self.window.points += 1
self.speed_y *= -1
# checks if ball hits the window
def hit_window(self):
if self.x + self.radius * 2 > self.window.frameGeometry().width() or self.x <= 0:
self.speed_x *= -1
elif self.y <= 0:
self.speed_y *= -1
# calculates the distance and returns where the ball hit the body
def touch_body(self, body):
x_middle = self.x + self.radius
y_middle = self.y + self.radius
x_value = x_middle
y_value = y_middle
if y_middle > body.bottom():
y_value = body.bottom()
elif y_middle < body.top():
y_value = -body.top()
if x_middle < body.left():
x_value = body.left()
elif x_middle > body.right():
x_value = body.right()
distance_x = x_middle - x_value
distance_y = y_middle - y_value
distance = math.sqrt(distance_x ** 2 + distance_y ** 2)
# returns 'in' if the ball is still in the game
# 'out' when the player hit the ball on the side
if distance <= self.radius:
if distance_x == 0:
return 'in'
elif distance_y == 0:
return 'out'
# if the ball didn't touch the body
return False
# checks if player is game over
def is_gameover(self):
if self.y > self.window.frameGeometry().height() or self.y <= 0:
self.window.on_gameover()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
game = Game()
app.exec()