본문 바로가기
개발일지/게임

게임개발일지 #3 - 파이썬으로 뱀서류 게임 만들어보기(feat.Pygame)

by Jay Anderson 2025. 6. 8.

↓이전 포스팅↓

 

게임개발일지 #2 - 파이썬으로 뱀서류 게임 만들어보기(feat.Pygame)

↓ 지난 포스팅 ↓https://andersonlab.tistory.com/20 게임개발일지 #1 - 파이썬으로 뱀서류 게임 만들어보기(feat.Pygame)문득뱀파이어서바이벌 스러운 게임을 만들고 싶어짐 별 계획없이 무턱대고 시작해

andersonlab.tistory.com

 

wasd 방향키가 반대로 인식되는 문제(어차피 모바일환경에서 돌릴거라 지금이게 큰 의미는 없다 ㅠㅠ)

그리고... 맵 초기화 코드로 인해 맵 까매지는 문제가 있었음.

 

일단 방향테스트랑 다른것까지 다 되고 나면 모바일버전으로 추가 빌드업할거니까... ㅇㅇ

먼저 방향입력을 좀 더 직관적으로 바꿔볼까 함.

 

# 입력 처리 - 맵이 플레이어 이동 방향처럼 보이게 반대로 움직이게 수정
if keys[pygame.K_w]:
    world_y -= speed  # 위로 이동
if keys[pygame.K_s]:
    world_y += speed  # 아래로 이동
if keys[pygame.K_a]:
    world_x -= speed  # 왼쪽으로 이동
if keys[pygame.K_d]:
    world_x += speed  # 오른쪽으로 이동

 

이렇게 했더니 방향은 제대로 맞음.

 

 

 

 

그럼 저 까만 부분을 해결해야...

그냥 게임 시작 자체를 좌측 상단에서 하는것 같다.

맵이 자동으로 그려지면, 캐릭터는 정 중앙에 위치해야 하는데, 64개의 월드맵 타일 중 좌측 상단의 타일에서 시작돼버리는것 같음.

타일 크기좀 수정하고, 수정하는김에 이번엔 무기를 발사하는 로직도 추가로 넣어보자.

 

 

import pygame
import sys
import random
import math

# 초기화
pygame.init()

# 해상도 설정 (모바일 기준)
SCREEN_WIDTH = 540
SCREEN_HEIGHT = 960
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("Game Project - Jay")

# 색상 정의
GREEN = (0, 255, 0)   # 플레이어
BLACK = (0, 0, 0)     # 배경
BULLET_COLOR = (238, 238, 238)  # 총알 색상



##################################################################
# 타일 설정
##################################################################

# 타일 이미지 불러오기
tile_images = [
    pygame.image.load("assets/tiles/bg_01.jpg").convert(),
    pygame.image.load("assets/tiles/bg_02.jpg").convert(),
    pygame.image.load("assets/tiles/bg_03.jpg").convert(),
    pygame.image.load("assets/tiles/bg_04.jpg").convert(),
    pygame.image.load("assets/tiles/bg_05.jpg").convert(),
    pygame.image.load("assets/tiles/bg_06.jpg").convert(),
]

# 타일 크기
TILE_SIZE = 125

# 타일 크기에 맞춰 조정
tile_images = [pygame.transform.scale(img, (TILE_SIZE, TILE_SIZE)) for img in tile_images]

# 랜덤 타일 맵 생성
WORLD_TILES = 64  # 맵 전체 타일 개수 (64 x 64 타일)
tile_map = [[random.choice(tile_images) for _ in range(WORLD_TILES)] for _ in range(WORLD_TILES)]




##################################################################
# 플레이어 설정
##################################################################

PLAYER_RADIUS = 20
player_pos = (SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2)  # 중앙 고정
player_color = (0, 255, 0) # 플레이어 색상

# 월드 좌표 오프셋 (맵 이동용)
world_x = 0
world_y = 0
speed = 2


# 플레이어 마지막 방향 (12시 방향 기본값)
last_angle = math.radians(-90)




##################################################################
# 총알 관련 설정
##################################################################

BULLET_RADIUS = 5
BULLET_SPEED = 8
BULLET_INTERVAL = 1000  # 밀리초(ms) 단위 (0.3초)
bullets = []

# 마지막 총알 발사 시간 초기화
last_shot_time = 0

# FPS 설정
clock = pygame.time.Clock()
FPS = 60

# 방향 설정
# angle = 0  # 캐릭터가 향하는 각도


# 총알 클래스
class Bullet:
    def __init__(self, x, y, angle):
        self.x = x
        self.y = y
        self.angle = angle
        self.speed = BULLET_SPEED
        self.dx = math.cos(self.angle) * self.speed
        self.dy = math.sin(self.angle) * self.speed

    def move(self):
        self.x += self.dx
        self.y += self.dy

    def draw(self, screen):
        pygame.draw.circle(screen, BULLET_COLOR, (int(self.x), int(self.y)), BULLET_RADIUS)




##################################################################
# 게임 루프
##################################################################

running = True
while running:
    clock.tick(FPS)
    keys = pygame.key.get_pressed()

    # 입력 처리 - 맵이 플레이어 이동 방향처럼 보이게 반대로 움직이게 수정
    if keys[pygame.K_w]:
        world_y -= speed  # 위로 이동
    if keys[pygame.K_s]:
        world_y += speed  # 아래로 이동
    if keys[pygame.K_a]:
        world_x -= speed  # 왼쪽으로 이동
    if keys[pygame.K_d]:
        world_x += speed  # 오른쪽으로 이동
    
    # 이벤트 처리
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    # 타일 시작 인덱스 계산
    start_tile_x = (world_x // TILE_SIZE) - 1
    start_tile_y = (world_y // TILE_SIZE) - 1

    # 타일 그리기
    for tx in range(start_tile_x, start_tile_x + (SCREEN_WIDTH // TILE_SIZE) + 3):
        for ty in range(start_tile_y, start_tile_y + (SCREEN_HEIGHT // TILE_SIZE) + 3):
            screen_x = (tx * TILE_SIZE) - world_x
            screen_y = (ty * TILE_SIZE) - world_y

            if 0 <= tx < WORLD_TILES and 0 <= ty < WORLD_TILES:
                tile = tile_map[ty][tx]
                screen.blit(tile, (screen_x, screen_y))

     # 현재 시간
    now = pygame.time.get_ticks()

        
    # 입력 방향에 따라 angle 설정
    angle = None
    
    # 화면상의 방향키 입력에 맞춰 각도 설정
    if keys[pygame.K_w] and keys[pygame.K_d]:
        angle = math.radians(-45)   # 1시 방향
    elif keys[pygame.K_w] and keys[pygame.K_a]:
        angle = math.radians(-135)  # 11시 방향
    elif keys[pygame.K_s] and keys[pygame.K_d]:
        angle = math.radians(45)    # 5시 방향
    elif keys[pygame.K_s] and keys[pygame.K_a]:
        angle = math.radians(135)   # 7시 방향
    elif keys[pygame.K_w]:
        angle = math.radians(-90)   # 12시 방향
    elif keys[pygame.K_s]:
        angle = math.radians(90)    # 6시 방향
    elif keys[pygame.K_a]:
        angle = math.radians(180)   # 9시 방향
    elif keys[pygame.K_d]:
        angle = math.radians(0)     # 3시 방향

     # 방향이 새로 입력되었으면 업데이트
    if angle is not None:
        last_angle = angle

    
    # 총알 발사 (항상 last_angle 기준)
    if now - last_shot_time > BULLET_INTERVAL:
        bullet_x, bullet_y = player_pos
        bullet = Bullet(bullet_x, bullet_y, last_angle)  # 여기서 last_angle 사용
        bullets.append(bullet)
        last_shot_time = now

    # 총알 이동 및 그리기
    for bullet in bullets[:]:
        bullet.move()
        if bullet.x < 0 or bullet.x > SCREEN_WIDTH or bullet.y < 0 or bullet.y > SCREEN_HEIGHT:
            bullets.remove(bullet)  # 화면 밖으로 나간 총알 제거
        else:
            bullet.draw(screen)

    # 플레이어 그리기
    pygame.draw.circle(screen, player_color, player_pos, PLAYER_RADIUS)

    # 화면 업데이트
    pygame.display.flip()

# 종료 처리
pygame.quit()
sys.exit()

 

 

 

아니 뭔... 레이저를 쏘누

그리고 위로 올라가면 어째선지 타일 bg들 중 첫번째 이미지만 무한반복된다.

 

생각해보니 방향에 따라 무기를 발사하는 각도도 달라져야 하는데, 계속 12시로 쏜다. ㄷㄷ

일단, 내가 원하는 무한맵을 구현하려면 실시간 무한 타일 생성구조로 바꿔야 할것같다.

 

 

# 타일 그리기 (동적 생성)
for tx in range(start_tile_x, start_tile_x + (SCREEN_WIDTH // TILE_SIZE) + 3):
    for ty in range(start_tile_y, start_tile_y + (SCREEN_HEIGHT // TILE_SIZE) + 3):
        screen_x = (tx * TILE_SIZE) - world_x
        screen_y = (ty * TILE_SIZE) - world_y

        tile = get_tile_at(tx, ty)
        screen.blit(tile, (screen_x, screen_y))

 

이렇게 하면 좌측이나 위로 가더라도 tx, ty가 음수가 되어도 무조건 같은 방식으로 타일이 결정되기 때문에,

무한히 확장되는 맵을 구현할 수 있을 것이라고 봄.

그리고 스폰위치를 중앙으로...

 

world_x = TILE_SIZE * WORLD_TILES // 2
world_y = TILE_SIZE * WORLD_TILES // 2

 

 

 

무한맵 개잘됨ㅋㅋㅋㅋㅋㅋ 이제 무기 발사하는 방향조절좀 해야겠음

 

 

##################################################################
# 총알 관련 설정
##################################################################

BULLET_RADIUS = 5
BULLET_SPEED = 8
BULLET_INTERVAL = 1000  # 밀리초
bullets = []
last_shot_time = 0

# FPS 설정
clock = pygame.time.Clock()
FPS = 60

# 총알 클래스
class Bullet:
    def __init__(self, x, y, angle):
        self.x = x
        self.y = y
        self.angle = angle
        self.speed = BULLET_SPEED
        self.dx = math.cos(self.angle) * self.speed
        self.dy = math.sin(self.angle) * self.speed

    def move(self):
        self.x += self.dx
        self.y += self.dy

    def draw(self, screen):
        pygame.draw.circle(screen, BULLET_COLOR, (int(self.x), int(self.y)), BULLET_RADIUS)

 

 

 

이제 정상적으로 진행방향에 따라 무기를 잘 발사하게 됨.

흠.. 다음 시간엔 캐릭터를 만들어볼까?

 

TOP

Designed by AndersonLab