2013-04-22 126 views
1

我试图添加一个滚动“相机”,跟随播放器移动时,但无法弄清楚如何做到这一点。我知道当你按下其中一个移动键时,你可以沿相反的方向移动水平线,但是我宁愿不这样做,因为我打算稍后添加敌人,并且不希望不断更新其坐标,因为玩家移动。在2D游戏中滚动?

我已经添加了我的代码,下面是一个样本级别。

代码:

import pygame, sys, time, random, math 
from pygame.locals import * 

BACKGROUNDCOLOR = (255, 255, 255) 

WINDOWW = 800 
WINDOWH = 600 
PLAYERW = 66 
PLAYERH = 22 
FPS = 60 
MOVESPEED = 3 
YACCEL = 0.13 
GRAVITY = 2 
BLOCKSIZE = 30 

pygame.init() 
screen = pygame.display.set_mode((WINDOWW, WINDOWH), 0, 32) 
mainClock = pygame.time.Clock() 

testLevel = [ 
      (1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,), 
      (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,), 
      (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,), 
      (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,), 
      (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,), 
      (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,), 
      (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,), 
      (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,), 
      (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,), 
      (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,), 
      (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,), 
      (1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,), 
      (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,), 
      (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,), 
      (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,), 
      (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,), 
      (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,), 
      (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,), 
      (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,), 
      (1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,)] 

def createblock(length, height, color): 
    tmpblock = pygame.Surface((length, height)) 
    tmpblock.fill(color) 
    tmpblock.convert() 
    return tmpblock 

def terminate(): # Used to shut down the software 
    pygame.quit() 
    sys.exit() 

def add_level(lvl, bSize): # Creates the level based on a map (lvl) and the size of blocks 
    bList = [] # List of every block 
    bListDisp = [] # List of every block to display  
    bTypeList = [] # List with corresponding type of block(wall, air, etc.) 

    for y in range(len(lvl)): 
     for x in range(len(lvl[0])): 

      if lvl[y][x] == 0: # If the block type on lvl[y][x] is '0', write "air" down in the type list 
       bTypeList.append("air") 
      elif lvl[y][x] == 1: # If the block type on lvl[y][x] is '1', write "wall" down in the type list 
       bTypeList.append("solid") 

      bList.append(pygame.Rect((bSize * x), (bSize * y), bSize, bSize)) #Append every block that is registered 
      bListDisp.append(pygame.Rect((bSize * x), (bSize * y), bSize, bSize)) #Append every block to display that is registered 

    return bList, bListDisp, bTypeList 

player = pygame.Rect((WINDOWW/2), (WINDOWH - BLOCKSIZE*3), PLAYERW, PLAYERH) 
wallblock = createblock(BLOCKSIZE, BLOCKSIZE,(20,0,50)) 

lastTime = pygame.time.get_ticks() 
isGrounded = False 

vx = 0 
vy = 0 

allLevels = [testLevel] # A list containing all lvls(only one for now) 
maxLevel = len(allLevels) # Checks which level is the last 
currLevel = allLevels[0] # Current level(start with the first lvl) 
blockList, blockListDisp, blockTypeList = add_level(currLevel, BLOCKSIZE) # A list with every block and another list with the blocks types 

thrusters = True 
jumping = False 
falling = True 
while True: 
    """COLLISION""" 
    collision = False 
    for i in range(len(blockTypeList)): 
     if blockTypeList[i] == "solid": 
      if player.colliderect(blockList[i]): 
       collision = True 
       if vx > 0 and not falling: 
        player.right = blockListDisp[i].left 
        vx = 0 
        print('Collide Right') 
       if vx < 0 and not falling: 
        player.left = blockListDisp[i].right 
        vx = 0 
        print('Collide Left') 
       if vy > 0: 
        player.bottom = blockListDisp[i].top 
        isGrounded = True 
        falling = False 
        vy = 0 
        print('Collide Bottom') 
       if vy < 0: 
        player.top = blockListDisp[i].bottom 
        vy = 0 
        print('Collide Top') 
      else: 
       player.bottom += 1 
       if player.colliderect(blockList[i]): 
        collision = True 
        #isGrounded = True 
        #falling = False 
       player.bottom -= 1 
    if not collision: 
     falling = True 
     isGrounded = False 

    # Input 
    pressedKeys = pygame.key.get_pressed() # Checks which keys are being pressed 
    timeDiff = pygame.time.get_ticks() - lastTime # Calculates time difference 
    lastTime += timeDiff # Last time checked reset to current time 

    # Shut-down if the ESC-key is pressed or the window is "crossed down" 
    for event in pygame.event.get(): 
     if event.type == QUIT or event.type == KEYDOWN and event.key == K_ESCAPE: 
      terminate()  

    """X-axis control""" 
    if pressedKeys[ord('a')]: 
     vx = -MOVESPEED 
    if pressedKeys[ord('d')]: 
     vx = MOVESPEED 
    if not pressedKeys[ord('d')] and not pressedKeys[ord('a')]: 
     vx = 0 

    """Y-axis control""" 
    # Controls for jumping 
    if pressedKeys[ord('w')] and thrusters == True: 
      vy -= YACCEL * timeDiff; # Accelerate along the y-xis when "jumping", but not above/below max speed 
      if vy <= -4: 
       vy = -4 
      isGrounded = False # You are airborne 
      jumping = True # You are jumping 

    if event.type == KEYUP: # If you let go of the "jump"-button, stop jumping 
     if event.key == ord('w') and vy < 0 and not isGrounded: 
      jumping = False 
      falling = True 

    player.x += vx 
    player.y += vy 

    # Gravity 
    if not isGrounded or falling: 
     vy += 0.3 
     if vy > 80: 
      vy = 80 

    screen.fill(BACKGROUNDCOLOR) 

    for i in range(len(blockTypeList)): 
     if blockTypeList[i] == "solid": 
      screen.blit(wallblock, (blockListDisp[i].x, blockListDisp[i].y)) #blit the wall-block graphics 

    pygame.draw.rect(screen, (0, 0, 0), player) 

    pygame.display.update() 
    mainClock.tick(FPS) 
+0

你可能想看看[这个问题](http://stackoverflow.com/questions/14354171/how-to-add-scrolling-to-a-platformer-in-pygame)。国际海事组织,接受的答案值得更多upvotes。 – 2013-04-22 18:15:12

+0

是的,我之前见过这个问题,但是因为我对python和pygame比较陌生,所以我仍然在理解类时遇到了一些麻烦,所以答案对我来说并不适用。 – user2274889 2013-04-22 19:14:01

回答

1

关键是要跟踪摄像机坐标并使用这些作为你的渲染代码偏移。看起来好像你正在渲染你已经发布的代码的末尾,用x,y坐标绘制每个块到屏幕上的像素x,y。

正如你所说,转移水平并不是很好。相反,让键输入(或其他摄像机移动设备)更改cameraX和cameraY变量,然后根据块x和y值添加(或减去,取决于您想要的方向)这些值,以更改映射到哪个像素块。即改变你的渲染到:

screen.blit(wallblock, (blockListDisp[i].x + cameraX, blockListDisp[i].y + cameraY)) 

这意味着如果摄像机移动到(10,20),然后在屏幕上的在块(5,5)映射到(15,25),跨越移动您的整体水平而你的基础模型保持不变。合理?

你也可以稍微进一步;如果你的相机只是被移动来跟随你的角色,你可以在上面交换cameraX和cameraY来获得角色位置的某些功能,并且直接在那里管理整个东西。

+0

我不太确定我明白你的意思与整个改变cameraX和cameraY变量的东西。你可能会发布一个示例代码? – user2274889 2013-04-22 18:22:54