滚动2D游戏?

时间:2013-04-22 17:59:17

标签: python camera scroll 2d pygame

我正在尝试添加一个滚动的“相机”,它跟随播放器移动但无法弄清楚如何执行此操作。我知道当你按下其中一个移动键时你可以向相反方向移动水平但是我不想这样做,因为我计划稍后添加敌人并且不希望必须更新他们的坐标作为球员移动。

我添加了以下示例级别的代码。

代码:

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)

1 个答案:

答案 0 :(得分:1)

诀窍是跟踪相机坐标并将其用作渲染代码中的偏移量。看起来你在你发布的代码末尾正在渲染,在屏幕上用coord 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),将您的整个关卡移动,同时您的基础模型保持在相同。有意义吗?

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