将滚动相机放在pygame中的迷你窗口中



我正在尝试创建一个游戏,其中动作显示在主屏幕对象内的一个小框中,为文本和菜单释放周围的空间。 由于地图大于分配的窗口,我编写了一个基本的"摄像机"来跟随玩家。 它大部分有效,但我在"修剪"此窗口之外的区域时遇到麻烦。

以下是相关的代码位(已编辑以提供工作示例(:

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()

将玩家移过摄像机窗口的边界会导致窗口完全卷起并消失。 我尝试按照前面的建议调整块坐标,但它似乎只会改变窗口滚动的方向。

从更新的代码来看,self.screen.blit(...)的块坐标仍在变化:self.camera.get_window()更改值,因为rec.xrec.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(...)并停止使用或重写了您的 Camera 函数,因为您将自己与所有 rec 变量混淆了。

为了说明它的工作原理,请将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)

一个提示也不要在每个循环中绘制整个地图,而只是绘制可见的部分。

最新更新