[PYGAME] Pirate Mario - 6

문승환·2022년 9월 6일
0

[PYGAME]

목록 보기
7/8

프로젝트 개요

  • pygame을 사용하여 Pirate Mario제작
  • Youtube Clear Code의 Platformer in Pygame을 따라하며 진행
  • 주요 과제: 월드맵을 구성하고 유저가 맵을 선택할 수 있는 것과 지형에서 떨어져 물에 닿으면 다시 월드맵으로 돌아가는 것을 구현

프로젝트 내용

game_data.py

# designed levels
level_0 = {
    'terrain': '../levels/0/level_0_terrain.csv',
    'coins': '../levels/0/level_0_coins.csv',
    'fg palms': '../levels/0/level_0_fg_palms.csv',
    'bg palms': '../levels/0/level_0_bg_palms.csv',
    'crates': '../levels/0/level_0_crates.csv',
    'enemies': '../levels/0/level_0_enemies.csv',
    'constraints': '../levels/0/level_0_constraints.csv',
    'player': '../levels/0/level_0_player.csv',
    'grass': '../levels/0/level_0_grass.csv',
    'node_pos': (110, 400),
    'unlock': 1,
    'node_graphics': '../graphics/overworld/0'
}

level_1 = {
    'terrain': '../levels/1/level_1_terrain.csv',
    'coins': '../levels/1/level_1_coins.csv',
    'fg palms': '../levels/1/level_1_fg_palms.csv',
    'bg palms': '../levels/1/level_1_bg_palms.csv',
    'crates': '../levels/1/level_1_crates.csv',
    'enemies': '../levels/1/level_1_enemies.csv',
    'constraints': '../levels/1/level_1_constraints.csv',
    'player': '../levels/1/level_1_player.csv',
    'grass': '../levels/1/level_1_grass.csv',
    'node_pos': (300, 220),
    'unlock': 2,
    'node_graphics': '../graphics/overworld/1'
}

level_2 = {
    'terrain': '../levels/2/level_2_terrain.csv',
    'coins': '../levels/2/level_2_coins.csv',
    'fg palms': '../levels/2/level_2_fg_palms.csv',
    'bg palms': '../levels/2/level_2_bg_palms.csv',
    'crates': '../levels/2/level_2_crates.csv',
    'enemies': '../levels/2/level_2_enemies.csv',
    'constraints': '../levels/2/level_2_constraints.csv',
    'player': '../levels/2/level_2_player.csv',
    'grass': '../levels/2/level_2_grass.csv',
    'node_pos': (480, 610),
    'unlock': 3,
    'node_graphics': '../graphics/overworld/2'
}

level_3 = {
    'terrain': '../levels/2/level_2_terrain.csv',
    'coins': '../levels/2/level_2_coins.csv',
    'fg palms': '../levels/2/level_2_fg_palms.csv',
    'bg palms': '../levels/2/level_2_bg_palms.csv',
    'crates': '../levels/2/level_2_crates.csv',
    'enemies': '../levels/2/level_2_enemies.csv',
    'constraints': '../levels/2/level_2_constraints.csv',
    'player': '../levels/2/level_2_player.csv',
    'grass': '../levels/2/level_2_grass.csv',
    'node_pos': (610, 350),
    'unlock': 4,
    'node_graphics': '../graphics/overworld/3'
}

level_4 = {
    'terrain': '../levels/2/level_2_terrain.csv',
    'coins': '../levels/2/level_2_coins.csv',
    'fg palms': '../levels/2/level_2_fg_palms.csv',
    'bg palms': '../levels/2/level_2_bg_palms.csv',
    'crates': '../levels/2/level_2_crates.csv',
    'enemies': '../levels/2/level_2_enemies.csv',
    'constraints': '../levels/2/level_2_constraints.csv',
    'player': '../levels/2/level_2_player.csv',
    'grass': '../levels/2/level_2_grass.csv',
    'node_pos': (880, 210),
    'unlock': 5,
    'node_graphics': '../graphics/overworld/4'
}

level_5 = {
    'terrain': '../levels/2/level_2_terrain.csv',
    'coins': '../levels/2/level_2_coins.csv',
    'fg palms': '../levels/2/level_2_fg_palms.csv',
    'bg palms': '../levels/2/level_2_bg_palms.csv',
    'crates': '../levels/2/level_2_crates.csv',
    'enemies': '../levels/2/level_2_enemies.csv',
    'constraints': '../levels/2/level_2_constraints.csv',
    'player': '../levels/2/level_2_player.csv',
    'grass': '../levels/2/level_2_grass.csv',
    'node_pos': (1050, 400),
    'unlock': 5,
    'node_graphics': '../graphics/overworld/5'
}

levels = {
    0: level_0,
    1: level_1,
    2: level_2,
    3: level_3,
    4: level_4,
    5: level_5
}
  • 기존의 데이터에 월드맵 데이터를 추가해 맵과 레벨을 호출할 때 사용하도록 수정

overworld.py

import pygame
from game_data import levels
from support import import_folder
from decoration import Sky

class Node(pygame.sprite.Sprite):
    def __init__(self, pos, status, icon_speed, path):
        super().__init__()
        self.frames = import_folder(path)
        self.frame_index = 0
        self.image = self.frames[self.frame_index]
        if status == 'available':
            self.status = 'available'
        else:
            self.status = 'locked'
        self.rect = self.image.get_rect(center = pos)

        self.detection_zone = pygame.Rect(self.rect.centerx - (icon_speed / 2), self.rect.centery - (icon_speed / 2), icon_speed, icon_speed)

    def animate(self):
        self.frame_index += 0.15
        if self.frame_index >= len(self.frames): self.frame_index = 0
        self.image = self.frames[int(self.frame_index)]

    def update(self):
        if self.status == 'available':
            self.animate()
        else:
            tint_surf = self.image.copy()
            tint_surf.fill('Black', None, pygame.BLEND_RGBA_MULT)
            self.image.blit(tint_surf, (0, 0))
class Icon(pygame.sprite.Sprite):
    def __init__(self, pos):
        super().__init__()
        self.pos = pos
        self.image = pygame.image.load('../graphics/overworld/hat.png').convert_alpha()
        self.rect = self.image.get_rect(center = pos)

    def update(self):
        self.rect.center = self.pos

class Overworld:
    def __init__(self, start_level, max_level, surface, create_level):

        # setup
        self.diplay_surface = surface
        self.max_level = max_level
        self.current_level = start_level
        self.create_level = create_level

        # movement logic
        self.moving = False
        self.move_direction = pygame.math.Vector2(0, 0)
        self.speed = 8

        # sprites
        self.setup_nodes()
        self.setup_icon()
        self.sky = Sky(8, 'overworld')

    def setup_nodes(self):
        self.nodes = pygame.sprite.Group()

        for index, node_data in enumerate(levels.values()):
            if index <= self.max_level:
                node_sprite = Node(node_data['node_pos'], 'available', self.speed, node_data['node_graphics'])
            else:
                node_sprite = Node(node_data['node_pos'], 'locked', self.speed, node_data['node_graphics'])
            self.nodes.add(node_sprite)

    def draw_path(self):
        if self.max_level > 0:
            points = [node['node_pos'] for index, node in enumerate(levels.values()) if index <= self.max_level]
            pygame.draw.lines(self.diplay_surface, '#a04f45', False, points, 6)

    def setup_icon(self):
        self.icon = pygame.sprite.GroupSingle()
        icon_sprite = Icon(self.nodes.sprites()[self.current_level].rect.center)
        self.icon.add(icon_sprite)

    def input(self):
        keys = pygame.key.get_pressed()

        if not self.moving:
            if keys[pygame.K_RIGHT] and self.current_level < self.max_level:
                self.move_direction = self.get_movement_data('next')
                self.current_level += 1
                self.moving = True
            elif keys[pygame.K_LEFT] and self.current_level > 0:
                self.move_direction = self.get_movement_data('previous')
                self.current_level -= 1
                self.moving = True
            elif keys[pygame.K_SPACE]:
                self.create_level(self.current_level)

    def get_movement_data(self, target):
        start = pygame.math.Vector2(self.nodes.sprites()[self.current_level].rect.center)

        if target == 'next':
            end = pygame.math.Vector2(self.nodes.sprites()[self.current_level + 1].rect.center)
        else:
            end = pygame.math.Vector2(self.nodes.sprites()[self.current_level - 1].rect.center)
        return (end - start).normalize()

    def update_icon_pos(self):
        if self.moving and self.move_direction:
            self.icon.sprite.pos += self.move_direction * self.speed
            target_node = self.nodes.sprites()[self.current_level]
            if target_node.detection_zone.collidepoint(self.icon.sprite.pos):
                self.moving = False
                self.move_direction = pygame.math.Vector2(0, 0)

    def run(self):
        self.input()
        self.update_icon_pos()
        self.icon.update()
        self.nodes.update()

        self.sky.draw(self.diplay_surface)
        self.draw_path()
        self.nodes.draw(self.diplay_surface)
        self.icon.draw(self.diplay_surface)
  • 월드맵을 실제로 구현하고 유저가 클리어한 레벨에 따라 각 노드를 이동할 수 있도록 구현

KEEP

  • 없음

PROBLEM

  • 부자연스러운 레벨 디자인
  • 일부 지형에서의 높은 적회피 난이도
  • 적의 움직임에서 간헐적인 버그 발생

TRY

  • 모든 요소를 구현한 후 문제점들을 하나씩 수정
    레벨 디자인 수정
    게임 난이도 조정
    버그 수정
profile
아직 모자란 수학과생

0개의 댓글