A small to medium sized pygame game Github Link To Code

Pastebin Link

I am well aware of how terrible the SettingsMenu class is, it's still a work in progress and is the way it is so it can actually work.
Can't paste it directly in the post because it would be mostly code.

I feel like this function needs work, but I've been over it a couple times and can't find anything meaningful to do.

def title_screen():
    background = assets_base_path + 'title_screen.png'
    font_size = 0
    frames = 0
    enter_game = False
    while not enter_game:
        for event_ in pygame.event.get():
            if event_.type == pygame.QUIT:
                quit()
            elif event_.type == pygame.KEYDOWN:
                if event_.key == pygame.K_KP_ENTER or pygame.K_SPACE:
                    enter_game = True
            # print(event_)

        game_display.blit(pygame.image.load(background), (0, 0))
        font = pygame.font.Font(fonts_path + 'Futura.ttf', font_size)
        game_display.blit(font.render(str('An RPG'), True, Color.Black), (500, 111))
        # game_display.blit(font.render(str(frames), True, Color.Goldenrod), (0, 0))

        if font_size &lt; 65: font_size += 1
        if font_size == 65:
            game_display.blit(font.render(str('Press Enter To Play'), True, Color.Black), (345, 400))

        pygame.display.update()
        frames += 1
        sleep(0.013)


I also feel like there's room to improve in this section. Seems like there should be a better way to do it, but I'm not sure what it would be.

rect_ = copy(player)
    if active_keys['w']: rect_.y -= config.player_movespeed_vertical
    if active_keys['s']: rect_.y += config.player_movespeed_vertical
    if active_keys['a']: rect_.x -= config.player_movespeed_horizontal
    if active_keys['d']: rect_.x += config.player_movespeed_horizontal
    rect_.refresh_rect()
    pillar_player_collisions_list = pygame.sprite.spritecollide(rect_, active_pillars, False)
    wall_player_collisions_list   = pygame.sprite.spritecollide(rect_, active_walls, False)
    if len(pillar_player_collisions_list + wall_player_collisions_list) != 0:
        # print('Collisions With Pillars')
        pass
    else:
        # print('No Collisions With Pillars')
        if active_keys['w']: player.y -= config.player_movespeed_vertical
        if active_keys['s']: player.y += config.player_movespeed_vertical
        if active_keys['a']: player.x -= config.player_movespeed_horizontal
        if active_keys['d']: player.x += config.player_movespeed_horizontal
        player.refresh_rect()


Thanks!
With respect to your title_screen function:


You are not using the standard python functions for operating on paths. Try using pathlib:

from pathlib import Path

Assets_base_path = Path('/path/to/assets')

def title_screen():
    background = Assets_base_path / 'title_screen.png'

In your while not enter_game loop, you are setting the enter_game 
status from the event loop, but that won't affect anything until the entire loop is completed. I'd suggest moving that code down to the bottom 
of the loop.
Your code calls this line:

game_display.blit(pygame.image.load(background), (0, 0))


over and over again. The loaded image should be cached - just load it into a variable outside the loop, instead of reading it from disk each time.
You have this code:

font = pygame.font.Font(fonts_path + 'Futura.ttf', font_size)
game_display.blit(font.render(str('An RPG'), True, Color.Black), (500, 111))


And a similar statement elsewhere in the function. I would suggest writing a helper function that does this work for you. Something like this:

def show_text(locn, text, *, color=None, font=None):
    global Game_display

    if font is None:
        font = get_current_font()

    if color is None:
        color = Color.Black

    Game_display.blit(font.render(text, True, color), locn)



Then you can just write:

  futura = pygame.font.Font(Fonts_path / 'Futura.ttf', font_size)
  # NB: Might have to use str() if pygame.font doesn't support pathlib

  show_text((500, 111), 'An RPG', font=futura)



In your collision-detection code, you have repeated code. I'd suggest that you write a function to handle updating your rectangle position:

future = copy(player)
move_rect(future)
future.refresh_rect()

Furthermore, you are concatenating two lists and then discarding the result, when all you really need to do is check the lists separately:

if pillar_hits or wall_hits:
    pass
else:  # No hits

Finally, you might consider just keeping the future-player variable, which is a copy() of player, when you accept the move:

else:  # No hits
    player = future