Python 작은 게임 의 300 줄 코드 는 러시아 블록 을 실현 합 니 다.

머리말
이 코드 는 python 3.6 과 pygame 1.9.4 를 바탕 으로 합 니 다.
러시아 블록 은 어 렸 을 때 가장 전형 적 인 게임 중 하나 로 pygame 을 처음 접 했 을 때 러시아 블록 을 쓰 고 싶 었 습 니 다.하지만 회전,정지,제거 등 을 생각하면 어 려 울 것 같 습 니 다.실제로 쓰 고 보 니 모두 300 줄 의 코드 가 있 습 니 다.어렵 지 않 습 니 다.
먼저 게임 캡 처 를 보 겠 습 니 다.좀 못 생 겼 습 니 다.좋 습 니 다.저 는 미술 세포 가 없 지만 주체 기능 이 모두 실현 되 어 놀 수 있 습 니 다.

이제 실현 과정 을 살 펴 보 자.
외형
러시아 블록 전체 화면 은 두 부분 으로 나 뉘 는데 하 나 는 왼쪽 의 게임 구역 이 고 다른 하 나 는 오른쪽 에 있 는 디 스 플레이 구역 으로 득점,속도,다음 사각형 스타일 등 을 나타 낸다.여 기 는 캡 처 를 놓 지 않 겠 습 니 다.위의 그림 을 보시 면 됩 니 다.
게임 구역 은 뱀 을 탐식 하 는 것 과 마찬가지 로 작은 사각형 으로 구성 되 어 있 습 니 다.직관 적 으로 보기 위해 저 는 특별히 격자 선 을 그 렸 습 니 다.

import sys
import pygame
from pygame.locals import *

SIZE = 30 #        
BLOCK_HEIGHT = 20 #      
BLOCK_WIDTH = 10 #      
BORDER_WIDTH = 4 #        
BORDER_COLOR = (40, 40, 200) #        
SCREEN_WIDTH = SIZE * (BLOCK_WIDTH + 5) #       
SCREEN_HEIGHT = SIZE * BLOCK_HEIGHT #       
BG_COLOR = (40, 40, 60) #    
BLACK = (0, 0, 0)


def print_text(screen, font, x, y, text, fcolor=(255, 255, 255)):
 imgText = font.render(text, True, fcolor)
 screen.blit(imgText, (x, y))


def main():
 pygame.init()
 screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
 pygame.display.set_caption('     ')

 font1 = pygame.font.SysFont('SimHei', 24) #   24
 font_pos_x = BLOCK_WIDTH * SIZE + BORDER_WIDTH + 10 #              X  
 font1_height = int(font1.size('  ')[1])

 score = 0  #   

 while True:
 for event in pygame.event.get():
  if event.type == QUIT:
  sys.exit()

 #      
 screen.fill(BG_COLOR)
 #         
 pygame.draw.line(screen, BORDER_COLOR,
    (SIZE * BLOCK_WIDTH + BORDER_WIDTH // 2, 0),
    (SIZE * BLOCK_WIDTH + BORDER_WIDTH // 2, SCREEN_HEIGHT), BORDER_WIDTH)
 #        
 for x in range(BLOCK_WIDTH):
  pygame.draw.line(screen, BLACK, (x * SIZE, 0), (x * SIZE, SCREEN_HEIGHT), 1)
 #        
 for y in range(BLOCK_HEIGHT):
  pygame.draw.line(screen, BLACK, (0, y * SIZE), (BLOCK_WIDTH * SIZE, y * SIZE), 1)

 print_text(screen, font1, font_pos_x, 10, f'  : ')
 print_text(screen, font1, font_pos_x, 10 + font1_height + 6, f'{score}')
 print_text(screen, font1, font_pos_x, 20 + (font1_height + 6) * 2, f'  : ')
 print_text(screen, font1, font_pos_x, 20 + (font1_height + 6) * 3, f'{score // 10000}')
 print_text(screen, font1, font_pos_x, 30 + (font1_height + 6) * 4, f'   :')

 pygame.display.flip()


if __name__ == '__main__':
 main()
네모 난 덩어리
다음은 사각형 을 정의 하 는 것 입 니 다.사각형 의 모양 은 모두 다음 과 같은 7 가지 가 있 습 니 다.

I 형

O 형

T 형

S 형

Z 형

L 형

J 형
여기 서 저 는 여러 번 변 경 했 습 니 다.사각형 의 가장 큰 길 이 는 긴 줄 모양 이 고 4 칸 이기 때문에 저 는 4 칸 을 통일 적 으로 사 용 했 습 니 다.× 4 의 격자 로 정의 합 니 다.이것 도 괜 찮 은 데 나중에 불편 하 다 는 것 을 알 게 되 었 다.
직관 을 위해 직접 2 차원 배열 로 사각형 을 정의 한다.그 중에서 빈 것 을 나타 내 고 0 은 진심 을 나타 낸다.(비..비 어 있 음 을 나타 내 는 것 은 직관 적 으로 보기 위해 서 이다.빈 칸 을 사용 하면 잘 보이 지 않 는 다.)
예 를 들 면 I 행,4 로× 사각형

['.0..',
 '.0..',
 '.0..',
 '.0..']
화해시키다

['....',
 '....',
 '0000',
 '....']
사각형 이 가장 어 려 운 것 은 회전 기능 을 실현 해 야 한 다 는 것 이다.예 를 들 어 I 형 은 가로 와 세로 두 가지 형태 가 있다.회전 이란 겉으로 볼 때 사각형 을 시계 방향 으로 90°회전 시 켰 지만 실제로 할 때 우 리 는 이'회전'의 효 과 를 실현 할 필요 가 없다.
최종 적 으로 실 현 될 때 이런 도형 들 은 모두 우리 가 화면 에 그린 것 이다.매번 에 새로 고 칠 때마다 화면 에 있 는 모든 내용 이 비 워 지고 다시 그린다.그래서 회전 은 현재 사각형 을 그 릴 때 예전 의 모양 을 그리 지 않 고 회전 후의 모양 을 그린다.
예 를 들 어 이 I 형 은 4 로 정의 되 었 다.× 4 의 모양 이지 만 실제로는 1 만 필요 하 다.× 4 또는 4× 1.면 됩 니 다.나머지 는 모두 비어 있 습 니 다.그것 은 T 형 과 달리 T 형 은 직사각형 이 아니 며,하나의 사각형 으로 정의 하면 반드시 두 개의 위치 가 비어 있 을 것 이다.그렇다면 I 형 은 정말 4 로 정의 할 필요 가 있다.× 4 요?
답 은 긍정 적 이다.하면,만약,만약...× 1 의 가로줄 하나,회전 후 1 이 된다.× 4 의 세로 줄,이 위 치 는 어떻게 확정 합 니까?좀 어 려 운 것 같 습 니 다.하면,만약,만약...× 4 의 정사각형,우 리 는 출발점 좌표(왼쪽 상단)를 고정 시 키 고 세로 줄 의 4 를× 4 바로 바 꾸 기 4× 4 구역,회전 이 되 는 거 아니 야?그리고 위 치 는 계산 하기 쉽다.
또 하 나 는 어떤 경우 에는 회전 할 수 없다.예 를 들 어 I 형의 세로 줄 은 좌우 테두리 에 밀 착 될 때 회전 할 수 없다.그 건 기억 나,확실 해.그러나 다른 모양 에 대해 저 는 확실 하지 않 습 니 다.바 이 두 는 웹 페이지 의 러시아 사각형 을 찾 아 놀 았 는데 안 된다 는 것 을 알 게 되 었 습 니 다.예 를 들 면:

오른쪽 테두리 에 바짝 붙 어 있 을 때 회전 할 수 없습니다.모든 모양 을 판단 하려 면 정말 짜증 이 난다.사각형 의 정의 에 착안 하여 쉽게 실현 할 수 있다.
예 를 들 어 세로 줄,정 의 는:

['.0..',
 '.0..',
 '.0..',
 '.0..']
세로 줄 은 가장 왼쪽 에 붙 일 수 있 기 때문에 X 축 좌 표 는-1 입 니 다.이것 은 정의 에서 왼쪽 의 세로 줄 이 비어 있 기 때 문 입 니 다.사각형 이 정의 하 는 모양(빈 부분 포함)이 게임 영역 에 완전히 있 을 때 만 회전 할 수 있 습 니 다.
내 가 전에 말 한 것 은 모두 4 로 정의 된다.× 4.좋 지 않 습 니 다.원인 은 바로 여기에 있 습 니 다.T 형 등 다른 모양 에 대해 서 는 이 판정 을 할 수 없습니다.그래서 T 형 등 모양 에 대해 서 는 3 으로 정의 할 수 있 습 니 다.× 3 의 형식:

['.0.',
 '000',
 '...']
또 다른 상황 은 회전 할 수 없 는 것 이다.회전 후의 위 치 는 이미 다른 사각형 에 의 해 차지 되 었 다 는 것 이다.또 행방,좌우 이동 은 모두 이 판단 을 해 야 한다.이것들 이 일치 하 는 이상 같은 방법 으로 판단 할 수 있다.
게임 을 정의 해 야 합 니 다area 변 수 는 전체 게임 영역의 현재 상 태 를 저장 하 는 데 사 용 됩 니 다.

game_area = [['.'] * BLOCK_WIDTH for _ in range(BLOCK_HEIGHT)]
초기 상태 가 모두 비어 있 기 때문에 모두 사용 합 니 다.초기 화하 면 됩 니 다.
또한 현재 떨 어 진 사각형 의 상 태 를 정의 하 는 변수 가 필요 합 니 다.

cur_block = None #       
cur_pos_x, cur_pos_y = 0, 0 #          
사각형 우 리 는 2 차원 배열 의 방식 으로 정의 되 고 빈 줄 과 빈 열 이 존재 합 니 다.만약 에 우리 가 이 2 차원 배열 을 옮 겨 다 니 며 자신 이 있 는 지역 이 현재 게임 구역 에서 다른 사각형 에 의 해 차지 되 었 는 지 판단 하면 이것 은 실현 할 수 있 습 니 다.우 리 는 다른 상황 을 고려 합 니 다.하 나 는 세로 줄 이 고 왼쪽 줄 은 비어 있 습 니 다.이 빈 줄 은 게임 구역 을 옮 길 수 있 습 니 다.이것 은 어떻게 판단 합 니까?왼쪽으로 이동 할 때마다 왼쪽 줄 이 다 비어 있 는 지 판단 해 볼 까요?이것 은 너무 번거롭다.그리고 사각형 은 모두 고정 되 어 있 기 때문에 우 리 는 미리 정 의 를 내 릴 수 있다.최종 블록 정 의 는 다음 과 같 습 니 다.

from collections import namedtuple

Point = namedtuple('Point', 'X Y')
Block = namedtuple('Block', 'template start_pos end_pos name next')

# S   
S_BLOCK = [Block(['.00',
     '00.',
     '...'], Point(0, 0), Point(2, 1), 'S', 1),
   Block(['0..',
     '00.',
     '.0.'], Point(0, 0), Point(1, 2), 'S', 0)]
사각형 은 두 가지 방법 을 포함 하여 무 작위 사각형 과 회전 을 가 져 올 때 회전 하 는 사각형 을 가 져 와 야 합 니 다.

BLOCKS = {'O': O_BLOCK,
   'I': I_BLOCK,
   'Z': Z_BLOCK,
   'T': T_BLOCK,
   'L': L_BLOCK,
   'S': S_BLOCK,
   'J': J_BLOCK}


def get_block():
 block_name = random.choice('OIZTLSJ')
 b = BLOCKS[block_name]
 idx = random.randint(0, len(b) - 1)
 return b[idx]


#         
def get_next_block(block):
 b = BLOCKS[block.name]
 return b[block.next]
회전,낙하,이동 이 가능 한 지 판단 하 는 방법 도 쉽게 이 루어 졌 다.

def _judge(pos_x, pos_y, block):
 nonlocal game_area
 for _i in range(block.start_pos.Y, block.end_pos.Y + 1):
  if pos_y + block.end_pos.Y >= BLOCK_HEIGHT:
   return False
  for _j in range(block.start_pos.X, block.end_pos.X + 1):
   if pos_y + _i >= 0 and block.template[_i][_j] != '.' and game_area[pos_y + _i][pos_x + _j] != '.':
    return False
 return True
정박 하 다
마지막 문 제 는 멈 추 는 것 이다.사각형 이 끝까지 떨 어 지 거나 다른 사각형 을 만 나 면 떨 어 질 수 없다.나 는 이것 을'정박'이 라 고 부 르 는데,이름 이 있 으 면 말 하기 도 좀 편리 하 다.
먼저 정박 할 수 있 는 지 여 부 를 판단 해 야 한다.정박 이 발생 한 후에 현재 사각형 의 비 빈 점 을 게임 구역 에 그 리 는 것 이다.다시 말 하면 4.567914.의 비 빈 점 을 대응 하 는 위치 에 따라 4.567914 리 로 복사 하 는 것 이다.그리고 한 줄 이 모두 채 워 졌 는 지 계산 하고,모두 채 우 면 제거한다.

def _dock():
 nonlocal cur_block, next_block, game_area, cur_pos_x, cur_pos_y, game_over
 for _i in range(cur_block.start_pos.Y, cur_block.end_pos.Y + 1):
  for _j in range(cur_block.start_pos.X, cur_block.end_pos.X + 1):
   if cur_block.template[_i][_j] != '.':
    game_area[cur_pos_y + _i][cur_pos_x + _j] = '0'
 if cur_pos_y + cur_block.start_pos.Y <= 0:
  game_over = True
 else:
  #     
  remove_idxs = []
  for _i in range(cur_block.start_pos.Y, cur_block.end_pos.Y + 1):
   if all(_x == '0' for _x in game_area[cur_pos_y + _i]):
    remove_idxs.append(cur_pos_y + _i)
  if remove_idxs:
   #   
   _i = _j = remove_idxs[-1]
   while _i >= 0:
    while _j in remove_idxs:
     _j -= 1
    if _j < 0:
     game_area[_i] = ['.'] * BLOCK_WIDTH
    else:
     game_area[_i] = game_area[_j]
    _i -= 1
    _j -= 1
  cur_block = next_block
  next_block = blocks.get_block()
  cur_pos_x, cur_pos_y = (BLOCK_WIDTH - cur_block.end_pos.X - 1) // 2, -1 - cur_block.end_pos.Y
이로써 전체 러시아 블록 의 주체 기능 은 완 성 된 셈 이다.
여기 서 많은 매개 변 수 는 조절 할 수 있 습 니 다.예 를 들 어 회전 이 어색 하고 사각형 의 정 의 를 직접 조정 할 수 있 으 며 코드 논 리 를 바 꾸 지 않 아 도 됩 니 다.
원본 다운로드:http://xiazai.jb51.net/201901/yuanma/python-Tetris.rar
총결산
이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가치 가 있 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.

좋은 웹페이지 즐겨찾기