2015-11-04 52 views
1

我想創建一個「雷電2」的靜脈自上而下的拍攝,我無法添加滾動的地圖。當我添加一個矩形地圖幷包含相機類時,相機不會將該船放置在地圖的底部,允許該船飛向地圖的下半部分,或者將該船保持在屏幕的中間。添加滾動到上/下射手

我想把船放在地圖的底部和相機上緩慢向上滾動,保持船在同一個地方。

下面是遊戲的簡化版本與船舶,你可以在屏幕上控制:

import sys, pygame, os, math 

# Force static position of screen 
os.environ['SDL_VIDEO_CENTERED'] = '1' 

# Constants 
LEFT = 'left' 
RIGHT = 'right' 

BLACK = (0, 0, 0) 
GRAY = (70, 70, 70) 
WHITE = (255, 255, 255) 

WIN_W = 500 
WIN_H = 800 

SHIP_WIDTH = WIN_W/15 
SHIP_HEIGHT = WIN_H/15 


class Entity(pygame.sprite.Sprite): 
    def __init__(self): 
     pygame.sprite.Sprite.__init__(self) 


class Ship(Entity): 
    def __init__(self, container): 
     Entity.__init__(self) 
     self.speed = 5 
     self.image = pygame.Surface((SHIP_WIDTH, SHIP_HEIGHT)).convert() 
     self.rect = self.image.get_rect() 
     self.rect.centerx = container.centerx 
     self.rect.y = container.centery 

    def update(self): 
     key = pygame.key.get_pressed() 
     if key[pygame.K_w]: 
      self.rect.centery -= self.speed 
     if key[pygame.K_s]: 
      self.rect.centery += self.speed 
     if key[pygame.K_d]: 
      self.rect.centerx += self.speed 
     if key[pygame.K_a]: 
      self.rect.centerx -= self.speed 

     # Ship Movement Boundaries 
     if self.rect.y < 0: 
      self.rect.y = 0 
     if self.rect.y > WIN_H - SHIP_HEIGHT: 
      self.rect.y = WIN_H - SHIP_HEIGHT 
     if self.rect.x < 0: 
      self.rect.x = 0 
     if self.rect.x > WIN_W - SHIP_WIDTH: 
      self.rect.x = WIN_W - SHIP_WIDTH 


def main(): 
    # Initialize Everything 
    pygame.init() 
    fps = 60 
    clock = pygame.time.Clock() 
    play = True 
    pygame.display.set_caption('Raiden') 
    screen = pygame.display.set_mode((WIN_W, WIN_H), pygame.SRCALPHA) 

    # Create Groups 
    shipGroup = pygame.sprite.Group() 

    # Create Game Objects 
    ship = Ship(pygame.rect.Rect(0, 0, WIN_W, WIN_H)) 

    # Add Game Objects to Groups 
    shipGroup.add(ship) 

    # Gameplay 
    while play: 
     # Checks if window exit button pressed 
     for event in pygame.event.get(): 
      if event.type == pygame.QUIT: sys.exit() 
      elif event.type == pygame.KEYDOWN: 
       if event.key == pygame.K_ESCAPE: 
        pygame.quit() 
        sys.exit() 

     # Update 
     ship.update() 


     # Print Background/Sprites 
     screen.fill(WHITE) 
     shipGroup.draw(screen) 

     # Limits frames per iteration of while loop 
     clock.tick(fps) 
     # Writes to main surface 
     pygame.display.flip() 

if __name__ == "__main__": 

這是當我添加一個矩形圖用相機類個究竟,發現地圖上有5'平臺'在右側,但是遊戲不允許你前往地圖的下半部分。

import sys, pygame, os, math 

# Force static position of screen 
os.environ['SDL_VIDEO_CENTERED'] = '1' 

# Constants 
LEFT = 'left' 
RIGHT = 'right' 

BLACK = (0, 0, 0) 
GRAY = (70, 70, 70) 
WHITE = (255, 255, 255) 

WIN_W = 500 
WIN_H = 800 

SHIP_WIDTH = WIN_W/15 
SHIP_HEIGHT = WIN_H/15 


class Entity(pygame.sprite.Sprite): 
    def __init__(self): 
     pygame.sprite.Sprite.__init__(self) 


class Ship(Entity): 
    def __init__(self, container): 
     Entity.__init__(self) 
     self.speed = 5 
     self.image = pygame.Surface((SHIP_WIDTH, SHIP_HEIGHT)).convert() 
     self.rect = self.image.get_rect() 
     self.rect.centerx = container.centerx 
     self.rect.y = container.centery 

    def update(self): 
     key = pygame.key.get_pressed() 
     if key[pygame.K_w]: 
      self.rect.centery -= self.speed 
     if key[pygame.K_s]: 
      self.rect.centery += self.speed 
     if key[pygame.K_d]: 
      self.rect.centerx += self.speed 
     if key[pygame.K_a]: 
      self.rect.centerx -= self.speed 

     # Ship Movement Boundaries 
     if self.rect.y < 0: 
      self.rect.y = 0 
     if self.rect.y > WIN_H - SHIP_HEIGHT: 
      self.rect.y = WIN_H - SHIP_HEIGHT 
     if self.rect.x < 0: 
      self.rect.x = 0 
     if self.rect.x > WIN_W - SHIP_WIDTH: 
      self.rect.x = WIN_W - SHIP_WIDTH 

class Camera(object): 
    def __init__(self, camera_func, width, height): 
     self.camera_func = camera_func 
     self.state = pygame.Rect(0, 0, width, height) 

    def apply(self, target): 
     return target.rect.move(self.state.topleft) 

    def update(self, target): 
     self.state = self.camera_func(self.state, target.rect) 


def simple_camera(camera, target_rect): 
    l, t, _, _ = target_rect 
    _, _, w, h = camera 
    return pygame.Rect(-l+WIN_W/2, -t+WIN_H/2, w, h) 


def complex_camera(camera, target_rect): 
    l, t, _, _ = target_rect 
    _, _, w, h = camera 
    l, t, _, _ = -l+WIN_W/2, -t+WIN_H/2, w, h 

    l = min(0, l)       # stop scrolling at the left edge 
    l = max(-(camera.width-WIN_W), l) # stop scrolling at the right edge 
    t = max(-(camera.height-WIN_H), t) # stop scrolling at the bottom 
    t = min(0, t)       # stop scrolling at the top 
    return pygame.Rect(l, t, w, h) 


class Platform(Entity): 
    def __init__(self, x, y): 
     Entity.__init__(self) 
     self.image = pygame.Surface((32, 32)) 
     self.image.convert() 
     self.image.fill(GRAY) 
     self.rect = pygame.Rect(x, y, 32, 32) 

    def update(self): 
     pass 

def main(): 
    # Initialize Everything 
    pygame.init() 
    fps = 60 
    clock = pygame.time.Clock() 
    play = True 
    pygame.display.set_caption('Raiden') 
    screen = pygame.display.set_mode((WIN_W, WIN_H), pygame.SRCALPHA) 

    # Create Groups 
    shipGroup = pygame.sprite.Group() 
    backgroundGroup = pygame.sprite.Group() 

    # Load Level 
    platforms = [] 
    x = y = 0 
    level = [ 
     "PPPPPPPPPPPPPPPP", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "PPPP   P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "PPPP   P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P   PPPP", 
     "P    P", 
     "PPPP   P", 
     "P    P", 
     "PPPP   P", 
     "P    P", 
     "P   PPPP", 
     "P    P", 
     "P    P", 
     "PPPP   P", 
     "P    P", 
     "P    P", 
     "P   PPPP", 
     "P    P", 
     "PPPP   P", 
     "P    P", 
     "P   PPPP", 
     "P    P", 
     "PPPP   P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "PPPP   P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P   PPPP", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "PPPP   P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "PPPPPPPPPPPPPPPP",] 
    # build the level 
    for row in level: 
     for col in row: 
      if col == "P": 
       p = Platform(x, y) 
       platforms.append(p) 
       backgroundGroup.add(p) 
      x += 32 
     y += 32 
     x = 0 

    total_level_width = len(level[0])*32 
    total_level_height = len(level)*32 

    camera = Camera(complex_camera, total_level_width, total_level_height) 


    # Create Game Objects 
    ship = Ship(pygame.rect.Rect(0, 0, WIN_W, WIN_H)) 

    # Add Game Objects to Groups 
    shipGroup.add(ship) 


    # Gameplay 
    while play: 
     # Checks if window exit button pressed 
     for event in pygame.event.get(): 
      if event.type == pygame.QUIT: sys.exit() 
      elif event.type == pygame.KEYDOWN: 
       if event.key == pygame.K_ESCAPE: 
        pygame.quit() 
        sys.exit() 
     camera.update(ship) 
     # Update 
     ship.update() 

     # Print Background/Sprites 
     screen.fill(WHITE) 

     for e in backgroundGroup: 
      screen.blit(e.image, camera.apply(e)) 

     shipGroup.draw(screen) 

     # Limits frames per iteration of while loop 
     clock.tick(fps) 
     # Writes to main surface 
     pygame.display.flip() 

if __name__ == "__main__": 
    main() 

回答

1

滾動相機的工作原理是計算一個新的精靈位置。對於您的背景拼貼,您使用screen.blit(e.image, camera.apply(e)),這將起作用,但對於船舶,您只需致電shipGroup.draw(screen)即可。

但是shipGroup不知道相機,因此將始終將船精靈擋在絕對位置,而不是攝像機類將計算的相對位置。

class CameraGroup(pygame.sprite.Group): 
    def __init__(self, camera): 
     pygame.sprite.Group.__init__(self) 
     self.camera = camera 

    def draw(self, surface): 
     sprites = self.sprites() 
     surface_blit = surface.blit 
     for spr in sprites: 
      self.spritedict[spr] = surface_blit(spr.image, self.camera.apply(spr)) 
     self.lostsprites = [] 

,並使用它:

... 
total_level_width = len(level[0])*32 
total_level_height = len(level)*32 

# Create Groups 
camera = Camera(complex_camera, total_level_width, total_level_height) 
shipGroup = CameraGroup(camera) 
backgroundGroup = CameraGroup(camera) 

# build the level 
for row in level: 
    ... 
... 

,並在主循環:

while play: 
    # Checks if window exit button pressed 
    for event in pygame.event.get(): 
     ... 

    camera.update(ship) 
    # Update 
    ship.update() 

    # Print Background/Sprites 
    screen.fill(WHITE) 

    backgroundGroup.draw(screen) 
    shipGroup.draw(screen) 

    # Limits frames per iteration of while loop 
    ... 

我們可以通過創建一個可處理攝像頭,像一個精靈組解決這個問題

現在滾動工作。另一個問題是,這個檢查你的Ship類:

if self.rect.y > WIN_H - SHIP_HEIGHT: 
     self.rect.y = WIN_H - SHIP_HEIGHT 

這將防止船舶進一步向下移動比WIN_H,但你的水平其實比畫面高度大。

爲了解決這個問題,我們創建了一個Rect描述的整體水平,並把它傳遞到Ship類:

total_rect = pygame.rect.Rect(0, 0, total_level_width, total_level_height) 

ship = Ship(total_rect) 

,然後我們用它在Ship類的級別的底部開始,而我們使用clamp_ip確保船舶不能離開屏幕:

class Ship(Entity): 
    def __init__(self, container): 
     Entity.__init__(self) 
     self.speed = 5 
     self.image = pygame.Surface((SHIP_WIDTH, SHIP_HEIGHT)).convert() 
     self.rect = self.image.get_rect() 
     self.rect.centerx = container.centerx 
     self.rect.y = container.bottom - self.rect.height * 2 
     self.container = container 

    def update(self): 
     key = pygame.key.get_pressed() 
     if key[pygame.K_w]: 
      self.rect.centery -= self.speed 
     if key[pygame.K_s]: 
      self.rect.centery += self.speed 
     if key[pygame.K_d]: 
      self.rect.centerx += self.speed 
     if key[pygame.K_a]: 
      self.rect.centerx -= self.speed 

     self.rect.clamp_ip(self.container) 

此外,由於你的水平寬度爲16塊* 32像素,WIN_W應該

WIN_W = 16*32 

如果你只想垂直滾動,而不是水平滾動也。

下面是完整的代碼:

import sys, pygame, os, math 

# Force static position of screen 
os.environ['SDL_VIDEO_CENTERED'] = '1' 

# Constants 
LEFT = 'left' 
RIGHT = 'right' 

BLACK = (0, 0, 0) 
GRAY = (70, 70, 70) 
WHITE = (255, 255, 255) 

WIN_W = 16*32 
WIN_H = 800 

SHIP_WIDTH = WIN_W/15 
SHIP_HEIGHT = WIN_H/15 


class Entity(pygame.sprite.Sprite): 
    def __init__(self): 
     pygame.sprite.Sprite.__init__(self) 


class Ship(Entity): 
    def __init__(self, container): 
     Entity.__init__(self) 
     self.speed = 5 
     self.image = pygame.Surface((SHIP_WIDTH, SHIP_HEIGHT)).convert() 
     self.rect = self.image.get_rect() 
     self.rect.centerx = container.centerx 
     self.rect.y = container.bottom - self.rect.height * 2 
     self.container = container 

    def update(self): 
     key = pygame.key.get_pressed() 
     if key[pygame.K_w]: 
      self.rect.centery -= self.speed 
     if key[pygame.K_s]: 
      self.rect.centery += self.speed 
     if key[pygame.K_d]: 
      self.rect.centerx += self.speed 
     if key[pygame.K_a]: 
      self.rect.centerx -= self.speed 

     self.rect.clamp_ip(self.container) 

class Camera(object): 
    def __init__(self, camera_func, width, height): 
     self.camera_func = camera_func 
     self.state = pygame.Rect(0, 0, width, height) 

    def apply(self, target): 
     return target.rect.move(self.state.topleft) 

    def update(self, target): 
     self.state = self.camera_func(self.state, target.rect) 


def simple_camera(camera, target_rect): 
    l, t, _, _ = target_rect 
    _, _, w, h = camera 
    return pygame.Rect(-l+WIN_W/2, -t+WIN_H/2, w, h) 


def complex_camera(camera, target_rect): 
    l, t, _, _ = target_rect 
    _, _, w, h = camera 
    l, t, _, _ = -l+WIN_W/2, -t+WIN_H/2, w, h 

    l = min(0, l)       # stop scrolling at the left edge 
    l = max(-(camera.width-WIN_W), l) # stop scrolling at the right edge 
    t = max(-(camera.height-WIN_H), t) # stop scrolling at the bottom 
    t = min(0, t)       # stop scrolling at the top 
    return pygame.Rect(l, t, w, h) 

class CameraGroup(pygame.sprite.Group): 
    def __init__(self, camera): 
     pygame.sprite.Group.__init__(self) 
     self.camera = camera 

    def draw(self, surface): 
     sprites = self.sprites() 
     surface_blit = surface.blit 
     for spr in sprites: 
      self.spritedict[spr] = surface_blit(spr.image, self.camera.apply(spr)) 
     self.lostsprites = [] 

class Platform(Entity): 
    def __init__(self, x, y): 
     Entity.__init__(self) 
     self.image = pygame.Surface((32, 32)) 
     self.image.convert() 
     self.image.fill(GRAY) 
     self.rect = pygame.Rect(x, y, 32, 32) 

    def update(self): 
     pass 

def main(): 
    # Initialize Everything 
    pygame.init() 
    fps = 60 
    clock = pygame.time.Clock() 
    play = True 
    pygame.display.set_caption('Raiden') 
    screen = pygame.display.set_mode((WIN_W, WIN_H), pygame.SRCALPHA) 

    # Load Level 
    platforms = [] 
    x = y = 0 
    level = [ 
     "PPPPPPPPPPPPPPPP", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "PPPP   P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "PPPP   P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P   PPPP", 
     "P    P", 
     "PPPP   P", 
     "P    P", 
     "PPPP   P", 
     "P    P", 
     "P   PPPP", 
     "P    P", 
     "P    P", 
     "PPPP   P", 
     "P    P", 
     "P    P", 
     "P   PPPP", 
     "P    P", 
     "PPPP   P", 
     "P    P", 
     "P   PPPP", 
     "P    P", 
     "PPPP   P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "PPPP   P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P   PPPP", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "PPPP   P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "P    P", 
     "PPPPPPPPPPPPPPPP",] 

    total_level_width = len(level[0])*32 
    total_level_height = len(level)*32 
    total_rect = pygame.rect.Rect(0, 0, total_level_width, total_level_height) 

    # Create Groups 
    camera = Camera(complex_camera, total_level_width, total_level_height) 
    shipGroup = CameraGroup(camera) 
    backgroundGroup = CameraGroup(camera) 

    # build the level 
    for row in level: 
     for col in row: 
      if col == "P": 
       p = Platform(x, y) 
       platforms.append(p) 
       backgroundGroup.add(p) 
      x += 32 
     y += 32 
     x = 0 

    # Create Game Objects 
    ship = Ship(total_rect) 

    # Add Game Objects to Groups 
    shipGroup.add(ship) 

    # Gameplay 
    while play: 
     # Checks if window exit button pressed 
     for event in pygame.event.get(): 
      if event.type == pygame.QUIT: sys.exit() 
      elif event.type == pygame.KEYDOWN: 
       if event.key == pygame.K_ESCAPE: 
        pygame.quit() 
        sys.exit() 

     camera.update(ship) 
     # Update 
     ship.update() 

     # Print Background/Sprites 
     screen.fill(WHITE) 

     backgroundGroup.draw(screen) 
     shipGroup.draw(screen) 

     # Limits frames per iteration of while loop 
     clock.tick(fps) 
     # Writes to main surface 
     pygame.display.flip() 

if __name__ == "__main__": 
    main()