황금캐기 게임

호호빵·2022년 4월 12일
0

기본 틀

import pygame

pygame.init()
screen_width = 1280
screen_height = 720
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("Gold Miner")

clock = pygame.time.Clock()

running = True
while running:
    clock.tick(30)  # FPS 값이 30으로 고정

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False



pygame.quit()

Group, Class


# 보석 클래스
class Gemstone(pygame.sprite.Sprite):
    def __init__(self, image, position):
        super().__init__()     # 상속받은 부모클래스 init
        self.image = image     # sprite에 반드시 image와 rect 변수 정의
        self.rect = image.get_rect(center=position)

def setup_gemstone():
    # 작은 금
    small_gold = Gemstone(gemstone_images[0], (200, 380))
    gemstone_group.add(small_gold) # 그룹에 추가

    # 큰 금, 돌, 다이아 (한 번에)
    gemstone_group.add(Gemstone(gemstone_images[1], (300, 500)))
    gemstone_group.add(Gemstone(gemstone_images[2], (300, 380)))
    gemstone_group.add(Gemstone(gemstone_images[3], (900, 420)))


# 4개 보석 이미지 불러오기 (금1, 금2, 돌, 다이아몬드)
gemstone_images = [
    pygame.image.load(os.path.join(current_path, "small.png")),
    pygame.image.load(os.path.join(current_path, "big.png")),
    pygame.image.load(os.path.join(current_path, "stone.png")),
    pygame.image.load(os.path.join(current_path, "diamond.png"))]

# 보석 그룹
gemstone_group = pygame.sprite.Group()
setup_gemstone() # 게임에 원하는만큼의 보석을 정의 


# character = pygame.image.load(...)
# charager_size = character.get_rect().size
# character_width, character_height 등등 으로 했었음
# 위처럼 4개 보석 다하기엔 좀.. 그래서 class 처리



삼각함수

import math # 모듈 선언

def set_position(self, position, angle):
        r = self.rect.size[0] // 2 # 동그라미 이미지 기준 반지름
        rad_angle = math.radians(angle) # 각도
        to_x = r * math.cos(rad_angle) # 삼각형의 밑변
        to_y = r * math.sin(rad_angle) # 삼각형의 높이

        self.rect.center = (position[0] + to_x, position[1] + to_y)

실제 코드

import os
import math
import pygame

# 집게 클래스
class Claw(pygame.sprite.Sprite):
    def __init__(self, image, position):
        super().__init__()
        self.image = image
        self.original_image = image
        self.rect = image.get_rect(center=position)

        self.offset = pygame.math.Vector2(default_offset_x_claw, 0) # 중심에서 살짝 오른쪽으로
        self.position = position

        self.direction = LEFT # 집게의 이동 방향
        self.angle_speed = 2.5 # 집게의 각도 변경 폭
        self.angle = 10 # 최초 각도 정의 (오른쪽 끝)
        
    def update(self, to_x):
        if self.direction == LEFT: # 왼쪽으로 이동하고 있다면
            self.angle += self.angle_speed
        elif self.direction == RIGHT:
            self.angle -= self.angle_speed
        
        if self.angle > 170: # 허용각을 벗어나면
            self.angle = 170
            self.set_direction(RIGHT)
        elif self.angle < 10:
            self.angle = 10 
            self.set_direction(LEFT)

        self.offset.x += to_x # 40 + 12 + 12 + ...

        self.rotate() # 회전 처리

        # print(self.angle, self.direction)
        # rect_center = self.position + self.offset # 집게를 약간 당겨주기
        # self.rect = self.image.get_rect(center=rect_center)

    def rotate(self):
        self.image = pygame.transform.rotozoom(self.original_image, -self.angle, 1)
        offset_rotated = self.offset.rotate(self.angle) # 각도에 맞는 offset 정보 얻어오기
        self.rect = self.image.get_rect(center=self.position + offset_rotated) 

    def set_direction(self, direction):
        self.direction = direction

    def draw(self, screen):
        screen.blit(self.image, self.rect)
        pygame.draw.line(screen, VIOLET, self.position, self.rect.center, 6)

    def set_init_state(self):
        self.offset.x = default_offset_x_claw
        self.angle = 10
        self.direction = LEFT


# 보석 클래스
class Gemstone(pygame.sprite.Sprite):
    def __init__(self, image, position, price, speed):
        super().__init__()     # 상속받은 부모클래스 init
        self.image = image     # sprite에 반드시 image와 rect 변수 정의
        self.rect = image.get_rect(center=position)
        self.price = price
        self.speed = speed

    def set_position(self, position, angle):
        r = self.rect.size[0] // 2 # 동그라미 이미지 기준 반지름
        rad_angle = math.radians(angle) # 각도
        to_x = r * math.cos(rad_angle) # 삼각형의 밑변
        to_y = r * math.sin(rad_angle) # 삼각형의 높이

        self.rect.center = (position[0] + to_x, position[1] + to_y)

def setup_gemstone():
    small_price, small_speed = 100, 5
    big_price, big_speed = 300, 2
    stone_price, stone_speed = 10, 2
    diamond_price, diamond_speed = 600, 7

    # 작은 금
    small_gold = Gemstone(gemstone_images[0], (200, 380), small_price, small_speed)
    gemstone_group.add(small_gold) # 그룹에 추가

    # 큰 금, 돌, 다이아
    gemstone_group.add(Gemstone(gemstone_images[1], (300, 500), big_price, big_speed))
    gemstone_group.add(Gemstone(gemstone_images[2], (300, 380), stone_price, stone_speed))
    gemstone_group.add(Gemstone(gemstone_images[3], (900, 420), diamond_price, diamond_speed))

def update_score(score):
    global curr_score
    curr_score += score

def display_score():
    txt_curr_score = game_font.render(f"Curr Score : {curr_score:,}", True, BLACK)
    screen.blit(txt_curr_score, (50, 20))
    
    txt_goal_score = game_font.render(f"Goal Score : {goal_score:,}", True, BLACK)
    screen.blit(txt_goal_score, (50, 80))

def display_time(time):
    txt_timer = game_font.render(f"Time : {time}", True, BLACK)
    screen.blit(txt_timer, (1100, 50))

def display_game_over():
    game_font = pygame.font.SysFont("arialrounded", 60)
    txt_game_over = game_font.render(game_result, True, VIOLET)
    rect_game_over = txt_game_over.get_rect(center=(int(screen_width / 2), int(screen_height / 2)))
    screen.blit(txt_game_over, rect_game_over)

pygame.init()
screen_width = 1280
screen_height = 720
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("Gold Miner")
clock = pygame.time.Clock()
game_font = pygame.font.SysFont("arialrounded", 30)

# 점수 관련 변수
goal_score = 1500
curr_score = 0

# 게임 오버 관련 변수
game_result = None 
total_time = 60
start_ticks = pygame.time.get_ticks() # 현재 tick을 받아옴


# 게임 관련 변수
default_offset_x_claw = 40 # 중심점으로부터 집게까지의 기본 x축 간격
to_x = 0 #  x좌표 기준으로 집게 이미지를 이동시킬 값 저장 변수
caught_gemstone = None # 집게로 잡은 보석 정보

move_speed = 12 # 발사 이동속도 (x좌표 기준으로 증가되는 값)
return_speed = 20 # 아무것도 없이 돌아올 때

LEFT = -1
STOP = 0 # 이동방향이 좌우가 아닌 고정
RIGHT = 1

RED = (255, 0, 0)
BLACK = (0, 0, 0)
VIOLET = (209, 174, 232)

# 배경 불러오기
current_path = os.path.dirname(__file__) # 현재 파일 위치 변환
background = pygame.image.load(os.path.join(current_path, "background.jpg"))

# 4개 보석 이미지 불러오기 (금1, 금2, 돌, 다이아몬드)
gemstone_images = [
    pygame.image.load(os.path.join(current_path, "small.png")).convert_alpha(),
    pygame.image.load(os.path.join(current_path, "big.png")).convert_alpha(),
    pygame.image.load(os.path.join(current_path, "stone.png")).convert_alpha(),
    pygame.image.load(os.path.join(current_path, "diamond.png")).convert_alpha()]
    # .convert_alpha() = 이미지의 투명도 조절

# 보석 그룹
gemstone_group = pygame.sprite.Group()
setup_gemstone() # 게임에 원하는만큼의 보석을 정의 

# 집게
claw_image = pygame.image.load(os.path.join(current_path, "claw.png")).convert_alpha()
claw = Claw(claw_image, (screen_width // 2, 110) )

running = True
while running:
    clock.tick(30)  # FPS 값이 30으로 고정

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        
    if event.type == pygame.MOUSEBUTTONDOWN:
        claw.set_direction(STOP) # 좌우 멈춤
        to_x = move_speed

    if claw.rect.left < 0 or claw.rect.right > screen_width or claw.rect.bottom > screen_height:
        to_x = -return_speed

    if claw.offset.x < default_offset_x_claw: # 원위치로 오면
        to_x = 0
        claw.set_init_state() # 처음 상태로 되돌림

        if caught_gemstone: # 잡힌 보석이 있다면
            update_score(caught_gemstone.price)
            gemstone_group.remove(caught_gemstone)
            caught_gemstone = None

    if not caught_gemstone: # 현재 잡힌 보석이 없을 때, 충돌 체크
        for gemstone in gemstone_group:
            # if claw.rect.colliderect(gemstone.rect): # 보석 정보와 맞다면 (직사각형 기준)
            if pygame.sprite.collide_mask(claw, gemstone): # 실제 영역에 충돌했을 때    
                caught_gemstone = gemstone # 잡힌 보석 정보 업데이트
                to_x = -gemstone.speed # 잡힌 보석이 돌아오는 속도
                break   # 이미 잡혀있기 때문에 또 충돌할 필요 없음

    if caught_gemstone:
        caught_gemstone.set_position(claw.rect.center, claw.angle)


    screen.blit(background, (0, 0))

    gemstone_group.draw(screen) # 그룹 내 모든 sprite를 스크린에 보여줘
    claw.update(to_x)
    claw.draw(screen)

    display_score()

    # 시간 계산, 1234 -> 1.234 -> 1
    elapsed_time = (pygame.time.get_ticks() - start_ticks) / 1000
    display_time(total_time - int(elapsed_time))

    if total_time - int(elapsed_time) <= 0:
        running = False
        if curr_score >= goal_score:
            game_result = "Mission Complete"
        else:
            game_result = "Game Over"

        display_game_over()

    pygame.display.update()

pygame.time.delay(2000) # 2초정도 대기
pygame.quit()

profile
하루에 한 개념씩

0개의 댓글