在 pygame 中使用滚动相机 [英] Using scrolling camera in pygame

查看:46
本文介绍了在 pygame 中使用滚动相机的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试在我用 pygame 制作的 2d 游戏中实现相机功能,但我唯一获得的是我的播放器设置在窗口中间.我看到它的 x 和 y 坐标如何变化,但玩家没有移动.我知道我必须对地图使用相机的应用方法,但我不知道该怎么做,因为这是我对 pygame 的第一种方法.这是我的代码:

I have tried to implement a camera function in my 2d game made with pygame but the only I obtain is my player set in the middle of the window. I see how its x and y cordenates changes but the player does not move.I know I must use the camera's apply method to the map but I don't know how to do it since is my first approach to pygame. Here is my code:

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

"""
dirt  0
grass 1
water 2
coal  3
"""

DIRT = 0
GRASS = 1
WATER = 2
COAL = 3
DIAMOND = 4
CLOUD = 5

cloudx = -200
cloudy = 0

WHITE = (255, 255, 255)
BLACK = (0,   0,   0  )
BROWN = (153, 76,  0  )
GREEN = (0,   255, 0  )
BLUE  = (0,   0,   255)

TILESIZE  = 40
MAPWIDTH  = 140
MAPHEIGHT = 120

WIN_WIDTH = 800
WIN_HEIGHT = 600

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

fpsClock = pygame.time.Clock()

colours = {
            DIRT: BROWN,
            GRASS: GREEN,
            WATER: BLUE,
            COAL: BLACK
          }

"""tilemap = [
            [GRASS, COAL,  DIRT ],
            [WATER, WATER, GRASS],
            [COAL,  WATER, GRASS],
            [DIRT,  WATER, COAL ],
            [GRASS, WATER, DIRT]
          ]"""

resources = [WATER, GRASS, COAL, DIRT, DIAMOND]
tilemap = [[random.choice(resources) for w in range(MAPWIDTH)] for h in range(MAPHEIGHT)]



textures = {
            DIRT: pygame.image.load("dirt.gif"),
            GRASS: pygame.image.load("grass.gif"),
            COAL: pygame.image.load("coal.gif"),
            WATER: pygame.image.load("water.gif"),
            DIAMOND: pygame.image.load("diamond.gif"),
            CLOUD: pygame.image.load("nube.gif")
           }

inventory = {
                DIRT    :0,
                WATER   :0,
                GRASS   :0,
                COAL    :0,
                DIAMOND :0

            }

playerPos = [50,50]
move = 0
vel_x = 0
vel_y = 0
speed = 1

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, rect):
        return rect.move(self.state.topleft)

    def update(self, target_rect):
        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+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-SCREEN_WIDTH), l)   # stop scrolling at the right edge
    t = max(-(camera.height-SCREEN_HEIGHT), t) # stop scrolling at the bottom
    t = min(0, t)                           # stop scrolling at the top
    return pygame.Rect(l, t, w, h)

global cameraX, cameraY
total_level_width = len(tilemap[0]) * TILESIZE
total_level_height = len(tilemap)*TILESIZE
camera = Camera(simple_camera ,total_level_width, total_level_height)

pygame.init()
DISPLAYSURF = pygame.display.set_mode((WIN_WIDTH, WIN_HEIGHT))
pygame.display.set_caption("My first game :)")
pygame.display.set_icon(pygame.image.load("player.gif"))

PLAYER = pygame.image.load("player.gif")
playerrect = PLAYER.get_rect()


for rw in range(MAPHEIGHT):
    for cl in range(MAPWIDTH):
        randomNumber = random.randint(0,50)

        if randomNumber <= 10:
            tile = COAL
        elif randomNumber > 11 and randomNumber <= 20:
            tile = WATER
        elif randomNumber > 21 and randomNumber <= 45:
            tile = GRASS
        elif randomNumber > 46 and randomNumber <= 49:
            tile = DIRT
        else:
            tile = DIAMOND

        tilemap[rw][cl] = tile

INVFONT = pygame.font.Font("freeSansBold.ttf", 18)

while True:
    for event in pygame.event.get():
        if event.type == QUIT or event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
            pygame.quit()
            sys.exit()
        elif event.type == KEYDOWN:
            #movement
            if event.key == K_RIGHT and playerPos[0] < MAPWIDTH - 1:
                playerPos[0] += move
            elif event.key == K_LEFT and playerPos[0] > 1/TILESIZE:
                playerPos[0] -= move
            elif event.key == K_DOWN and playerPos[1] < MAPHEIGHT - 1:
                playerPos[1] += move
            elif event.key == K_UP and playerPos[1] > 1/TILESIZE:
                playerPos[1] -= move

            #pick up resource
            elif event.key == K_SPACE:
                currentTile = tilemap[playerPos[1]][playerPos[0]]
                inventory[currentTile] += 1
                tilemap[playerPos[1]][playerPos[0]] = DIRT

            #place resources
            elif event.key == K_1:
                currentTile = tilemap[playerPos[1]][playerPos[0]]
                if inventory[WATER] > 0:
                    inventory[WATER] -= 1
                    tilemap[playerPos[1]][playerPos[0]] = WATER
                    inventory[currentTile] += 1
            elif event.key == K_2:
                currentTile = tilemap[playerPos[1]][playerPos[0]]
                if inventory[GRASS] > 0:
                    inventory[GRASS] -= 1
                    tilemap[playerPos[1]][playerPos[0]] = GRASS
                    inventory[currentTile] += 1
            elif event.key == K_3:
                currentTile = tilemap[playerPos[1]][playerPos[0]]
                if inventory[COAL] > 0:
                    inventory[COAL] -= 1
                    tilemap[playerPos[1]][playerPos[0]] = COAL
                    inventory[currentTile] += 1
            elif event.key == K_4:
                currentTile = tilemap[playerPos[1]][playerPos[0]]
                if inventory[DIRT] > 0:
                    inventory[DIRT] -= 1
                    tilemap[playerPos[1]][playerPos[0]] = DIRT
                    inventory[currentTile] += 1
            elif event.key == K_5:
                currentTile = tilemap[playerPos[1]][playerPos[0]]
                if inventory[DIAMOND] > 0:
                    inventory[DIAMOND] -= 1
                    tilemap[playerPos[1]][playerPos[0]] = DIAMOND
                    inventory[currentTile] += 1
    keys = pygame.key.get_pressed()
    if keys[K_LEFT] and playerPos[0] > 1/TILESIZE:
        playerPos[0] -= speed
    if keys[K_RIGHT] and playerPos[0] < MAPWIDTH - 1:
        playerPos[0] += speed
    if keys[K_UP] and playerPos[1] > 1/TILESIZE:
        playerPos[1] -= speed
    if keys[K_DOWN] and playerPos[1] < MAPHEIGHT - 1:
        playerPos[1] += speed

    for row in range(MAPHEIGHT):
        for column in range(MAPWIDTH):
            DISPLAYSURF.blit(textures[tilemap[row][column]], (column*TILESIZE, row*TILESIZE))
            #DISPLAYSURF.blit(PLAYER, (playerPos[0]*TILESIZE, playerPos[1]*TILESIZE))


    DISPLAYSURF.blit(PLAYER, camera.apply(pygame.Rect(playerPos[0],playerPos[1],42,42)))
    camera.update(PLAYER.get_rect().move((playerPos[0],playerPos[1])))

    pygame.display.update()
    fpsClock.tick(10)
    print playerPos

推荐答案

首先,删除这块代码:

        if event.key == K_RIGHT and playerPos[0] < MAPWIDTH - 1:
            playerPos[0] += move
        elif event.key == K_LEFT and playerPos[0] > 1/TILESIZE:
            playerPos[0] -= move
        elif event.key == K_DOWN and playerPos[1] < MAPHEIGHT - 1:
            playerPos[1] += move
        elif event.key == K_UP and playerPos[1] > 1/TILESIZE:
            playerPos[1] -= move

您已经使用 pygame.key.get_pressed() 进行移动,因此无需检查按键(不要忘记更改以下 elifif).

You already use pygame.key.get_pressed() for movement, so there's not need to check for a key press (Don't forget to change the following elif to if).

我知道我必须对地图使用相机的应用方法

I know I must use the camera's apply method to the map

是的,您走对了.

您已经创建了一个变量 playerrect,所以让我们用它来存储玩家的位置.另外,让我们创建一个 Rect 来存储地图的大小.这很快就会派上用场:

You already create a variable playerrect, so let's use it to store the position of the player. Also, let's create a Rect to store the size of the map. That will come in handy soon:

playerrect = PLAYER.get_rect(top=50, left=50)
mapsize = pygame.rect.Rect(0, 0, MAPWIDTH*TILESIZE, MAPHEIGHT*TILESIZE)

现在,当按住键移动播放器时,我们可以简单地使用

Now, when keys are hold down to move the player, we can simply use

keys = pygame.key.get_pressed()

if keys[K_LEFT]:  playerrect.move_ip(-speed, 0)
if keys[K_RIGHT]: playerrect.move_ip(speed, 0)
if keys[K_UP]:    playerrect.move_ip(0, -speed)
if keys[K_DOWN]:  playerrect.move_ip(0, speed)

playerrect.clamp_ip(mapsize)

改变玩家的位置,playerrect.clamp_ip(mapsize)确保玩家永远不会离开地图.

to change the position of the player, and playerrect.clamp_ip(mapsize) makes sure that the player never leaves the map.

至于绘图,您应该先清除屏幕.要绘制图块,您必须为每个图块创建一个 Rect(也许稍后您可以创建它们并存储/重用它们).

As for drawing, you should clear the screen first. To draw the tiles, you have to create a Rect for each tile (maybe later you could create them once and store/reuse them).

DISPLAYSURF.fill(pygame.color.Color('Black'))
for row in range(MAPHEIGHT):
    for column in range(MAPWIDTH):
        DISPLAYSURF.blit(textures[tilemap[row][column]], camera.apply(pygame.rect.Rect((column*TILESIZE, row*TILESIZE), (TILESIZE, TILESIZE))))

DISPLAYSURF.blit(PLAYER, camera.apply(playerrect))
camera.update(playerrect)

这篇关于在 pygame 中使用滚动相机的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆