import pygame
import sys
import math
import random
from pygame.locals import *
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
YELLOW = (255, 224, 0)
tmr = 0 # 타이머 변수
DATA_LR = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2,
3, 2, 1, 0, 2, 4, 2, 4, 2, 0, 0, 0, -2, -2,
-4, -4, -2, -1, 0, 0, 0, 0, 0, 0, 0]
DATA_UD = [0, 0, 1, 2, 3, 2, 1, 0, -2, -4, -4, 0, 0,
0, 0, 0, -1, -2, -3, -4, -3, -2, -1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, -3, 3, 0, -6, 6, 0]
CLEN = len(DATA_LR)
BOARD = 120
CMAX = BOARD * CLEN
curve = [0] * CMAX
updown = [0] * CMAX
object_left = [0] * CMAX
object_right = [0] * CMAX
CAR = 30
car_x = [0] * CAR
car_y = [0] * CAR
car_lr = [0] * CAR
car_spd = [0] * CAR
PLCAR_Y = 10
def make_course():
for i in range(CLEN):
lr1 = DATA_LR[i]
lr2 = DATA_LR[(i + 1) % CLEN]
ud1 = DATA_UD[i]
ud2 = DATA_UD[(i + 1) % CLEN]
for j in range(BOARD):
pos = j + BOARD * i
curve[pos] = lr1 * (BOARD - j) / BOARD + lr2 * j / BOARD
updown[pos] = ud1 * (BOARD - j) / BOARD + ud2 * j / BOARD
if j == 60:
object_right[pos] = 1
if i % 8 < 7:
if j % 12 == 0:
object_left[pos] = 2
else:
if j % 20 == 0:
object_left[pos] = 3
if j % 12 == 6:
object_left[pos] = 9
def draw_obj(bg, img, x, y, sc):
img_rz = pygame.transform.rotozoom(img, 0, sc)
w = img_rz.get_width()
h = img_rz.get_height()
bg.blit(img_rz, [x - w / 2, y - h])
def draw_shadow(bg, x, y, siz):
shadow = pygame.Surface([siz, siz / 4])
shadow.fill(RED)
shadow.set_colorkey(RED)
shadow.set_alpha(128)
pygame.draw.ellipse(shadow, BLACK, [0, 0, siz, siz / 4])
bg.blit(shadow, [x - siz / 2, y - siz / 4])
def init_car(): # 차량 관리 리스트 초기값 대입 함수
for i in range(1, CAR): # 반복, COM 차량의
car_x[i] = random.randint(50, 750) # 가로방향 좌표 무작위 결정
car_y[i] = random.randint(200, CMAX - 200) # 코스 상 위치 무작위 결정
car_lr[i] = 0 # 좌우 움직임 0 대입(정면 향함)
car_spd[i] = random.randint(100, 200) # 속도 무작위 결정
car_x[0] = 400 # 플레이어 차량 가로 방향 화면 중앙
car_y[i] = 0 # 플레이어 차량 코스 상 위치 초기화
car_lr[0] = 0 # 플레이어 차량 방향 0 대입
car_spd[0] = 0 # 플레이어 차량 속도 0 대입
def drive_car(key):
if key[K_LEFT] == 1:
if car_lr[0] > -3:
car_lr[0] -= 1
car_x[0] = car_x[0] + (car_lr[0] - 3) * car_spd[0] / 100 - 5
elif key[K_RIGHT] == 1:
if car_lr[0] < 3:
car_lr[0] += 1
car_x[0] = car_x[0] + (car_lr[0] + 3) * car_spd[0] / 100 + 5
else:
car_lr[0] = int(car_lr[0] * 0.9)
if key[K_a] == 1:
car_spd[0] += 3
elif key[K_z] == 1:
car_spd[0] -= 10
else:
car_spd[0] -= 0.25
if car_spd[0] < 0:
car_spd[0] = 0
if car_spd[0] > 320:
car_spd[0] = 320
car_x[0] -= car_spd[0] * curve[int(car_y[0] + PLCAR_Y) % CMAX] / 50
if car_x[0] < 0:
car_x[0] = 0
car_spd[0] *= 0.9
if car_x[0] > 800:
car_x[0] = 800
car_spd[0] *= 0.9
car_y[0] = car_y[0] + car_spd[0] / 100
if car_y[0] > CMAX - 1:
car_y[0] -= CMAX
def move_car(cs): # COM 차량 제어 함수
for i in range(cs, CAR): # 반복해서 모든 차량 처리
if car_spd[i] < 100: # 속도가 100보다 작으면
car_spd[i] += 3 # 속도 증가
if i == tmr % 120: # 일정 시간 별로
car_lr[i] += random.choice([-1, 0, 1]) # 방향을 무작위로 변경
if car_lr[i] < -3: car_lr[i] = -3 # 방향이 -3 미만이면 -3 대입
if car_lr[i] > 3: car_lr[i] = 3 # 방향이 3 초과면 3 대입
car_x[i] = car_x[i] + car_lr[i] * car_spd[i] / 100 # 차량 방향, 속도에서 가로 좌표 계산
if car_x[i] < 50: # 왼쪽 길 끝에 가깝다면
car_x[i] = 50 # 그 이상 움직이지 않도록
car_lr[i] = int(car_lr[i] * 0.9) # 정면 쪽으로 이동
if car_x[i] > 750: # 오른쪽 길 끝에 가깝다면
car_x[i] = 750 # 그 이상 움직이지 않도록
car_lr[i] = int(car_lr[i] * 0.9) # 정면 쪽으로 이동
car_y[i] += car_spd[i] / 100 # 차량 속도에서 코스상 위치 계산
if car_y[i] > CMAX - 1: # 코스 종점을 넘었다면
car_y[i] -= CMAX # 코스 시작으로 되돌림
def draw_text(scrn, txt, x, y, col, fnt): # 그림자 포함 문자열 표시 함수
sur = fnt.render(txt, True, BLACK) # 검은색 문자열을 그릴 Surface 생성
x -= sur.get_width() / 2 # 센터링 X 좌표 계산
y -= sur.get_height() / 2 # 센터링 Y 좌표 계산
scrn.blit(sur, [x + 2, y + 2]) # Surface를 화면으로 전송
sur = fnt.render(txt, True, col) # 지정색으로 문자열을 그릴 Surface 생성
scrn.blit(sur, [x, y]) # Surface를 화면으로 전송
def main():
global tmr # 전역 변수 선언
pygame.init()
pygame.display.set_caption("Python Racer")
screen = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()
fnt_m = pygame.font.Font(None, 50) # 폰트 객체 생성, 중간 크기 문자
img_bg = pygame.image.load("Python_workspace/python_game/Chapter11/image_pr/bg.png").convert()
img_sea = pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/sea.png').convert_alpha()
img_obj = [
None,
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/board.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/yashi.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/yacht.png').convert_alpha()
]
img_car = [
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car00.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car01.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car02.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car03.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car04.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car05.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car06.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car10.png').convert_alpha(), # COM 차량 1 이미지
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car11.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car12.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car13.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car14.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car15.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car16.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car20.png').convert_alpha(), # COM 차량 2 이미지
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car21.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car22.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car23.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car24.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car25.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car26.png').convert_alpha()
]
# 도로 판의 기본 형태 계산
BOARD_W = [0] * BOARD
BOARD_H = [0] * BOARD
BOARD_UD = [0] * BOARD
for i in range(BOARD):
BOARD_W[i] = 10 + (BOARD - i) * (BOARD - i) / 12
BOARD_H[i] = 3.4 * (BOARD - i) / BOARD
BOARD_UD[i] = 2 * math.sin(math.radians(i * 1.5))
make_course()
init_car() # 차량 관리 리스트 초기화 대입
vertical = 0
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN: # 키를 누르는 이벤트 발생 시
if event.key == K_F1: # F1 키라면
screen = pygame.display.set_mode((800, 600), FULLSCREEN) # 전체화면 모드
if event.key == K_F2 or event.key == K_ESCAPE: # F2키 혹은 Esc 키라면
screen = pygame.display.set_mode((800, 600)) # 일반 화면 모드
tmr += 1 # tmr 값 1 증가
# 화면에 그릴 도로 X 좌표와 높낮이 계산
di = 0
ud = 0
board_x = [0] * BOARD
board_ud = [0] * BOARD
for i in range(BOARD):
di += curve[int(car_y[0] + i) % CMAX]
ud += updown[int(car_y[0] + i) % CMAX]
board_x[i] = 400 - BOARD_W[i] * car_x[0] / 800 + di / 2
board_ud[i] = ud / 30
horizon = 400 + int(ud / 3)
sy = horizon
vertical = vertical - int(car_spd[0] * di / 8000)
if vertical < 0:
vertical += 800
if vertical >= 800:
vertical -= 800
# 필드 그리기
screen.fill((0, 56, 255))
screen.blit(img_bg, [vertical - 800, horizon - 400])
screen.blit(img_bg, [vertical, horizon - 400])
screen.blit(img_sea, [board_x[BOARD - 1] - 780, sy])
# 그리기 데이터를 기초로 도로 그리기
for i in range(BOARD - 1, 0, -1):
ux = board_x[i]
uy = sy - BOARD_UD[i] * board_ud[i]
uw = BOARD_W[i]
sy = sy + BOARD_H[i] * (600 - horizon) / 200
bx = board_x[i - 1]
by = sy - BOARD_UD[i - 1] * board_ud[i - 1]
bw = BOARD_W[i - 1]
col = (160, 160, 160)
pygame.draw.polygon(screen, col, [[ux, uy], [ux + uw, uy], [bx + bw, by], [bx, by]])
if int(car_y[0] + i) % 10 <= 4:
pygame.draw.polygon(screen, YELLOW, [[ux, uy], [ux + uw * 0.02, uy], [bx + bw * 0.02, by], [bx, by]])
pygame.draw.polygon(screen, YELLOW, [[ux + uw * 0.98, uy], [ux + uw, uy], [bx + bw, by], [bx + bw * 0.98, by]])
if int(car_y[0] + i) % 20 <= 10:
pygame.draw.polygon(screen, WHITE, [[ux + uw * 0.24, uy], [ux + uw * 0.26, uy], [bx + bw * 0.26, by], [bx + bw * 0.24, by]])
pygame.draw.polygon(screen, WHITE, [[ux + uw * 0.49, uy], [ux + uw * 0.51, uy], [bx + bw * 0.51, by], [bx + bw * 0.49, by]])
pygame.draw.polygon(screen, WHITE, [[ux + uw * 0.74, uy], [ux + uw * 0.76, uy], [bx + bw * 0.76, by], [bx + bw * 0.74, by]])
scale = 1.5 * BOARD_W[i] / BOARD_W[0]
obj_l = object_left[int(car_y[0] + i) % CMAX]
if obj_l == 2:
draw_obj(screen, img_obj[obj_l], ux - uw * 0.05, uy, scale)
if obj_l == 3:
draw_obj(screen, img_obj[obj_l], ux - uw * 0.5, uy, scale)
if obj_l == 9:
screen.blit(img_sea, [ux - uw * 0.5 - 780, uy])
obj_r = object_right[int(car_y[0] + i) % CMAX]
if obj_r == 1:
draw_obj(screen, img_obj[obj_r], ux + uw * 1.3, uy, scale)
for c in range(1, CAR): # COM 차량
if int(car_y[c]) % CMAX == int(car_y[0] + i) % CMAX: # 해당 판 COM 차량 유무 확인
lr = int(4 * (car_x[0] - car_x[c]) / 800) # 플레이어가 보는 COM 차량 방향 계산
if lr < -3: lr = -3 # -3 보다 작으면 -3 대입
if lr > 3: lr = 3 # 3 보다 크면 3 대입
draw_obj(screen, img_car[(c % 3) * 7 + 3 + lr], ux + car_x[c] * BOARD_W[i] / 800, uy, 0.05 + BOARD_W[i] / BOARD_W[0]) # COM 차량 그리기
if i == PLCAR_Y:
draw_shadow(screen, ux + car_x[0] * BOARD_W[i] / 800, uy, 200 * BOARD_W[i] / BOARD_W[0])
draw_obj(screen, img_car[3 + car_lr[0]], ux + car_x[0] * BOARD_W[i] / 800, uy, 0.05 + BOARD_W[i] / BOARD_W[0])
draw_text(screen, str(int(car_spd[0])) + 'km/h', 680, 30, RED, fnt_m) # 속도 표시
key = pygame.key.get_pressed()
drive_car(key)
move_car(1)
pygame.display.update()
clock.tick(60)
if __name__ == '__main__':
main()
실행하면 컴퓨터가 움직이는 여러 차량이 도로 위를 달린다.
def init_car(): # 차량 관리 리스트 초기값 대입 함수
for i in range(1, CAR): # 반복, COM 차량의
car_x[i] = random.randint(50, 750) # 가로방향 좌표 무작위 결정
car_y[i] = random.randint(200, CMAX - 200) # 코스 상 위치 무작위 결정
car_lr[i] = 0 # 좌우 움직임 0 대입(정면 향함)
car_spd[i] = random.randint(100, 200) # 속도 무작위 결정
car_x[0] = 400 # 플레이어 차량 가로 방향 화면 중앙
car_y[i] = 0 # 플레이어 차량 코스 상 위치 초기화
car_lr[0] = 0 # 플레이어 차량 방향 0 대입
car_spd[0] = 0 # 플레이어 차량 속도 0 대입
init_car() 함수에서 플레이어 차량을 포함한 모든 차량을 관리하는 리스트에 초기값을 대입한다. COM 차량의 가로 방향 좌표, 코스 상 위치, 속도는 무작위로 결정한다.
def move_car(cs): # COM 차량 제어 함수
for i in range(cs, CAR): # 반복해서 모든 차량 처리
if car_spd[i] < 100: # 속도가 100보다 작으면
car_spd[i] += 3 # 속도 증가
if i == tmr % 120: # 일정 시간 별로
car_lr[i] += random.choice([-1, 0, 1]) # 방향을 무작위로 변경
if car_lr[i] < -3: car_lr[i] = -3 # 방향이 -3 미만이면 -3 대입
if car_lr[i] > 3: car_lr[i] = 3 # 방향이 3 초과면 3 대입
car_x[i] = car_x[i] + car_lr[i] * car_spd[i] / 100 # 차량 방향, 속도에서 가로 좌표 계산
if car_x[i] < 50: # 왼쪽 길 끝에 가깝다면
car_x[i] = 50 # 그 이상 움직이지 않도록
car_lr[i] = int(car_lr[i] * 0.9) # 정면 쪽으로 이동
if car_x[i] > 750: # 오른쪽 길 끝에 가깝다면
car_x[i] = 750 # 그 이상 움직이지 않도록
car_lr[i] = int(car_lr[i] * 0.9) # 정면 쪽으로 이동
car_y[i] += car_spd[i] / 100 # 차량 속도에서 코스상 위치 계산
if car_y[i] > CMAX - 1: # 코스 종점을 넘었다면
car_y[i] -= CMAX # 코스 시작으로 되돌림
move_car() 함수는 COM 차량을 제어한다.
이 함수가 수행하는 작업은 다음과 같다.
- 속도가 100 미만이면 3씩 증가한다.
- 일정 시간별로 방향을 무작위로 변경한다.
- 도로 왼쪽, 혹은 도로 오른쪽으로 너무 많이 가지 않게 한다.
- 속도에 맞춰 코스 상 위치를 변화시켜 코스 종점을 지나면 코스 시작 위치로 되돌린다.
move_car 함수는 0을 인수로 받으면 0번째 차량도 자동으로 움직이게할 수 있다.
게임 중에는 move_car(1)으로 실행해서 COM 차량을 움직이고, 타이틀 화면에서는 move_car(0)로 실행해 플레이어 차량을 포함한 모든 차량을 자동으로 움직이게 할 수 있다.
for c in range(1, CAR): # COM 차량
if int(car_y[c]) % CMAX == int(car_y[0] + i) % CMAX: # 해당 판 COM 차량 유무 확인
lr = int(4 * (car_x[0] - car_x[c]) / 800) # 플레이어가 보는 COM 차량 방향 계산
if lr < -3: lr = -3 # -3 보다 작으면 -3 대입
if lr > 3: lr = 3 # 3 보다 크면 3 대입
draw_obj(screen, img_car[(c % 3) * 7 + 3 + lr], ux + car_x[c] * BOARD_W[i] / 800, uy, 0.05 + BOARD_W[i] / BOARD_W[0]) # COM 차량 그리기
main() 함수 안의 도로를 그리는 처리를 하는 부분에서 COM 차량을 표시한다.
for c in range(1, CAR)라는 반복과 if int(car_y[c]) % CMAX == int(car_y[0] + i) % CMAX라는 조건 분기로 COM 차량이 도로를 구성하는 판 위에 있는지 확인하고 있다면 플레이어 차량에서 본 COM 차량의 방향을 계산해 이미지를 확대 축소해서 표시하는 draw_obj 함수로 COM 차량을 그린다.
COM 차량의 스케일은 0.05 + BOARD_W[i] / BOARD_W[0]으로 계산한다.
COM 차량의 이미지 번호 지정을 img_car[(c % 3) * 7 + 3 + lr]로 하여 1대씩 색상이 달라지도록 한다.
int(car_y[0] + i) % CMAX는 플레이어가 본 도로 위의 판의 번호이다. 이는 '화면에 판을 표시할 때 해당 판의 위치에 COM 차량이 있는지를 확인하는 식'으로 생각하면 된다.
import pygame
import sys
import math
import random
from pygame.locals import *
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
YELLOW = (255, 224, 0)
tmr = 0
se_crash = None # 충돌 시 사용할 효과음 로딩 변수
'''
변경 사항 없음, 생략
'''
def move_car(cs):
for i in range(cs, CAR):
if car_spd[i] < 100:
car_spd[i] += 3
if i == tmr % 120:
car_lr[i] += random.choice([-1, 0, 1])
if car_lr[i] < -3: car_lr[i] = -3
if car_lr[i] > 3: car_lr[i] = 3
car_x[i] = car_x[i] + car_lr[i] * car_spd[i] / 100
if car_x[i] < 50:
car_x[i] = 50
car_lr[i] = int(car_lr[i] * 0.9)
if car_x[i] > 750:
car_x[i] = 750
car_lr[i] = int(car_lr[i] * 0.9)
car_y[i] += car_spd[i] / 100
if car_y[i] > CMAX - 1:
car_y[i] -= CMAX
cx = car_x[i] - car_x[0] # 플레이어 차량과 가로 방향 거리
cy = car_y[i] - (car_y[0] + PLCAR_Y) % CMAX # 플레이어 차량과 코스 상 거리
if -100 <= cx and cx <= 100 and -10 <= cy and cy <= 10: # 이들이 범위 이내라면(충돌 시)
car_x[0] -= cx / 4 # 플레이어 차량 가로로 이동
car_x[i] += cx / 4 # COM 차량 가로로 이동
car_spd[0], car_spd[i] = car_spd[i] * 0.3, car_spd[0] * 0.3 # 2개 차량 속도를 서로 바꿔 감속
se_crash.play() # 충돌음 출력
'''
변경 사항 없음, 생략
'''
def main():
global tmr, se_crash # 전역 변수 선언
pygame.init()
pygame.display.set_caption("Python Racer")
screen = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()
fnt_m = pygame.font.Font(None, 50)
img_bg = pygame.image.load("Python_workspace/python_game/Chapter11/image_pr/bg.png").convert()
img_sea = pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/sea.png').convert_alpha()
img_obj = [
None,
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/board.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/yashi.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/yacht.png').convert_alpha()
]
img_car = [
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car00.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car01.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car02.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car03.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car04.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car05.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car06.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car10.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car11.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car12.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car13.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car14.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car15.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car16.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car20.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car21.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car22.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car23.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car24.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car25.png').convert_alpha(),
pygame.image.load('Python_workspace/python_game/Chapter11/image_pr/car26.png').convert_alpha()
]
se_crash = pygame.mixer.Sound('Python_workspace/python_game/Chapter11/sound_pr/crash.ogg') # 충돌음 로딩
# 도로 판의 기본 형태 계산
BOARD_W = [0] * BOARD
BOARD_H = [0] * BOARD
BOARD_UD = [0] * BOARD
for i in range(BOARD):
BOARD_W[i] = 10 + (BOARD - i) * (BOARD - i) / 12
BOARD_H[i] = 3.4 * (BOARD - i) / BOARD
BOARD_UD[i] = 2 * math.sin(math.radians(i * 1.5))
make_course()
init_car() # 차량 관리 리스트 초기화 대입
vertical = 0
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_F1:
screen = pygame.display.set_mode((800, 600), FULLSCREEN)
if event.key == K_F2 or event.key == K_ESCAPE:
screen = pygame.display.set_mode((800, 600))
tmr += 1
# 화면에 그릴 도로 X 좌표와 높낮이 계산
di = 0
ud = 0
board_x = [0] * BOARD
board_ud = [0] * BOARD
for i in range(BOARD):
di += curve[int(car_y[0] + i) % CMAX]
ud += updown[int(car_y[0] + i) % CMAX]
board_x[i] = 400 - BOARD_W[i] * car_x[0] / 800 + di / 2
board_ud[i] = ud / 30
horizon = 400 + int(ud / 3)
sy = horizon
vertical = vertical - int(car_spd[0] * di / 8000)
if vertical < 0:
vertical += 800
if vertical >= 800:
vertical -= 800
# 필드 그리기
screen.fill((0, 56, 255))
screen.blit(img_bg, [vertical - 800, horizon - 400])
screen.blit(img_bg, [vertical, horizon - 400])
screen.blit(img_sea, [board_x[BOARD - 1] - 780, sy])
# 그리기 데이터를 기초로 도로 그리기
for i in range(BOARD - 1, 0, -1):
ux = board_x[i]
uy = sy - BOARD_UD[i] * board_ud[i]
uw = BOARD_W[i]
sy = sy + BOARD_H[i] * (600 - horizon) / 200
bx = board_x[i - 1]
by = sy - BOARD_UD[i - 1] * board_ud[i - 1]
bw = BOARD_W[i - 1]
col = (160, 160, 160)
pygame.draw.polygon(screen, col, [[ux, uy], [ux + uw, uy], [bx + bw, by], [bx, by]])
if int(car_y[0] + i) % 10 <= 4:
pygame.draw.polygon(screen, YELLOW, [[ux, uy], [ux + uw * 0.02, uy], [bx + bw * 0.02, by], [bx, by]])
pygame.draw.polygon(screen, YELLOW, [[ux + uw * 0.98, uy], [ux + uw, uy], [bx + bw, by], [bx + bw * 0.98, by]])
if int(car_y[0] + i) % 20 <= 10:
pygame.draw.polygon(screen, WHITE, [[ux + uw * 0.24, uy], [ux + uw * 0.26, uy], [bx + bw * 0.26, by], [bx + bw * 0.24, by]])
pygame.draw.polygon(screen, WHITE, [[ux + uw * 0.49, uy], [ux + uw * 0.51, uy], [bx + bw * 0.51, by], [bx + bw * 0.49, by]])
pygame.draw.polygon(screen, WHITE, [[ux + uw * 0.74, uy], [ux + uw * 0.76, uy], [bx + bw * 0.76, by], [bx + bw * 0.74, by]])
scale = 1.5 * BOARD_W[i] / BOARD_W[0]
obj_l = object_left[int(car_y[0] + i) % CMAX]
if obj_l == 2:
draw_obj(screen, img_obj[obj_l], ux - uw * 0.05, uy, scale)
if obj_l == 3:
draw_obj(screen, img_obj[obj_l], ux - uw * 0.5, uy, scale)
if obj_l == 9:
screen.blit(img_sea, [ux - uw * 0.5 - 780, uy])
obj_r = object_right[int(car_y[0] + i) % CMAX]
if obj_r == 1:
draw_obj(screen, img_obj[obj_r], ux + uw * 1.3, uy, scale)
for c in range(1, CAR):
if int(car_y[c]) % CMAX == int(car_y[0] + i) % CMAX:
lr = int(4 * (car_x[0] - car_x[c]) / 800)
if lr < -3: lr = -3
if lr > 3: lr = 3
draw_obj(screen, img_car[(c % 3) * 7 + 3 + lr], ux + car_x[c] * BOARD_W[i] / 800, uy, 0.05 + BOARD_W[i] / BOARD_W[0])
if i == PLCAR_Y:
draw_shadow(screen, ux + car_x[0] * BOARD_W[i] / 800, uy, 200 * BOARD_W[i] / BOARD_W[0])
draw_obj(screen, img_car[3 + car_lr[0]], ux + car_x[0] * BOARD_W[i] / 800, uy, 0.05 + BOARD_W[i] / BOARD_W[0])
draw_text(screen, str(int(car_spd[0])) + 'km/h', 680, 30, RED, fnt_m)
key = pygame.key.get_pressed()
drive_car(key)
move_car(1)
pygame.display.update()
clock.tick(60)
if __name__ == '__main__':
main()
프로그램을 실행하면 플레이어 차량과 COM 차량이 접촉하면 충돌음이 재생되고 서로 조금씩 튀면서 속도가 줄어든다.
def move_car(cs):
for i in range(cs, CAR):
if car_spd[i] < 100:
car_spd[i] += 3
if i == tmr % 120:
car_lr[i] += random.choice([-1, 0, 1])
if car_lr[i] < -3: car_lr[i] = -3
if car_lr[i] > 3: car_lr[i] = 3
car_x[i] = car_x[i] + car_lr[i] * car_spd[i] / 100
if car_x[i] < 50:
car_x[i] = 50
car_lr[i] = int(car_lr[i] * 0.9)
if car_x[i] > 750:
car_x[i] = 750
car_lr[i] = int(car_lr[i] * 0.9)
car_y[i] += car_spd[i] / 100
if car_y[i] > CMAX - 1:
car_y[i] -= CMAX
cx = car_x[i] - car_x[0] # 플레이어 차량과 가로 방향 거리
cy = car_y[i] - (car_y[0] + PLCAR_Y) % CMAX # 플레이어 차량과 코스 상 거리
if -100 <= cx and cx <= 100 and -10 <= cy and cy <= 10: # 이들이 범위 이내라면(충돌 시)
car_x[0] -= cx / 4 # 플레이어 차량 가로로 이동
car_x[i] += cx / 4 # COM 차량 가로로 이동
car_spd[0], car_spd[i] = car_spd[i] * 0.3, car_spd[0] * 0.3 # 2개 차량 속도를 서로 바꿔 감속
se_crash.play() # 충돌음 출력
차량 충돌 판정과 충돌했을 때의 처리는 move_car() 함수가 실행한다.
플레이어 차량과 COm 차량의 가로 방향 좌표 차이를 cx에 대입하고 코스 상 위치의 차이를 cy에 대입한다. 이들 값이 -100 <= cx and cx <= 100 and -10 <= cy and cy <= 10 범위에 있다면 충돌한 것으로 판단한다. 이는 사각형 사이에서의 히트 체크이다.
충돌했다면 플레이어 차량의 가로 방향 좌표를 car_x[0] -= cx / 4, COM 차량의 좌표는 car_x[i] += cx / 4로 계산해서 서로 반대 방향으로 이동시킨다.
충돌 시 속도는 car_spd[0], car_spd[i] = car_spd[i] * 0.3, car_spd[0] * 0.3으로 계산한다. 이러면 플레이어 차량 속도는 COM 차량 속도의 30%, COM 차량 속도는 플레이어 차량 속도의 30%가 된다.