테트리스 소스코드 출처:http://zetcode.com/wxpython/thetetrisgame/
클래스
Tetris, Board, Tetrinomoes, Shape
리스트
board, : 보드 리스트
coordsTable, : 모든 Shape 리스트
coords : 한개 Shape 리스트
변수
self.isWaitingAfterLine : 블록이 최초 생성인지 확인하기 위한 것
화면 그리기:
블록(piece) 하나 그리기, 블록 쌓인 것 그리기,
기능 :
블록 하나 생성, 블록회전, 이동, 충돌검사, 채워짐 검사 세팅, 블록 제거 세팅, 보드 상단 접촉 검사
배열 :
보드 초기화, 보드 블록 유무 세팅, 블록 이동 보드 배열 값 수정
키 눌러짐 검사
반복 실행(작업)
프로그램 최초 시작
app = wx.App()
Tetris(None, title='Tetris')
app.MainLoop()
블록 쌓인 것 그리기, 블록 하나 그리기, 블록 이동
방법: 배열 값에 따라 전 화면을 다시 그려준다.
블록 쌓인 것 그리기
블록 전체(쌓인부분, 빈공간)를 그린다.
for i in range(Board.BoardHeight):
for j in range(Board.BoardWidth):
shape = self.shapeAt(j, Board.BoardHeight - i - 1)
if shape != Tetrominoes.NoShape:
self.drawSquare(dc,
0 + j * self.squareWidth(),
boardTop + i * self.squareHeight(), shape)
for문 설명:
블록 하나 그리기, 블록 이동
블록 하나를 빈공간에 그린다. 블록이 이동하는 것처럼 보인다.
if self.curPiece.shape() != Tetrominoes.NoShape:
for i in range(4):
x = self.curX + self.curPiece.x(i)
y = self.curY - self.curPiece.y(i)
self.drawSquare(dc, 0 + x * self.squareWidth(),
boardTop + (Board.BoardHeight - y - 1) * self.squareHeight(),
self.curPiece.shape())
블록 이동 좌표 수정
X,Y 좌표를 수정한다.
self.curY-1 : 좌표 값을 줄이면 위치가 바뀐다.
self.tryMove(self.curPiece, self.curX, self.curY - 1):
def tryMove(self, newPiece, newX, newY):
for i in range(4):
x = newX + newPiece.x(i)
y = newY - newPiece.y(i)
if x < 0 or x >= Board.BoardWidth or y < 0 or y >= Board.BoardHeight:
return False
if self.shapeAt(x, y) != Tetrominoes.NoShape:
return False
self.curPiece = newPiece
self.curX = newX 변한 좌표 값을 전달 받는 곳
self.curY = newY
self.Refresh()
return True
블록 이동 보드 배열 수정
def pieceDropped(self):
for i in range(4):
x = self.curX + self.curPiece.x(i)
y = self.curY - self.curPiece.y(i)
self.setShapeAt(x, y, self.curPiece.shape())
self.removeFullLines()
블록 하나 생성
self.nextPiece.setRandomShape()
블록 회전
회전 수학 공식 : https://ilvjesuscoding.tistory.com/73?category=708594
def rotatedLeft(self):
if self.pieceShape == Tetrominoes.SquareShape:
return self
result = Shape()
result.pieceShape = self.pieceShape
for i in range(4):
result.setX(i, self.y(i))
result.setY(i, -self.x(i))
return result
def rotatedRight(self):
if self.pieceShape == Tetrominoes.SquareShape:
return self
result = Shape()
result.pieceShape = self.pieceShape
for i in range(4):
result.setX(i, -self.y(i))
result.setY(i, self.x(i))
return result
블록 이동, 충돌 검사 (벽)
좌표 값을 비교한다.
self.tryMove(self.curPiece, self.curX - 1, self.curY)
if x < 0 or x >= Board.BoardWidth or y < 0 or y >= Board.BoardHeight:
return False
if self.shapeAt(x, y) != Tetrominoes.NoShape:
return False
블록 보드 상단 접촉 검사 : 블록이 더이상 내려갈 수 없는지 검사
if not self.tryMove(self.curPiece, self.curX, self.curY):
self.curPiece.setShape(Tetrominoes.NoShape)
self.timer.Stop()
self.isStarted = False
statusbar.SetStatusText('Game over')
보드 블록 유무 세팅
배열 값을 수정한다.
shape = self.shapeAt(j, Board.BoardHeight - i - 1)
self.board = []
self.clearBoard()
블록 한줄 채워짐 검사
배열 값을 비교한다. 그리고 총 갯수를 센다.
for i in range(Board.BoardHeight):
n = 0
for j in range(Board.BoardWidth):
if not self.shapeAt(j, i) == Tetrominoes.NoShape:
n = n + 1
if n == 10:
rowsToRemove.append(i)
블록 제거 세팅
방법: 배열 값을 바꾼다.
rowsToRemove.reverse()
for m in rowsToRemove: for k in range(m, Board.BoardHeight): for l in range(Board.BoardWidth): self.setShapeAt(l, k, self.shapeAt(l, k + 1))
키 눌러짐 검사
self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
def OnKeyDown(self, event):
if not self.isStarted or self.curPiece.shape() == Tetrominoes.NoShape:
event.Skip()
return
keycode = event.GetKeyCode()
if keycode == ord('P') or keycode == ord('p'):
self.pause()
return
if self.isPaused:
return
elif keycode == ord('J') or keycode == ord('j'):
self.tryMove(self.curPiece, self.curX - 1, self.curY)
elif keycode == ord('L') or keycode == ord('l'):
self.tryMove(self.curPiece, self.curX + 1, self.curY)
elif keycode == wx.WXK_DOWN:
self.tryMove(self.curPiece.rotatedRight(), self.curX, self.curY)
elif keycode == ord('I') or keycode == ord('i'):
self.tryMove(self.curPiece.rotatedLeft(), self.curX, self.curY)
elif keycode == wx.WXK_SPACE:
self.dropDown()
elif keycode == ord('D') or keycode == ord('d'):
self.oneLineDown()
else:
event.Skip()
반복 실행 : 블록이 계속해서(반복해서) 그려지고 떨어지는 작업
self.Bind(wx.EVT_TIMER, self.OnTimer, id=Board.ID_TIMER)
def OnTimer(self, event):
if event.GetId() == Board.ID_TIMER:
if self.isWaitingAfterLine:
self.isWaitingAfterLine = False
self.newPiece()
else:
self.oneLineDown()
else:
event.Skip()