pygame如何使地图自动滚动

时间:2013-10-03 19:54:50

标签: pygame

我正在尝试制作一个游戏,您需要在地图自动滚动时避开障碍物。到目前为止,我已经从其他人那里获取了一些代码以试图重新利用它,但我遇到了一些麻烦。我是pygame的新手,所以任何帮助都会非常感激。

我想简化这段代码,但每当我更改一行时,就会出现问题。我不需要任何重力,我想随意上下移动(有点像R-Type或其他一些旧的太空射击者)。最重要的部分是使地图自己从右向左滚动,如果玩家触摸墙壁,则玩家将死亡。

我知道我需要告诉它移动播放器周围的所有内容,但我不知道如何在此代码中表达它。

以下是代码:

import pygame
from pygame import *

WIN_WIDTH = 800
WIN_HEIGHT = 640
HALF_WIDTH = int(WIN_WIDTH / 2)
HALF_HEIGHT = int(WIN_HEIGHT / 2)

DISPLAY = (WIN_WIDTH, WIN_HEIGHT)
DEPTH = 32
FLAGS = 0
CAMERA_SLACK = 30

def main():
    global cameraX, cameraY
    pygame.init()
    screen = pygame.display.set_mode(DISPLAY, FLAGS, DEPTH)
    pygame.display.set_caption("Use arrows to move!")
    timer = pygame.time.Clock()

    up = down = left = right = running = False
    bg = Surface((32,32))
    bg.convert()
    bg.fill(Color("#000000"))
    entities = pygame.sprite.Group()
    player = Player(32, 32)
    platforms = []

    x = y = 0
    level = [
        "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP  PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP",
        "P                                                                                               P  P                                                                                                                                                                                                           E",
        "P                                                                                               P  P                                                  PPP                                                                                       PPPPPPPPPPPPP                                                  E",
        "P                                                                                               P  P                                                  PPP                                                                                       PPPPPPPPPPPPP                                                  E",
        "P                                                                                               P  P                                                                                                      PPPPPPPPP                                                                                            P",
        "P                                                            PPPP                               P  P                                                                                                      PPPPPPPPP                                                                                            P",
        "P                                                            P  P                               PPPP                               PPP                                                                                       PPPPPPPPPPPP                                                                      P",
        "P                                                            P  P                                                                  PPP                                           PPP                                         PPPPPPPPPPPP                                                                      P",
        "P                                                            P  P                                                                  PPP                                           PPP                                                                                                                           P",
        "P                                                            P  P                                                                                                                PPP                                                                       PPPPPPP                                             P",
        "P                                                            P  P                                                                                                                                                                                          PPPPPPP                                             P",
        "P                                                            P  P                                                                                                                                                                                                                                              P",
        "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP  PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP"]

    # build the level
    for row in level:
        for col in row:
            if col == "P":
                p = Platform(x, y)
                platforms.append(p)
                entities.add(p)
            if col == "E":
                e = ExitBlock(x, y)
                platforms.append(e)
                entities.add(e)
            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)
    entities.add(player)

    while 1:
        timer.tick(60)

        for e in pygame.event.get():
            if e.type == QUIT: raise SystemExit, "QUIT"
            if e.type == KEYDOWN and e.key == K_ESCAPE:
                raise SystemExit, "ESCAPE"
            if e.type == KEYDOWN and e.key == K_UP:
                up = True
            if e.type == KEYDOWN and e.key == K_DOWN:
                down = True
            if e.type == KEYDOWN and e.key == K_LEFT:
                left = True
            if e.type == KEYDOWN and e.key == K_RIGHT:
                right = True
            if e.type == KEYDOWN and e.key == K_SPACE:
                running = True

            if e.type == KEYUP and e.key == K_UP:
                up = False
            if e.type == KEYUP and e.key == K_DOWN:
                down = False
            if e.type == KEYUP and e.key == K_RIGHT:
                right = False
            if e.type == KEYUP and e.key == K_LEFT:
                left = False
            if e.type == KEYUP and e.key == K_RIGHT:
                right = False

        # draw background
        for y in range(32):
            for x in range(32):
                screen.blit(bg, (x * 32, y * 32))

        camera.update(player)

        # update player, draw everything else
        player.update(up, down, left, right, running, platforms)
        for e in entities:
            screen.blit(e.image, camera.apply(e))

        pygame.display.update()

class Camera(object):
    def __init__(self, camera_func, width, height):
        self.camera_func = camera_func
        self.state = 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 Rect(-l+HALF_WIDTH, -t+HALF_HEIGHT, w, h)

def complex_camera(camera, target_rect):
    l, t, _, _ = target_rect
    _, _, w, h = camera
    l, t, _, _ = -l+HALF_WIDTH, -t+HALF_HEIGHT, w, h

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

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

class Player(Entity):
    def __init__(self, x, y):
        Entity.__init__(self)
        self.xvel = 0
        self.yvel = 0
        self.onGround = False
        self.image = Surface((32,32))
        self.image.fill(Color("#0000FF"))
        self.image.convert()
        self.rect = Rect(x, y, 32, 32)

    def update(self, up, down, left, right, running, platforms):
        if up:
            # only jump if on the ground
            if self.onGround: self.yvel -= 10
            pass
        if down:
            pass
        if running:
            self.xvel = 12
        if left:
            self.xvel = -8
        if right:
            self.xvel = 8
        if not self.onGround:
            # only accelerate with gravity if in the air
            self.yvel += 0.3
            # max falling speed
            if self.yvel > 100: self.yvel = 100
        if not(left or right):
            self.xvel = 0
        # increment in x direction
        self.rect.left += self.xvel
        # do x-axis collisions
        self.collide(self.xvel, 0, platforms)
        # increment in y direction
        self.rect.top += self.yvel
        # assuming we're in the air
        self.onGround = False;
        # do y-axis collisions
        self.collide(0, self.yvel, platforms)

    def collide(self, xvel, yvel, platforms):
        for p in platforms:
            if pygame.sprite.collide_rect(self, p):
                if isinstance(p, ExitBlock):
                    pygame.event.post(pygame.event.Event(QUIT))
                if xvel > 0:
                    self.rect.right = p.rect.left
                    print "collide right"
                if xvel < 0:
                    self.rect.left = p.rect.right
                    print "collide left"
                if yvel > 0:
                    self.rect.bottom = p.rect.top
                    self.onGround = True
                    self.yvel = 0
                if yvel < 0:
                    self.rect.top = p.rect.bottom


class Platform(Entity):
    def __init__(self, x, y):
        Entity.__init__(self)
        self.image = Surface((32, 32))
        self.image.convert()
        self.image.fill(Color("#DDDDDD"))
        self.rect = Rect(x, y, 32, 32)

    def update(self):
        pass

class ExitBlock(Platform):
    def __init__(self, x, y):
        Platform.__init__(self, x, y)
        self.image.fill(Color("#0033FF"))

if __name__ == "__main__":
    main()

感谢Dominic Kexel提供了大部分代码。

1 个答案:

答案 0 :(得分:1)

我认为在这里使用相机是错误的做法;我宁愿自己移动块。

看看这个简单的例子(它应该让你开始):

import pygame

lvl = """
##################################################################
                                      #      #                    
 #          #           #                                    #    
                            #   #     #         #                 
                #                               #     #        #  

                        #          #         #            #       
         #       #      #   #                      #           #  
   #                        #                #                    
          ####       #              #                 #           
    #                       #       #        #                    
##################################################################"""

# initialisation
pygame.init()
clock = pygame.time.Clock()
lvl = lvl.split('\n')[1:]
TOTAL_H, TOTAL_W = len(lvl)*32, len(lvl[0])*32
screen = pygame.display.set_mode((800, TOTAL_H))
LEVEL_SPEED = 5
player, PLAYER_SPEED = pygame.Rect(100, 100, 32, 32), 4
font = pygame.font.SysFont('Arial', 52)
text = font.render('FAILED !', True, (255, 0, 0))
timeout = 0

# create Rects that represent the level
x, y = 0, 0
blocks = []
for line in lvl:
    for char in line:
        if char == '#':
            blocks.append(pygame.Rect(x*32, y*32, 32, 32))
        x += 1
    x, y = 0, y + 1

run = True
while run:
    for e in pygame.event.get():
        if e.type == pygame.QUIT:
            run = False
            break

    if timeout:
        timeout -= 1
    else:
        pressed = pygame.key.get_pressed()
        if pressed[pygame.K_UP]: player.move_ip(0, -PLAYER_SPEED)
        if pressed[pygame.K_DOWN]: player.move_ip(0, PLAYER_SPEED)
        if pressed[pygame.K_LEFT]: player.move_ip(-PLAYER_SPEED, 0)
        if pressed[pygame.K_RIGHT]: player.move_ip(PLAYER_SPEED, 0)

    for block in blocks:
        # move each block
        block.move_ip(-LEVEL_SPEED, 0)
        # collision detection
        if not timeout and block.colliderect(player):
            timeout = 100
        # if blocks move out of view, 
        # let'm reappear on the right to
        # create an endless loop
        if block.right < 0:
            block.move_ip(TOTAL_W, 0)

    screen.fill((0, 0, 0))
    for block in blocks:
        pygame.draw.rect(screen, (200, 200, 0), block)

    if not timeout:
        pygame.draw.rect(screen, (100, 200, 200), player)
    else:
        screen.blit(text, (200, 150))

    pygame.display.flip()
    clock.tick(40)

enter image description here