pygame - 为什么玩家的移动速度比镜头快?
pygame - Why player move faster than camera?
我正在学习pygame。我想让相机跟随玩家,让玩家一直在屏幕中间。即使我将相机移动到相同的矢量,播放器移动得更快并跑出屏幕。在此先感谢您提供的任何帮助。我发布了整个代码,但问题可能出在函数之一:player.move()、level.move_camera() 或 level.render().
import pygame
from pygame.math import Vector2
#####SETTINGS#####
HEIGHT = 1080
WIDTH = 1920
TICKRATE = 60
BLOCK_SIZE = 60
GRAVITY = 18
##################
class Level():
def __init__(self, file):
self.file = file
self.blocks = [] # list of tills
self.map = self.load_from_file()
self.camera_position = Vector2(WIDTH / 2, 0)
# loading map
def load_from_file(self):
map = []
file = open(self.file + '.txt', 'r')
data = file.read()
file.close()
data = data.split('\n')
for x in data:
map.append(list(x))
return map
def move_camera(self, player):
self.camera_position.x += player.shift.x
def render(self, screen):
self.blocks = []
y = 0
for row in self.map:
x = 0
for block in row:
if block != '0':
self.blocks.append(pygame.Rect(x * BLOCK_SIZE - self.camera_position.x, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE))
if block == '1':
pygame.draw.rect(screen, (56,24,0), (x * BLOCK_SIZE - self.camera_position.x, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE))
elif block == '2':
pygame.draw.rect(screen, (18,115,81), (x * BLOCK_SIZE - self.camera_position.x, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE))
x += 1
y += 1
class Player():
def __init__(self, x, y, color):
self.position = Vector2(x, y)
self.shift = Vector2(0, 0)
self.jump = Vector2(0, 0)
self.color = color
self.rect = pygame.Rect(x, y, BLOCK_SIZE, BLOCK_SIZE)
self.go_left = False
self.go_right = False
self.go_up = False
self.collisions = {'left' : False, 'right' : False, 'top' : False, 'bottom' : False}
# moving the player object
def move(self, level):
self.shift = Vector2(0, GRAVITY)
self.position.y = int(self.position.y)
# left / right section
if self.go_left:
self.go_left = False
self.collisions = test_collisions(pygame.Rect(self.position.x - 1, self.position.y, BLOCK_SIZE, BLOCK_SIZE), level.blocks)
if not self.collisions['left']:
self.shift += Vector2(-10, 0)
if self.go_right:
self.go_right = False
self.collisions = test_collisions(pygame.Rect(self.position.x + 1, self.position.y, BLOCK_SIZE, BLOCK_SIZE), level.blocks)
if not self.collisions['right']:
self.shift += Vector2(10, 0)
# gravity section
self.collisions = test_collisions(pygame.Rect(self.position.x, self.position.y + GRAVITY, BLOCK_SIZE, BLOCK_SIZE), level.blocks)
if self.collisions['bottom']:
self.shift -= Vector2(0, GRAVITY)
if self.position.y % BLOCK_SIZE > 0:
self.position.y += BLOCK_SIZE - (self.position.y % BLOCK_SIZE)
# jump section
if self.go_up:
self.go_up = False
self.collisions = test_collisions(pygame.Rect(self.position.x, self.position.y + GRAVITY, BLOCK_SIZE, BLOCK_SIZE), level.blocks)
if self.collisions['bottom']:
self.jump = Vector2(0, -80)
self.collisions = test_collisions(pygame.Rect(self.position.x, self.position.y - 1, BLOCK_SIZE, BLOCK_SIZE), level.blocks)
if self.jump.y > GRAVITY or self.collisions['top']:
self.jump = Vector2(0, 0)
else:
self.jump *= 0.9
self.shift += self.jump
# new position
self.position += self.shift
self.rect = pygame.Rect(self.position.x, self.position.y, BLOCK_SIZE, BLOCK_SIZE)
# checking if player is death
def check_death(self):
if self.position.y > HEIGHT:
new_game()
# render player
def render(self, screen):
pygame.draw.rect(screen, self.color, self.rect)
# render section
def render(screen, player, level):
screen.fill((49, 113, 181))
level.render(screen)
player.render(screen)
pygame.display.update()
# keyboard handling
def handle_events(player):
for event in pygame.event.get():
if event.type == pygame.QUIT or event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
run = False
pygame.quit()
keys = pygame.key.get_pressed()
if keys[pygame.K_a] or keys[pygame.K_LEFT]:
player.go_left = True
if keys[pygame.K_d] or keys[pygame.K_RIGHT]:
player.go_right = True
if keys[pygame.K_w] or keys[pygame.K_UP] or keys[pygame.K_SPACE]:
player.go_up = True
# test direction of collison (rects have to overlap)
def test_collisions(object, rects):
collisions = {'left' : False, 'right' : False, 'top' : False, 'bottom' : False}
for rect in rects:
if object.colliderect(rect):
if object.x <= rect.x:
collisions['right'] = True
if object.x >= rect.x:
collisions['left'] = True
if object.y >= rect.y:
collisions['top'] = True
if object.y <= rect.y:
collisions['bottom'] = True
return(collisions)
# game loop
def main_loop(run, screen, level, player):
clock = pygame.time.Clock()
while run:
clock.tick(TICKRATE)
handle_events(player)
player.move(level)
player.check_death()
level.move_camera(player)
render(screen, player, level)
# init new game
def new_game():
run = True
screen = pygame.display.set_mode((WIDTH, HEIGHT))
level = Level('assets/level_two')
level.camera_position = Vector2(0, 0)
player = Player(WIDTH / 2, 0, (255,255,0))
main_loop(run, screen, level, player)
# launch new game on start
if __name__ == "__main__":
new_game()
你没有考虑玩家自身的移动,你只将它应用到方块上。为了让它始终位于中心,创建一个从玩家朝向中心的方向向量并将其添加到玩家位置,如下所示:
class Player():
#...
def move(self, level):
#...
#either this
self.position.x += ((WIDTH / 2) - self.position.x)
#or if you want a camera following with a delay effect
delay = 5
self.position.x += ((WIDTH / 2) - self.position.x) / delay
我正在学习pygame。我想让相机跟随玩家,让玩家一直在屏幕中间。即使我将相机移动到相同的矢量,播放器移动得更快并跑出屏幕。在此先感谢您提供的任何帮助。我发布了整个代码,但问题可能出在函数之一:player.move()、level.move_camera() 或 level.render().
import pygame
from pygame.math import Vector2
#####SETTINGS#####
HEIGHT = 1080
WIDTH = 1920
TICKRATE = 60
BLOCK_SIZE = 60
GRAVITY = 18
##################
class Level():
def __init__(self, file):
self.file = file
self.blocks = [] # list of tills
self.map = self.load_from_file()
self.camera_position = Vector2(WIDTH / 2, 0)
# loading map
def load_from_file(self):
map = []
file = open(self.file + '.txt', 'r')
data = file.read()
file.close()
data = data.split('\n')
for x in data:
map.append(list(x))
return map
def move_camera(self, player):
self.camera_position.x += player.shift.x
def render(self, screen):
self.blocks = []
y = 0
for row in self.map:
x = 0
for block in row:
if block != '0':
self.blocks.append(pygame.Rect(x * BLOCK_SIZE - self.camera_position.x, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE))
if block == '1':
pygame.draw.rect(screen, (56,24,0), (x * BLOCK_SIZE - self.camera_position.x, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE))
elif block == '2':
pygame.draw.rect(screen, (18,115,81), (x * BLOCK_SIZE - self.camera_position.x, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE))
x += 1
y += 1
class Player():
def __init__(self, x, y, color):
self.position = Vector2(x, y)
self.shift = Vector2(0, 0)
self.jump = Vector2(0, 0)
self.color = color
self.rect = pygame.Rect(x, y, BLOCK_SIZE, BLOCK_SIZE)
self.go_left = False
self.go_right = False
self.go_up = False
self.collisions = {'left' : False, 'right' : False, 'top' : False, 'bottom' : False}
# moving the player object
def move(self, level):
self.shift = Vector2(0, GRAVITY)
self.position.y = int(self.position.y)
# left / right section
if self.go_left:
self.go_left = False
self.collisions = test_collisions(pygame.Rect(self.position.x - 1, self.position.y, BLOCK_SIZE, BLOCK_SIZE), level.blocks)
if not self.collisions['left']:
self.shift += Vector2(-10, 0)
if self.go_right:
self.go_right = False
self.collisions = test_collisions(pygame.Rect(self.position.x + 1, self.position.y, BLOCK_SIZE, BLOCK_SIZE), level.blocks)
if not self.collisions['right']:
self.shift += Vector2(10, 0)
# gravity section
self.collisions = test_collisions(pygame.Rect(self.position.x, self.position.y + GRAVITY, BLOCK_SIZE, BLOCK_SIZE), level.blocks)
if self.collisions['bottom']:
self.shift -= Vector2(0, GRAVITY)
if self.position.y % BLOCK_SIZE > 0:
self.position.y += BLOCK_SIZE - (self.position.y % BLOCK_SIZE)
# jump section
if self.go_up:
self.go_up = False
self.collisions = test_collisions(pygame.Rect(self.position.x, self.position.y + GRAVITY, BLOCK_SIZE, BLOCK_SIZE), level.blocks)
if self.collisions['bottom']:
self.jump = Vector2(0, -80)
self.collisions = test_collisions(pygame.Rect(self.position.x, self.position.y - 1, BLOCK_SIZE, BLOCK_SIZE), level.blocks)
if self.jump.y > GRAVITY or self.collisions['top']:
self.jump = Vector2(0, 0)
else:
self.jump *= 0.9
self.shift += self.jump
# new position
self.position += self.shift
self.rect = pygame.Rect(self.position.x, self.position.y, BLOCK_SIZE, BLOCK_SIZE)
# checking if player is death
def check_death(self):
if self.position.y > HEIGHT:
new_game()
# render player
def render(self, screen):
pygame.draw.rect(screen, self.color, self.rect)
# render section
def render(screen, player, level):
screen.fill((49, 113, 181))
level.render(screen)
player.render(screen)
pygame.display.update()
# keyboard handling
def handle_events(player):
for event in pygame.event.get():
if event.type == pygame.QUIT or event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
run = False
pygame.quit()
keys = pygame.key.get_pressed()
if keys[pygame.K_a] or keys[pygame.K_LEFT]:
player.go_left = True
if keys[pygame.K_d] or keys[pygame.K_RIGHT]:
player.go_right = True
if keys[pygame.K_w] or keys[pygame.K_UP] or keys[pygame.K_SPACE]:
player.go_up = True
# test direction of collison (rects have to overlap)
def test_collisions(object, rects):
collisions = {'left' : False, 'right' : False, 'top' : False, 'bottom' : False}
for rect in rects:
if object.colliderect(rect):
if object.x <= rect.x:
collisions['right'] = True
if object.x >= rect.x:
collisions['left'] = True
if object.y >= rect.y:
collisions['top'] = True
if object.y <= rect.y:
collisions['bottom'] = True
return(collisions)
# game loop
def main_loop(run, screen, level, player):
clock = pygame.time.Clock()
while run:
clock.tick(TICKRATE)
handle_events(player)
player.move(level)
player.check_death()
level.move_camera(player)
render(screen, player, level)
# init new game
def new_game():
run = True
screen = pygame.display.set_mode((WIDTH, HEIGHT))
level = Level('assets/level_two')
level.camera_position = Vector2(0, 0)
player = Player(WIDTH / 2, 0, (255,255,0))
main_loop(run, screen, level, player)
# launch new game on start
if __name__ == "__main__":
new_game()
你没有考虑玩家自身的移动,你只将它应用到方块上。为了让它始终位于中心,创建一个从玩家朝向中心的方向向量并将其添加到玩家位置,如下所示:
class Player():
#...
def move(self, level):
#...
#either this
self.position.x += ((WIDTH / 2) - self.position.x)
#or if you want a camera following with a delay effect
delay = 5
self.position.x += ((WIDTH / 2) - self.position.x) / delay