Python / Pygame - Как создать камеру для просмотра карты мира (сверху вниз, без персонажа игрока) - PullRequest
0 голосов
/ 12 января 2020

Я пытаюсь реализовать функцию камеры, которая работает в том, что изображения перемещаются - однако:

1) Последующие изображения - такие как новое меню - создаются в том месте, где они были бы создано, если бы я не двигал камеру. Поэтому, если я переместу камеру на 30 пикселей вправо, последующие изображения, которые были бы созданы в (0,0), теперь будут созданы в (30,0). Это также относится к взаимодействию с кнопками; В приведенном выше примере, чтобы использовать кнопку, которая была бы создана в (0,0), мне нужно удерживать мою мышь в (0,0), даже если кнопка теперь появляется в (30,0)

Таким образом, если я перемещаю камеру, я получаю результаты, такие как https://i.imgur.com/FsydpSj.png (посмотрите, как я выбираю новую игру, когда моя мышь находится над ней? Где моя мышь, там, где была кнопка до того, как я переместился камера) или https://i.imgur.com/wAr9pFJ.png (игра помнит, как я перемещал камеру в предыдущем меню, и теперь создает следующее меню в том же месте, где было исходное меню, до того, как я переместил камеру

2) Если я создаю изображение, превышающее ширину экрана или высоту экрана, а затем перемещаю камеру, я фактически не вижу остальную часть изображения. Вместо этого я вижу что-то вроде этого: https://i.imgur.com/e0qgUW1.png

Таким образом, вместо отображения остальной части карты, игра просто перемещает снимок (размера экрана по ширине экрана) вокруг: https://i.imgur.com/pYMsR8B.png - но если бы я увеличил меню, вы могли бы видеть, что карта должна быть намного больше, и я, очевидно, хочу видеть остальную часть карты, когда я перемещаю камеру: https://i.imgur.com/Y3WmcBa.png

Соответствующие переменные объявлены в классе Controller:

    windowWidth = 800 #1792
    windowHeight = 600 #896
    windowResize = False
    cameraactive = False
    camera = pygame.display.set_mode((windowWidth, windowHeight))
    screen = pygame.Surface((windowWidth, windowHeight))
    mouse = pygame.mouse.get_pos()
    camerax = 0
    cameray = 0
    sprites = pygame.sprite.Group()
# All the other sprite.Group()s, such as spritesciv, are created just like this one
    spriteslist = [sprites , spritesciv , tiles , cities , texttiles , textcities , textcitiesselected , buttonscitiesselected , textbuttonscitiesselected , buttons , buttonsselectciv , buttonsrandomciv , textinputs]
    buttonslist = [tiles , cities , buttonscitiesselected , buttons , buttonsselectciv , buttonsrandomciv , textinputs]

Соответствующие функции, все в Controller

    def on_event(self):
        keys = pygame.key.get_pressed()
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self._running = False
            if keys[K_ESCAPE]:
                self._running = False
            if event.type == MOUSEMOTION:
                Controller.mouse = pygame.mouse.get_pos()
            if event.type == pygame.VIDEORESIZE: #Controller.windowResize
                screensize = event.size
                Controller.windowWidth = event.w
                Controller.windowHeight = event.h
                screen = pygame.display.set_mode(screensize,RESIZABLE)
            if self.cameraactive:
                if Controller.mouse[0]<50:
                    self.camerax += 8
                if (self.windowWidth - Controller.mouse[0])<50:
                    self.camerax -= 8
                if Controller.mouse[1]<50:
                    self.cameray += 8
                if (self.windowHeight - Controller.mouse[1])<50:
                    self.cameray -= 8
            if keys[K_SPACE] and event.type == pygame.KEYUP:
                self.nextturn()
            if keys[K_TAB] and event.type == pygame.KEYUP:
                i = Controller.civilisationsactive.index(Controller.civilisation)
                if i < (len(Controller.civilisationsactive)-1):
                    Controller.civilisation = Controller.civilisationsactive[i + 1]
                else:
                    Controller.civilisation = Controller.civilisationsactive[0]
            for i in Controller.buttonslist:
                for button in i:
                    button._create_event(event)
    def empty_draw(self):
        for i in Controller.spriteslist:
            i.empty()
    def on_draw(self):
        self.screen.fill((255, 255, 255))
        for i in Controller.spriteslist:
            i.draw(self.screen)
        self.camera.blit(self.screen, (self.camerax, self.cameray))
        pygame.display.flip()
        pygame.display.update()

Спасибо большое за помощь. :)

1 Ответ

0 голосов
/ 16 января 2020

Вы можете создать поверхность с полной картой и скопировать часть этой карты на экран

screen.blit(fullmap, (0,0), camera)

Но я бы использовал другие имена:

screen (в конечном итоге window) - поверхность, созданная с помощью set_mode((800,600))

fullmap - поверхность, созданная с помощью Surface((2000, 1000)) для рисования всех элементов

camera - Rect, а не Surface с положением / смещением камера


Минимальный рабочий код.

Я использую стрелки, чтобы изменить положение (x, y) camera (Rect) и проверить, не остается ли этот прямоугольник заполненным карта.

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

Я также добавил «иконку», которая бликает отдельно - всегда в одном и том же месте - так что никогда двигаться со стрелками.

import pygame
import random # to draw random rectangles on map

# --- constants ---

RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
COLORS = (RED, GREEN, BLUE)

TILE_SIZE = 50

# --- main ---

pygame.init()

# - window -
screen = pygame.display.set_mode((800,600))
screen_rect = screen.get_rect()

# - map - (with random rectangles)
fullmap = pygame.Surface((2000, 1000))
#for y in range(TILE_SIZE, 1000-TILE_SIZE, TILE_SIZE):
#    for x in range(TILE_SIZE, 2000-TILE_SIZE, TILE_SIZE):
for y in range(0, 1000, TILE_SIZE):
    for x in range(0, 2000, TILE_SIZE):
        pygame.draw.rect(fullmap, random.choice(COLORS), (x, y, TILE_SIZE, TILE_SIZE))
fullmap_rect = fullmap.get_rect()

# - icon(s) which not move -
icon = pygame.Surface((100, 100))
icon.fill((255,255,255))
icon_rect = icon.get_rect()
icon_rect.right = screen_rect.right - 10
icon_rect.bottom = screen_rect.bottom - 10

# - camera -
# `camera` is not `Surface` but only `Rect` with value/offset which I uses to cut map
camera = screen.get_rect()

# --- loop ---                         
running = True
while running:

    # - events -

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

    # - updates (without draws) -

    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT]:
        camera.x -= 5
        if camera.left < fullmap_rect.left:
            camera.left = fullmap_rect.left
    if keys[pygame.K_RIGHT]:
        camera.x += 5
        if camera.right > fullmap_rect.right:
            camera.right = fullmap_rect.right
    if keys[pygame.K_UP]:
        camera.y -= 5
        if camera.top < fullmap_rect.top:
            camera.top = fullmap_rect.top
    if keys[pygame.K_DOWN]:
        camera.y += 5
        if camera.bottom > fullmap_rect.bottom:
            camera.bottom = fullmap_rect.bottom

    # - draws (without updates) -

    # moving map - using `camera` to copy part of `fullmap` to `screen`
    screen.blit(fullmap, (0,0), camera)

    # static icon(s)
    screen.blit(icon, icon_rect)

    pygame.display.update()

# --- end ---    
pygame.quit()
...