Установка прокрутки камеры в мини-окне в Pygame - PullRequest
0 голосов
/ 02 июля 2018

Я пытаюсь создать игру, в которой действие отображается в маленьком окошке внутри основного экрана, освобождая окружающее пространство для текста и меню и чего-то еще. Поскольку карта больше выделенного окна, я кодировал базовую «камеру», которая следует за игроком. В основном это работает, но у меня возникают проблемы с «обрезкой» области за пределами этого окна.

Вот соответствующие биты кода (отредактировано для предоставления рабочего примера):

import pygame, os, sys
from pygame.locals import *
pygame.init()

RIGHT = 'RIGHT'
LEFT = 'LEFT'
UP = 'UP'
DOWN = 'DOWN'

class Camera():
    def __init__(self, screen, x_ratio = 1, y_ratio = 1, x_offset = 0, y_offset = 0):
        self.screen = screen.copy()
        self.rec = self.screen.get_rect()
        self.rec.width *= x_ratio
        self.rec.height *= y_ratio
        self.x_offset = x_offset
        self.y_offset = y_offset
    def get_pos(self):
        return (self.x_offset - self.rec.x, self.y_offset - self.rec.y)
    def get_window(self):
        w = pygame.Rect(self.rec)
        w.topleft = (0 - self.rec.x, 0 - self.rec.y)
        return w
    def move(self, x, y):
        """Move camera into new position"""
        self.rec.x = x
        self.rec.y = y
    def track(self, obj):
        while obj.rec.left < self.rec.left:
            self.rec.x -= 1
        while obj.rec.right > self.rec.right:
            self.rec.x += 1
        while obj.rec.top < self.rec.top:
            self.rec.y -= 1
        while obj.rec.bottom > self.rec.bottom:
            self.rec.y += 1

class Map:
    def __init__(self, width, height):
        self.width = width
        self.height = height
        self.rec = pygame.Rect(0,0,self.width,self.height)

    def draw(self, screen):
        pygame.draw.rect(screen, (200,200,200), self.rec)

class Obj:
    def __init__(self, char, x = 0, y = 0, width = 0, height = 0):
        self.width = width
        self.height = height
        self.rec = pygame.Rect(x, y, width, height)
        self.cur_map = None
        self.timers = {}

        #Dummying in chars for sprites
        self.char = char

        self.x_dir = 1
        self.y_dir = 1
        self.speed = 1
        self.moving = False        

    def move(self):
        if self.x_dir != 0 or self.y_dir != 0:
            new_x = self.rec.x + (self.x_dir*self.speed)
            new_y = self.rec.y + (self.y_dir*self.speed)
            new_rec = pygame.Rect(new_x, new_y, self.width, self.height)

            #Keep movement within bounds of map
            while new_rec.left < self.cur_map.rec.left:
                new_rec.x += 1
            while new_rec.right > self.cur_map.rec.right:
                new_rec.x -= 1
            while new_rec.top < self.cur_map.rec.top:
                new_rec.y += 1
            while new_rec.bottom > self.cur_map.rec.bottom:
                new_rec.y -= 1

            self.rec = new_rec

    def set_dir(self, d):
        self.x_dir = 0
        self.y_dir = 0
        if d == LEFT:
            self.x_dir = -1
        elif d == RIGHT:
            self.x_dir = 1
        elif d == UP:
            self.y_dir = -1
        elif d == DOWN:
            self.y_dir = 1

    def set_moving(self, val = True):
        self.moving = val

class Game:
    def __init__(self):
        self.screen_size = (800, 600)
        self.screen = pygame.display.set_mode(self.screen_size)
        self.map_screen = self.screen.copy()
        self.title = 'RPG'
        pygame.display.set_caption(self.title)

        self.camera = Camera(self.screen, 0.75, 0.75)#, 10, 75)

        self.fps = 80
        self.clock = pygame.time.Clock()
        self.debug = False
        self.bg_color = (255,255,255)
        self.text_size = 18
        self.text_font = 'Arial'
        self.text_style = pygame.font.SysFont(self.text_font, self.text_size)
        self.key_binds = {LEFT : [K_LEFT, K_a], RIGHT : [K_RIGHT, K_d], UP : [K_UP, K_w], DOWN : [K_DOWN, K_s],
                          'interact' : [K_RETURN, K_z], 'inventory' : [K_i,  K_SPACE], 'quit' : [K_ESCAPE]}

        self.player = Obj('p', 0, 0, 10, self.text_size)     

    def draw(self, obj):
        char = obj.char       
        self.draw_text(char, obj.rec.x, obj.rec.y, screen = self.map_screen)

    def draw_text(self, text, x, y, color = (0,0,0), screen = None):
        textobj = self.text_style.render(text, 1, color)
        textrect = textobj.get_rect()
        textrect.x = x
        textrect.y = y
        if screen == None:
            """Use default screen"""
            self.screen.blit(textobj, textrect)
        else:
            screen.blit(textobj, textrect)

    def play(self):
        done = False
        cur_map = Map(800, 800)
        self.map_screen = pygame.Surface((cur_map.width, cur_map.height))
        self.map_screen.fill(self.bg_color)

        bg = pygame.Surface((cur_map.width, cur_map.height))
        cur_map.draw(bg)

        self.player.cur_map = cur_map

        while not done:

            for event in pygame.event.get():
                if event.type == QUIT:
                    pygame.quit()
                    sys.exit()
                if event.type == KEYDOWN:
                    if event.key in self.key_binds[LEFT]:
                        self.player.set_dir(LEFT)
                        self.player.set_moving()
                    elif event.key in self.key_binds[RIGHT]:
                        self.player.set_dir(RIGHT)
                        self.player.set_moving()
                    elif event.key in self.key_binds[UP]:
                        self.player.set_dir(UP)
                        self.player.set_moving()
                    elif event.key in self.key_binds[DOWN]:
                        self.player.set_dir(DOWN)
                        self.player.set_moving()

                elif event.type == KEYUP:
                    self.player.set_moving(False)


            if self.player.moving:
                self.player.move()

            self.camera.track(self.player)
            self.clock.tick()

            self.screen.fill(self.bg_color)
            self.map_screen.blit(bg, (0,0))            
            self.draw(self.player)

            pygame.draw.rect(self.map_screen, (0,0,0), self.camera.rec, 1)
            #self.screen.blit(self.map_screen, (0,0), [0 - self.camera.rec.x, 0 - self.camera.rec.y, self.camera.rec.width, self.camera.rec.height])
            self.screen.blit(self.map_screen, self.camera.get_pos(), self.camera.get_window())
            pygame.display.flip()

game = Game()
game.play()

Перемещение игрока за пределы окна камеры приводит к тому, что окно полностью закрывается и исчезает. Я попытался отрегулировать блитинговые координаты, как советовалось ранее, но, похоже, он только меняет направление, в котором окно открывается.

1 Ответ

0 голосов
/ 04 июля 2018

Из вашего обновленного кода, блиц-координаты для self.screen.blit(...) все еще меняются: self.camera.get_window() меняет значение, потому что rec.x и rec.y - это значения, относящиеся к позиции игрока на карте. Следовательно, вы должны определить постоянную координату мини-карты, которая должна совпадать со смещением камеры.

self.screen.blit(self.map_screen, (self.camera.x_offset,self.camera.y_offset), (*self.camera.get_pos(), self.camera.rec.width, self.camera.rec.height))

Измените Camera().get_pos() на:

def get_pos(self):
    return (self.rec.x, self.rec.y)

Полагаю, я только изменил self.screen.blit(...) и прекратил использовать или переписал функции камеры, поскольку вы путаете себя со всеми переменными записи.

Чтобы проиллюстрировать это, измените Map().draw(screen) на:

def draw(self, screen):
    pygame.draw.rect(screen, (200,200,200), self.rec)
    pygame.draw.circle(screen, (255, 255, 255), (50, 50), 20, 2)

Также не советуйте рисовать всю карту в каждом цикле, только ту часть, которая будет видна.

...