-
Notifications
You must be signed in to change notification settings - Fork 51
/
Copy pathblock.py
203 lines (180 loc) · 6.83 KB
/
block.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
#!/usr/bin/env python3
# File: block.py
# Description: This file contains the declaration of basic tetris block class.
# Author: Pavel Benáček <[email protected]>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import pdb
import constants
import pygame
import math
import copy
import sys
class Block(object):
"""
Class for handling of tetris block
"""
def __init__(self,shape,x,y,screen,color,rotate_en):
"""
Initialize the tetris block class
Parameters:
- shape - list of block data. The list contains [X,Y] coordinates of
building blocks.
- x - X coordinate of first tetris shape block
- y - Y coordinate of first tetris shape block
- screen - screen to draw on
- color - the color of each shape block in RGB notation
- rotate_en - enable or disable the rotation
"""
# The initial shape (convert all to Rect objects)
self.shape = []
for sh in shape:
bx = sh[0]*constants.BWIDTH + x
by = sh[1]*constants.BHEIGHT + y
block = pygame.Rect(bx,by,constants.BWIDTH,constants.BHEIGHT)
self.shape.append(block)
# Setup the rotation attribute
self.rotate_en = rotate_en
# Setup the rest of variables
self.x = x
self.y = y
# Movement in the X,Y coordinates
self.diffx = 0
self.diffy = 0
# Screen to drawn on
self.screen = screen
self.color = color
# Rotation of the screen
self.diff_rotation = 0
def draw(self):
"""
Draw the block from shape blocks. Each shape block
is filled with a color and black border.
"""
for bl in self.shape:
pygame.draw.rect(self.screen,self.color,bl)
pygame.draw.rect(self.screen,constants.BLACK,bl,constants.MESH_WIDTH)
def get_rotated(self,x,y):
"""
Compute the new coordinates based on the rotation angle.
Parameters:
- x - the X coordinate to transfer
- y - the Y coordinate to transfer
Returns the tuple with new (X,Y) coordinates.
"""
# Use the classic transformation matrix:
# https://www.siggraph.org/education/materials/HyperGraph/modeling/mod_tran/2drota.htm
rads = self.diff_rotation * (math.pi / 180.0)
newx = x*math.cos(rads) - y*math.sin(rads)
newy = y*math.cos(rads) + x*math.sin(rads)
return (newx,newy)
def move(self,x,y):
"""
Move all elements of the block using the given offset.
Parameters:
- x - movement in the X coordinate
- y - movement in the Y coordinate
"""
# Accumulate X,Y coordinates and call the update function
self.diffx += x
self.diffy += y
self._update()
def remove_blocks(self,y):
"""
Remove blocks on the Y coordinate. All blocks
above the Y are moved one step down.
Parameters:
- y - Y coordinate to work with.
"""
new_shape = []
for shape_i in range(len(self.shape)):
tmp_shape = self.shape[shape_i]
if tmp_shape.y < y:
# Block is above the y, move down and add it to the list of active shape
# blocks.
new_shape.append(tmp_shape)
tmp_shape.move_ip(0,constants.BHEIGHT)
elif tmp_shape.y > y:
# Block is below the y, add it to the list. The block doesn't need to be moved because
# the removed line is above it.
new_shape.append(tmp_shape)
# Setup the new list of block shapes.
self.shape = new_shape
def has_blocks(self):
"""
Returns true if the block has some shape blocks in the shape list.
"""
return True if len(self.shape) > 0 else False
def rotate(self):
"""
Setup the rotation value to 90 degrees.
"""
# Setup the rotation and update coordinates of all shape blocks.
# The block is rotated iff the rotation is enabled
if self.rotate_en:
self.diff_rotation = 90
self._update()
def _update(self):
"""
Update the position of all shape boxes.
"""
for bl in self.shape:
# Get old coordinates and compute new x,y coordinates.
# All rotation calculates are done in the original coordinates.
origX = (bl.x - self.x)/constants.BWIDTH
origY = (bl.y - self.y)/constants.BHEIGHT
rx,ry = self.get_rotated(origX,origY)
newX = rx*constants.BWIDTH + self.x + self.diffx
newY = ry*constants.BHEIGHT + self.y + self.diffy
# Compute the relative move
newPosX = newX - bl.x
newPosY = newY - bl.y
bl.move_ip(newPosX,newPosY)
# Everyhting was moved. Setup new x,y, coordinates and reset all disable the move
# variables.
self.x += self.diffx
self.y += self.diffy
self.diffx = 0
self.diffy = 0
self.diff_rotation = 0
def backup(self):
"""
Backup the current configuration of shape blocks.
"""
# Make the deep copy of the shape list. Also, remember
# the current configuration.
self.shape_copy = copy.deepcopy(self.shape)
self.x_copy = self.x
self.y_copy = self.y
self.rotation_copy = self.diff_rotation
def restore(self):
"""
Restore the previous configuraiton.
"""
self.shape = self.shape_copy
self.x = self.x_copy
self.y = self.y_copy
self.diff_rotation = self.rotation_copy
def check_collision(self,rect_list):
"""
The function checks if the block colides with any other block
in the shape list.
Parameters:
- rect_list - the function accepts the list of Rect object which
are used for the collistion detection.
"""
for blk in rect_list:
collist = blk.collidelistall(self.shape)
if len(collist):
return True
return False