所以我在pygame中编写了一个小平台游戏,在那里你可以放置块并在其中跳转...但是,游戏仅限于窗口的边界(显然)。那么我怎么能添加一个用A和D键滚动“相机”的方法呢?
以下是游戏的代码:
import pygame,random
from pygame.locals import *
from collections import namedtuple
pygame.init()
clock=pygame.time.Clock()
screen=pygame.display.set_mode((640,480))
pygame.display.set_caption("PiBlocks | By Sam Tubb")
max_gravity = 100
blocksel="texture\\dirt.png"
curs = pygame.image.load("texture\\cursor.png").convert()
curs.set_colorkey((0,255,0))
class Block(object):
def __init__(self,x,y,sprite):
self.sprite = pygame.image.load(sprite).convert_alpha()
self.rect = self.sprite.get_rect(centery=y, centerx=x)
class Player(object):
sprite = pygame.image.load("texture\\playr.png").convert()
sprite.set_colorkey((0,255,0))
def __init__(self, x, y):
self.rect = self.sprite.get_rect(centery=y, centerx=x)
# indicates that we are standing on the ground
# and thus are "allowed" to jump
self.on_ground = True
self.xvel = 0
self.yvel = 0
self.jump_speed = 7
self.move_speed = 3
def update(self, move, blocks):
# check if we can jump
if move.up and self.on_ground:
self.yvel -= self.jump_speed
# simple left/right movement
if move.left: self.xvel = -self.move_speed
if move.right: self.xvel = self.move_speed
# if in the air, fall down
if not self.on_ground:
self.yvel += 0.3
# but not too fast
if self.yvel > max_gravity: self.yvel = max_gravity
# if no left/right movement, x speed is 0, of course
if not (move.left or move.right):
self.xvel = 0
# move horizontal, and check for horizontal collisions
self.rect.left += self.xvel
self.collide(self.xvel, 0, blocks)
# move vertically, and check for vertical collisions
self.rect.top += self.yvel
self.on_ground = False;
self.collide(0, self.yvel, blocks)
def collide(self, xvel, yvel, blocks):
# all blocks that we collide with
for block in [blocks[i] for i in self.rect.collidelistall(blocks)]:
# if xvel is > 0, we know our right side bumped
# into the left side of a block etc.
if xvel > 0: self.rect.right = block.rect.left
if xvel < 0: self.rect.left = block.rect.right
# if yvel > 0, we are falling, so if a collision happpens
# we know we hit the ground (remember, we seperated checking for
# horizontal and vertical collision, so if yvel != 0, xvel is 0)
if yvel > 0:
self.rect.bottom = block.rect.top
self.on_ground = True
self.yvel = 0
# if yvel < 0 and a collision occurs, we bumped our head
# on a block above us
if yvel < 0: self.rect.top = block.rect.bottom
colliding = False
Move = namedtuple('Move', ['up', 'left', 'right'])
player=[]
blocklist=[]
font=pygame.font.Font(None,20)
while True:
screen.fill((25,30,90))
mse = pygame.mouse.get_pos()
key = pygame.key.get_pressed()
if key[K_1]:
blocksel="texture\\dirt.png"
if key[K_2]:
blocksel="texture\\stonetile.png"
if key[K_3]:
blocksel="texture\\sand.png"
if key[K_ESCAPE]:
exit()
for event in pygame.event.get():
if event.type == QUIT:
exit()
if key[K_LSHIFT]:
if event.type==MOUSEMOTION:
if not any(block.rect.collidepoint(mse) for block in blocklist):
x=(int(mse[0]) / 32)*32
y=(int(mse[1]) / 32)*32
blocklist.append(Block(x+16,y+16,blocksel))
else:
if event.type == pygame.MOUSEBUTTONUP:
if event.button == 1:
to_remove = [b for b in blocklist if b.rect.collidepoint(mse)]
for b in to_remove:
blocklist.remove(b)
if not to_remove:
x=(int(mse[0]) / 32)*32
y=(int(mse[1]) / 32)*32
blocklist.append(Block(x+16,y+16,blocksel))
elif event.button == 3:
x=(int(mse[0]) / 32)*32
y=(int(mse[1]) / 32)*32
player=Player(x+16,y+16)
move = Move(key[K_UP], key[K_LEFT], key[K_RIGHT])
for b in blocklist:
screen.blit(b.sprite, b.rect)
if player:
player.update(move, blocklist)
screen.blit(player.sprite, player.rect)
x=(int(mse[0]) / 32)*32
y=(int(mse[1]) / 32)*32
screen.blit(curs,(x,y))
clock.tick(60)
x=blocksel.replace('texture\\','')
x=x.replace('.png','')
words=font.render('Selected Block: '+str(x), True, (255,255,255))
screen.blit(words,(1,1))
pygame.display.flip()
感谢任何帮助:)
答案 0 :(得分:5)
为了拥有滚动相机,您必须区分屏幕坐标和世界坐标。
在此图中,屏幕轮廓(和屏幕坐标)以红色显示。世界坐标为黑色。虚线箭头显示屏幕原点与世界原点的偏移(相机矢量或相机位置)。
在绘制对象时,您需要从世界坐标转换为屏幕坐标(相机变换),并将屏幕坐标转换回世界坐标(逆相机变换)计算鼠标指向哪个块时。
在二维中,这些变换很简单:摄像机变换是#34;世界坐标减去摄像机位置&#34;,逆摄像机变换是&#34;屏幕坐标加摄像机位置&#34;。 / p>
如果您对代码的更一般性评论感兴趣,可以考虑将代码发布到Code Review(当您认为代码与您的代码一样好时)。< / p>
我发现的一些问题的快速说明:
每次创建新块时都会加载纹理并生成精灵。这似乎有点浪费:为什么不加载每个纹理一次并多次使用精灵?
玩家无法控制跳跃的高度。值得仔细观察超级马里奥世界等经典平台游戏,看看跳跃是如何运作的。
速度以每帧像素数表示,这意味着您无法改变帧速率。考虑以每秒像素数表示速度并乘以时间步长。
变量max_gravity
命名不佳:它是玩家的终端向下速度。 (另外,由于它是常量,您可能希望将其命名为大写。)
有许多重复的代码可以转换为函数或方法。例如,代码如下:
x=(int(mse[0]) / 32)*32
y=(int(mse[1]) / 32)*32
... x+16,y+16 ...
出现在四个地方。 (当您修改代码以添加摄像机位置时,这将成为逆摄像机变换。)
如果您为常量命名,这将使代码更容易理解,例如:
BACKGROUND_COLOR = 25, 30, 90
TEXT_COLOR = pygame.Color('white')
BLOCK_SIZE = 32, 32
SCREEN_SIZE = 640, 480
FRAMES_PER_SECOND = 60
答案 1 :(得分:3)
我所知道的最简单的方法是设置包含摄像机坐标的游戏变量(或单独的类)。这些作为绘制精灵的补偿。
因此,如果camera_x和camera_y是所谓的变量,您将更改所有screen.blit调用以包括偏移量 - 除了光标和UI文本,以及应该相对于屏幕原点定位的任何其他内容而不是世界。
为了移动相机,您可以使用与移动角色相同的方法。如果按下D键,设置关键处理以增加camera_x,并将其减少为A.请记住,如果使用正x轴表示屏幕空间,则应从blit调用中减去此偏移量(如果摄像机向右移动,则x增加,精灵在屏幕上向左移动。)